[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 fillNone = false;
|
||||||
bool strokeNone = false;
|
bool strokeNone = false;
|
||||||
std::string content = _element->getAttribute("fill");
|
std::string content;
|
||||||
if (content.size()!=0) {
|
// ---------------- stroke ----------------
|
||||||
m_paint.fill = parseColor(content);
|
|
||||||
if (m_paint.fill.a() == 0) {
|
|
||||||
fillNone = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content = _element->getAttribute("stroke");
|
content = _element->getAttribute("stroke");
|
||||||
if (content.size()!=0) {
|
if (content.size()!=0) {
|
||||||
m_paint.stroke = parseColor(content);
|
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) {
|
if (content.size()!=0) {
|
||||||
m_paint.strokeWidth = parseLength(content);
|
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");
|
content = _element->getAttribute("stroke-opacity");
|
||||||
if (content.size()!=0) {
|
if (content.size()!=0) {
|
||||||
float opacity = parseLength(content);
|
float opacity = parseLength(content);
|
||||||
opacity = std::avg(0.0f, opacity, 1.0f);
|
opacity = std::avg(0.0f, opacity, 1.0f);
|
||||||
m_paint.stroke.setA(opacity);
|
m_paint.stroke.setA(opacity);
|
||||||
}
|
}
|
||||||
content = _element->getAttribute("fill-rule");
|
|
||||||
|
content = _element->getAttribute("stroke-dasharray");
|
||||||
if (content.size()!=0) {
|
if (content.size()!=0) {
|
||||||
if (content == "nonzero") {
|
if (content == "none" ) {
|
||||||
m_paint.flagEvenOdd = false;
|
// OK, Nothing to do ...
|
||||||
} else if (content == "evenodd" ) {
|
|
||||||
m_paint.flagEvenOdd = true;
|
|
||||||
} else {
|
} else {
|
||||||
SVG_ERROR("not know fill-rule value : \"" << content << "\", not in [nonzero,evenodd]");
|
SVG_TODO(" 'stroke-dasharray' not implemented ...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
content = _element->getAttribute("stroke-linecap");
|
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);
|
float tmp = parseLength(content);
|
||||||
m_paint.miterLimit = std::max(0.0f, tmp);
|
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");
|
content = _element->getAttribute("style");
|
||||||
if (content.size()!=0) {
|
if (content.size()!=0) {
|
||||||
std::string outputType;
|
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;
|
m_paint.lineJoin = esvg::join_miter;
|
||||||
SVG_ERROR("not know " << outputType << " value : \"" << outputValue << "\", not in [miter,round,bevel]");
|
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") {
|
} else if (outputType == "stroke-miterlimit") {
|
||||||
float tmp = parseLength(outputValue);
|
float tmp = parseLength(outputValue);
|
||||||
m_paint.miterLimit = std::max(0.0f, tmp);
|
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:
|
// check if somewere none is set to the filling:
|
||||||
if (true == fillNone) {
|
if (fillNone == true) {
|
||||||
m_paint.fill.setA(0);
|
m_paint.fill.setA(0.0f);
|
||||||
}
|
}
|
||||||
if (true == strokeNone) {
|
if (strokeNone == true) {
|
||||||
m_paint.stroke.setA(0);
|
m_paint.stroke.setA(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ esvg::Renderer::Renderer(const ivec2& _size, bool _visualDebug) :
|
|||||||
m_nbSubScanLine(8) {
|
m_nbSubScanLine(8) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (m_visualDebug == true) {
|
if (m_visualDebug == true) {
|
||||||
m_factor = 10;
|
m_factor = 20;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
setSize(_size);
|
setSize(_size);
|
||||||
|
@ -157,8 +157,11 @@ esvg::render::PointList esvg::render::Path::generateListPoints(int32_t _level, i
|
|||||||
// find the previous tart of the path ...
|
// find the previous tart of the path ...
|
||||||
tmpListPoint.front().m_type = esvg::render::Point::type_join;
|
tmpListPoint.front().m_type = esvg::render::Point::type_join;
|
||||||
// Remove the last point if it is the same position...
|
// 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();
|
tmpListPoint.pop_back();
|
||||||
|
SVG_VERBOSE(" Remove point Z property : " << tmpListPoint.back().m_pos << " with delta=" << delta);
|
||||||
}
|
}
|
||||||
out.addList(tmpListPoint);
|
out.addList(tmpListPoint);
|
||||||
tmpListPoint.clear();
|
tmpListPoint.clear();
|
||||||
|
@ -189,17 +189,59 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
|
|||||||
vec2 rightPoint(0,0);
|
vec2 rightPoint(0,0);
|
||||||
if (itListPoint.size() > 0) {
|
if (itListPoint.size() > 0) {
|
||||||
if (itListPoint.front().m_type == esvg::render::Point::type_join) {
|
if (itListPoint.front().m_type == esvg::render::Point::type_join) {
|
||||||
// cyclic path...
|
const esvg::render::Point& it = itListPoint.back();
|
||||||
if ( itListPoint.back().m_type == esvg::render::Point::type_join
|
|
||||||
|| itListPoint.back().m_type == esvg::render::Point::type_interpolation) {
|
|
||||||
// Calculate the perpendiculary axis ...
|
// Calculate the perpendiculary axis ...
|
||||||
leftPoint = itListPoint.back().m_pos
|
leftPoint = itListPoint.back().m_pos
|
||||||
+ itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
+ itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||||
rightPoint = itListPoint.back().m_pos
|
rightPoint = itListPoint.back().m_pos
|
||||||
- itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
- itListPoint.back().m_orthoAxePrevious*_width*0.5f;
|
||||||
|
// cyclic path...
|
||||||
|
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 = it.m_pos
|
||||||
|
+ it.m_orthoAxePrevious*_width*0.5f;
|
||||||
|
rightPoint = it.m_pos
|
||||||
|
- it.m_orthoAxePrevious*_width*0.5f;
|
||||||
// project on the miter Axis ...
|
// project on the miter Axis ...
|
||||||
leftPoint = getIntersect(leftPoint, itListPoint.back().m_pos-itListPoint.back().m_posPrevious, itListPoint.back().m_pos, itListPoint.back().m_miterAxe);
|
switch (_join) {
|
||||||
rightPoint = getIntersect(rightPoint, itListPoint.back().m_pos-itListPoint.back().m_posPrevious, itListPoint.back().m_pos, itListPoint.back().m_miterAxe);
|
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 {
|
} else {
|
||||||
SVG_ERROR("Start list point with a join, but last lement is not a join");
|
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);
|
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 -----------------------------------------------------
|
// ------------------------------------------------------ Round test -----------------------------------------------------
|
||||||
|
|
||||||
@ -237,6 +262,19 @@ TEST(TestJoin, roundLeft4) {
|
|||||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft4.bmp", g_visualDebug);
|
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 -----------------------------------------------------
|
// ------------------------------------------------------ Bevel test -----------------------------------------------------
|
||||||
|
|
||||||
@ -328,3 +366,15 @@ TEST(TestJoin, bevelLeft4) {
|
|||||||
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft4.bmp", g_visualDebug);
|
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 : ...
|
// TODO : ...
|
||||||
EXPECT_EQ(1, 2);
|
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