Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
Path.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors: see git history
6 *
7 * Copyright (C) 2014 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10/*
11 * Path.h
12 * nlivarot
13 *
14 * Created by fred on Tue Jun 17 2003.
15 *
16 */
17
18#ifndef my_path
19#define my_path
20
21#include <span>
22#include <vector>
23#include "LivarotDefs.h"
24#include <2geom/point.h>
25
26struct PathDescr;
27struct PathDescrLineTo;
28struct PathDescrArcTo;
29struct PathDescrCubicTo;
30
31class SPStyle;
32
33/*
34 * the Path class: a structure to hold path description and their polyline approximation (not kept in sync)
35 * the path description is built with regular commands like MoveTo() LineTo(), etc
36 * the polyline approximation is built by a call to Convert() or its variants
37 * another possibility would be to call directly the AddPoint() functions, but that is not encouraged
38 * the conversion to polyline can salvage data as to where on the path each polyline's point lies; use
39 * ConvertWithBackData() for this. after this call, it's easy to rewind the polyline: sequences of points
40 * of the same path command can be reassembled in a command
41 */
42
43// polyline description commands
44enum
45{
46 polyline_lineto = 0, // a lineto
47 polyline_moveto = 1, // a moveto
48 polyline_forced = 2 // a forced point, ie a point that was an angle or an intersection in a previous life
49 // or more realistically a control point in the path description that created the polyline
50 // forced points are used as "breakable" points for the polyline -> cubic bezier patch operations
51 // each time the bezier fitter encounters such a point in the polyline, it decreases its treshhold,
52 // so that it is more likely to cut the polyline at that position and produce a bezier patch
53};
54
55class Shape;
56
57// path creation: 2 phases: first the path is given as a succession of commands (MoveTo, LineTo, CurveTo...); then it
58// is converted in a polyline
59// a polylone can be stroked or filled to make a polygon
60
92class Path
93{
94 friend class Shape;
95
96 // flags for the path construction
97 enum
98 {
100 descr_doing_subpath = 2, // we're doing a path, so there is a moveto somewhere
101 descr_dirty = 16 // the path description was modified
102 };
103
104 // some data for the construction: what's pending, and some flags
106
107public:
108 std::vector<PathDescr*> descr_cmd;
117 {
118 path_lineto(bool m, Geom::Point const &pp) : isMoveTo(m), p(pp) {}
119 path_lineto(bool m, Geom::Point const &pp, int pie, double tt) : isMoveTo(m), p(pp), piece(pie), t(tt) {}
120
123 int piece = -1;
124 double t = 0.0;
125 bool closed = false;
126 };
127
128 std::vector<path_lineto> pts;
130private:
131 bool back = false;
134 // list of points at which to ensure the polyline approximation will be subdivided, sorted ascending by path time
136 {
137 int piece;
138 double t;
139 };
140 std::vector<ForcedSubdivision> forced_subdivisions;
141
142public:
143 ~Path();
144
145 // creation of the path description
146
151 void Reset();
152
159 void Copy (Path * who);
160
179 int ForcePoint();
180
188 int Close();
189
196 int MoveTo ( Geom::Point const &ip);
197
204 int LineTo ( Geom::Point const &ip);
205
219 int CubicTo ( Geom::Point const &ip, Geom::Point const &iStD, Geom::Point const &iEnD);
220
235 int ArcTo ( Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise);
236
237 // transforms a description in a polyline (for stroking and filling)
238 // treshhold is the max length^2 (sort of)
239
249 void Convert (double treshhold);
250
263 void ConvertEvenLines (double treshhold); // decomposes line segments too, for later recomposition
264
276 void ConvertWithBackData(double threshhold, bool relative = false);
277
278 // creation of the polyline (you can tinker with these function if you want)
279
285 void SetBackData (bool nVal); // has back data?
286
290 void ResetPoints(); // resets to the empty polyline
291
292private:
310 int AddPoint ( Geom::Point const &iPt, bool mvto = false); // add point
311
328 int AddPoint ( Geom::Point const &iPt, int ip, double it, bool mvto = false);
329
339 int AddForcedPoint();
340
341public:
342 // transform in a polygon (in a graph, in fact; a subsequent call to ConvertToShape is needed)
343 // - fills the polyline; justAdd=true doesn't reset the Shape dest, but simply adds the polyline into it
344 // closeIfNeeded=false prevent the function from closing the path (resulting in a non-eulerian graph
345 // pathID is a identification number for the path, and is used for recomposing curves from polylines
346 // give each different Path a different ID, and feed the appropriate orig[] to the ConvertToForme() function
347
379 void Fill(Shape *dest, int pathID = -1, bool justAdd = false,
380 bool closeIfNeeded = true, bool invert = false);
381
382 // - stroke the path; usual parameters: type of cap=butt, type of join=join and miter (see LivarotDefs.h)
383 // doClose treat the path as closed (ie a loop)
384 void Stroke(Shape *dest, bool doClose, double width, JoinType join,
385 ButtType butt, double miter, bool justAdd = false);
386
387 // build a Path that is the outline of the Path instance's description (the result is stored in dest)
388 // it doesn't compute the exact offset (it's way too complicated, but an approximation made of cubic bezier patches
389 // and segments. the algorithm was found in a plugin for Impress (by Chris Cox), but i can't find it back...
390 void Outline(Path *dest, double width, JoinType join, ButtType butt,
391 double miter);
392
393 // half outline with edges having the same direction as the original
394 void OutsideOutline(Path *dest, double width, JoinType join, ButtType butt,
395 double miter);
396
397 // half outline with edges having the opposite direction as the original
398 void InsideOutline (Path * dest, double width, JoinType join, ButtType butt,
399 double miter);
400
401 // polyline to cubic bezier patches
402
417 void Simplify (double treshhold);
418
428 void Coalesce (double tresh);
429
430 // utilities
431 // piece is a command no in the command list
432 // "at" is an abcissis on the path portion associated with this command
433 // 0=beginning of portion, 1=end of portion.
434 void PointAt (int piece, double at, Geom::Point & pos);
435 void PointAndTangentAt (int piece, double at, Geom::Point & pos, Geom::Point & tgt);
436
437 // last control point before the command i (i included)
438 // used when dealing with quadratic bezier spline, cause these can contain arbitrarily many commands
439 const Geom::Point PrevPoint (const int i) const;
440
441 // dash the polyline
442 // the result is stored in the polyline, so you lose the original. make a copy before if needed
443 void DashPolyline(float head,float tail,float body,int nbD, const float dashs[],bool stPlain,float stOffset);
444
445 void DashPolylineFromStyle(SPStyle *style, float scale, float min_len);
446
447 //utilitaire pour inkscape
448
461 void LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append = false);
462
472 void LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation);
473
481 void LoadPathVector(Geom::PathVector const &pv);
482
491 void LoadPathVector(Geom::PathVector const &pv, std::vector<Geom::PathVectorTime> const &cuts);
492
502
510 void Transform(const Geom::Affine &trans);
511
512 // decompose le chemin en ses sous-chemin
513 // killNoSurf=true -> oublie les chemins de surface nulle
514 Path** SubPaths(int &outNb,bool killNoSurf);
515 // pour recuperer les trous
516 // nbNest= nombre de contours
517 // conts= debut de chaque contour
518 // nesting= parent de chaque contour
519 Path** SubPathsWithNesting(int &outNb,bool killNoSurf,int nbNest,int* nesting,int* conts);
520 // surface du chemin (considere comme ferme)
521 double Surface();
522 void PolylineBoundingBox(double &l,double &t,double &r,double &b);
523 void FastBBox(double &l,double &t,double &r,double &b);
524 // longueur (totale des sous-chemins)
525 double Length();
526
528 void ConvertForcedToVoid();
530 int piece;
531 double t;
532 };
533 cut_position* CurvilignToPosition(int nbCv,double* cvAbs,int &nbCut);
534 cut_position PointToCurvilignPosition(Geom::Point const &pos, unsigned seg = 0) const;
535 //Should this take a cut_position as a param?
536 double PositionToLength(int piece, double t);
537
538 // caution: not tested on quadratic b-splines, most certainly buggy
539 void ConvertPositionsToMoveTo(int nbPos,cut_position* poss);
540 void ConvertPositionsToForced(int nbPos,cut_position* poss);
541
542 void Affiche();
543 std::string svg_dump_path() const;
544
545 bool IsLineSegment(int piece);
546
547 private:
548 // utilitary functions for the path construction
549 void CloseSubpath();
550 void InsertMoveTo (Geom::Point const &iPt,int at);
551 void InsertForcePoint (int at);
552 void InsertLineTo (Geom::Point const &iPt,int at);
553 void InsertArcTo (Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise,int at);
554 void InsertCubicTo (Geom::Point const &ip, Geom::Point const &iStD, Geom::Point const &iEnD,int at);
555
556 // creation of dashes: take the polyline given by spP (length spL) and dash it according to head, body, etc. put the result in
557 // the polyline of this instance
558 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);
559
560 // Functions used by the conversion.
561 // they append points to the polyline
581 void DoArc ( Geom::Point const &iS, Geom::Point const &iE, double rx, double ry,
582 double angle, bool large, bool wise, double tresh);
632 void RecCubicTo ( Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double tresh, int lev,
633 double maxL = -1.0);
634
635 void DoArc(Geom::Point const &iS, Geom::Point const &iE, double rx, double ry,
636 double angle, bool large, bool wise, double tresh, int piece,
637 bool relative, std::vector<double> const &cuts = {});
638 void RecCubicTo ( Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double tresh, int lev,
639 double st, double et, int piece, bool relative);
640 void RecCubicTo(Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double thresh, int lev,
641 double st, double et, int piece, bool relative, std::span<double> const &cuts);
642
643 static void ArcAngles ( Geom::Point const &iS, Geom::Point const &iE, double rx,
644 double ry, double angle, bool large, bool wise,
645 double &sang, double &eang);
646 static void CubicTangent (double t, Geom::Point &oPt, Geom::Point const &iS,
647 Geom::Point const &iSd, Geom::Point const &iE,
648 Geom::Point const &iEd);
649
650 struct outline_callback_data
651 {
652 Path *orig;
653 int piece;
654 double tSt, tEn;
655 Path *dest;
656 double x1, y1, x2, y2;
657 union
658 {
659 struct
660 {
661 double dx1, dy1, dx2, dy2;
662 }
663 c;
664 struct
665 {
666 double mx, my;
667 }
668 b;
669 struct
670 {
671 double rx, ry, angle;
672 bool clock, large;
673 double stA, enA;
674 }
675 a;
676 }
677 d;
678 };
679
680 typedef void (outlineCallback) (outline_callback_data * data, double tol, double width);
681 struct outline_callbacks
682 {
683 outlineCallback *cubicto;
684 outlineCallback *arcto;
685 };
686
687 void SubContractOutline (int off, int num_pd,
688 Path * dest, outline_callbacks & calls,
689 double tolerance, double width, JoinType join,
690 ButtType butt, double miter, bool closeIfNeeded,
691 bool skipMoveto, Geom::Point & lastP, Geom::Point & lastT);
692 void DoStroke(int off, int N, Shape *dest, bool doClose, double width, JoinType join,
693 ButtType butt, double miter, bool justAdd = false);
694
695 static void TangentOnSegAt(double at, Geom::Point const &iS, PathDescrLineTo const &fin,
696 Geom::Point &pos, Geom::Point &tgt, double &len);
697 static void TangentOnArcAt(double at, Geom::Point const &iS, PathDescrArcTo const &fin,
698 Geom::Point &pos, Geom::Point &tgt, double &len, double &rad);
699 static void TangentOnCubAt (double at, Geom::Point const &iS, PathDescrCubicTo const &fin, bool before,
700 Geom::Point &pos, Geom::Point &tgt, double &len, double &rad);
701 static void OutlineJoin (Path * dest, Geom::Point pos, Geom::Point stNor, Geom::Point enNor,
702 double width, JoinType join, double miter, int nType);
703
704 static bool IsNulCurve (std::vector<PathDescr*> const &cmd, int curD, Geom::Point const &curX);
705
706 static void RecStdCubicTo (outline_callback_data * data, double tol,
707 double width, int lev);
708 static void StdCubicTo (outline_callback_data * data, double tol,
709 double width);
710 static void RecStdArcTo (outline_callback_data * data, double tol,
711 double width, int lev);
712 static void StdArcTo (outline_callback_data * data, double tol, double width);
713
714 // fonctions annexes pour le stroke
715 static void DoButt (Shape * dest, double width, ButtType butt, Geom::Point pos,
716 Geom::Point dir, int &leftNo, int &rightNo);
717 static void DoJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
718 Geom::Point prev, Geom::Point next, double miter, double prevL,
719 double nextL, int *stNo, int *enNo);
720 static void DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
721 Geom::Point prev, Geom::Point next, double miter, double prevL,
722 double nextL, int &leftStNo, int &leftEnNo,int pathID=-1,int pieceID=0,double tID=0.0);
723 static void DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
724 Geom::Point prev, Geom::Point next, double miter, double prevL,
725 double nextL, int &rightStNo, int &rightEnNo,int pathID=-1,int pieceID=0,double tID=0.0);
726 static void RecRound (Shape * dest, int sNo, int eNo,
727 Geom::Point const &iS, Geom::Point const &iE,
728 Geom::Point const &nS, Geom::Point const &nE,
729 Geom::Point &origine,float width);
730
731
744 void DoSimplify(int off, int N, double treshhold);
745
758 bool AttemptSimplify(int off, int N, double treshhold, PathDescrCubicTo &res, int &worstP);
759 /*
760 * The actual fitting code that takes a sequence and fits stuff on it.
761 *
762 * Totally based on the algorithm from:
763 * http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/INT-APP/CURVE-APP-global.html
764 *
765 * @param start The start point of the cubic bezier which is already known.
766 * @param res The cubic Bezier path command that function will populate after doing the maths.
767 * @param Xk The array of X coordinates of the point to fit.
768 * @param Yk The array of Y coordinates of the point to fit.
769 * @param Qk An array to store some intermediate values.
770 * @param tk The time values for the points.
771 * @param nbPt The total points to fit on.
772 *
773 * @return True if the fit was done correctly, false if something bad happened. (Non-invertible
774 * matrix).
775 */
776 static bool FitCubic(Geom::Point const &start,
777 PathDescrCubicTo &res,
778 double *Xk, double *Yk, double *Qk, double *tk, int nbPt);
787 struct fitting_tables {
788 int nbPt;
789 int maxPt;
790 int inPt;
791 double *Xk;
792 double *Yk;
793 double *Qk;
794 double *tk;
795 double *lk;
796 char *fk;
797 double totLen;
798 };
799
809 bool AttemptSimplify (fitting_tables &data,double treshhold, PathDescrCubicTo & res,int &worstP);
810
830 bool ExtendFit(int off, int N, fitting_tables &data,double treshhold, PathDescrCubicTo & res,int &worstP);
836 double RaffineTk (Geom::Point pt, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, double it);
837 void FlushPendingAddition(Path* dest,PathDescr *lastAddition,PathDescrCubicTo &lastCubic,int lastAD);
838
839private:
858 void AddCurve(Geom::Curve const &c);
859};
860
861#endif
862
863/*
864 Local Variables:
865 mode:c++
866 c-file-style:"stroustrup"
867 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
868 indent-tabs-mode:nil
869 fill-column:99
870 End:
871*/
872// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Cartesian point / 2D vector and related operations.
TODO: insert short description here.
ButtType
Definition LivarotDefs.h:52
JoinType
Definition LivarotDefs.h:61
@ polyline_moveto
Definition Path.h:47
@ polyline_lineto
Definition Path.h:46
@ polyline_forced
Definition Path.h:48
3x3 matrix representing an affine transformation.
Definition affine.h:70
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
Two-dimensional point that doubles as a vector.
Definition point.h:66
Path and its polyline approximation.
Definition Path.h:93
@ descr_doing_subpath
Definition Path.h:100
@ descr_dirty
Definition Path.h:101
@ descr_ready
Definition Path.h:99
void ConvertWithBackData(double threshhold, bool relative=false)
Creates a polyline approximation of the path.
~Path()
Definition Path.cpp:26
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 Affiche()
Definition Path.cpp:34
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
void OutsideOutline(Path *dest, double width, JoinType join, ButtType butt, double miter)
void ResetPoints()
Clears the polyline approximation.
Definition Path.cpp:248
double Length()
void ConvertForcedToMoveTo()
void Fill(Shape *dest, int pathID=-1, bool justAdd=false, bool closeIfNeeded=true, bool invert=false)
Fills the shape with the polyline approximation stored in this object.
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
int AddForcedPoint()
Adds a forced point to the polyline approximation's list of points.
Definition Path.cpp:284
std::string svg_dump_path() const
Definition Path.cpp:577
std::vector< path_lineto > pts
Definition Path.h:128
void Transform(const Geom::Affine &trans)
Apply a transformation on all path commands.
Definition Path.cpp:422
void ConvertEvenLines(double treshhold)
Creates a polyline approximation of the path.
void LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation)
Load a lib2geom Geom::PathVector in this path object.
void PointAndTangentAt(int piece, double at, Geom::Point &pos, Geom::Point &tgt)
Definition Path.cpp:368
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
void Outline(Path *dest, double width, JoinType join, ButtType butt, double miter)
Path ** SubPathsWithNesting(int &outNb, bool killNoSurf, int nbNest, int *nesting, int *conts)
void DoArc(Geom::Point const &iS, Geom::Point const &iE, double rx, double ry, double angle, bool large, bool wise, double tresh)
The function is quite similar to RecCubicTo.
void DashPolyline(float head, float tail, float body, int nbD, const float dashs[], bool stPlain, float stOffset)
void ConvertPositionsToMoveTo(int nbPos, cut_position *poss)
void InsideOutline(Path *dest, double width, JoinType join, ButtType butt, double miter)
bool IsLineSegment(int piece)
Definition Path.cpp:590
cut_position * CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
void Coalesce(double tresh)
Simplify the path with a different approach.
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
void FastBBox(double &l, double &t, double &r, double &b)
Definition Path.cpp:427
void Stroke(Shape *dest, bool doClose, double width, JoinType join, ButtType butt, double miter, bool justAdd=false)
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
void CloseSubpath()
Definition Path.cpp:75
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 InsertMoveTo(Geom::Point const &iPt, int at)
Definition Path.cpp:137
void Simplify(double treshhold)
Simplify the path.
void Convert(double treshhold)
Creates a polyline approximation of the path.
void PolylineBoundingBox(double &l, double &t, double &r, double &b)
Definition Path.cpp:301
void InsertForcePoint(int at)
Definition Path.cpp:95
int ForcePoint()
Appends a forced point path command.
Definition Path.cpp:80
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
A class to store/manipulate directed graphs.
Definition Shape.h:65
double c[8][4]
Geom::Point orig
Geom::Point start
double angle(std::vector< Point > const &A)
int off
auto len
Definition safe-printf.h:21
void append(std::vector< T > &vec, std::vector< T > const &other)
Definition sanitize.cpp:55
size_t N
void invert(const double v[16], double alpha[16])
static const Point data[]
Elliptical Arc path command.
Cubic Bezier path command.
A LineTo path command.
A base class for Livarot's path commands.
Points of the polyline approximation.
Definition Path.h:117
path_lineto(bool m, Geom::Point const &pp)
Definition Path.h:118
Geom::Point p
Definition Path.h:122
path_lineto(bool m, Geom::Point const &pp, int pie, double tt)
Definition Path.h:119
double width