511 lines
20 KiB
C++
511 lines
20 KiB
C++
/** @file
|
|
* @author Edouard DUPIN
|
|
*
|
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
*
|
|
* @license APACHE v2.0 (see license file)
|
|
*/
|
|
|
|
#include <esvg/render/SegmentList.h>
|
|
#include <esvg/debug.h>
|
|
#include <etk/math/Matrix2.h>
|
|
|
|
esvg::render::SegmentList::SegmentList() {
|
|
|
|
}
|
|
#ifdef DEBUG
|
|
void esvg::render::SegmentList::addSegment(const vec2& _pos0, const vec2& _pos1) {
|
|
m_data.push_back(Segment(_pos0, _pos1));
|
|
}
|
|
#endif
|
|
|
|
void esvg::render::SegmentList::addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1) {
|
|
// Skip horizontal Segments
|
|
if (_pos0.m_pos.y() == _pos1.m_pos.y()) {
|
|
// remove /0 operation
|
|
return;
|
|
}
|
|
m_data.push_back(Segment(_pos0.m_pos, _pos1.m_pos));
|
|
}
|
|
|
|
void esvg::render::SegmentList::addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1, bool _disableHorizontal) {
|
|
// Skip horizontal Segments
|
|
if ( _disableHorizontal == true
|
|
&& _pos0.m_pos.y() == _pos1.m_pos.y()) {
|
|
// remove /0 operation
|
|
return;
|
|
}
|
|
m_data.push_back(Segment(_pos0.m_pos, _pos1.m_pos));
|
|
}
|
|
|
|
std::pair<vec2, vec2> esvg::render::SegmentList::getViewPort() {
|
|
std::pair<vec2, vec2> out(vec2(9999999999.0,9999999999.0),vec2(-9999999999.0,-9999999999.0));
|
|
for (auto &it : m_data) {
|
|
out.first.setMin(it.p0);
|
|
out.second.setMax(it.p0);
|
|
out.first.setMin(it.p1);
|
|
out.second.setMax(it.p1);
|
|
}
|
|
return out;
|
|
}
|
|
void esvg::render::SegmentList::createSegmentList(const esvg::render::PointList& _listPoint) {
|
|
for (auto &it : _listPoint.m_data) {
|
|
// Build Segments
|
|
for (int32_t iii=0, jjj=it.size()-1;
|
|
iii < it.size();
|
|
jjj = iii++) {
|
|
addSegment(it[jjj], it[iii]);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
ESVG_ERROR("Get divider / 0.0f");
|
|
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);
|
|
ESVG_VERBOSE(" segment :" << ppp2 << " -> " << ppp1);
|
|
} else {
|
|
addSegment(ppp1, ppp2);
|
|
ESVG_VERBOSE(" segment :" << ppp1 << " -> " << ppp2);
|
|
}
|
|
ppp1 = ppp2;
|
|
}
|
|
if (_isStart == true) {
|
|
addSegment(_point2, ppp1);
|
|
ESVG_VERBOSE(" segment :" << _point2 << " -> " << ppp1);
|
|
} else {
|
|
addSegment(ppp1, _point2);
|
|
ESVG_VERBOSE(" segment :" << ppp1 << " -> " << _point2);
|
|
}
|
|
}
|
|
|
|
void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint,
|
|
float _width,
|
|
enum esvg::cap _cap,
|
|
enum esvg::join _join,
|
|
float _miterLimit) {
|
|
for (auto &itListPoint : _listPoint.m_data) {
|
|
// generate for every point all the orthogonal elements
|
|
//
|
|
// normal edge * end path
|
|
// (mitter) * | * * * * * * * * * * * * * *
|
|
// * |<--*----this | *
|
|
// * | * this -->| *
|
|
// * * * | *
|
|
// * . | . * . . . . . . . . * *
|
|
// * . | . * | *
|
|
// * A . | . B * | *
|
|
// . * . | *
|
|
// . * * . * * * * * * * * * * * * *
|
|
// * *
|
|
// * *
|
|
for (int32_t idPevious=itListPoint.size()-1, idCurrent=0, idNext=1;
|
|
idCurrent < itListPoint.size();
|
|
idPevious = idCurrent++, idNext++) {
|
|
if (idNext == itListPoint.size()) {
|
|
idNext = 0;
|
|
}
|
|
if ( itListPoint[idCurrent].m_type == esvg::render::Point::type_join
|
|
|| itListPoint[idCurrent].m_type == esvg::render::Point::type_interpolation) {
|
|
if (idPevious < 0 ) {
|
|
ESVG_ERROR("an error occure a previous ID is < 0.... ");
|
|
continue;
|
|
}
|
|
if (idNext >= itListPoint.size()) {
|
|
ESVG_ERROR("an error occure a next ID is >= nbPoint len .... ");
|
|
continue;
|
|
}
|
|
//ESVG_DEBUG("JOIN : id : prev/curr/next : " << idPevious << "/" << idCurrent << "/" << idNext);
|
|
//ESVG_DEBUG("JOIN : val : prev/curr/next : " << itListPoint[idPevious].m_pos << "/" << itListPoint[idCurrent].m_pos << "/" << itListPoint[idNext].m_pos);
|
|
vec2 vecA = itListPoint[idCurrent].m_pos - itListPoint[idPevious].m_pos;
|
|
//ESVG_DEBUG("JOIN : vecA : " << vecA);
|
|
vecA.safeNormalize();
|
|
vec2 vecB = itListPoint[idNext].m_pos - itListPoint[idCurrent].m_pos;
|
|
//ESVG_DEBUG("JOIN : vecB : " << vecB);
|
|
vecB.safeNormalize();
|
|
vec2 vecC = vecA - vecB;
|
|
//ESVG_DEBUG("JOIN : vecC : " << vecC);
|
|
if (vecC == vec2(0.0f, 0.0f)) {
|
|
// special case: 1 line ...
|
|
itListPoint[idCurrent].m_miterAxe = vec2(vecA.y(), vecA.x());
|
|
} else {
|
|
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());
|
|
//ESVG_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 ) {
|
|
ESVG_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 {
|
|
ESVG_TODO("Unsupported type of point ....");
|
|
}
|
|
}
|
|
// create segment list:
|
|
bool haveStartLine = false;
|
|
vec2 leftPoint(0,0);
|
|
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 (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 ...
|
|
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;
|
|
ESVG_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 {
|
|
ESVG_ERROR("Start list point with a join, but last lement is not a join");
|
|
}
|
|
}
|
|
}
|
|
for (auto &it : itListPoint) {
|
|
switch (it.m_type) {
|
|
case esvg::render::Point::type_single:
|
|
// just do nothing ....
|
|
ESVG_VERBOSE("Find Single " << it.m_pos);
|
|
break;
|
|
case esvg::render::Point::type_start:
|
|
ESVG_VERBOSE("Find Start " << it.m_pos);
|
|
if (haveStartLine == true) {
|
|
// close previous :
|
|
ESVG_WARNING(" find a non close path ...");
|
|
addSegment(leftPoint, rightPoint);
|
|
}
|
|
haveStartLine = true;
|
|
startStopPoint(leftPoint, rightPoint, it, _cap, _width, true);
|
|
break;
|
|
case esvg::render::Point::type_stop:
|
|
ESVG_VERBOSE("Find Stop " << it.m_pos);
|
|
if (haveStartLine == false) {
|
|
ESVG_WARNING("find close path without start part ...");
|
|
break;
|
|
}
|
|
haveStartLine = false;
|
|
startStopPoint(leftPoint, rightPoint, it, _cap, _width, false);
|
|
break;
|
|
case esvg::render::Point::type_interpolation:
|
|
{
|
|
ESVG_VERBOSE("Find interpolation " << it.m_pos);
|
|
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);
|
|
//Draw from previous point:
|
|
addSegment(leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
|
|
addSegment(right, rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
|
|
leftPoint = left;
|
|
rightPoint = right;
|
|
}
|
|
break;
|
|
case esvg::render::Point::type_join:
|
|
ESVG_VERBOSE("Find join " << it.m_pos);
|
|
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;
|
|
ESVG_VERBOSE(" miter Limit: " << limitRight << " " << limitLeft << " <= " << _miterLimit);
|
|
if ( limitRight <= _miterLimit
|
|
&& limitLeft <= _miterLimit) {
|
|
//Draw from previous point:
|
|
addSegment(leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
|
|
addSegment(right, rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
|
|
leftPoint = left;
|
|
rightPoint = right;
|
|
break;
|
|
} else {
|
|
// We do a bevel join ...
|
|
ESVG_VERBOSE(" Find miter Limit ... ==> create BEVEL");
|
|
}
|
|
}
|
|
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) {
|
|
vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
|
vec2 left1 = it.m_pos
|
|
+ it.m_orthoAxePrevious*_width*0.5f;
|
|
vec2 left2 = it.m_pos
|
|
+ it.m_orthoAxeNext*_width*0.5f;
|
|
//Draw from previous point:
|
|
addSegment(leftPoint, left1);
|
|
ESVG_VERBOSE(" segment :" << leftPoint << " -> " << left1);
|
|
if (_join != esvg::join_round) {
|
|
// Miter and bevel:
|
|
addSegment(left1, left2);
|
|
ESVG_VERBOSE(" segment :" << left1 << " -> " << left2);
|
|
}else {
|
|
createSegmentListStroke(left1,
|
|
left2,
|
|
it.m_pos,
|
|
_width,
|
|
false);
|
|
}
|
|
addSegment(right, rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
|
|
leftPoint = left2;
|
|
rightPoint = right;
|
|
} else {
|
|
vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
|
|
vec2 right1 = it.m_pos
|
|
- it.m_orthoAxePrevious*_width*0.5f;
|
|
vec2 right2 = it.m_pos
|
|
- it.m_orthoAxeNext*_width*0.5f;//Draw from previous point:
|
|
addSegment(leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
|
|
addSegment(right1, rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right1 << " -> " << rightPoint);
|
|
if (_join != esvg::join_round) {
|
|
// Miter and bevel:
|
|
addSegment(right2, right1);
|
|
ESVG_VERBOSE(" segment :" << right2 << " -> " << right1);
|
|
} else {
|
|
createSegmentListStroke(right1,
|
|
right2,
|
|
it.m_pos,
|
|
_width,
|
|
true);
|
|
}
|
|
leftPoint = left;
|
|
rightPoint = right2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void esvg::render::SegmentList::startStopPoint(vec2& _leftPoint,
|
|
vec2& _rightPoint,
|
|
const esvg::render::Point& _point,
|
|
enum esvg::cap _cap,
|
|
float _width,
|
|
bool _isStart) {
|
|
switch (_cap) {
|
|
case esvg::cap_butt:
|
|
{
|
|
vec2 left = _point.m_pos
|
|
+ _point.m_miterAxe*_width*0.5f;
|
|
vec2 right = _point.m_pos
|
|
- _point.m_miterAxe*_width*0.5f;
|
|
if (_isStart == false) {
|
|
//Draw from previous point:
|
|
addSegment(_leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
|
|
addSegment(right, _rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
|
|
}
|
|
_leftPoint = left;
|
|
_rightPoint = right;
|
|
}
|
|
if (_isStart == false) {
|
|
addSegment(_leftPoint, _rightPoint);
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
|
|
} else {
|
|
addSegment(_rightPoint, _leftPoint);
|
|
ESVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
|
|
}
|
|
break;
|
|
case esvg::cap_round:
|
|
{
|
|
if (_isStart == false) {
|
|
vec2 left = _point.m_pos
|
|
+ _point.m_miterAxe*_width*0.5f;
|
|
vec2 right = _point.m_pos
|
|
- _point.m_miterAxe*_width*0.5f;
|
|
if (_isStart == false) {
|
|
//Draw from previous point:
|
|
addSegment(_leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
|
|
addSegment(right, _rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
|
|
}
|
|
_leftPoint = left;
|
|
_rightPoint = right;
|
|
}
|
|
int32_t nbDot = int32_t(_width);
|
|
if (nbDot <= 2) {
|
|
nbDot = 2;
|
|
}
|
|
float baseAngle = M_PI/float(nbDot);
|
|
float iii;
|
|
_leftPoint = _point.m_pos
|
|
+ _point.m_miterAxe*_width*0.5f;
|
|
_rightPoint = _point.m_pos
|
|
- _point.m_miterAxe*_width*0.5f;
|
|
createSegmentListStroke(_leftPoint,
|
|
_rightPoint,
|
|
_point.m_pos,
|
|
_width,
|
|
_isStart);
|
|
}
|
|
break;
|
|
case esvg::cap_square:
|
|
{
|
|
vec2 nextAxe;
|
|
if (_isStart == true) {
|
|
nextAxe = _point.m_posNext - _point.m_pos;
|
|
} else {
|
|
nextAxe = _point.m_posPrevious - _point.m_pos;
|
|
}
|
|
vec2 left = _point.m_pos
|
|
+ _point.m_miterAxe*_width*0.5f;
|
|
vec2 right = _point.m_pos
|
|
- _point.m_miterAxe*_width*0.5f;
|
|
mat2 tmpMat = etk::mat2Translate(nextAxe.safeNormalize()*_width*-0.5f);
|
|
left = tmpMat*left;
|
|
right = tmpMat*right;
|
|
if (_isStart == false) {
|
|
if (_isStart == false) {
|
|
//Draw from previous point:
|
|
addSegment(_leftPoint, left);
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
|
|
addSegment(right, _rightPoint);
|
|
ESVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
|
|
}
|
|
}
|
|
_leftPoint = left;
|
|
_rightPoint = right;
|
|
if (_isStart == false) {
|
|
addSegment(_leftPoint, _rightPoint);
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
|
|
} else {
|
|
addSegment(_rightPoint, _leftPoint);
|
|
ESVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
|
|
}
|
|
ESVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
|
|
}
|
|
break;
|
|
default:
|
|
ESVG_ERROR(" Undefined CAP TYPE");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void esvg::render::SegmentList::applyMatrix(const mat2& _transformationMatrix) {
|
|
for (auto &it : m_data) {
|
|
it.applyMatrix(_transformationMatrix);
|
|
}
|
|
}
|
|
|