[DEV] Create correct join_roind and factorize rounding and add miter-limit

This commit is contained in:
Edouard DUPIN 2015-12-01 21:27:52 +01:00
parent 9b7a8a6d5a
commit ef8d2a889e
13 changed files with 415 additions and 85 deletions

View File

@ -23,6 +23,7 @@ esvg::PaintState::PaintState() :
flagEvenOdd(false), flagEvenOdd(false),
lineCap(esvg::cap_butt), lineCap(esvg::cap_butt),
lineJoin(esvg::join_miter), lineJoin(esvg::join_miter),
miterLimit(4.0f),
viewPort(255,255), viewPort(255,255),
opacity(1.0) { opacity(1.0) {
@ -36,6 +37,7 @@ void esvg::PaintState::clear() {
flagEvenOdd = false; flagEvenOdd = false;
lineJoin = esvg::join_miter; lineJoin = esvg::join_miter;
lineCap = esvg::cap_butt; lineCap = esvg::cap_butt;
miterLimit = 4.0f;
opacity = 1.0; opacity = 1.0;
} }
@ -168,21 +170,29 @@ float esvg::Base::parseLength(const std::string& _dataInput) {
return n; return n;
} else if (unit[0] == '%') { // xxx % } else if (unit[0] == '%') { // xxx %
return n / 100.0 * m_paint.viewPort.x(); return n / 100.0 * m_paint.viewPort.x();
} else if (unit[0] == 'e' && unit[1] == 'm') { // xxx em } else if ( unit[0] == 'e'
&& unit[1] == 'm') { // xxx em
return n * font_size; return n * font_size;
} else if (unit[0] == 'e' && unit[1] == 'x') { // xxx ex } else if ( unit[0] == 'e'
&& unit[1] == 'x') { // xxx ex
return n / 2.0f * font_size; return n / 2.0f * font_size;
} else if (unit[0] == 'p' && unit[1] == 'x') { // xxx px } else if ( unit[0] == 'p'
&& unit[1] == 'x') { // xxx px
return n; return n;
} else if (unit[0] == 'p' && unit[1] == 't') { // xxx pt } else if ( unit[0] == 'p'
&& unit[1] == 't') { // xxx pt
return n * 1.25f; return n * 1.25f;
} else if (unit[0] == 'p' && unit[1] == 'c') { // xxx pc } else if ( unit[0] == 'p'
&& unit[1] == 'c') { // xxx pc
return n * 15.0f; return n * 15.0f;
} else if (unit[0] == 'm' && unit[1] == 'm') { // xxx mm } else if ( unit[0] == 'm'
&& unit[1] == 'm') { // xxx mm
return n * 3.543307f; return n * 3.543307f;
} else if (unit[0] == 'c' && unit[1] == 'm') { // xxx cm } else if ( unit[0] == 'c'
&& unit[1] == 'm') { // xxx cm
return n * 35.43307f; return n * 35.43307f;
} else if (unit[0] == 'i' && unit[1] == 'n') { // xxx in } else if ( unit[0] == 'i'
&& unit[1] == 'n') { // xxx in
return n * 90.0f; return n * 90.0f;
} }
return 0.0f; return 0.0f;
@ -255,13 +265,13 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
content = _element->getAttribute("fill-opacity"); content = _element->getAttribute("fill-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.fill.setA(opacity*0xFF); m_paint.fill.setA(opacity*0xFF);
} }
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*0xFF); m_paint.stroke.setA(opacity*0xFF);
} }
content = _element->getAttribute("fill-rule"); content = _element->getAttribute("fill-rule");
@ -300,6 +310,11 @@ void esvg::Base::parsePaintAttr(const std::shared_ptr<const exml::Element>& _ele
SVG_ERROR("not know stroke-linejoin value : \"" << content << "\", not in [miter,round,bevel]"); SVG_ERROR("not know stroke-linejoin value : \"" << content << "\", not in [miter,round,bevel]");
} }
} }
content = _element->getAttribute("stroke-miterlimit");
if (content.size()!=0) {
float tmp = parseLength(content);
m_paint.miterLimit = std::max(0.0f, tmp);
}
content = _element->getAttribute("style"); content = _element->getAttribute("style");
if (content.size()!=0) { if (content.size()!=0) {
std::string outputType; std::string outputType;

View File

@ -53,6 +53,7 @@ namespace esvg {
bool flagEvenOdd; //!< Fill rules bool flagEvenOdd; //!< Fill rules
enum esvg::cap lineCap; enum esvg::cap lineCap;
enum esvg::join lineJoin; enum esvg::join lineJoin;
float miterLimit;
vec2 viewPort; vec2 viewPort;
float opacity; float opacity;
}; };

View File

@ -115,7 +115,8 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -120,7 +120,8 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -88,7 +88,8 @@ void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -282,7 +282,8 @@ void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke); tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke);
} }

