Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
PathCutting.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * PathCutting.cpp
4 * nlivarot
5 *
6 * Created by fred on someday in 2004.
7 * public domain
8 *
9 * Additional Code by Authors:
10 * Richard Hughes <cyreve@users.sf.net>
11 *
12 * Copyright (C) 2005 Richard Hughes
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include <cmath>
18#include <cstdio>
19#include <vector>
20
21#include <2geom/pathvector.h>
22#include <2geom/point.h>
23#include <2geom/affine.h>
25#include <2geom/curves.h>
26
27#include "Path.h"
28#include "style.h"
30#include "helper/geom-curves.h"
31
32void Path::DashPolyline(float head,float tail,float body,int nbD, const float dashs[],bool stPlain,float stOffset)
33{
34 if ( nbD <= 0 || body <= 0.0001 ) return; // pas de tirets, en fait
35
36 std::vector<path_lineto> orig_pts = pts;
37 pts.clear();
38
39 int lastMI=-1;
40 int curP = 0;
41 int lastMP = -1;
42
43 for (int i = 0; i < int(orig_pts.size()); i++) {
44 if ( orig_pts[curP].isMoveTo == polyline_moveto ) {
45 if ( lastMI >= 0 && lastMI < i-1 ) { // au moins 2 points
46 DashSubPath(i-lastMI,lastMP, orig_pts, head,tail,body,nbD,dashs,stPlain,stOffset);
47 }
48 lastMI=i;
49 lastMP=curP;
50 }
51 curP++;
52 }
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);
55 }
56}
57
58void Path::DashPolylineFromStyle(SPStyle *style, float scale, float min_len)
59{
60 if (style->stroke_dasharray.values.empty() || !style->stroke_dasharray.is_valid()) return;
61
62 double dlen = 0.0;
63 // Find total length
64 for (auto & value : style->stroke_dasharray.values) {
65 dlen += value.value * scale;
66 }
67 if (dlen >= min_len) {
68 // Extract out dash pattern (relative positions)
69 double dash_offset = style->stroke_dashoffset.value * scale;
70 size_t n_dash = style->stroke_dasharray.values.size();
71 std::vector<double> dash(n_dash);
72 for (unsigned i = 0; i < n_dash; i++) {
73 dash[i] = style->stroke_dasharray.values[i].value * scale;
74 }
75
76 // Convert relative positions to absolute positions
77 int nbD = n_dash;
78 std::vector<float> dashes(n_dash);
79 if (dlen > 0) {
80 while (dash_offset >= dlen) dash_offset -= dlen;
81 }
82 dashes[0] = dash[0];
83 for (int i = 1; i < nbD; ++i) {
84 dashes[i] = dashes[i-1] + dash[i];
85 }
86
87 // modulo dlen
88 DashPolyline(0.0, 0.0, dlen, nbD, dashes.data(), true, dash_offset);
89 }
90}
91
92
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)
94{
95 if ( spL <= 0 || spP == -1 ) return;
96
97 double totLength=0;
98 Geom::Point lastP;
99 lastP = orig_pts[spP].p;
100 for (int i=1;i<spL;i++) {
101 Geom::Point const n = orig_pts[spP + i].p;
102 Geom::Point d=n-lastP;
103 double nl=Geom::L2(d);
104 if ( nl > 0.0001 ) {
105 totLength+=nl;
106 lastP=n;
107 }
108 }
109
110 if ( totLength <= head+tail ) return; // tout mange par la tete et la queue
111
112 double curLength=0;
113 double dashPos=0;
114 int dashInd=0;
115 bool dashPlain=false;
116 double lastT=0;
117 int lastPiece=-1;
118 lastP = orig_pts[spP].p;
119 for (int i=1;i<spL;i++) {
120 Geom::Point n;
121 int nPiece=-1;
122 double nT=0;
123 if ( back ) {
124 n = orig_pts[spP + i].p;
125 nPiece = orig_pts[spP + i].piece;
126 nT = orig_pts[spP + i].t;
127 } else {
128 n = orig_pts[spP + i].p;
129 }
130 Geom::Point d=n-lastP;
131 double nl=Geom::L2(d);
132 if ( nl > 0.0001 ) {
133 double stLength=curLength;
134 double enLength=curLength+nl;
135 // couper les bouts en trop
136 if ( curLength <= head && curLength+nl > head ) {
137 nl-=head-curLength;
138 curLength=head;
139 dashInd=0;
140 dashPos=stOffset;
141 bool nPlain=stPlain;
142 while ( dashs[dashInd] < stOffset ) {
143 dashInd++;
144 nPlain=!(nPlain);
145 if ( dashInd >= nbD ) {
146 dashPos=0;
147 dashInd=0;
148 break;
149 }
150 }
151 if ( nPlain == true && dashPlain == false ) {
152 Geom::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
153 p/=(enLength-stLength);
154 if ( back ) {
155 double pT=0;
156 if ( nPiece == lastPiece ) {
157 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
158 } else {
159 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
160 }
161 AddPoint(p,nPiece,pT,true);
162 } else {
163 AddPoint(p,true);
164 }
165 } else if ( nPlain == false && dashPlain == true ) {
166 }
167 dashPlain=nPlain;
168 }
169 // faire les tirets
170 if ( curLength >= head /*&& curLength+nl <= totLength-tail*/ ) {
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;
176 }
177 if ( leftInDash <= nl ) {
178 bool nPlain=false;
179 if ( dashInd < nbD ) {
180 dashPos=dashs[dashInd];
181 dashInd++;
182 if ( dashPlain ) nPlain=false; else nPlain=true;
183 } else {
184 dashInd=0;
185 dashPos=0;
186 //nPlain=stPlain;
187 nPlain=dashPlain;
188 }
189 if ( nPlain == true && dashPlain == false ) {
190 Geom::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
191 p/=(enLength-stLength);
192 if ( back ) {
193 double pT=0;
194 if ( nPiece == lastPiece ) {
195 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
196 } else {
197 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
198 }
199 AddPoint(p,nPiece,pT,true);
200 } else {
201 AddPoint(p,true);
202 }
203 } else if ( nPlain == false && dashPlain == true ) {
204 Geom::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
205 p/=(enLength-stLength);
206 if ( back ) {
207 double pT=0;
208 if ( nPiece == lastPiece ) {
209 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
210 } else {
211 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
212 }
213 AddPoint(p,nPiece,pT,false);
214 } else {
215 AddPoint(p,false);
216 }
217 }
218 dashPlain=nPlain;
219
220 curLength+=leftInDash;
221 nl-=leftInDash;
222 } else {
223 dashPos+=nl;
224 curLength+=nl;
225 nl=0;
226 }
227 }
228 if ( dashPlain ) {
229 if ( back ) {
230 AddPoint(n,nPiece,nT,false);
231 } else {
232 AddPoint(n,false);
233 }
234 }
235 nl=enLength-curLength;
236 }
237 if ( curLength <= totLength-tail && curLength+nl > totLength-tail ) {
238 nl=totLength-tail-curLength;
239 dashInd=0;
240 dashPos=0;
241 bool nPlain=false;
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);
246 if ( back ) {
247 double pT=0;
248 if ( nPiece == lastPiece ) {
249 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
250 } else {
251 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
252 }
253 AddPoint(p,nPiece,pT,false);
254 } else {
255 AddPoint(p,false);
256 }
257 }
258 dashPlain=nPlain;
259 }
260 // continuer
261 curLength=enLength;
262 lastP=n;
263 lastPiece=nPiece;
264 lastT=nT;
265 }
266 }
267}
268
275{
277
278 Geom::Path *currentpath = nullptr;
279 Geom::Point lastP;
280
281 for (auto c : descr_cmd) {
282 switch (c->getType()) {
283 case descr_close: {
284 currentpath->close(true);
285 break;
286 }
287 case descr_lineto: {
288 auto data = static_cast<PathDescrLineTo const *>(c);
289 currentpath->appendNew<Geom::LineSegment>(data->p);
290 lastP = data->p;
291 break;
292 }
293 case descr_moveto: {
294 auto data = static_cast<PathDescrMoveTo const *>(c);
295 pv.push_back(Geom::Path());
296 currentpath = &pv.back();
297 currentpath->start(data->p);
298 lastP = data->p;
299 break;
300 }
301 case descr_arcto: {
302 auto data = static_cast<PathDescrArcTo const *>(c);
303 currentpath->appendNew<Geom::EllipticalArc>(data->rx, data->ry, Geom::rad_from_deg(data->angle), data->large, !data->clockwise, data->p);
304 lastP = data->p;
305 break;
306 }
307 case descr_cubicto: {
308 auto data = static_cast<PathDescrCubicTo const *>(c);
309 currentpath->appendNew<Geom::CubicBezier>(lastP + data->start / 3, data->p - data->end / 3, data->p);
310 lastP = data->p;
311 break;
312 }
313 default:
314 break;
315 }
316 }
317
318 return pv;
319}
320
321void Path::AddCurve(Geom::Curve const &c)
322{
323 if (dynamic_cast<Geom::LineSegment const *>(&c)) {
324 LineTo(c.finalPoint());
325 } else if (auto cubic = dynamic_cast<Geom::CubicBezier const *>(&c)) {
326 if (is_straight_curve(*cubic)) {
327 LineTo(c.finalPoint());
328 } else {
329 CubicTo((*cubic)[3],
330 3 * ((*cubic)[1] - (*cubic)[0]),
331 3 * ((*cubic)[3] - (*cubic)[2]));
332 }
333 } else if (auto arc = dynamic_cast<Geom::EllipticalArc const *>(&c)) {
334 ArcTo(arc->finalPoint(),
335 arc->rays().x(), arc->rays().y(),
336 Geom::deg_from_rad(arc->rotationAngle()),
337 arc->largeArc(), !arc->sweep());
338 } else {
339 // This case handles sbasis as well as all other curve types.
340 auto const sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1);
341
342 // Recurse to convert the new path resulting from the sbasis to svgd.
343 for (auto const &iter : sbasis_path) {
344 AddCurve(iter);
345 }
346 }
347}
348
351void Path::LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append)
352{
353 if (!append) {
354 SetBackData (false);
355 Reset();
356 }
357 if (path.empty())
358 return;
359
360 // TODO: this can be optimized by not generating a new path here, but doing the transform in AddCurve
361 // directly on the curve parameters
362
363 Geom::Path const pathtr = doTransformation ? path * tr : path;
364
365 MoveTo( pathtr.initialPoint() );
366
367 for(const auto & cit : pathtr) {
368 AddCurve(cit);
369 }
370
371 if (pathtr.closed()) {
372 Close();
373 }
374}
375
377{
378 LoadPathVector(pv, Geom::Affine(), false);
379}
380
381void Path::LoadPathVector(Geom::PathVector const &pv, std::vector<Geom::PathVectorTime> const &cuts)
382{
383 SetBackData(false);
384 Reset();
385
386 forced_subdivisions.reserve(cuts.size());
387 auto it = cuts.begin();
388
389 for (int i = 0, maxi = pv.size(); i < maxi; i++) {
390 auto const &path = pv[i];
391
392 if (path.empty()) {
393 continue;
394 }
395
396 MoveTo(path.initialPoint());
397
398 for (int j = 0, maxj = path.size(); j < maxj; j++) {
399 auto const &curve = path[j];
400
401 AddCurve(curve);
402
403 while (it != cuts.end() && it->path_index == i && it->curve_index == j) {
404 forced_subdivisions.push_back({ .piece = (int)descr_cmd.size() - 1, .t = it->t });
405 ++it;
406 }
407 }
408
409 if (path.closed()) {
410 Close();
411 }
412 }
413
414 assert(it == cuts.end());
415}
416
417void Path::LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation)
418{
419 SetBackData (false);
420 Reset();
421
422 for(const auto & it : pv) {
423 LoadPath(it, tr, doTransformation, true);
424 }
425}
426
432{
433 if ( pts.empty() ) {
434 return 0;
435 }
436
437 Geom::Point lastP = pts[0].p;
438
439 double len = 0;
440 for (const auto & pt : pts) {
441
442 if ( pt.isMoveTo != polyline_moveto ) {
443 len += Geom::L2(pt.p - lastP);
444 }
445
446 lastP = pt.p;
447 }
448
449 return len;
450}
451
452
454{
455 if ( pts.empty() ) {
456 return 0;
457 }
458
459 Geom::Point lastM = pts[0].p;
460 Geom::Point lastP = lastM;
461
462 double surf = 0;
463 for (const auto & pt : pts) {
464
465 if ( pt.isMoveTo == polyline_moveto ) {
466 surf += Geom::cross(lastM, lastM - lastP);
467 lastP = lastM = pt.p;
468 } else {
469 surf += Geom::cross(pt.p, pt.p - lastP);
470 lastP = pt.p;
471 }
472
473 }
474
475 return surf;
476}
477
478
479Path** Path::SubPaths(int &outNb,bool killNoSurf)
480{
481 int nbRes=0;
482 Path** res=nullptr;
483 Path* curAdd=nullptr;
484
485 for (auto & i : descr_cmd) {
486 int const typ = i->getType();
487 switch ( typ ) {
488 case descr_moveto:
489 if ( curAdd ) {
490 if ( curAdd->descr_cmd.size() > 1 ) {
491 curAdd->Convert(1.0);
492 double addSurf=curAdd->Surface();
493 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
494 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
495 res[nbRes++]=curAdd;
496 } else {
497 delete curAdd;
498 }
499 } else {
500 delete curAdd;
501 }
502 curAdd=nullptr;
503 }
504 curAdd=new Path;
505 curAdd->SetBackData(false);
506 {
507 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(i);
508 curAdd->MoveTo(nData->p);
509 }
510 break;
511 case descr_close:
512 {
513 curAdd->Close();
514 }
515 break;
516 case descr_lineto:
517 {
518 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(i);
519 curAdd->LineTo(nData->p);
520 }
521 break;
522 case descr_cubicto:
523 {
524 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(i);
525 curAdd->CubicTo(nData->p,nData->start,nData->end);
526 }
527 break;
528 case descr_arcto:
529 {
530 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(i);
531 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
532 }
533 break;
534 default:
535 break;
536 }
537 }
538 if ( curAdd ) {
539 if ( curAdd->descr_cmd.size() > 1 ) {
540 curAdd->Convert(1.0);
541 double addSurf=curAdd->Surface();
542 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
543 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
544 res[nbRes++]=curAdd;
545 } else {
546 delete curAdd;
547 }
548 } else {
549 delete curAdd;
550 }
551 }
552 curAdd=nullptr;
553
554 outNb=nbRes;
555 return res;
556}
557Path** Path::SubPathsWithNesting(int &outNb,bool killNoSurf,int nbNest,int* nesting,int* conts)
558{
559 int nbRes=0;
560 Path** res=nullptr;
561 Path* curAdd=nullptr;
562 bool increment=false;
563
564 for (int i=0;i<int(descr_cmd.size());i++) {
565 int const typ = descr_cmd[i]->getType();
566 switch ( typ ) {
567 case descr_moveto:
568 {
569 if ( curAdd && increment == false ) {
570 if ( curAdd->descr_cmd.size() > 1 ) {
571 // sauvegarder descr_cmd[0]->associated
572 int savA=curAdd->descr_cmd[0]->associated;
573 curAdd->Convert(1.0);
574 curAdd->descr_cmd[0]->associated=savA; // associated n'est pas utilise apres
575 double addSurf=curAdd->Surface();
576 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
577 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
578 res[nbRes++]=curAdd;
579 } else {
580 delete curAdd;
581 }
582 } else {
583 delete curAdd;
584 }
585 curAdd=nullptr;
586 }
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 ) {
593 hasParent=res[k];
594 break;
595 }
596 }
597 }
598 if ( conts[j] > i ) break;
599 }
600 if ( hasParent ) {
601 curAdd=hasParent;
602 increment=true;
603 } else {
604 curAdd=new Path;
605 curAdd->SetBackData(false);
606 increment=false;
607 }
608 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
609 int mNo=curAdd->MoveTo(nData->p);
610 curAdd->descr_cmd[mNo]->associated=i;
611 }
612 break;
613 case descr_close:
614 {
615 curAdd->Close();
616 }
617 break;
618 case descr_lineto:
619 {
620 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
621 curAdd->LineTo(nData->p);
622 }
623 break;
624 case descr_cubicto:
625 {
626 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
627 curAdd->CubicTo(nData->p,nData->start,nData->end);
628 }
629 break;
630 case descr_arcto:
631 {
632 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
633 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
634 }
635 break;
636 default:
637 break;
638 }
639 }
640 if ( curAdd && increment == false ) {
641 if ( curAdd->descr_cmd.size() > 1 ) {
642 curAdd->Convert(1.0);
643 double addSurf=curAdd->Surface();
644 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
645 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
646 res[nbRes++]=curAdd;
647 } else {
648 delete curAdd;
649 }
650 } else {
651 delete curAdd;
652 }
653 }
654 curAdd=nullptr;
655
656 outNb=nbRes;
657 return res;
658}
659
660
662{
663 for (int i=0; i < int(descr_cmd.size()); i++) {
664 if ( descr_cmd[i]->getType() == descr_forced) {
665 delete descr_cmd[i];
666 descr_cmd.erase(descr_cmd.begin() + i);
667 }
668 }
669}
670
671
673{
674 Geom::Point lastSeen(0, 0);
675 Geom::Point lastMove(0, 0);
676
677 {
678 Geom::Point lastPos(0, 0);
679 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
680 int const typ = descr_cmd[i]->getType();
681 switch ( typ ) {
682 case descr_forced:
683 {
684 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
685 d->p = lastPos;
686 break;
687 }
688 case descr_close:
689 {
690 PathDescrClose *d = dynamic_cast<PathDescrClose *>(descr_cmd[i]);
691 d->p = lastPos;
692 break;
693 }
694 case descr_moveto:
695 {
696 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
697 lastPos = d->p;
698 break;
699 }
700 case descr_lineto:
701 {
702 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
703 lastPos = d->p;
704 break;
705 }
706 case descr_arcto:
707 {
708 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
709 lastPos = d->p;
710 break;
711 }
712 case descr_cubicto:
713 {
714 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
715 lastPos = d->p;
716 break;
717 }
718 default:
719 break;
720 }
721 }
722 }
723
724 bool hasMoved = false;
725 for (int i = 0; i < int(descr_cmd.size()); i++) {
726 int const typ = descr_cmd[i]->getType();
727 switch ( typ ) {
728 case descr_forced:
729 if ( i < int(descr_cmd.size()) - 1 && hasMoved ) { // sinon il termine le chemin
730
731 delete descr_cmd[i];
732 descr_cmd[i] = new PathDescrMoveTo(lastSeen);
733 lastMove = lastSeen;
734 hasMoved = true;
735 }
736 break;
737
738 case descr_moveto:
739 {
740 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
741 lastMove = lastSeen = nData->p;
742 hasMoved = true;
743 }
744 break;
745 case descr_close:
746 {
747 lastSeen=lastMove;
748 }
749 break;
750 case descr_lineto:
751 {
752 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
753 lastSeen=nData->p;
754 }
755 break;
756 case descr_cubicto:
757 {
758 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
759 lastSeen=nData->p;
760 }
761 break;
762 case descr_arcto:
763 {
764 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
765 lastSeen=nData->p;
766 }
767 break;
768 default:
769 break;
770 }
771 }
772}
773static int CmpPosition(const void * p1, const void * p2) {
776 if ( cp1->piece < cp2->piece ) return -1;
777 if ( cp1->piece > cp2->piece ) return 1;
778 if ( cp1->t < cp2->t ) return -1;
779 if ( cp1->t > cp2->t ) return 1;
780 return 0;
781}
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;
787 return 0;
788}
789
790
791Path::cut_position* Path::CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
792{
793 if ( nbCv <= 0 || pts.empty() || back == false ) {
794 return nullptr;
795 }
796
797 qsort(cvAbs, nbCv, sizeof(double), CmpCurv);
798
799 cut_position *res = nullptr;
800 nbCut = 0;
801 int curCv = 0;
802
803 double len = 0;
804 double lastT = 0;
805 int lastPiece = -1;
806
807 Geom::Point lastM = pts[0].p;
808 Geom::Point lastP = lastM;
809
810 for (const auto & pt : pts) {
811
812 if ( pt.isMoveTo == polyline_moveto ) {
813
814 lastP = lastM = pt.p;
815 lastT = pt.t;
816 lastPiece = pt.piece;
817
818 } else {
819
820 double const add = Geom::L2(pt.p - lastP);
821 double curPos = len;
822 double curAdd = add;
823
824 while ( curAdd > 0.0001 && curCv < nbCv && curPos + curAdd >= cvAbs[curCv] ) {
825 double const theta = (cvAbs[curCv] - len) / add;
826 res = (cut_position*) g_realloc(res, (nbCut + 1) * sizeof(cut_position));
827 res[nbCut].piece = pt.piece;
828 res[nbCut].t = theta * pt.t + (1 - theta) * ( (lastPiece != pt.piece) ? 0 : lastT);
829 nbCut++;
830 curAdd -= cvAbs[curCv] - curPos;
831 curPos = cvAbs[curCv];
832 curCv++;
833 }
834
835 len += add;
836 lastPiece = pt.piece;
837 lastP = pt.p;
838 lastT = pt.t;
839 }
840 }
841
842 return res;
843}
844
845/*
846Moved from Layout-TNG-OutIter.cpp
847TODO: clean up uses of the original function and remove
848
849Original Comment:
850"this function really belongs to Path. I'll probably move it there eventually,
851hence the Path-esque coding style"
852
853*/
854template<typename T> inline static T square(T x) {return x*x;}
856{
857 // if the parameter "seg" == 0, then all segments will be considered
858 // In however e.g. "seg" == 6 , then only the 6th segment will be considered
859
860 unsigned bestSeg = 0;
861 double bestRangeSquared = DBL_MAX;
862 double bestT = 0.0; // you need a sentinel, or make sure that you prime with correct values.
863
864 for (unsigned i = 1 ; i < pts.size() ; i++) {
865 if (pts[i].isMoveTo == polyline_moveto || (seg > 0 && i != seg)) continue;
866 Geom::Point p1, p2, localPos;
867 double thisRangeSquared;
868 double t;
869
870 if (pts[i - 1].p == pts[i].p) {
871 thisRangeSquared = square(pts[i].p[Geom::X] - pos[Geom::X]) + square(pts[i].p[Geom::Y] - pos[Geom::Y]);
872 t = 0.0;
873 } else {
874 // we rotate all our coordinates so we're always looking at a mostly vertical line.
875 if (fabs(pts[i - 1].p[Geom::X] - pts[i].p[Geom::X]) < fabs(pts[i - 1].p[Geom::Y] - pts[i].p[Geom::Y])) {
876 p1 = pts[i - 1].p;
877 p2 = pts[i].p;
878 localPos = pos;
879 } else {
880 p1 = pts[i - 1].p.cw();
881 p2 = pts[i].p.cw();
882 localPos = pos.cw();
883 }
884 double gradient = (p2[Geom::X] - p1[Geom::X]) / (p2[Geom::Y] - p1[Geom::Y]);
885 double intersection = p1[Geom::X] - gradient * p1[Geom::Y];
886 /*
887 orthogonalGradient = -1.0 / gradient; // you are going to have numerical problems here.
888 orthogonalIntersection = localPos[Geom::X] - orthogonalGradient * localPos[Geom::Y];
889 nearestY = (orthogonalIntersection - intersection) / (gradient - orthogonalGradient);
890
891 expand out nearestY fully :
892 nearestY = (localPos[Geom::X] - (-1.0 / gradient) * localPos[Geom::Y] - intersection) / (gradient - (-1.0 / gradient));
893
894 multiply top and bottom by gradient:
895 nearestY = (localPos[Geom::X] * gradient - (-1.0) * localPos[Geom::Y] - intersection * gradient) / (gradient * gradient - (-1.0));
896
897 and simplify to get:
898 */
899 double nearestY = (localPos[Geom::X] * gradient + localPos[Geom::Y] - intersection * gradient)
900 / (gradient * gradient + 1.0);
901 t = (nearestY - p1[Geom::Y]) / (p2[Geom::Y] - p1[Geom::Y]);
902 if (t <= 0.0) {
903 thisRangeSquared = square(p1[Geom::X] - localPos[Geom::X]) + square(p1[Geom::Y] - localPos[Geom::Y]);
904 t = 0.0;
905 } else if (t >= 1.0) {
906 thisRangeSquared = square(p2[Geom::X] - localPos[Geom::X]) + square(p2[Geom::Y] - localPos[Geom::Y]);
907 t = 1.0;
908 } else {
909 thisRangeSquared = square(nearestY * gradient + intersection - localPos[Geom::X]) + square(nearestY - localPos[Geom::Y]);
910 }
911 }
912
913 if (thisRangeSquared < bestRangeSquared) {
914 bestSeg = i;
915 bestRangeSquared = thisRangeSquared;
916 bestT = t;
917 }
918 }
920 if (bestSeg == 0) {
921 result.piece = 0;
922 result.t = 0.0;
923 } else {
924 result.piece = pts[bestSeg].piece;
925 if (result.piece == pts[bestSeg - 1].piece) {
926 result.t = pts[bestSeg - 1].t * (1.0 - bestT) + pts[bestSeg].t * bestT;
927 } else {
928 result.t = pts[bestSeg].t * bestT;
929 }
930 }
931 return result;
932}
933/*
934 this one also belongs to Path
935 returns the length of the path up to the position indicated by t (0..1)
936
937 TODO: clean up uses of the original function and remove
938
939 should this take a cut_position as a parameter?
940*/
941double Path::PositionToLength(int piece, double t)
942{
943 double length = 0.0;
944 for (unsigned i = 1 ; i < pts.size() ; i++) {
945 if (pts[i].isMoveTo == polyline_moveto) continue;
946 if (pts[i].piece == piece && t < pts[i].t) {
947 length += Geom::L2((t - pts[i - 1].t) / (pts[i].t - pts[i - 1].t) * (pts[i].p - pts[i - 1].p));
948 break;
949 }
950 length += Geom::L2(pts[i].p - pts[i - 1].p);
951 }
952 return length;
953}
954
956{
957 if ( nbPos <= 0 ) {
958 return;
959 }
960
961 {
962 Geom::Point lastPos(0, 0);
963 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
964 int const typ = descr_cmd[i]->getType();
965 switch ( typ ) {
966
967 case descr_forced:
968 {
969 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
970 d->p = lastPos;
971 break;
972 }
973
974 case descr_close:
975 {
976 delete descr_cmd[i];
977 descr_cmd[i] = new PathDescrLineTo(Geom::Point(0, 0));
978
979 int fp = i - 1;
980 while ( fp >= 0 && (descr_cmd[fp]->getType()) != descr_moveto ) {
981 fp--;
982 }
983
984 if ( fp >= 0 ) {
985 PathDescrMoveTo *oData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[fp]);
986 dynamic_cast<PathDescrLineTo*>(descr_cmd[i])->p = oData->p;
987 }
988 }
989 break;
990
991 case descr_moveto:
992 {
993 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
994 lastPos = d->p;
995 break;
996 }
997 case descr_lineto:
998 {
999 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1000 lastPos = d->p;
1001 break;
1002 }
1003 case descr_arcto:
1004 {
1005 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1006 lastPos = d->p;
1007 break;
1008 }
1009 case descr_cubicto:
1010 {
1011 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1012 lastPos = d->p;
1013 break;
1014 }
1015 default:
1016 break;
1017 }
1018 }
1019 }
1020 if (descr_cmd[0]->getType() == descr_moveto)
1021 descr_flags |= descr_doing_subpath; // see LP Bug 166302
1022
1023 qsort(poss, nbPos, sizeof(cut_position), CmpPosition);
1024
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;
1031
1032 int const typ = descr_cmd[cp]->getType();
1033 if ( typ == descr_moveto || typ == descr_forced || typ == descr_close ) {
1034 // ponctuel= rien a faire
1035 } else if ( typ == descr_lineto || typ == descr_arcto || typ == descr_cubicto ) {
1036 // facile: creation d'un morceau et d'un forced -> 2 commandes
1037 Geom::Point theP;
1038 Geom::Point theT;
1039 Geom::Point startP;
1040 startP=PrevPoint(cp-1);
1041 if ( typ == descr_cubicto ) {
1042 double len,rad;
1043 Geom::Point stD,enD,endP;
1044 {
1045 PathDescrCubicTo *oData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1046 stD=oData->start;
1047 enD=oData->end;
1048 endP=oData->p;
1049 TangentOnCubAt (ct, startP, *oData,true, theP,theT,len,rad);
1050 }
1051
1052 theT*=len;
1053
1054 InsertCubicTo(endP,(1-ct)*theT,(1-ct)*enD,cp+1);
1055 InsertForcePoint(cp+1);
1056 {
1057 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1058 nData->start=ct*stD;
1059 nData->end=ct*theT;
1060 nData->p=theP;
1061 }
1062 // decalages dans le tableau des positions de coupe
1063 for (int j=curP+1;j<nbPos;j++) {
1064 if ( poss[j].piece == cp ) {
1065 poss[j].piece+=2;
1066 poss[j].t=(poss[j].t-ct)/(1-ct);
1067 } else {
1068 poss[j].piece+=2;
1069 }
1070 }
1071 } else if ( typ == descr_lineto ) {
1072 Geom::Point endP;
1073 {
1074 PathDescrLineTo *oData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1075 endP=oData->p;
1076 }
1077
1078 theP=ct*endP+(1-ct)*startP;
1079
1080 InsertLineTo(endP,cp+1);
1081 InsertForcePoint(cp+1);
1082 {
1083 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1084 nData->p=theP;
1085 }
1086 // decalages dans le tableau des positions de coupe
1087 for (int j=curP+1;j<nbPos;j++) {
1088 if ( poss[j].piece == cp ) {
1089 poss[j].piece+=2;
1090 poss[j].t=(poss[j].t-ct)/(1-ct);
1091 } else {
1092 poss[j].piece+=2;
1093 }
1094 }
1095 } else if ( typ == descr_arcto ) {
1096 Geom::Point endP;
1097 double rx,ry,angle;
1098 bool clockw,large;
1099 double delta=0;
1100 {
1101 PathDescrArcTo *oData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1102 endP=oData->p;
1103 rx=oData->rx;
1104 ry=oData->ry;
1105 angle=oData->angle;
1106 clockw=oData->clockwise;
1107 large=oData->large;
1108 }
1109 {
1110 double sang,eang;
1111 ArcAngles(startP,endP,rx,ry,angle*M_PI/180.0,large,clockw,sang,eang);
1112
1113 if (clockw) {
1114 if ( sang < eang ) sang += 2*M_PI;
1115 delta=eang-sang;
1116 } else {
1117 if ( sang > eang ) sang -= 2*M_PI;
1118 delta=eang-sang;
1119 }
1120 if ( delta < 0 ) delta=-delta;
1121 }
1122
1123 PointAt (cp,ct, theP);
1124
1125 if ( delta*(1-ct) > M_PI ) {
1126 InsertArcTo(endP,rx,ry,angle,true,clockw,cp+1);
1127 } else {
1128 InsertArcTo(endP,rx,ry,angle,false,clockw,cp+1);
1129 }
1130 InsertForcePoint(cp+1);
1131 {
1132 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1133 nData->p=theP;
1134 if ( delta*ct > M_PI ) {
1135 nData->large=true;
1136 } else {
1137 nData->large=false;
1138 }
1139 }
1140 // decalages dans le tableau des positions de coupe
1141 for (int j=curP+1;j<nbPos;j++) {
1142 if ( poss[j].piece == cp ) {
1143 poss[j].piece+=2;
1144 poss[j].t=(poss[j].t-ct)/(1-ct);
1145 } else {
1146 poss[j].piece+=2;
1147 }
1148 }
1149 }
1150 }
1151 }
1152}
1153
1155{
1156 ConvertPositionsToForced(nbPos,poss);
1157// ConvertForcedToMoveTo();
1158 // on fait une version customizee a la place
1159
1160 Path* res=new Path;
1161
1162 Geom::Point lastP(0,0);
1163 for (int i=0;i<int(descr_cmd.size());i++) {
1164 int const typ = descr_cmd[i]->getType();
1165 if ( typ == descr_moveto ) {
1166 Geom::Point np;
1167 {
1168 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1169 np=nData->p;
1170 }
1171 Geom::Point endP;
1172 bool hasClose=false;
1173 int hasForced=-1;
1174 bool doesClose=false;
1175 int j=i+1;
1176 for (;j<int(descr_cmd.size());j++) {
1177 int const ntyp = descr_cmd[j]->getType();
1178 if ( ntyp == descr_moveto ) {
1179 j--;
1180 break;
1181 } else if ( ntyp == descr_forced ) {
1182 if ( hasForced < 0 ) hasForced=j;
1183 } else if ( ntyp == descr_close ) {
1184 hasClose=true;
1185 break;
1186 } else if ( ntyp == descr_lineto ) {
1187 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[j]);
1188 endP=nData->p;
1189 } else if ( ntyp == descr_arcto ) {
1190 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[j]);
1191 endP=nData->p;
1192 } else if ( ntyp == descr_cubicto ) {
1193 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[j]);
1194 endP=nData->p;
1195 }
1196 }
1197 if ( Geom::LInfty(endP-np) < 0.00001 ) {
1198 doesClose=true;
1199 }
1200 if ( ( doesClose || hasClose ) && hasForced >= 0 ) {
1201 // printf("nasty i=%i j=%i frc=%i\n",i,j,hasForced);
1202 // aghhh.
1203 Geom::Point nMvtP=PrevPoint(hasForced);
1204 res->MoveTo(nMvtP);
1205 Geom::Point nLastP=nMvtP;
1206 for (int k = hasForced + 1; k < j; k++) {
1207 int ntyp=descr_cmd[k]->getType();
1208 if ( ntyp == descr_moveto ) {
1209 // ne doit pas arriver
1210 } else if ( ntyp == descr_forced ) {
1211 res->MoveTo(nLastP);
1212 } else if ( ntyp == descr_close ) {
1213 // rien a faire ici; de plus il ne peut y en avoir qu'un
1214 } else if ( ntyp == descr_lineto ) {
1215 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1216 res->LineTo(nData->p);
1217 nLastP=nData->p;
1218 } else if ( ntyp == descr_arcto ) {
1219 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1220 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1221 nLastP=nData->p;
1222 } else if ( ntyp == descr_cubicto ) {
1223 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1224 res->CubicTo(nData->p,nData->start,nData->end);
1225 nLastP=nData->p;
1226 }
1227 }
1228 if ( doesClose == false ) res->LineTo(np);
1229 nLastP=np;
1230 for (int k=i+1;k<hasForced;k++) {
1231 int ntyp=descr_cmd[k]->getType();
1232 if ( ntyp == descr_moveto ) {
1233 // ne doit pas arriver
1234 } else if ( ntyp == descr_forced ) {
1235 res->MoveTo(nLastP);
1236 } else if ( ntyp == descr_close ) {
1237 // rien a faire ici; de plus il ne peut y en avoir qu'un
1238 } else if ( ntyp == descr_lineto ) {
1239 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1240 res->LineTo(nData->p);
1241 nLastP=nData->p;
1242 } else if ( ntyp == descr_arcto ) {
1243 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1244 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1245 nLastP=nData->p;
1246 } else if ( ntyp == descr_cubicto ) {
1247 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1248 res->CubicTo(nData->p,nData->start,nData->end);
1249 nLastP=nData->p;
1250 }
1251 }
1252 lastP=nMvtP;
1253 i=j;
1254 } else {
1255 // regular, just move on
1256 res->MoveTo(np);
1257 lastP=np;
1258 }
1259 } else if ( typ == descr_close ) {
1260 res->Close();
1261 } else if ( typ == descr_forced ) {
1262 res->MoveTo(lastP);
1263 } else if ( typ == descr_lineto ) {
1264 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1265 res->LineTo(nData->p);
1266 lastP=nData->p;
1267 } else if ( typ == descr_arcto ) {
1268 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1269 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1270 lastP=nData->p;
1271 } else if ( typ == descr_cubicto ) {
1272 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1273 res->CubicTo(nData->p,nData->start,nData->end);
1274 lastP=nData->p;
1275 } else {
1276 }
1277 }
1278
1279 Copy(res);
1280 delete res;
1281 return;
1282}
1283
1284/*
1285 Local Variables:
1286 mode:c++
1287 c-file-style:"stroustrup"
1288 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1289 indent-tabs-mode:nil
1290 fill-column:99
1291 End:
1292*/
1293// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Cartesian point / 2D vector and related operations.
static int CmpCurv(const void *p1, const void *p2)
static T square(T x)
static int CmpPosition(const void *p1, const void *p2)
TODO: insert short description here.
@ polyline_moveto
Definition Path.h:47
double scale
Definition aa.cpp:228
3x3 affine transformation matrix.
3x3 matrix representing an affine transformation.
Definition affine.h:70
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
Elliptical arc curve.
Sequence of subpaths.
Definition pathvector.h:122
size_type size() const
Get the number of paths in the vector.
Definition pathvector.h:147
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
Sequence of contiguous curves, aka spline.
Definition path.h:353
bool closed() const
Check whether the path is closed.
Definition path.h:503
void close(bool closed=true)
Set whether the path is closed.
Definition path.cpp:322
bool empty() const
Check whether path is empty.
Definition path.h:500
Point initialPoint() const
Get the first point in the path.
Definition path.h:705
void appendNew(Args &&... args)
Append a new curve to the path.
Definition path.h:804
void start(Point const &p)
Definition path.cpp:426
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Point cw() const
Return a point like this point but rotated +90 degrees.
Definition point.h:137
Path and its polyline approximation.
Definition Path.h:93
@ descr_doing_subpath
Definition Path.h:100
int LineTo(Geom::Point const &ip)
Appends a LineTo path command.
Definition Path.cpp:151
void SetBackData(bool nVal)
Sets the back variable to the value passed in and clears the polyline approximation.
Definition Path.cpp:232
double Surface()
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)
Definition Path.cpp:161
int Close()
Appends a close path command.
Definition Path.cpp:109
void ConvertForcedToVoid()
cut_position PointToCurvilignPosition(Geom::Point const &pos, unsigned seg=0) const
double Length()
void ConvertForcedToMoveTo()
int ArcTo(Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise)
Appends an ArcTo path command.
Definition Path.cpp:200
void PointAt(int piece, double at, Geom::Point &pos)
Definition Path.cpp:328
std::vector< path_lineto > pts
Definition Path.h:128
void LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation)
Load a lib2geom Geom::PathVector in this path object.
int descr_flags
Definition Path.h:105
Geom::PathVector MakePathVector() const
Create a lib2geom Geom::PathVector from this Path object.
int MoveTo(Geom::Point const &ip)
Appends a MoveTo path command.
Definition Path.cpp:125
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)
Definition Path.cpp:212
std::vector< ForcedSubdivision > forced_subdivisions
Definition Path.h:140
void Copy(Path *who)
Clear all stored path commands, resets flags and imports path commands from the passed Path object.
Definition Path.cpp:57
bool back
Definition Path.h:131
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)
Definition Path.cpp:186
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.
Definition Path.cpp:175
std::vector< PathDescr * > descr_cmd
Definition Path.h:108
int AddPoint(Geom::Point const &iPt, bool mvto=false)
Adds a point to the polyline approximation's list of points.
Definition Path.cpp:254
void Convert(double treshhold)
Creates a polyline approximation of the path.
void InsertForcePoint(int at)
Definition Path.cpp:95
void Reset()
Clears all stored path commands and resets flags that are used by command functions while adding path...
Definition Path.cpp:45
double PositionToLength(int piece, double t)
An SVG style object.
Definition style.h:45
T< SPAttr::STROKE_DASHARRAY, SPIDashArray > stroke_dasharray
stroke-dasharray
Definition style.h:257
T< SPAttr::STROKE_DASHOFFSET, SPILength > stroke_dashoffset
stroke-dashoffset
Definition style.h:259
Css & result
Include all curve types.
double c[8][4]
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
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)
Definition d2-sbasis.cpp:42
Coord LInfty(Point const &p)
TODO: insert short description here.
@ descr_lineto
@ descr_arcto
@ descr_moveto
@ descr_cubicto
@ descr_close
@ descr_forced
PathVector - a sequence of subpaths.
auto len
Definition safe-printf.h:21
void append(std::vector< T > &vec, std::vector< T > const &other)
Definition sanitize.cpp:55
Conversion between SBasis and Bezier basis polynomials.
static const Point data[]
Elliptical Arc path command.
Close Path instruction.
Cubic Bezier path command.
A forced point path command.
A LineTo path command.
A MoveTo path command.
Definition curve.h:24
SPStyle - a style object for SPItem objects.
int delta
static double square(double const x)