GCC Code Coverage Report


Directory: ./
File: src/2geom/pathvector.cpp
Date: 2024-03-18 17:01:34
Exec Total Coverage
Lines: 67 158 42.4%
Functions: 11 24 45.8%
Branches: 51 166 30.7%

Line Branch Exec Source
1 /** @file
2 * @brief PathVector - a sequence of subpaths
3 *//*
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>
37 #include <2geom/svg-path-writer.h>
38 #include <2geom/sweeper.h>
39 #include <optional>
40
41 namespace Geom {
42
43 //PathVector &PathVector::operator+=(PathVector const &other);
44
45 15 PathVector::size_type PathVector::curveCount() const
46 {
47 15 size_type n = 0;
48
2/2
✓ Branch 6 taken 29 times.
✓ Branch 7 taken 15 times.
44 for (const auto & it : *this) {
49
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 n += it.size_default();
50 }
51 15 return n;
52 }
53
54 void 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
64 900 PathVector PathVector::reversed(bool reverse_paths) const
65 {
66 900 PathVector ret;
67
2/2
✓ Branch 7 taken 164700 times.
✓ Branch 8 taken 900 times.
165600 for (const auto & i : *this) {
68
2/4
✓ Branch 2 taken 164700 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 164700 times.
✗ Branch 6 not taken.
164700 ret.push_back(i.reversed());
69 }
70
1/2
✓ Branch 0 taken 900 times.
✗ Branch 1 not taken.
900 if (reverse_paths) {
71
1/2
✓ Branch 3 taken 900 times.
✗ Branch 4 not taken.
900 std::reverse(ret.begin(), ret.end());
72 }
73 900 return ret;
74 }
75
76 Path &PathVector::pathAt(Coord t, Coord *rest)
77 {
78 return const_cast<Path &>(static_cast<PathVector const*>(this)->pathAt(t, rest));
79 }
80 Path const &PathVector::pathAt(Coord t, Coord *rest) const
81 {
82 PathVectorTime pos = _factorTime(t);
83 if (rest) {
84 *rest = Coord(pos.curve_index) + pos.t;
85 }
86 return at(pos.path_index);
87 }
88 Curve const &PathVector::curveAt(Coord t, Coord *rest) const
89 {
90 PathVectorTime pos = _factorTime(t);
91 if (rest) {
92 *rest = pos.t;
93 }
94 return at(pos.path_index).at(pos.curve_index);
95 }
96 Coord PathVector::valueAt(Coord t, Dim2 d) const
97 {
98 PathVectorTime pos = _factorTime(t);
99 return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d);
100 }
101 Point PathVector::pointAt(Coord t) const
102 {
103 PathVectorTime pos = _factorTime(t);
104 return at(pos.path_index).at(pos.curve_index).pointAt(pos.t);
105 }
106
107 28 OptRect PathVector::boundsFast() const
108 {
109 28 OptRect bound;
110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if (empty()) return bound;
111
112 28 bound = front().boundsFast();
113
1/2
✗ Branch 10 not taken.
✓ Branch 11 taken 28 times.
28 for (const_iterator it = ++begin(); it != end(); ++it) {
114 bound.unionWith(it->boundsFast());
115 }
116 return bound;
117 }
118
119 OptRect PathVector::boundsExact() const
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
131 void PathVector::snapEnds(Coord precision)
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
141 class PathIntersectionSweepSet {
142 public:
143 struct PathRecord {
144 boost::intrusive::list_member_hook<> _hook;
145 Path const *path;
146 std::size_t index;
147 unsigned which;
148
149 12 PathRecord(Path const &p, std::size_t i, unsigned w)
150 24 : path(&p)
151 12 , index(i)
152 12 , which(w)
153 12 {}
154 };
155
156 typedef std::vector<PathRecord>::iterator ItemIterator;
157
158 6 PathIntersectionSweepSet(std::vector<PVIntersection> &result,
159 PathVector const &a, PathVector const &b, Coord precision)
160 6 : _result(result)
161
2/8
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
18 , _precision(precision)
162 {
163
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 _records.reserve(a.size() + b.size());
164
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
12 for (std::size_t i = 0; i < a.size(); ++i) {
165
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 _records.emplace_back(a[i], i, 0);
166 }
167
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
12 for (std::size_t i = 0; i < b.size(); ++i) {
168
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 _records.emplace_back(b[i], i, 1);
169 }
170
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
6 }
171
172 30 std::vector<PathRecord> &items() { return _records; }
173
174 12 Interval itemBounds(ItemIterator ii) {
175
1/2
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
12 OptRect r = ii->path->boundsFast();
176
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (!r) return Interval();
177 12 return (*r)[X];
178 }
179
180 12 void addActiveItem(ItemIterator ii) {
181 12 unsigned w = ii->which;
182 12 unsigned ow = (ii->which + 1) % 2;
183
184
4/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 12 times.
29 for (auto & i : _active[ow]) {
185
4/8
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 5 times.
5 if (!ii->path->boundsFast().intersects(i.path->boundsFast())) continue;
186
1/2
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 std::vector<PathIntersection> px = ii->path->intersect(*i.path, _precision);
187
2/2
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 5 times.
27 for (auto & k : px) {
188 22 PathVectorTime tw(ii->index, k.first), tow(i.index, k.second);
189
5/6
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
44 _result.emplace_back(
190 w == 0 ? tw : tow,
191 w == 0 ? tow : tw,
192 44 k.point());
193 }
194 5 }
195 12 _active[w].push_back(*ii);
196 12 }
197
198 12 void removeActiveItem(ItemIterator ii) {
199 12 ActivePathList &apl = _active[ii->which];
200
2/4
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
24 apl.erase(apl.iterator_to(*ii));
201 12 }
202
203 private:
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];
216 Coord _precision;
217 };
218
219 6 std::vector<PVIntersection> PathVector::intersect(PathVector const &other, Coord precision) const
220 {
221 6 std::vector<PVIntersection> result;
222
223
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 PathIntersectionSweepSet pisset(result, *this, other, precision);
224
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 Sweeper<PathIntersectionSweepSet> sweeper(pisset);
225
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 sweeper.process();
226
227
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 std::sort(result.begin(), result.end());
228
229 12 return result;
230 6 }
231
232 210052 int PathVector::winding(Point const &p) const
233 {
234 210052 int wind = 0;
235
2/2
✓ Branch 7 taken 285048 times.
✓ Branch 8 taken 210052 times.
495100 for (const auto & i : *this) {
236
4/6
✓ Branch 2 taken 285048 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 285048 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 139778 times.
✓ Branch 9 taken 145270 times.
285048 if (!i.boundsFast().contains(p)) continue;
237
1/2
✓ Branch 1 taken 145270 times.
✗ Branch 2 not taken.
145270 wind += i.winding(p);
238 }
239 210052 return wind;
240 }
241
242 std::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
262 std::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
285 std::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
297 PathVectorTime PathVector::_factorTime(Coord t) const
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
317 std::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 :
337