1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3  * Path utilities.
4  *//*
5  * Authors:
6  * see git history
7  *  Created by fred on Fri Dec 05 2003.
8  *  tweaked endlessly by bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2018 Authors
11  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12  */
13 
14 #ifdef HAVE_CONFIG_H
15 #endif
16 
17 #include <vector>
18 
19 #include "path-util.h"
20 
21 #include "text-editing.h"
22 
23 #include "livarot/Path.h"
24 #include "livarot/Shape.h"
25 
26 #include "object/sp-flowtext.h"
27 #include "object/sp-image.h"
28 #include "object/sp-marker.h"
29 #include "object/sp-path.h"
30 #include "object/sp-text.h"
31 
32 #include "display/curve.h"
33 
34 // derived from Path_for_item
35 Path *
Path_for_pathvector(Geom::PathVector const & epathv)36 Path_for_pathvector(Geom::PathVector const &epathv)
37 {
38     /*std::cout << "converting to Livarot path" << std::endl;
39 
40     Geom::SVGPathWriter wr;
41     wr.feed(epathv);
42     std::cout << wr.str() << std::endl;*/
43 
44     Path *dest = new Path;
45     dest->LoadPathVector(epathv);
46     return dest;
47 }
48 
49 Path *
Path_for_item(SPItem * item,bool doTransformation,bool transformFull)50 Path_for_item(SPItem *item, bool doTransformation, bool transformFull)
51 {
52     std::unique_ptr<SPCurve> curve = curve_for_item(item);
53 
54     if (curve == nullptr)
55         return nullptr;
56 
57     Geom::PathVector *pathv =
58         pathvector_for_curve(item, curve.get(), doTransformation, transformFull, Geom::identity(), Geom::identity());
59 
60     /*std::cout << "converting to Livarot path" << std::endl;
61 
62     Geom::SVGPathWriter wr;
63     if (pathv) {
64         wr.feed(*pathv);
65     }
66     std::cout << wr.str() << std::endl;*/
67 
68     Path *dest = new Path;
69     dest->LoadPathVector(*pathv);
70     delete pathv;
71 
72     /*gchar *str = dest->svg_dump_path();
73     std::cout << "After conversion:\n" << str << std::endl;
74     g_free(str);*/
75 
76     return dest;
77 }
78 
79 /**
80  * Obtains an item's Path before the LPE stack has been applied.
81  */
82 Path *
Path_for_item_before_LPE(SPItem * item,bool doTransformation,bool transformFull)83 Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull)
84 {
85     std::unique_ptr<SPCurve> curve = curve_for_item_before_LPE(item);
86 
87     if (curve == nullptr)
88         return nullptr;
89 
90     Geom::PathVector *pathv =
91         pathvector_for_curve(item, curve.get(), doTransformation, transformFull, Geom::identity(), Geom::identity());
92 
93     Path *dest = new Path;
94     dest->LoadPathVector(*pathv);
95     delete pathv;
96 
97     return dest;
98 }
99 
100 /*
101  * NOTE: Returns empty pathvector if curve == NULL
102  * TODO: see if calling this method can be optimized. All the pathvector copying might be slow.
103  */
104 Geom::PathVector*
pathvector_for_curve(SPItem * item,SPCurve * curve,bool doTransformation,bool transformFull,Geom::Affine extraPreAffine,Geom::Affine extraPostAffine)105 pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Affine extraPreAffine, Geom::Affine extraPostAffine)
106 {
107     if (curve == nullptr)
108         return nullptr;
109 
110     Geom::PathVector *dest = new Geom::PathVector;
111     *dest = curve->get_pathvector(); // Make a copy; must be freed by the caller!
112 
113     if (doTransformation) {
114         if (transformFull) {
115             *dest *= extraPreAffine * item->i2doc_affine() * extraPostAffine;
116         } else {
117             *dest *= extraPreAffine * (Geom::Affine)item->transform * extraPostAffine;
118         }
119     } else {
120         *dest *= extraPreAffine * extraPostAffine;
121     }
122 
123     return dest;
124 }
125 
126 /**
127  * Obtains an item's curve. For SPPath, it is the path *before* LPE. For SPShapes other than path, it is the path *after* LPE.
128  * So the result is somewhat ill-defined, and probably this method should not be used... See curve_for_item_before_LPE.
129  */
curve_for_item(SPItem * item)130 std::unique_ptr<SPCurve> curve_for_item(SPItem *item)
131 {
132     if (!item)
133         return nullptr;
134 
135     std::unique_ptr<SPCurve> curve;
136 
137     if (auto path = dynamic_cast<SPPath const *>(item)) {
138         curve = SPCurve::copy(path->curveForEdit());
139     } else if (auto shape = dynamic_cast<SPShape const *>(item)) {
140         curve = SPCurve::copy(shape->curve());
141     } else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
142         curve = te_get_layout(item)->convertToCurves();
143     } else if (auto image = dynamic_cast<SPImage const *>(item)) {
144         curve = image->get_curve();
145     }
146 
147     return curve;
148 }
149 
150 /**
151  * Obtains an item's curve *before* LPE.
152  */
curve_for_item_before_LPE(SPItem * item)153 std::unique_ptr<SPCurve> curve_for_item_before_LPE(SPItem *item)
154 {
155     if (!item)
156         return nullptr;
157 
158     std::unique_ptr<SPCurve> curve;
159 
160     if (auto shape = dynamic_cast<SPShape const *>(item)) {
161         curve = SPCurve::copy(shape->curveForEdit());
162     } else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
163         curve = te_get_layout(item)->convertToCurves();
164     } else if (auto image = dynamic_cast<SPImage const *>(item)) {
165         curve = image->get_curve();
166     }
167 
168     return curve;
169 }
170 
get_nearest_position_on_Path(Path * path,Geom::Point p,unsigned seg)171 std::optional<Path::cut_position> get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg)
172 {
173     //get nearest position on path
174     Path::cut_position pos = path->PointToCurvilignPosition(p, seg);
175     return pos;
176 }
177 
get_point_on_Path(Path * path,int piece,double t)178 Geom::Point get_point_on_Path(Path *path, int piece, double t)
179 {
180     Geom::Point p;
181     path->PointAt(piece, t, p);
182     return p;
183 }
184 
185 
186 /*
187   Local Variables:
188   mode:c++
189   c-file-style:"stroustrup"
190   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
191   indent-tabs-mode:nil
192   fill-column:99
193   End:
194 */
195 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
196