View File

@ -101,7 +101,8 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -98,7 +98,8 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -115,7 +115,8 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32
listSegmentStroke.createSegmentListStroke(listPoints, listSegmentStroke.createSegmentListStroke(listPoints,
m_paint.strokeWidth, m_paint.strokeWidth,
m_paint.lineCap, m_paint.lineCap,
m_paint.lineJoin); m_paint.lineJoin,
m_paint.miterLimit);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(), _myRenderer.getNumberSubScanLine(),

View File

@ -24,9 +24,11 @@ esvg::Renderer::Renderer(const ivec2& _size, bool _visualDebug) :
m_interpolationRecurtionMax(10), m_interpolationRecurtionMax(10),
m_interpolationThreshold(0.25f), m_interpolationThreshold(0.25f),
m_nbSubScanLine(8) { m_nbSubScanLine(8) {
if (m_visualDebug == true) { #ifdef DEBUG
m_factor = 10; if (m_visualDebug == true) {
} m_factor = 10;
}
#endif
setSize(_size); setSize(_size);
} }

View File

@ -56,10 +56,54 @@ static vec2 getIntersect(const vec2& _point1,
return _point2; return _point2;
} }
void esvg::render::SegmentList::createSegmentListStroke(const vec2& _point1,
const vec2& _point2,
const vec2& _center,
float _width,
bool _isStart) {
int32_t nbDot = int32_t(_width);
if (nbDot <= 2) {
nbDot = 2;
}
float angleToDraw = acos((_point1 - _center).safeNormalize().dot((_point2 - _center).safeNormalize()));
float baseAngle = angleToDraw/float(nbDot);
float iii;
vec2 axe = (_point1 - _center).safeNormalize();
vec2 ppp1(_point1);
vec2 ppp2(_point2);
for (iii=baseAngle; iii<angleToDraw; iii+=baseAngle) {
mat2 tmpMat;
if (_isStart == true) {
tmpMat = etk::mat2Rotate(-iii);
} else {
tmpMat = etk::mat2Rotate(iii);
}
vec2 axeRotate = tmpMat * axe;
ppp2 = _center
+ axeRotate*_width*0.5f;
if (_isStart == true) {
addSegment(ppp2, ppp1);
SVG_VERBOSE(" segment :" << ppp2 << " -> " << ppp1);
} else {
addSegment(ppp1, ppp2);
SVG_VERBOSE(" segment :" << ppp1 << " -> " << ppp2);
}
ppp1 = ppp2;
}
if (_isStart == true) {
addSegment(_point2, ppp1);
SVG_VERBOSE(" segment :" << _point2 << " -> " << ppp1);
} else {
addSegment(ppp1, _point2);
SVG_VERBOSE(" segment :" << ppp1 << " -> " << _point2);
}
}
void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint, void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint,
float _width, float _width,
enum esvg::cap _cap, enum esvg::cap _cap,
enum esvg::join _join) { enum esvg::join _join,
float _miterLimit) {
for (auto &itListPoint : _listPoint.m_data) { for (auto &itListPoint : _listPoint.m_data) {
// generate for every point all the orthogonal elements // generate for every point all the orthogonal elements
// //
@ -136,7 +180,7 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
itListPoint[idCurrent].m_orthoAxePrevious = itListPoint[idCurrent].m_miterAxe; itListPoint[idCurrent].m_orthoAxePrevious = itListPoint[idCurrent].m_miterAxe;
itListPoint[idCurrent].m_orthoAxeNext = itListPoint[idCurrent].m_miterAxe; itListPoint[idCurrent].m_orthoAxeNext = itListPoint[idCurrent].m_miterAxe;
} else { } else {
SVG_TODO("lklklklklkl"); SVG_TODO("Unsupported type of point ....");
} }
} }
// create segment list: // create segment list:
@ -207,15 +251,25 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
{ {
vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe); 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); vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
//Draw from previous point: // Check the miter limit:
addSegment(leftPoint, left); float limitRight = (left - it.m_pos).length() / _width * 2.0f;
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left); float limitLeft = (right - it.m_pos).length() / _width * 2.0f;
addSegment(right, rightPoint); SVG_VERBOSE(" miter Limit: " << limitRight << " " << limitLeft << " <= " << _miterLimit);
SVG_VERBOSE(" segment :" << right << " -> " << rightPoint); if ( limitRight <= _miterLimit
leftPoint = left; && limitLeft <= _miterLimit) {
rightPoint = right; //Draw from previous point:
addSegment(leftPoint, left);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
addSegment(right, rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
leftPoint = left;
rightPoint = right;
break;
} else {
// We do a bevel join ...
SVG_VERBOSE(" Find miter Limit ... ==> create BEVEL");
}
} }
break;
case esvg::join_round: case esvg::join_round:
case esvg::join_bevel: case esvg::join_bevel:
{ {
@ -232,11 +286,16 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left1); addSegment(leftPoint, left1);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left1); SVG_VERBOSE(" segment :" << leftPoint << " -> " << left1);
if (_join == esvg::join_bevel) { if (_join != esvg::join_round) {
// Miter and bevel:
addSegment(left1, left2); addSegment(left1, left2);
SVG_VERBOSE(" segment :" << left1 << " -> " << left2); SVG_VERBOSE(" segment :" << left1 << " -> " << left2);
}else { }else {
createSegmentListStroke(left1,
left2,
it.m_pos,
_width,
false);
} }
addSegment(right, rightPoint); addSegment(right, rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << rightPoint); SVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
@ -252,11 +311,16 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left); SVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
addSegment(right1, rightPoint); addSegment(right1, rightPoint);
SVG_VERBOSE(" segment :" << right1 << " -> " << rightPoint); SVG_VERBOSE(" segment :" << right1 << " -> " << rightPoint);
if (_join == esvg::join_bevel) { if (_join != esvg::join_round) {
// Miter and bevel:
addSegment(right2, right1); addSegment(right2, right1);
SVG_VERBOSE(" segment :" << right2 << " -> " << right1); SVG_VERBOSE(" segment :" << right2 << " -> " << right1);
} else { } else {
createSegmentListStroke(right1,
right2,
it.m_pos,
_width,
true);
} }
leftPoint = left; leftPoint = left;
rightPoint = right2; rightPoint = right2;
@ -270,8 +334,6 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
} }
} }
void esvg::render::SegmentList::startStopPoint(vec2& _leftPoint, void esvg::render::SegmentList::startStopPoint(vec2& _leftPoint,
vec2& _rightPoint, vec2& _rightPoint,
const esvg::render::Point& _point, const esvg::render::Point& _point,
@ -326,38 +388,15 @@ void esvg::render::SegmentList::startStopPoint(vec2& _leftPoint,
} }
float baseAngle = M_PI/float(nbDot); float baseAngle = M_PI/float(nbDot);
float iii; float iii;
_rightPoint = _point.m_pos
- _point.m_miterAxe*_width*0.5f;
vec2 storeOld(_rightPoint);
for (iii=baseAngle; iii<M_PI; iii+=baseAngle) {
mat2 tmpMat;
if (_isStart == true) {
tmpMat = etk::mat2Rotate(iii);
} else {
tmpMat = etk::mat2Rotate(-iii);
}
vec2 miterRotate = tmpMat * _point.m_miterAxe;
_leftPoint = _point.m_pos
- miterRotate*_width*0.5f;
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
}
_rightPoint = _leftPoint;
}
_leftPoint = _point.m_pos _leftPoint = _point.m_pos
+ _point.m_miterAxe*_width*0.5f; + _point.m_miterAxe*_width*0.5f;
if (_isStart == false) { _rightPoint = _point.m_pos
addSegment(_leftPoint, _rightPoint); - _point.m_miterAxe*_width*0.5f;
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint); createSegmentListStroke(_leftPoint,
} else { _rightPoint,
addSegment(_rightPoint, _leftPoint); _point.m_pos,
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint); _width,
} _isStart);
_rightPoint = storeOld;
} }
break; break;
case esvg::cap_square: case esvg::cap_square:

