[DEBUG] correct miter/bevel/rount start cyclic path and some smal bugs
This commit is contained in:
parent
bbe79f971d
commit
462958f749
@ -239,13 +239,8 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
|
||||
}
|
||||
bool fillNone = false;
|
||||
bool strokeNone = false;
|
||||
std::string content = _element->getAttribute("fill");
|
||||
if (content.size()!=0) {
|
||||
m_paint.fill = parseColor(content);
|
||||
if (m_paint.fill.a() == 0) {
|
||||
fillNone = true;
|
||||
}
|
||||
}
|
||||
std::string content;
|
||||
// ---------------- stroke ----------------
|
||||
content = _element->getAttribute("stroke");
|
||||
if (content.size()!=0) {
|
||||
m_paint.stroke = parseColor(content);
|
||||
@ -257,31 +252,19 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
|
||||
if (content.size()!=0) {
|
||||
m_paint.strokeWidth = parseLength(content);
|
||||
}
|
||||
content = _element->getAttribute("opacity");
|
||||
if (content.size()!=0) {
|
||||
m_paint.opacity = parseLength(content);
|
||||
m_paint.opacity = std::avg(0.0f, m_paint.opacity, 1.0f);
|
||||
}
|
||||
content = _element->getAttribute("fill-opacity");
|
||||
if (content.size()!=0) {
|
||||
float opacity = parseLength(content);
|
||||
opacity = std::avg(0.0f, opacity, 1.0f);
|
||||
m_paint.fill.setA(opacity);
|
||||
}
|
||||
content = _element->getAttribute("stroke-opacity");
|
||||
if (content.size()!=0) {
|
||||
float opacity = parseLength(content);
|
||||
opacity = std::avg(0.0f, opacity, 1.0f);
|
||||
m_paint.stroke.setA(opacity);
|
||||
}
|
||||
content = _element->getAttribute("fill-rule");
|
||||
|
||||
content = _element->getAttribute("stroke-dasharray");
|
||||
if (content.size()!=0) {
|
||||
if (content == "nonzero") {
|
||||
m_paint.flagEvenOdd = false;
|
||||
} else if (content == "evenodd" ) {
|
||||
m_paint.flagEvenOdd = true;
|
||||
if (content == "none" ) {
|
||||
// OK, Nothing to do ...
|
||||
} else {
|
||||
SVG_ERROR("not know fill-rule value : \"" << content << "\", not in [nonzero,evenodd]");
|
||||
SVG_TODO(" 'stroke-dasharray' not implemented ...");
|
||||
}
|
||||
}
|
||||
content = _element->getAttribute("stroke-linecap");
|
||||
@ -315,6 +298,37 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
|
||||
float tmp = parseLength(content);
|
||||
m_paint.miterLimit = std::max(0.0f, tmp);
|
||||
}
|
||||
// ---------------- FILL ----------------
|
||||
content = _element->getAttribute("fill");
|
||||
if (content.size()!=0) {
|
||||
m_paint.fill = parseColor(content);
|
||||
if (m_paint.fill.a() == 0) {
|
||||
fillNone = true;
|
||||
}
|
||||
}
|
||||
content = _element->getAttribute("fill-opacity");
|
||||
if (content.size()!=0) {
|
||||
float opacity = parseLength(content);
|
||||
opacity = std::avg(0.0f, opacity, 1.0f);
|
||||
m_paint.fill.setA(opacity);
|
||||
}
|
||||
content = _element->getAttribute("fill-rule");
|
||||
if (content.size()!=0) {
|
||||
if (content == "nonzero") {
|
||||
m_paint.flagEvenOdd = false;
|
||||
} else if (content == "evenodd" ) {
|
||||
m_paint.flagEvenOdd = true;
|
||||
} else {
|
||||
SVG_ERROR("not know fill-rule value : \"" << content << "\", not in [nonzero,evenodd]");
|
||||
}
|
||||
}
|
||||
// ---------------- opacity ----------------
|
||||
content = _element->getAttribute("opacity");
|
||||
if (content.size()!=0) {
|
||||
m_paint.opacity = parseLength(content);
|
||||
m_paint.opacity = std::avg(0.0f, m_paint.opacity, 1.0f);
|
||||
}
|
||||
// ---------------- STYLE ----------------
|
||||
content = _element->getAttribute("style");
|
||||
if (content.size()!=0) {
|
||||
std::string outputType;
|
||||
@ -383,6 +397,12 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
|
||||
m_paint.lineJoin = esvg::join_miter;
|
||||
SVG_ERROR("not know " << outputType << " value : \"" << outputValue << "\", not in [miter,round,bevel]");
|
||||
}
|
||||
} else if (outputType == "stroke-dasharray") {
|
||||
if (outputValue == "none") {
|
||||
// OK, Nothing to do ...
|
||||
} else {
|
||||
SVG_TODO(" 'stroke-dasharray' not implemented ...");
|
||||
}
|
||||
} else if (outputType == "stroke-miterlimit") {
|
||||
float tmp = parseLength(outputValue);
|
||||
m_paint.miterLimit = std::max(0.0f, tmp);
|
||||
@ -394,11 +414,11 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
|
||||
}
|
||||
}
|
||||
// check if somewere none is set to the filling:
|
||||
if (true == fillNone) {
|
||||
m_paint.fill.setA(0);
|
||||
if (fillNone == true) {
|
||||
m_paint.fill.setA(0.0f);
|
||||
}
|
||||
if (true == strokeNone) {
|
||||
m_paint.stroke.setA(0);
|
||||
if (strokeNone == true) {
|
||||
m_paint.stroke.setA(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ esvg::Renderer::Renderer(const ivec2& _size, bool _visualDebug) :
|
||||
m_nbSubScanLine(8) {
|
||||
#ifdef DEBUG
|
||||
if (m_visualDebug == true) {
|
||||
m_factor = 10;
|
||||
m_factor = 20;
|
||||
}
|
||||
#endif
|
||||
setSize(_size);
|
||||
|
@ -157,8 +157,11 @@ esvg::render::PointList esvg::render::Path::generateListPoints(int32_t _level, i
|
||||
// find the previous tart of the path ...
|
||||
tmpListPoint.front().m_type = esvg::render::Point::type_join;
|
||||
// Remove the last point if it is the same position...
|
||||
if (tmpListPoint.front().m_pos == tmpListPoint.back().m_pos) {
|
||||
vec2 delta = (tmpListPoint.front().m_pos - tmpListPoint.back().m_pos).absolute();
|
||||
if ( delta.x() <= 0.00001
|
||||
&& delta.y() <= 0.00001) {
|
||||
tmpListPoint.pop_back();
|
||||
SVG_VERBOSE(" Remove point Z property : " << tmpListPoint.back().m_pos << " with delta=" << delta);
|
||||
}
|
||||
out.addList(tmpListPoint);
|
||||
tmpListPoint.clear();
|
||||
|
@ -189,17 +189,59 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
|
||||
vec2 rightPoint(0,0);
|
||||
if (itListPoint.size() > 0) {
|
||||
if (itListPoint.front().m_type == esvg::render::Point::type_join) {
|
||||
const esvg::render::Point& it = itListPoint.back();
|
||||
// Calculate the perpendiculary axis ...
|
||||
leftPoint = itListPoint.back().m_pos
|
||||
+ itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||
rightPoint = itListPoint.back().m_pos
|
||||
- itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||
// cyclic path...
|
||||
if ( itListPoint.back().m_type == esvg::render::Point::type_join
|
||||
|| itListPoint.back().m_type == esvg::render::Point::type_interpolation) {
|
||||
if (it.m_type == esvg::render::Point::type_interpolation) {
|
||||
leftPoint = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
rightPoint = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
} else if (it.m_type == esvg::render::Point::type_join) {
|
||||
// Calculate the perpendiculary axis ...
|
||||
leftPoint = itListPoint.back().m_pos
|
||||
+ itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||
rightPoint = itListPoint.back().m_pos
|
||||
- itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||
leftPoint = it.m_pos
|
||||
+ it.m_orthoAxePrevious*_width*0.5f;
|
||||
rightPoint = it.m_pos
|
||||
- it.m_orthoAxePrevious*_width*0.5f;
|
||||
// project on the miter Axis ...
|
||||
leftPoint = getIntersect(leftPoint, itListPoint.back().m_pos-itListPoint.back().m_posPrevious, itListPoint.back().m_pos, itListPoint.back().m_miterAxe);
|
||||
rightPoint = getIntersect(rightPoint, itListPoint.back().m_pos-itListPoint.back().m_posPrevious, itListPoint.back().m_pos, itListPoint.back().m_miterAxe);
|
||||
switch (_join) {
|
||||
case esvg::join_miter:
|
||||
{
|
||||
vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
// Check the miter limit:
|
||||
float limitRight = (left - it.m_pos).length() / _width * 2.0f;
|
||||
float limitLeft = (right - it.m_pos).length() / _width * 2.0f;
|
||||
SVG_VERBOSE(" miter Limit: " << limitRight << " " << limitLeft << " <= " << _miterLimit);
|
||||
if ( limitRight <= _miterLimit
|
||||
&& limitLeft <= _miterLimit) {
|
||||
leftPoint = left;
|
||||
rightPoint = right;
|
||||
break;
|
||||
} else {
|
||||
// BEVEL the miter point ...
|
||||
}
|
||||
}
|
||||
case esvg::join_round:
|
||||
case esvg::join_bevel:
|
||||
{
|
||||
vec2 axePrevious = (it.m_pos-it.m_posPrevious).safeNormalize();
|
||||
vec2 axeNext = (it.m_posNext - it.m_pos).safeNormalize();
|
||||
float cross = axePrevious.cross(axeNext);
|
||||
if (cross > 0.0f) {
|
||||
rightPoint = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
leftPoint = it.m_pos
|
||||
+ it.m_orthoAxeNext*_width*0.5f;
|
||||
} else {
|
||||
leftPoint = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
||||
rightPoint = it.m_pos
|
||||
- it.m_orthoAxeNext*_width*0.5f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SVG_ERROR("Start list point with a join, but last lement is not a join");
|
||||
}
|
||||
|
@ -146,6 +146,31 @@ TEST(TestJoin, miterLimit4) {
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLimit4.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestJoin, miterCornerCasePath) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
|
||||
"<svg height='100' width='100'>"
|
||||
" <path"
|
||||
" d='m 37.984608,9.9629707 c 6.211703,0 12.423406,0 18.635109,0 0,2.5633883 0,5.1267763 0,7.6901643 -6.211703,0 -12.423406,0 -18.635109,0 0,-2.563388 0,-5.126776 0,-7.6901643 z'\n"
|
||||
" stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter'/>"
|
||||
"</svg>");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestJoin_miterCornerCasePath.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterCornerCasePath.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestJoin, miterCornerCasePathLimit) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
|
||||
"<svg height='100' width='100'>"
|
||||
" <path"
|
||||
" d='m 37.984608,9.9629707 c 6.211703,0 12.423406,0 18.635109,0 0,2.5633883 0,5.1267763 0,7.6901643 -6.211703,0 -12.423406,0 -18.635109,0 0,-2.563388 0,-5.126776 0,-7.6901643 z'\n"
|
||||
" stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter' stroke-miterlimit='0.3'/>"
|
||||
"</svg>");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestJoin_miterCornerCasePathLimit.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterCornerCasePathLimit.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------ Round test -----------------------------------------------------
|
||||
|
||||
@ -237,6 +262,19 @@ TEST(TestJoin, roundLeft4) {
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft4.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestJoin, roundCornerCasePath) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
|
||||
"<svg height='100' width='100'>"
|
||||
" <path"
|
||||
" d='m 37.984608,9.9629707 c 6.211703,0 12.423406,0 18.635109,0 0,2.5633883 0,5.1267763 0,7.6901643 -6.211703,0 -12.423406,0 -18.635109,0 0,-2.563388 0,-5.126776 0,-7.6901643 z'\n"
|
||||
" stroke='green' stroke-width='5' fill='orange' stroke-linejoin='round'/>"
|
||||
"</svg>");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestJoin_roundCornerCasePath.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundCornerCasePath.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Bevel test -----------------------------------------------------
|
||||
|
||||
@ -328,3 +366,15 @@ TEST(TestJoin, bevelLeft4) {
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft4.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestJoin, bevelCornerCasePath) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
|
||||
"<svg height='100' width='100'>"
|
||||
" <path"
|
||||
" d='m 37.984608,9.9629707 c 6.211703,0 12.423406,0 18.635109,0 0,2.5633883 0,5.1267763 0,7.6901643 -6.211703,0 -12.423406,0 -18.635109,0 0,-2.563388 0,-5.126776 0,-7.6901643 z'\n"
|
||||
" stroke='green' stroke-width='5' fill='orange' stroke-linejoin='bevel'/>"
|
||||
"</svg>");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestJoin_bevelCornerCasePath.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelCornerCasePath.bmp", g_visualDebug);
|
||||
}
|
||||
|
@ -107,3 +107,21 @@ TEST(TestPath, arc) {
|
||||
// TODO : ...
|
||||
EXPECT_EQ(1, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TEST(TestPath, end_path_border_case) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
|
||||
"<svg height='100' width='100'>"
|
||||
" <path\n"
|
||||
" style='fill:#9fecff;fill-opacity:1;stroke:#1b57df;stroke-width:8.81125546;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94901961'\n"
|
||||
" d='M 83.073072,55.099829 C 83.886712,33.687876 60.475404,16.478179 40.263655,23.556532 19.565051,29.111554 9.9926694,56.534855 22.756336,73.74319 c 11.428293,18.124001 40.474216,19.151787 53.156943,1.880953 4.612608,-5.778118 7.177805,-13.13422 7.159793,-20.524314 z'\n"
|
||||
" id='path3421'\n"
|
||||
" inkscape:connector-curvature='0' />\n"
|
||||
"</svg>");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPath_end_path_border_case.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_end_path_border_case.bmp", g_visualDebug);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user