32void Path::DashPolyline(
float head,
float tail,
float body,
int nbD,
const float dashs[],
bool stPlain,
float stOffset)
34 if ( nbD <= 0 || body <= 0.0001 )
return;
36 std::vector<path_lineto> orig_pts =
pts;
43 for (
int i = 0; i < int(orig_pts.size()); i++) {
45 if ( lastMI >= 0 && lastMI < i-1 ) {
46 DashSubPath(i-lastMI,lastMP, orig_pts, head,tail,body,nbD,dashs,stPlain,stOffset);
53 if ( lastMI >= 0 && lastMI <
int(orig_pts.size()) - 1 ) {
54 DashSubPath(orig_pts.size() - lastMI, lastMP, orig_pts, head, tail, body, nbD, dashs, stPlain, stOffset);
65 dlen += value.value *
scale;
67 if (dlen >= min_len) {
71 std::vector<double> dash(n_dash);
72 for (
unsigned i = 0; i < n_dash; i++) {
78 std::vector<float> dashes(n_dash);
80 while (dash_offset >= dlen) dash_offset -= dlen;
83 for (
int i = 1; i < nbD; ++i) {
84 dashes[i] = dashes[i-1] + dash[i];
88 DashPolyline(0.0, 0.0, dlen, nbD, dashes.data(),
true, dash_offset);
93void Path::DashSubPath(
int spL,
int spP, std::vector<path_lineto>
const &orig_pts,
float head,
float tail,
float body,
int nbD,
const float dashs[],
bool stPlain,
float stOffset)
95 if ( spL <= 0 || spP == -1 )
return;
99 lastP = orig_pts[spP].p;
100 for (
int i=1;i<spL;i++) {
110 if ( totLength <= head+tail )
return;
115 bool dashPlain=
false;
118 lastP = orig_pts[spP].p;
119 for (
int i=1;i<spL;i++) {
124 n = orig_pts[spP + i].p;
125 nPiece = orig_pts[spP + i].piece;
126 nT = orig_pts[spP + i].t;
128 n = orig_pts[spP + i].p;
133 double stLength=curLength;
134 double enLength=curLength+nl;
136 if ( curLength <= head && curLength+nl > head ) {
142 while ( dashs[dashInd] < stOffset ) {
145 if ( dashInd >= nbD ) {
151 if ( nPlain ==
true && dashPlain ==
false ) {
152 Geom::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
153 p/=(enLength-stLength);
156 if ( nPiece == lastPiece ) {
157 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
159 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
165 }
else if ( nPlain ==
false && dashPlain ==
true ) {
170 if ( curLength >= head ) {
171 while ( curLength <= totLength-tail && nl > 0 ) {
172 if ( enLength <= totLength-tail ) nl=enLength-curLength;
else nl=totLength-tail-curLength;
173 double leftInDash=body-dashPos;
174 if ( dashInd < nbD ) {
175 leftInDash=dashs[dashInd]-dashPos;
177 if ( leftInDash <= nl ) {
179 if ( dashInd < nbD ) {
180 dashPos=dashs[dashInd];
182 if ( dashPlain ) nPlain=
false;
else nPlain=
true;
189 if ( nPlain ==
true && dashPlain ==
false ) {
190 Geom::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
191 p/=(enLength-stLength);
194 if ( nPiece == lastPiece ) {
195 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
197 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
203 }
else if ( nPlain ==
false && dashPlain ==
true ) {
204 Geom::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
205 p/=(enLength-stLength);
208 if ( nPiece == lastPiece ) {
209 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
211 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
220 curLength+=leftInDash;
235 nl=enLength-curLength;
237 if ( curLength <= totLength-tail && curLength+nl > totLength-tail ) {
238 nl=totLength-tail-curLength;
242 if ( nPlain ==
true && dashPlain ==
false ) {
243 }
else if ( nPlain ==
false && dashPlain ==
true ) {
244 Geom::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
245 p/=(enLength-stLength);
248 if ( nPiece == lastPiece ) {
249 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
251 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
282 switch (
c->getType()) {
284 currentpath->
close(
true);
296 currentpath = &pv.
back();
330 3 * ((*cubic)[1] - (*cubic)[0]),
331 3 * ((*cubic)[3] - (*cubic)[2]));
334 ArcTo(arc->finalPoint(),
335 arc->rays().x(), arc->rays().y(),
336 Geom::deg_from_rad(arc->rotationAngle()),
337 arc->largeArc(), !arc->sweep());
343 for (
auto const &iter : sbasis_path) {
363 Geom::Path const pathtr = doTransformation ? path * tr : path;
367 for(
const auto & cit : pathtr) {
387 auto it = cuts.begin();
389 for (
int i = 0, maxi = pv.
size(); i < maxi; i++) {
390 auto const &path = pv[i];
396 MoveTo(path.initialPoint());
398 for (
int j = 0, maxj = path.size(); j < maxj; j++) {
399 auto const &
curve = path[j];
403 while (it != cuts.end() && it->path_index == i && it->curve_index == j) {
414 assert(it == cuts.end());
422 for(
const auto & it : pv) {
423 LoadPath(it, tr, doTransformation,
true);
440 for (
const auto & pt :
pts) {
463 for (
const auto & pt :
pts) {
467 lastP = lastM = pt.p;
483 Path* curAdd=
nullptr;
486 int const typ = i->getType();
492 double addSurf=curAdd->
Surface();
493 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
494 res=(
Path**)g_realloc(res,(nbRes+1)*
sizeof(
Path*));
541 double addSurf=curAdd->
Surface();
542 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
543 res=(
Path**)g_realloc(res,(nbRes+1)*
sizeof(
Path*));
561 Path* curAdd=
nullptr;
562 bool increment=
false;
564 for (
int i=0;i<int(
descr_cmd.size());i++) {
569 if ( curAdd && increment ==
false ) {
572 int savA=curAdd->
descr_cmd[0]->associated;
575 double addSurf=curAdd->
Surface();
576 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
577 res=(
Path**)g_realloc(res,(nbRes+1)*
sizeof(
Path*));
587 Path* hasParent=
nullptr;
588 for (
int j=0;j<nbNest;j++) {
589 if ( conts[j] == i && nesting[j] >= 0 ) {
590 int parentMvt=conts[nesting[j]];
591 for (
int k=0;k<nbRes;k++) {
592 if ( res[k] && res[k]->
descr_cmd.empty() ==
false && res[k]->
descr_cmd[0]->associated == parentMvt ) {
598 if ( conts[j] > i )
break;
609 int mNo=curAdd->
MoveTo(nData->
p);
640 if ( curAdd && increment ==
false ) {
643 double addSurf=curAdd->
Surface();
644 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
645 res=(
Path**)g_realloc(res,(nbRes+1)*
sizeof(
Path*));
663 for (
int i=0; i < int(
descr_cmd.size()); i++) {
679 for (
int i =
int(
descr_cmd.size()) - 1; i >= 0; i--) {
724 bool hasMoved =
false;
725 for (
int i = 0; i < int(
descr_cmd.size()); i++) {
729 if ( i <
int(
descr_cmd.size()) - 1 && hasMoved ) {
741 lastMove = lastSeen = nData->
p;
778 if ( cp1->
t < cp2->
t )
return -1;
779 if ( cp1->
t > cp2->
t )
return 1;
782static int CmpCurv(
const void * p1,
const void * p2) {
783 double *cp1=(
double*)p1;
784 double *cp2=(
double*)p2;
785 if ( *cp1 < *cp2 )
return -1;
786 if ( *cp1 > *cp2 )
return 1;
793 if ( nbCv <= 0 ||
pts.empty() ||
back ==
false ) {
797 qsort(cvAbs, nbCv,
sizeof(
double),
CmpCurv);
810 for (
const auto & pt :
pts) {
814 lastP = lastM = pt.p;
816 lastPiece = pt.piece;
820 double const add =
Geom::L2(pt.p - lastP);
824 while ( curAdd > 0.0001 && curCv < nbCv && curPos + curAdd >= cvAbs[curCv] ) {
825 double const theta = (cvAbs[curCv] -
len) / add;
827 res[nbCut].
piece = pt.piece;
828 res[nbCut].
t = theta * pt.t + (1 - theta) * ( (lastPiece != pt.piece) ? 0 : lastT);
830 curAdd -= cvAbs[curCv] - curPos;
831 curPos = cvAbs[curCv];
836 lastPiece = pt.piece;
854template<
typename T>
inline static T
square(T x) {
return x*x;}
860 unsigned bestSeg = 0;
861 double bestRangeSquared = DBL_MAX;
864 for (
unsigned i = 1 ; i <
pts.size() ; i++) {
867 double thisRangeSquared;
870 if (
pts[i - 1].p ==
pts[i].p) {
880 p1 =
pts[i - 1].p.
cw();
899 double nearestY = (localPos[
Geom::X] * gradient + localPos[
Geom::Y] - intersection * gradient)
900 / (gradient * gradient + 1.0);
905 }
else if (t >= 1.0) {
913 if (thisRangeSquared < bestRangeSquared) {
915 bestRangeSquared = thisRangeSquared;
925 if (
result.piece ==
pts[bestSeg - 1].piece) {
926 result.t =
pts[bestSeg - 1].t * (1.0 - bestT) +
pts[bestSeg].t * bestT;
944 for (
unsigned i = 1 ; i <
pts.size() ; i++) {
946 if (
pts[i].piece == piece && t <
pts[i].t) {
963 for (
int i =
int(
descr_cmd.size()) - 1; i >= 0; i--) {
1025 for (
int curP=0;curP<nbPos;curP++) {
1026 int cp=poss[curP].
piece;
1027 if ( cp < 0 || cp >=
int(
descr_cmd.size()) )
break;
1028 float ct=poss[curP].
t;
1029 if ( ct < 0 )
continue;
1030 if ( ct > 1 )
continue;
1032 int const typ =
descr_cmd[cp]->getType();
1049 TangentOnCubAt (ct, startP, *oData,
true, theP,theT,
len,rad);
1058 nData->
start=ct*stD;
1063 for (
int j=curP+1;j<nbPos;j++) {
1064 if ( poss[j].piece == cp ) {
1066 poss[j].
t=(poss[j].
t-ct)/(1-ct);
1078 theP=ct*endP+(1-ct)*startP;
1087 for (
int j=curP+1;j<nbPos;j++) {
1088 if ( poss[j].piece == cp ) {
1090 poss[j].
t=(poss[j].
t-ct)/(1-ct);
1111 ArcAngles(startP,endP,rx,ry,angle*M_PI/180.0,large,clockw,sang,eang);
1114 if ( sang < eang ) sang += 2*M_PI;
1117 if ( sang > eang ) sang -= 2*M_PI;
1125 if (
delta*(1-ct) > M_PI ) {
1134 if (
delta*ct > M_PI ) {
1141 for (
int j=curP+1;j<nbPos;j++) {
1142 if ( poss[j].piece == cp ) {
1144 poss[j].
t=(poss[j].
t-ct)/(1-ct);
1163 for (
int i=0;i<int(
descr_cmd.size());i++) {
1164 int const typ =
descr_cmd[i]->getType();
1172 bool hasClose=
false;
1174 bool doesClose=
false;
1177 int const ntyp =
descr_cmd[j]->getType();
1182 if ( hasForced < 0 ) hasForced=j;
1200 if ( ( doesClose || hasClose ) && hasForced >= 0 ) {
1206 for (
int k = hasForced + 1; k < j; k++) {
1228 if ( doesClose ==
false ) res->
LineTo(np);
1230 for (
int k=i+1;k<hasForced;k++) {
Cartesian point / 2D vector and related operations.
static int CmpCurv(const void *p1, const void *p2)
static int CmpPosition(const void *p1, const void *p2)
TODO: insert short description here.
3x3 affine transformation matrix.
3x3 matrix representing an affine transformation.
Abstract continuous curve on a plane defined on [0,1].
size_type size() const
Get the number of paths in the vector.
void push_back(Path const &path)
Append a path at the end.
Sequence of contiguous curves, aka spline.
bool closed() const
Check whether the path is closed.
void close(bool closed=true)
Set whether the path is closed.
bool empty() const
Check whether path is empty.
Point initialPoint() const
Get the first point in the path.
void appendNew(Args &&... args)
Append a new curve to the path.
void start(Point const &p)
Two-dimensional point that doubles as a vector.
constexpr Point cw() const
Return a point like this point but rotated +90 degrees.
Path and its polyline approximation.
int LineTo(Geom::Point const &ip)
Appends a LineTo path command.
void SetBackData(bool nVal)
Sets the back variable to the value passed in and clears the polyline approximation.
void DashSubPath(int spL, int spP, std::vector< path_lineto > const &orig_pts, float head, float tail, float body, int nbD, const float dashs[], bool stPlain, float stOffset)
void DashPolylineFromStyle(SPStyle *style, float scale, float min_len)
void InsertLineTo(Geom::Point const &iPt, int at)
int Close()
Appends a close path command.
void ConvertForcedToVoid()
cut_position PointToCurvilignPosition(Geom::Point const &pos, unsigned seg=0) const
void ConvertForcedToMoveTo()
int ArcTo(Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise)
Appends an ArcTo path command.
void PointAt(int piece, double at, Geom::Point &pos)
std::vector< path_lineto > pts
void LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation)
Load a lib2geom Geom::PathVector in this path object.
Geom::PathVector MakePathVector() const
Create a lib2geom Geom::PathVector from this Path object.
int MoveTo(Geom::Point const &ip)
Appends a MoveTo path command.
void LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append=false)
Load a lib2geom Geom::Path in this path object.
void InsertArcTo(Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise, int at)
std::vector< ForcedSubdivision > forced_subdivisions
void Copy(Path *who)
Clear all stored path commands, resets flags and imports path commands from the passed Path object.
const Geom::Point PrevPoint(const int i) const
Path ** SubPathsWithNesting(int &outNb, bool killNoSurf, int nbNest, int *nesting, int *conts)
void DashPolyline(float head, float tail, float body, int nbD, const float dashs[], bool stPlain, float stOffset)
void ConvertPositionsToMoveTo(int nbPos, cut_position *poss)
cut_position * CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
void ConvertPositionsToForced(int nbPos, cut_position *poss)
void InsertCubicTo(Geom::Point const &ip, Geom::Point const &iStD, Geom::Point const &iEnD, int at)
Path ** SubPaths(int &outNb, bool killNoSurf)
int CubicTo(Geom::Point const &ip, Geom::Point const &iStD, Geom::Point const &iEnD)
Appends a CubicBezier path command.
std::vector< PathDescr * > descr_cmd
int AddPoint(Geom::Point const &iPt, bool mvto=false)
Adds a point to the polyline approximation's list of points.
void Convert(double treshhold)
Creates a polyline approximation of the path.
void InsertForcePoint(int at)
void Reset()
Clears all stored path commands and resets flags that are used by command functions while adding path...
double PositionToLength(int piece, double t)
T< SPAttr::STROKE_DASHARRAY, SPIDashArray > stroke_dasharray
stroke-dasharray
T< SPAttr::STROKE_DASHOFFSET, SPILength > stroke_dashoffset
stroke-dashoffset
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Path cubicbezierpath_from_sbasis(D2< SBasis > const &B, double tol)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
Coord LInfty(Point const &p)
TODO: insert short description here.
PathVector - a sequence of subpaths.
void append(std::vector< T > &vec, std::vector< T > const &other)
Conversion between SBasis and Bezier basis polynomials.
Elliptical Arc path command.
Cubic Bezier path command.
A forced point path command.
SPStyle - a style object for SPItem objects.
static double square(double const x)