1 /** @file
2  * @brief PathVector - a sequence of subpaths
3  *//*
4  * Authors:
5  *   Johan Engelen <j.b.c.engelen@alumnus.utwente.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 #ifndef LIB2GEOM_SEEN_PATHVECTOR_H
35 #define LIB2GEOM_SEEN_PATHVECTOR_H
36 
37 #include <optional>
38 #include <boost/concept/requires.hpp>
39 #include <boost/shared_ptr.hpp>
40 #include <boost/range/algorithm/equal.hpp>
41 #include <2geom/forward.h>
42 #include <2geom/path.h>
43 #include <2geom/transforms.h>
44 
45 namespace Geom {
46 
47 /** @brief Generalized time value in the path vector.
48  *
49  * This class exists because mapping the range of multiple curves onto the same interval
50  * as the curve index, we lose some precision. For instance, a path with 16 curves will
51  * have 4 bits less precision than a path with 1 curve. If you need high precision results
52  * in long paths, use this class and related methods instead of the standard methods
53  * pointAt(), nearestTime() and so on.
54  *
55  * @ingroup Paths */
56 struct PathVectorTime
57     : public PathTime
58     , boost::totally_ordered<PathVectorTime>
59 {
60     size_type path_index; ///< Index of the path in the vector
61 
PathVectorTimePathVectorTime62     PathVectorTime() : PathTime(0, 0), path_index(0) {}
PathVectorTimePathVectorTime63     PathVectorTime(size_type _i, size_type _c, Coord _t)
64         : PathTime(_c, _t), path_index(_i) {}
PathVectorTimePathVectorTime65     PathVectorTime(size_type _i, PathTime const &pos)
66         : PathTime(pos), path_index(_i) {}
67 
68     bool operator<(PathVectorTime const &other) const {
69         if (path_index < other.path_index) return true;
70         if (path_index == other.path_index) {
71             return static_cast<PathTime const &>(*this) < static_cast<PathTime const &>(other);
72         }
73         return false;
74     }
75     bool operator==(PathVectorTime const &other) const {
76         return path_index == other.path_index
77             && static_cast<PathTime const &>(*this) == static_cast<PathTime const &>(other);
78     }
79 
asPathTimePathVectorTime80     PathTime const &asPathTime() const {
81         return *static_cast<PathTime const *>(this);
82     }
83 };
84 
85 inline std::ostream &operator<<(std::ostream &os, PathVectorTime const &pvt) {
86     os << pvt.path_index << ": " << pvt.asPathTime();
87     return os;
88 }
89 
90 typedef Intersection<PathVectorTime> PathVectorIntersection;
91 typedef PathVectorIntersection PVIntersection; ///< Alias to save typing
92 
93 template <>
94 struct ShapeTraits<PathVector> {
95     typedef PathVectorTime TimeType;
96     //typedef PathVectorInterval IntervalType;
97     typedef PathVector AffineClosureType;
98     typedef PathVectorIntersection IntersectionType;
99 };
100 
101 /** @brief Sequence of subpaths.
102  *
103  * This class corresponds to the SVG notion of a path:
104  * a sequence of any number of open or closed contiguous subpaths.
105  * Unlike Path, this class is closed under boolean operations.
106  *
107  * If you want to represent an arbitrary shape, this is the best class to use.
108  * Shapes with a boundary that is composed of only a single contiguous
109  * component can be represented with Path instead.
110  *
111  * @ingroup Paths
112  */
113 class PathVector
114     : MultipliableNoncommutative< PathVector, Affine
115     , MultipliableNoncommutative< PathVector, Translate
116     , MultipliableNoncommutative< PathVector, Scale
117     , MultipliableNoncommutative< PathVector, Rotate
118     , MultipliableNoncommutative< PathVector, HShear
119     , MultipliableNoncommutative< PathVector, VShear
120     , MultipliableNoncommutative< PathVector, Zoom
121     , boost::equality_comparable< PathVector
122       > > > > > > > >
123 {
124     typedef std::vector<Path> Sequence;
125 public:
126     typedef PathVectorTime Position;
127     typedef Sequence::iterator iterator;
128     typedef Sequence::const_iterator const_iterator;
129     typedef Sequence::size_type size_type;
130     typedef Path value_type;
131     typedef Path &reference;
132     typedef Path const &const_reference;
133     typedef Path *pointer;
134     typedef std::ptrdiff_t difference_type;
135 
136     PathVector() {}
137     PathVector(Path const &p)
138         : _data(1, p)
139     {}
140     template <typename InputIter>
141     PathVector(InputIter first, InputIter last)
142         : _data(first, last)
143     {}
144 
145     /// Check whether the vector contains any paths.
146     bool empty() const { return _data.empty(); }
147     /// Get the number of paths in the vector.
148     size_type size() const { return _data.size(); }
149     /// Get the total number of curves in the vector.
150     size_type curveCount() const;
151 
152     iterator begin() { return _data.begin(); }
153     iterator end() { return _data.end(); }
154     const_iterator begin() const { return _data.begin(); }
155     const_iterator end() const { return _data.end(); }
156     Path &operator[](size_type index) {
157         return _data[index];
158     }
159     Path const &operator[](size_type index) const {
160         return _data[index];
161     }
162     Path &at(size_type index) {
163         return _data.at(index);
164     }
165     Path const &at(size_type index) const {
166         return _data.at(index);
167     }
168     Path &front() { return _data.front(); }
169     Path const &front() const { return _data.front(); }
170     Path &back() { return _data.back(); }
171     Path const &back() const { return _data.back(); }
172     /// Append a path at the end.
173     void push_back(Path const &path) {
174         _data.push_back(path);
175     }
176     /// Remove the last path.
177     void pop_back() {
178         _data.pop_back();
179     }
180     iterator insert(iterator pos, Path const &p) {
181         return _data.insert(pos, p);
182     }
183     template <typename InputIter>
184     void insert(iterator out, InputIter first, InputIter last) {
185         _data.insert(out, first, last);
186     }
187     /// Remove a path from the vector.
188     iterator erase(iterator i) {
189         return _data.erase(i);
190     }
191     /// Remove a range of paths from the vector.
192     iterator erase(iterator first, iterator last) {
193         return _data.erase(first, last);
194     }
195     /// Remove all paths from the vector.
196     void clear() { _data.clear(); }
197     /** @brief Change the number of paths.
198      * If the vector size increases, it is passed with paths that contain only
199      * a degenerate closing segment at (0,0). */
200     void resize(size_type n) { _data.resize(n); }
201     /** @brief Reverse the direction of paths in the vector.
202      * @param reverse_paths If this is true, the order of paths is reversed as well;
203      *                      otherwise each path is reversed, but their order in the
204      *                      PathVector stays the same */
205     void reverse(bool reverse_paths = true);
206     /** @brief Get a new vector with reversed direction of paths.
207      * @param reverse_paths If this is true, the order of paths is reversed as well;
208      *                      otherwise each path is reversed, but their order in the
209      *                      PathVector stays the same */
210     PathVector reversed(bool reverse_paths = true) const;
211 
212     /// Get the range of allowed time values.
213     Interval timeRange() const {
214         Interval ret(0, curveCount()); return ret;
215     }
216     /** @brief Get the first point in the first path of the vector.
217      * This method will throw an exception if the vector doesn't contain any paths. */
218     Point initialPoint() const {
219         return _data.front().initialPoint();
220     }
221     /** @brief Get the last point in the last path of the vector.
222      * This method will throw an exception if the vector doesn't contain any paths. */
223     Point finalPoint() const {
224         return _data.back().finalPoint();
225     }
226     Path &pathAt(Coord t, Coord *rest = NULL);
227     Path const &pathAt(Coord t, Coord *rest = NULL) const;
228     Curve const &curveAt(Coord t, Coord *rest = NULL) const;
229     Coord valueAt(Coord t, Dim2 d) const;
230     Point pointAt(Coord t) const;
231 
232     Path &pathAt(PathVectorTime const &pos) {
233         return const_cast<Path &>(static_cast<PathVector const*>(this)->pathAt(pos));
234     }
235     Path const &pathAt(PathVectorTime const &pos) const {
236         return at(pos.path_index);
237     }
238     Curve const &curveAt(PathVectorTime const &pos) const {
239         return at(pos.path_index).at(pos.curve_index);
240     }
241     Point pointAt(PathVectorTime const &pos) const {
242         return at(pos.path_index).at(pos.curve_index).pointAt(pos.t);
243     }
244     Coord valueAt(PathVectorTime const &pos, Dim2 d) const {
245         return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d);
246     }
247 
248     OptRect boundsFast() const;
249     OptRect boundsExact() const;
250 
251     template <typename T>
252     BOOST_CONCEPT_REQUIRES(((TransformConcept<T>)), (PathVector &))
253     operator*=(T const &t) {
254         if (empty()) return *this;
255         for (iterator i = begin(); i != end(); ++i) {
256             *i *= t;
257         }
258         return *this;
259     }
260 
261     bool operator==(PathVector const &other) const {
262         return boost::range::equal(_data, other._data);
263     }
264 
265     void snapEnds(Coord precision = EPSILON);
266 
267     std::vector<PVIntersection> intersect(PathVector const &other, Coord precision = EPSILON) const;
268 
269     /** @brief Determine the winding number at the specified point.
270      * This is simply the sum of winding numbers for constituent paths. */
271     int winding(Point const &p) const;
272 
273     std::optional<PathVectorTime> nearestTime(Point const &p, Coord *dist = NULL) const;
274     std::vector<PathVectorTime> allNearestTimes(Point const &p, Coord *dist = NULL) const;
275 
276     std::vector<Point> nodes() const;
277 
278 private:
279     PathVectorTime _factorTime(Coord t) const;
280 
281     Sequence _data;
282 };
283 
284 inline OptRect bounds_fast(PathVector const &pv) { return pv.boundsFast(); }
285 inline OptRect bounds_exact(PathVector const &pv) { return pv.boundsExact(); }
286 
287 std::ostream &operator<<(std::ostream &out, PathVector const &pv);
288 
289 } // end namespace Geom
290 
291 #endif // LIB2GEOM_SEEN_PATHVECTOR_H
292 
293 /*
294   Local Variables:
295   mode:c++
296   c-file-style:"stroustrup"
297   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
298   indent-tabs-mode:nil
299   fill-column:99
300   End:
301 */
302 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
303