Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
pathvector.cpp
Go to the documentation of this file.
1/*
4 * Authors:
5 * Johan Engelen <goejendaagh@zonnet.nl>
6 * Krzysztof KosiƄski <tweenk.pl@gmail.com>
7 *
8 * Copyright 2008-2014 Authors
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it either under the terms of the GNU Lesser General Public
12 * License version 2.1 as published by the Free Software Foundation
13 * (the "LGPL") or, at your option, under the terms of the Mozilla
14 * Public License Version 1.1 (the "MPL"). If you do not alter this
15 * notice, a recipient may use your version of this file under either
16 * the MPL or the LGPL.
17 *
18 * You should have received a copy of the LGPL along with this library
19 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * You should have received a copy of the MPL along with this library
22 * in the file COPYING-MPL-1.1
23 *
24 * The contents of this file are subject to the Mozilla Public License
25 * Version 1.1 (the "License"); you may not use this file except in
26 * compliance with the License. You may obtain a copy of the License at
27 * http://www.mozilla.org/MPL/
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
30 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
31 * the specific language governing rights and limitations.
32 */
33
34#include <2geom/affine.h>
35#include <2geom/path.h>
36#include <2geom/pathvector.h>
38#include <2geom/sweeper.h>
39#include <optional>
40
41namespace Geom {
42
43//PathVector &PathVector::operator+=(PathVector const &other);
44
46{
47 size_type n = 0;
48 for (const auto & it : *this) {
49 n += it.size_default();
50 }
51 return n;
52}
53
54void PathVector::reverse(bool reverse_paths)
55{
56 if (reverse_paths) {
57 std::reverse(begin(), end());
58 }
59 for (auto & i : *this) {
60 i = i.reversed();
61 }
62}
63
64PathVector PathVector::reversed(bool reverse_paths) const
65{
66 PathVector ret;
67 for (const auto & i : *this) {
68 ret.push_back(i.reversed());
69 }
70 if (reverse_paths) {
71 std::reverse(ret.begin(), ret.end());
72 }
73 return ret;
74}
75
77{
78 return const_cast<Path &>(static_cast<PathVector const*>(this)->pathAt(t, rest));
79}
80Path const &PathVector::pathAt(Coord t, Coord *rest) const
81{
83 if (rest) {
84 *rest = Coord(pos.curve_index) + pos.t;
85 }
86 return at(pos.path_index);
87}
88Curve const &PathVector::curveAt(Coord t, Coord *rest) const
89{
91 if (rest) {
92 *rest = pos.t;
93 }
94 return at(pos.path_index).at(pos.curve_index);
95}
97{
99 return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d);
100}
102{
104 return at(pos.path_index).at(pos.curve_index).pointAt(pos.t);
105}
106
108{
109 OptRect bound;
110 if (empty()) return bound;
111
112 bound = front().boundsFast();
113 for (const_iterator it = ++begin(); it != end(); ++it) {
114 bound.unionWith(it->boundsFast());
115 }
116 return bound;
117}
118
120{
121 OptRect bound;
122 if (empty()) return bound;
123
124 bound = front().boundsExact();
125 for (const_iterator it = ++begin(); it != end(); ++it) {
126 bound.unionWith(it->boundsExact());
127 }
128 return bound;
129}
130
132{
133 for (std::size_t i = 0; i < size(); ++i) {
134 (*this)[i].snapEnds(precision);
135 }
136}
137
138// sweepline optimization
139// this is very similar to CurveIntersectionSweepSet in path.cpp
140// should probably be merged
141class PathIntersectionSweepSet {
142public:
143 struct PathRecord {
144 boost::intrusive::list_member_hook<> _hook;
145 Path const *path;
146 std::size_t index;
147 unsigned which;
148
149 PathRecord(Path const &p, std::size_t i, unsigned w)
150 : path(&p)
151 , index(i)
152 , which(w)
153 {}
154 };
155
156 typedef std::vector<PathRecord>::iterator ItemIterator;
157
158 PathIntersectionSweepSet(std::vector<PVIntersection> &result,
159 PathVector const &a, PathVector const &b, Coord precision)
160 : _result(result)
161 , _precision(precision)
162 {
163 _records.reserve(a.size() + b.size());
164 for (std::size_t i = 0; i < a.size(); ++i) {
165 _records.emplace_back(a[i], i, 0);
166 }
167 for (std::size_t i = 0; i < b.size(); ++i) {
168 _records.emplace_back(b[i], i, 1);
169 }
170 }
171
172 std::vector<PathRecord> &items() { return _records; }
173
174 Interval itemBounds(ItemIterator ii) {
175 OptRect r = ii->path->boundsFast();
176 if (!r) return Interval();
177 return (*r)[X];
178 }
179
180 void addActiveItem(ItemIterator ii) {
181 unsigned w = ii->which;
182 unsigned ow = (ii->which + 1) % 2;
183
184 for (auto & i : _active[ow]) {
185 if (!ii->path->boundsFast().intersects(i.path->boundsFast())) continue;
186 std::vector<PathIntersection> px = ii->path->intersect(*i.path, _precision);
187 for (auto & k : px) {
188 PathVectorTime tw(ii->index, k.first), tow(i.index, k.second);
189 _result.emplace_back(
190 w == 0 ? tw : tow,
191 w == 0 ? tow : tw,
192 k.point());
193 }
194 }
195 _active[w].push_back(*ii);
196 }
197
198 void removeActiveItem(ItemIterator ii) {
199 ActivePathList &apl = _active[ii->which];
200 apl.erase(apl.iterator_to(*ii));
201 }
202
203private:
204 typedef boost::intrusive::list
205 < PathRecord
206 , boost::intrusive::member_hook
207 < PathRecord
208 , boost::intrusive::list_member_hook<>
209 , &PathRecord::_hook
210 >
211 > ActivePathList;
212
213 std::vector<PVIntersection> &_result;
214 std::vector<PathRecord> _records;
215 ActivePathList _active[2];
217};
218
219std::vector<PVIntersection> PathVector::intersect(PathVector const &other, Coord precision) const
220{
221 std::vector<PVIntersection> result;
222
223 PathIntersectionSweepSet pisset(result, *this, other, precision);
224 Sweeper<PathIntersectionSweepSet> sweeper(pisset);
225 sweeper.process();
226
227 std::sort(result.begin(), result.end());
228
229 return result;
230}
231
232int PathVector::winding(Point const &p) const
233{
234 int wind = 0;
235 for (const auto & i : *this) {
236 if (!i.boundsFast().contains(p)) continue;
237 wind += i.winding(p);
238 }
239 return wind;
240}
241
242std::optional<PathVectorTime> PathVector::nearestTime(Point const &p, Coord *dist) const
243{
244 std::optional<PathVectorTime> retval;
245
246 Coord mindist = infinity();
247 for (size_type i = 0; i < size(); ++i) {
248 Coord d;
249 PathTime pos = (*this)[i].nearestTime(p, &d);
250 if (d < mindist) {
251 mindist = d;
252 retval = PathVectorTime(i, pos.curve_index, pos.t);
253 }
254 }
255
256 if (dist) {
257 *dist = mindist;
258 }
259 return retval;
260}
261
262std::vector<PathVectorTime> PathVector::allNearestTimes(Point const &p, Coord *dist) const
263{
264 std::vector<PathVectorTime> retval;
265
266 Coord mindist = infinity();
267 for (size_type i = 0; i < size(); ++i) {
268 Coord d;
269 PathTime pos = (*this)[i].nearestTime(p, &d);
270 if (d < mindist) {
271 mindist = d;
272 retval.clear();
273 }
274 if (d <= mindist) {
275 retval.emplace_back(i, pos.curve_index, pos.t);
276 }
277 }
278
279 if (dist) {
280 *dist = mindist;
281 }
282 return retval;
283}
284
285std::vector<Point> PathVector::nodes() const
286{
287 std::vector<Point> result;
288 for (size_type i = 0; i < size(); ++i) {
289 size_type path_size = (*this)[i].size_closed();
290 for (size_type j = 0; j < path_size; ++j) {
291 result.push_back((*this)[i][j].initialPoint());
292 }
293 }
294 return result;
295}
296
298{
299 PathVectorTime ret;
300 Coord rest = 0;
301 ret.t = modf(t, &rest);
302 ret.curve_index = rest;
303 for (; ret.path_index < size(); ++ret.path_index) {
304 unsigned s = _data.at(ret.path_index).size_default();
305 if (s > ret.curve_index) break;
306 // special case for the last point
307 if (s == ret.curve_index && ret.path_index + 1 == size()) {
308 --ret.curve_index;
309 ret.t = 1;
310 break;
311 }
312 ret.curve_index -= s;
313 }
314 return ret;
315}
316
317std::ostream &operator<<(std::ostream &out, PathVector const &pv)
318{
319 SVGPathWriter wr;
320 wr.feed(pv);
321 out << wr.str();
322 return out;
323}
324
325} // namespace Geom
326
327/*
328 Local Variables:
329 mode:c++
330 c-file-style:"stroustrup"
331 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
332 indent-tabs-mode:nil
333 fill-column:99
334 End:
335*/
336// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Path - a sequence of contiguous curves.
3x3 affine transformation matrix.
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
virtual Coord valueAt(Coord t, Dim2 d) const
Evaluate one of the coordinates at the specified time value.
Definition curve.h:116
virtual Point pointAt(Coord t) const
Evaluate the curve at a specified time value.
Definition curve.h:110
void unionWith(CRect const &b)
Enlarge the rectangle to contain the argument.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
virtual void feed(Curve const &c, bool moveto_initial=true)
Definition path-sink.cpp:39
Sequence of subpaths.
Definition pathvector.h:122
std::vector< PathVectorTime > allNearestTimes(Point const &p, Coord *dist=NULL) const
PathVectorTime _factorTime(Coord t) const
size_type size() const
Get the number of paths in the vector.
Definition pathvector.h:147
Coord valueAt(Coord t, Dim2 d) const
std::vector< Point > nodes() const
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
Sequence::const_iterator const_iterator
Definition pathvector.h:127
OptRect boundsExact() const
int winding(Point const &p) const
Determine the winding number at the specified point.
Point pointAt(Coord t) const
Sequence::size_type size_type
Definition pathvector.h:128
void snapEnds(Coord precision=EPSILON)
OptRect boundsFast() const
Curve const & curveAt(Coord t, Coord *rest=NULL) const
Path & at(size_type index)
Definition pathvector.h:161
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
PathVector reversed(bool reverse_paths=true) const
Get a new vector with reversed direction of paths.
std::optional< PathVectorTime > nearestTime(Point const &p, Coord *dist=NULL) const
void reverse(bool reverse_paths=true)
Reverse the direction of paths in the vector.
iterator begin()
Definition pathvector.h:151
size_type curveCount() const
Get the total number of curves in the vector.
iterator end()
Definition pathvector.h:152
std::vector< PVIntersection > intersect(PathVector const &other, Coord precision=EPSILON) const
Path & pathAt(Coord t, Coord *rest=NULL)
Sequence of contiguous curves, aka spline.
Definition path.h:353
OptRect boundsExact() const
Get a tight-fitting bounding box.
Definition path.cpp:372
OptRect boundsFast() const
Get the approximate bounding box.
Definition path.cpp:348
Curve const & at(size_type i) const
Access a curve by index.
Definition path.h:438
Two-dimensional point that doubles as a vector.
Definition point.h:66
Serialize paths to SVG path data strings.
std::string str() const
Retrieve the generated path data string.
Generic sweepline algorithm.
Definition sweeper.h:93
void process()
Process entry and exit events.
Definition sweeper.h:109
const double w
Definition conic-4.cpp:19
Css & result
std::vector< ItemIterator > _active
double const _precision
std::vector< Geom::PathVector > _result
Dim2
2D axis enumeration (X or Y).
Definition coord.h:48
constexpr Coord infinity()
Get a value representing infinity.
Definition coord.h:88
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
@ X
Definition coord.h:48
Various utility functions.
Definition affine.h:22
std::ostream & operator<<(std::ostream &os, const Bezier &b)
Definition bezier.h:372
PathVector - a sequence of subpaths.
GList * items
Generalized time value in the path.
Definition path.h:139
size_type curve_index
Index of the curve in the path.
Definition path.h:143
Coord t
Time value in the curve.
Definition path.h:142
Generalized time value in the path vector.
Definition pathvector.h:58
size_type path_index
Index of the path in the vector.
Definition pathvector.h:59
Path sink which writes an SVG-compatible command string.
Class for implementing sweepline algorithms.
int index