View File

@ -28,7 +28,8 @@ namespace esvg {
void createSegmentListStroke(esvg::render::PointList& _listPoint, void createSegmentListStroke(esvg::render::PointList& _listPoint,
float _width, float _width,
enum esvg::cap _cap, enum esvg::cap _cap,
enum esvg::join _join); enum esvg::join _join,
float _miterLimit);
private: private:
void startStopPoint(vec2& _leftPoint, void startStopPoint(vec2& _leftPoint,
vec2& _rightPoint, vec2& _rightPoint,
@ -36,6 +37,11 @@ namespace esvg {
enum esvg::cap _cap, enum esvg::cap _cap,
float _width, float _width,
bool _isStart); bool _isStart);
void createSegmentListStroke(const vec2& _point1,
const vec2& _point2,
const vec2& _center,
float _width,
bool _isStart);
}; };
} }
} }

View File

@ -12,59 +12,319 @@
#undef __class__ #undef __class__
#define __class__ "TestLine" #define __class__ "TestLine"
// ------------------------------------------------------ Miter test -----------------------------------------------------
TEST(TestJoin, miter) { TEST(TestJoin, miterRight1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miter.svg", data); etk::FSNodeWriteAllData("TestJoin_miterRight1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miter.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestJoin_miterRight1.bmp", g_visualDebug);
} }
TEST(TestJoin, roundRight) { TEST(TestJoin, miterRight2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterRight2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterRight2.bmp", g_visualDebug);
}
TEST(TestJoin, miterRight3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterRight3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterRight3.bmp", g_visualDebug);
}
TEST(TestJoin, miterRight4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterRight4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterRight4.bmp", g_visualDebug);
}
TEST(TestJoin, miterLeft1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLeft1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLeft1.bmp", g_visualDebug);
}
TEST(TestJoin, miterLeft2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLeft2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLeft2.bmp", g_visualDebug);
}
TEST(TestJoin, miterLeft3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLeft3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLeft3.bmp", g_visualDebug);
}
TEST(TestJoin, miterLeft4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLeft4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLeft4.bmp", g_visualDebug);
}
TEST(TestJoin, miterLimit1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='10,10 25,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLimit1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLimit1.bmp", g_visualDebug);
}
TEST(TestJoin, miterLimit2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='10,10 50,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLimit2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLimit2.bmp", g_visualDebug);
}
TEST(TestJoin, miterLimit3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='10,10 75,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLimit3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLimit3.bmp", g_visualDebug);
}
TEST(TestJoin, miterLimit4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='10,10 90,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_miterLimit4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_miterLimit4.bmp", g_visualDebug);
}
// ------------------------------------------------------ Round test -----------------------------------------------------
TEST(TestJoin, roundRight1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundRight.svg", data); etk::FSNodeWriteAllData("TestJoin_roundRight1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundRight.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestJoin_roundRight1.bmp", g_visualDebug);
} }
TEST(TestJoin, roundLeft) { TEST(TestJoin, roundRight2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundRight2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundRight2.bmp", g_visualDebug);
}
TEST(TestJoin, roundRight3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundRight3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundRight3.bmp", g_visualDebug);
}
TEST(TestJoin, roundRight4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundRight4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundRight4.bmp", g_visualDebug);
}
TEST(TestJoin, roundLeft1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundLeft.svg", data); etk::FSNodeWriteAllData("TestJoin_roundLeft1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft1.bmp", g_visualDebug);
} }
TEST(TestJoin, bevelRight) { TEST(TestJoin, roundLeft2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundLeft2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft2.bmp", g_visualDebug);
}
TEST(TestJoin, roundLeft3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundLeft3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft3.bmp", g_visualDebug);
}
TEST(TestJoin, roundLeft4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_roundLeft4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_roundLeft4.bmp", g_visualDebug);
}
// ------------------------------------------------------ Bevel test -----------------------------------------------------
TEST(TestJoin, bevelRight1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelRight.svg", data); etk::FSNodeWriteAllData("TestJoin_bevelRight1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelRight.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelRight1.bmp", g_visualDebug);
} }
TEST(TestJoin, bevelRight2) {
TEST(TestJoin, bevelLeft) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='80,20 60,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelLeft.svg", data); etk::FSNodeWriteAllData("TestJoin_bevelRight2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelRight2.bmp", g_visualDebug);
} }
TEST(TestJoin, bevelRight3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelRight3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelRight3.bmp", g_visualDebug);
}
TEST(TestJoin, bevelRight4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelRight4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelRight4.bmp", g_visualDebug);
}
TEST(TestJoin, bevelLeft1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelLeft1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft1.bmp", g_visualDebug);
}
TEST(TestJoin, bevelLeft2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelLeft2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft2.bmp", g_visualDebug);
}
TEST(TestJoin, bevelLeft3) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelLeft3.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft3.bmp", g_visualDebug);
}
TEST(TestJoin, bevelLeft4) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestJoin_bevelLeft4.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestJoin_bevelLeft4.bmp", g_visualDebug);
}