diff --git a/esvg/Circle.cpp b/esvg/Circle.cpp index 09a86ca..7f48b34 100644 --- a/esvg/Circle.cpp +++ b/esvg/Circle.cpp @@ -112,7 +112,10 @@ void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/Ellipse.cpp b/esvg/Ellipse.cpp index cce038e..8479e79 100644 --- a/esvg/Ellipse.cpp +++ b/esvg/Ellipse.cpp @@ -117,7 +117,10 @@ void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/Line.cpp b/esvg/Line.cpp index d18383a..75b0df9 100644 --- a/esvg/Line.cpp +++ b/esvg/Line.cpp @@ -85,7 +85,10 @@ void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/Path.cpp b/esvg/Path.cpp index af29588..010d2a4 100644 --- a/esvg/Path.cpp +++ b/esvg/Path.cpp @@ -279,7 +279,10 @@ void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t _l // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke); } diff --git a/esvg/Polygon.cpp b/esvg/Polygon.cpp index 2a927b3..cc6ee8b 100644 --- a/esvg/Polygon.cpp +++ b/esvg/Polygon.cpp @@ -98,7 +98,10 @@ void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_t // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/Polyline.cpp b/esvg/Polyline.cpp index dd442b1..cfd7a3a 100644 --- a/esvg/Polyline.cpp +++ b/esvg/Polyline.cpp @@ -95,7 +95,10 @@ void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32_ // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/Rectangle.cpp b/esvg/Rectangle.cpp index fb2c435..e3ef440 100644 --- a/esvg/Rectangle.cpp +++ b/esvg/Rectangle.cpp @@ -112,7 +112,10 @@ void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2& _basicTrans, int32 // check if we need to display stroke: if ( m_paint.strokeWidth > 0 && m_paint.stroke.a() != 0x00) { - listSegmentStroke.createSegmentListStroke(listPoints, m_paint.strokeWidth); + listSegmentStroke.createSegmentListStroke(listPoints, + m_paint.strokeWidth, + m_paint.lineCap, + m_paint.lineJoin); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), diff --git a/esvg/render/Point.h b/esvg/render/Point.h index 25ee595..485091c 100644 --- a/esvg/render/Point.h +++ b/esvg/render/Point.h @@ -28,6 +28,10 @@ namespace esvg { vec2 m_pos; //!< position of the point enum esvg::render::Point::type m_type; vec2 m_miterAxe; + vec2 m_orthoAxePrevious; + vec2 m_orthoAxeNext; + vec2 m_posPrevious; + vec2 m_posNext; vec2 m_delta; float m_len; Point(const vec2& _pos, enum esvg::render::Point::type _type = esvg::render::Point::type_join) : diff --git a/esvg/render/SegmentList.cpp b/esvg/render/SegmentList.cpp index fcbabb8..3fd8c1f 100644 --- a/esvg/render/SegmentList.cpp +++ b/esvg/render/SegmentList.cpp @@ -43,12 +43,32 @@ void esvg::render::SegmentList::createSegmentList(const esvg::render::PointList& std::sort(m_data.begin(), m_data.end(), sortSegmentFunction); } -void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint, float _width) { +static vec2 getIntersect(const vec2& _point1, + const vec2& _vect1, + const vec2& _point2, + const vec2& _vect2) { + float diviseur = _vect1.x() * _vect2.y() - _vect1.y() * _vect2.x(); + if(diviseur != 0.0f) { + float mmm = ( _vect1.x() * _point1.y() + - _vect1.x() * _point2.y() + - _vect1.y() * _point1.x() + + _vect1.y() * _point2.x() + ) / diviseur; + return vec2(_point2 + _vect2 * mmm); + } + SVG_ERROR("Get divider / 0.0f"); + return _point2; +} + +void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint, + float _width, + enum esvg::cap _cap, + enum esvg::join _join) { for (auto &itListPoint : _listPoint.m_data) { // generate for every point all the orthogonal elements // // normal edge * end path - // * | * * * * * * * * * * * * * * + // (mitter) * | * * * * * * * * * * * * * * // * |<--*----this | * // * | * this -->| * // * * * | * @@ -93,19 +113,33 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& vecC.safeNormalize(); itListPoint[idCurrent].m_miterAxe = vecC; } + itListPoint[idCurrent].m_posPrevious = itListPoint[idPevious].m_pos; + itListPoint[idCurrent].m_posNext = itListPoint[idNext].m_pos; + vecB = itListPoint[idNext].m_pos - itListPoint[idCurrent].m_pos; + vecB.safeNormalize(); + itListPoint[idCurrent].m_orthoAxeNext = vec2(vecB.y(), -vecB.x()); + vecB = itListPoint[idCurrent].m_pos - itListPoint[idPevious].m_pos; + vecB.safeNormalize(); + itListPoint[idCurrent].m_orthoAxePrevious = vec2(vecB.y(), -vecB.x()); //SVG_DEBUG("JOIN : miterAxe " << itListPoint[idCurrent].m_miterAxe); } else if (itListPoint[idCurrent].m_type == esvg::render::Point::type_start) { + itListPoint[idCurrent].m_posNext = itListPoint[idNext].m_pos; vec2 vecB = itListPoint[idNext].m_pos - itListPoint[idCurrent].m_pos; vecB.safeNormalize(); itListPoint[idCurrent].m_miterAxe = vec2(vecB.y(), -vecB.x()); + itListPoint[idCurrent].m_orthoAxePrevious = itListPoint[idCurrent].m_miterAxe; + itListPoint[idCurrent].m_orthoAxeNext = itListPoint[idCurrent].m_miterAxe; } else if (itListPoint[idCurrent].m_type == esvg::render::Point::type_stop) { if (idPevious < 0 ) { SVG_ERROR("an error occure a previous ID is < 0.... "); continue; } + itListPoint[idCurrent].m_posPrevious = itListPoint[idPevious].m_pos; vec2 vecA = itListPoint[idCurrent].m_pos - itListPoint[idPevious].m_pos; vecA.safeNormalize(); itListPoint[idCurrent].m_miterAxe = vec2(vecA.y(), -vecA.x()); + itListPoint[idCurrent].m_orthoAxePrevious = itListPoint[idCurrent].m_miterAxe; + itListPoint[idCurrent].m_orthoAxeNext = itListPoint[idCurrent].m_miterAxe; } else { SVG_TODO("lklklklklkl"); } @@ -119,10 +153,14 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& // cyclic path... if ( itListPoint.back().m_type == esvg::render::Point::type_join || itListPoint.back().m_type == esvg::render::Point::type_interpolation) { + // Calculate the perpendiculary axis ... leftPoint = itListPoint.back().m_pos - + itListPoint.back().m_miterAxe*_width*0.5f; + + itListPoint.back().m_orthoAxePrevious*_width*0.5f; rightPoint = itListPoint.back().m_pos - - itListPoint.back().m_miterAxe*_width*0.5f; + - itListPoint.back().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); } else { SVG_ERROR("Start list point with a join, but last lement is not a join"); } @@ -143,7 +181,6 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& addSegment(leftPoint, rightPoint); } haveStartLine = true; - // TODO : Calculate intersection ... (now we do a simple fast test of path display ...) leftPoint = it.m_pos + it.m_miterAxe*_width*0.5f; rightPoint = it.m_pos @@ -160,7 +197,6 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& break; } haveStartLine = false; - // TODO : Calculate intersection ... (now we do a simple fast test of path display ...) vec2 left = it.m_pos + it.m_miterAxe*_width*0.5f; vec2 right = it.m_pos @@ -173,7 +209,11 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& leftPoint = left; rightPoint = right; // end line ... - addSegment(rightPoint, leftPoint); + if (rightPoint.y() <= leftPoint.y()) { + addSegment(leftPoint, rightPoint); + } else { + addSegment(rightPoint, leftPoint); + } SVG_VERBOSE(" segment :" << rightPoint << " -> " << leftPoint); } break; @@ -181,10 +221,15 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& { SVG_VERBOSE("Find interpolation " << it.m_pos); // TODO : Calculate intersection ... (now we do a simple fast test of path display ...) + #if 1 + 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); + #else vec2 left = it.m_pos + it.m_miterAxe*_width*0.5f; vec2 right = it.m_pos - it.m_miterAxe*_width*0.5f; + #endif //Draw from previous point: addSegment(leftPoint, left); SVG_VERBOSE(" segment :" << leftPoint << " -> " << left); @@ -198,10 +243,15 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& { SVG_VERBOSE("Find Join " << it.m_pos); // TODO : Calculate intersection ... (now we do a simple fast test of path display ...) + #if 1 + 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); + #else vec2 left = it.m_pos + it.m_miterAxe*_width*0.5f; vec2 right = it.m_pos - it.m_miterAxe*_width*0.5f; + #endif //Draw from previous point: addSegment(leftPoint, left); SVG_VERBOSE(" segment :" << leftPoint << " -> " << left); diff --git a/esvg/render/SegmentList.h b/esvg/render/SegmentList.h index c665b97..52379dd 100644 --- a/esvg/render/SegmentList.h +++ b/esvg/render/SegmentList.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -23,7 +25,10 @@ namespace esvg { SegmentList(); void addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1); void createSegmentList(const esvg::render::PointList& _listPoint); - void createSegmentListStroke(esvg::render::PointList& _listPoint, float _width); + void createSegmentListStroke(esvg::render::PointList& _listPoint, + float _width, + enum esvg::cap _cap, + enum esvg::join _join); }; } } diff --git a/esvg/render/Weight.h b/esvg/render/Weight.h index 18f1604..6e6ecdc 100644 --- a/esvg/render/Weight.h +++ b/esvg/render/Weight.h @@ -11,6 +11,7 @@ #include #include +#include #include #include