1 /*
2 * Path - Series of continuous curves
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 * Marco Cecchetti <mrcekets at gmail.com>
7 *
8 * Copyright 2007-2008 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 */
37 #ifndef SEEN_GEOM_PATH_H
38 #define SEEN_GEOM_PATH_H
41 #include <2geom/curves.h>
43 #include <iterator>
46 namespace Geom
47 {
49 // Conditional expression for types. If true, first, if false, second.
50 template<bool _Cond, typename _Iftrue, typename _Iffalse>
51 struct __conditional_type
52 { typedef _Iftrue __type; };
54 template<typename _Iftrue, typename _Iffalse>
55 struct __conditional_type<false, _Iftrue, _Iffalse>
56 { typedef _Iffalse __type; };
59 template <typename IteratorImpl>
60 class BaseIterator
61 : public std::iterator<std::forward_iterator_tag, Curve const>
62 {
63 public:
64 BaseIterator() {}
66 // default construct
67 // default copy
69 // Allow Sequence::iterator to Sequence::const_iterator conversion
70 // unfortunately I do not know how to imitate the way __normal_iterator
71 // does it, because I don't see a way to get the typename of the container
72 // IteratorImpl is pointing at...
73 typedef std::vector<Curve *> Sequence;
74 BaseIterator ( typename __conditional_type<
75 (std::__are_same<IteratorImpl, Sequence::const_iterator >::__value), // check if this instantiation is of const_iterator type
76 const BaseIterator< Sequence::iterator >, // if true: accept iterator in const_iterator instantiation
77 const BaseIterator<IteratorImpl> > ::__type // if false: default to standard copy constructor
78 & __other)
79 : impl_(__other.impl_) { }
80 friend class BaseIterator< Sequence::const_iterator >;
83 bool operator==(BaseIterator const &other) {
84 return other.impl_ == impl_;
85 }
86 bool operator!=(BaseIterator const &other) {
87 return other.impl_ != impl_;
88 }
90 Curve const &operator*() const { return **impl_; }
91 Curve const *operator->() const { return *impl_; }
93 BaseIterator &operator++() {
94 ++impl_;
95 return *this;
96 }
98 BaseIterator operator++(int) {
99 BaseIterator old=*this;
100 ++(*this);
101 return old;
102 }
104 BaseIterator &operator--() {
105 --impl_;
106 return *this;
107 }
109 BaseIterator operator--(int) {
110 BaseIterator old=*this;
111 --(*this);
112 return old;
113 }
115 private:
116 BaseIterator(IteratorImpl const &pos) : impl_(pos) {}
118 IteratorImpl impl_;
119 friend class Path;
120 };
122 template <typename Iterator>
123 class DuplicatingIterator
124 : public std::iterator<std::input_iterator_tag, Curve *>
125 {
126 public:
127 DuplicatingIterator() {}
128 DuplicatingIterator(Iterator const &iter) : impl_(iter) {}
130 bool operator==(DuplicatingIterator const &other) {
131 return other.impl_ == impl_;
132 }
133 bool operator!=(DuplicatingIterator const &other) {
134 return other.impl_ != impl_;
135 }
137 Curve *operator*() const { return (*impl_)->duplicate(); }
139 DuplicatingIterator &operator++() {
140 ++impl_;
141 return *this;
142 }
143 DuplicatingIterator operator++(int) {
144 DuplicatingIterator old=*this;
145 ++(*this);
146 return old;
147 }
149 private:
150 Iterator impl_;
151 };
153 /*
154 * Open and closed paths: all paths, whether open or closed, store a final
155 * segment which connects the initial and final endpoints of the "real"
156 * path data. While similar to the "z" in an SVG path, it exists for
157 * both open and closed paths, and is not considered part of the "normal"
158 * path data, which is always covered by the range [begin(), end_open()).
159 * Conversely, the range [begin(), end_closed()) always contains the "extra"
160 * closing segment.
161 *
162 * The only difference between a closed and an open path is whether end()
163 * returns end_closed() or end_open(). The idea behind this is to let
164 * any path be stroked using [begin(), end_default()), and filled using
165 * [begin(), end_closed()), without requiring a separate "filled" version
166 * of the path to use for filling.
167 */
168 class Path {
169 private:
170 typedef std::vector<Curve *> Sequence;
172 public:
173 typedef BaseIterator<Sequence::iterator> iterator;
174 typedef BaseIterator<Sequence::const_iterator> const_iterator;
175 typedef Sequence::size_type size_type;
176 typedef Sequence::difference_type difference_type;
178 class ClosingSegment : public LineSegment {
179 public:
180 ClosingSegment() : LineSegment() {}
181 ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
182 virtual Curve *duplicate() const { return new ClosingSegment(*this); }
183 };
185 enum Stitching {
186 NO_STITCHING=0,
187 STITCH_DISCONTINUOUS
188 };
190 class StitchSegment : public LineSegment {
191 public:
192 StitchSegment() : LineSegment() {}
193 StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
194 virtual Curve *duplicate() const { return new StitchSegment(*this); }
195 };
197 Path()
198 : final_(new ClosingSegment()), closed_(false)
199 {
200 curves_.push_back(final_);
201 }
203 Path(Path const &other)
204 : final_(new ClosingSegment()), closed_(other.closed_)
205 {
206 curves_.push_back(final_);
207 insert(begin(), other.begin(), other.end());
208 }
210 explicit Path(Point p)
211 : final_(new ClosingSegment(p, p)), closed_(false)
212 {
213 curves_.push_back(final_);
214 }
216 template <typename Impl>
217 Path(BaseIterator<Impl> first, BaseIterator<Impl> last, bool closed=false)
218 : closed_(closed), final_(new ClosingSegment())
219 {
220 curves_.push_back(final_);
221 insert(begin(), first, last);
222 }
224 virtual ~Path() {
225 delete_range(curves_.begin(), curves_.end()-1);
226 delete final_;
227 }
229 Path &operator=(Path const &other) {
230 clear();
231 insert(begin(), other.begin(), other.end());
232 close(other.closed_);
233 return *this;
234 }
236 void swap(Path &other);
238 Curve const &operator[](unsigned i) const { return *curves_[i]; }
240 Curve const &front() const { return *curves_[0]; }
241 Curve const &back() const { return *curves_[curves_.size()-2]; }
242 Curve const &back_open() const { return *curves_[curves_.size()-2]; }
243 Curve const &back_closed() const { return *curves_[curves_.size()-1]; }
244 Curve const &back_default() const {
245 return ( closed_ ? back_closed() : back_open() );
246 }
248 const_iterator begin() const { return curves_.begin(); }
249 const_iterator end() const { return curves_.end()-1; }
250 iterator begin() { return curves_.begin(); }
251 iterator end() { return curves_.end()-1; }
253 const_iterator end_open() const { return curves_.end()-1; }
254 const_iterator end_closed() const { return curves_.end(); }
255 const_iterator end_default() const {
256 return ( closed_ ? end_closed() : end_open() );
257 }
259 size_type size() const { return curves_.size()-1; }
260 size_type max_size() const { return curves_.max_size()-1; }
262 bool empty() const { return curves_.size() == 1; }
263 bool closed() const { return closed_; }
264 void close(bool closed=true) { closed_ = closed; }
266 Rect boundsFast() const;
267 Rect boundsExact() const;
269 Piecewise<D2<SBasis> > toPwSb() const {
270 Piecewise<D2<SBasis> > ret;
271 ret.push_cut(0);
272 unsigned i = 1;
273 // pw<d2<>> is always open. so if path is closed, add closing segment as well to pwd2.
274 for(const_iterator it = begin(); it != end_default(); ++it) {
275 if (!it->isDegenerate()) {
276 ret.push(it->toSBasis(), i++);
277 }
278 }
279 return ret;
280 }
282 bool operator==(Path const &m) const {
283 if (size() != m.size() || closed() != m.closed())
284 return false;
285 const_iterator it2 = m.curves_.begin();
286 for(const_iterator it = curves_.begin(); it != curves_.end(); ++it) {
287 const Curve& a = (*it);
288 const Curve& b = (*it2);
289 if(!(a == b))
290 return false;
291 ++it2;
292 }
293 return true;
294 }
296 /*
297 Path operator*=(Matrix)
298 This is not possible without at least partly regenerating the curves of
299 the path, because a path can consist of many types of curves,
300 e.g. a HLineSegment.
301 Such a segment cannot be transformed and stay a HLineSegment in general
302 (take for example rotations).
303 This means that these curves of the path have to be replaced with
304 LineSegments: new Curves.
305 So an implementation of this method should check the curve's type to see
306 whether operator*= is doable for that curve type, ...
307 */
308 Path operator*(Matrix const &m) const {
309 Path ret;
310 ret.curves_.reserve(curves_.size());
311 for(const_iterator it = begin(); it != end(); ++it) {
312 Curve *curve = it->transformed(m);
313 ret.do_append(curve);
314 }
315 ret.close(closed_);
316 return ret;
317 }
319 /*
320 // this should be even quickier but it works at low level
321 Path operator*(Matrix const &m) const
322 {
323 Path result;
324 size_t sz = curves_.size() - 1;
325 if (sz == 0) return result;
326 result.curves_.resize(curves_.size());
327 result.curves_.back() = result.final_;
328 result.curves_[0] = (curves_[0])->transformed(m);
329 for (size_t i = 1; i < sz; ++i)
330 {
331 result.curves_[i] = (curves_[i])->transformed(m);
332 if ( result.curves_[i]->initialPoint() != result.curves_[i-1]->finalPoint() ) {
333 THROW_CONTINUITYERROR();
334 }
335 }
336 result.final_->setInitial( (result.curves_[sz])->finalPoint() );
337 result.final_->setFinal( (result.curves_[0])->initialPoint() );
338 result.closed_ = closed_;
339 return result;
340 }
341 */
343 Point pointAt(double t) const
344 {
345 unsigned int sz = size();
346 if ( closed() ) ++sz;
347 if ( t < 0 || t > sz )
348 {
349 THROW_RANGEERROR("parameter t out of bounds");
350 }
351 if ( empty() ) return Point(0,0);
352 double k, lt = modf(t, &k);
353 unsigned int i = static_cast<unsigned int>(k);
354 if ( i == sz )
355 {
356 --i;
357 lt = 1;
358 }
359 return (*this)[i].pointAt(lt);
360 }
362 double valueAt(double t, Dim2 d) const
363 {
364 unsigned int sz = size();
365 if ( closed() ) ++sz;
366 if ( t < 0 || t > sz )
367 {
368 THROW_RANGEERROR("parameter t out of bounds");
369 }
370 if ( empty() ) return 0;
371 double k, lt = modf(t, &k);
372 unsigned int i = static_cast<unsigned int>(k);
373 if ( i == sz )
374 {
375 --i;
376 lt = 1;
377 }
378 return (*this)[i].valueAt(lt, d);
379 }
382 Point operator() (double t) const
383 {
384 return pointAt(t);
385 }
387 std::vector<double> roots(double v, Dim2 d) const {
388 std::vector<double> res;
389 for(unsigned i = 0; i <= size(); i++) {
390 std::vector<double> temp = (*this)[i].roots(v, d);
391 for(unsigned j = 0; j < temp.size(); j++)
392 res.push_back(temp[j] + i);
393 }
394 return res;
395 }
397 std::vector<double>
398 allNearestPoints(Point const& _point, double from, double to) const;
400 std::vector<double>
401 allNearestPoints(Point const& _point) const
402 {
403 unsigned int sz = size();
404 if ( closed() ) ++sz;
405 return allNearestPoints(_point, 0, sz);
406 }
409 double nearestPoint(Point const& _point, double from, double to) const;
411 double nearestPoint(Point const& _point) const
412 {
413 unsigned int sz = size();
414 if ( closed() ) ++sz;
415 return nearestPoint(_point, 0, sz);
416 }
418 void appendPortionTo(Path &p, double f, double t) const;
420 Path portion(double f, double t) const {
421 Path ret;
422 ret.close(false);
423 appendPortionTo(ret, f, t);
424 return ret;
425 }
426 Path portion(Interval i) const { return portion(i.min(), i.max()); }
428 Path reverse() const {
429 Path ret;
430 ret.close(closed_);
431 for(int i = size() - (closed_ ? 0 : 1); i >= 0; i--) {
432 Curve *temp = (*this)[i].reverse();
433 ret.append(*temp);
434 // delete since append makes a copy
435 delete temp;
436 }
437 return ret;
438 }
440 void insert(iterator pos, Curve const &curve, Stitching stitching=NO_STITCHING) {
441 Sequence source(1, curve.duplicate());
442 try {
443 if (stitching) stitch(pos.impl_, pos.impl_, source);
444 do_update(pos.impl_, pos.impl_, source.begin(), source.end());
445 } catch (...) {
446 delete_range(source.begin(), source.end());
447 throw;
448 }
449 }
451 template <typename Impl>
452 void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> last, Stitching stitching=NO_STITCHING)
453 {
454 Sequence source(DuplicatingIterator<Impl>(first.impl_),
455 DuplicatingIterator<Impl>(last.impl_));
456 try {
457 if (stitching) stitch(pos.impl_, pos.impl_, source);
458 do_update(pos.impl_, pos.impl_, source.begin(), source.end());
459 } catch (...) {
460 delete_range(source.begin(), source.end());
461 throw;
462 }
463 }
465 void clear() {
466 do_update(curves_.begin(), curves_.end()-1,
467 curves_.begin(), curves_.begin());
468 }
470 void erase(iterator pos, Stitching stitching=NO_STITCHING) {
471 if (stitching) {
472 Sequence stitched;
473 stitch(pos.impl_, pos.impl_+1, stitched);
474 try {
475 do_update(pos.impl_, pos.impl_+1, stitched.begin(), stitched.end());
476 } catch (...) {
477 delete_range(stitched.begin(), stitched.end());
478 throw;
479 }
480 } else {
481 do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin());
482 }
483 }
485 void erase(iterator first, iterator last, Stitching stitching=NO_STITCHING) {
486 if (stitching) {
487 Sequence stitched;
488 stitch(first.impl_, last.impl_, stitched);
489 try {
490 do_update(first.impl_, last.impl_, stitched.begin(), stitched.end());
491 } catch (...) {
492 delete_range(stitched.begin(), stitched.end());
493 throw;
494 }
495 } else {
496 do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin());
497 }
498 }
500 // erase last segment of path
501 void erase_last() {
502 erase(curves_.end()-2);
503 }
505 void replace(iterator replaced, Curve const &curve, Stitching stitching=NO_STITCHING) {
506 Sequence source(1, curve.duplicate());
507 try {
508 if (stitching) stitch(replaced.impl_, replaced.impl_+1, source);
509 do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
510 } catch (...) {
511 delete_range(source.begin(), source.end());
512 throw;
513 }
514 }
516 void replace(iterator first_replaced, iterator last_replaced,
517 Curve const &curve, Stitching stitching=NO_STITCHING)
518 {
519 Sequence source(1, curve.duplicate());
520 try {
521 if (stitching) stitch(first_replaced.impl_, last_replaced.impl_, source);
522 do_update(first_replaced.impl_, last_replaced.impl_,
523 source.begin(), source.end());
524 } catch (...) {
525 delete_range(source.begin(), source.end());
526 throw;
527 }
528 }
530 template <typename Impl>
531 void replace(iterator replaced,
532 BaseIterator<Impl> first, BaseIterator<Impl> last,
533 Stitching stitching=NO_STITCHING)
534 {
535 Sequence source(DuplicatingIterator<Impl>(first.impl_),
536 DuplicatingIterator<Impl>(last.impl_));
537 try {
538 if (stitching) stitch(replaced.impl_, replaced.impl_+1, source);
539 do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
540 } catch (...) {
541 delete_range(source.begin(), source.end());
542 throw;
543 }
544 }
546 template <typename Impl>
547 void replace(iterator first_replaced, iterator last_replaced,
548 BaseIterator<Impl> first, BaseIterator<Impl> last,
549 Stitching stitching=NO_STITCHING)
550 {
551 Sequence source(first.impl_, last.impl_);
552 try {
553 if (stitching) stitch(first_replaced.impl_, last_replaced.impl_, source);
554 do_update(first_replaced.impl_, last_replaced.impl_,
555 source.begin(), source.end());
556 } catch (...) {
557 delete_range(source.begin(), source.end());
558 throw;
559 }
560 }
562 void start(Point p) {
563 clear();
564 final_->setPoint(0, p);
565 final_->setPoint(1, p);
566 }
568 Point initialPoint() const { return (*final_)[1]; }
569 Point finalPoint() const { return (*final_)[0]; }
571 void setInitial(Point const& p)
572 {
573 if ( empty() ) return;
574 Curve* head = front().duplicate();
575 head->setInitial(p);
576 Sequence::iterator replaced = curves_.begin();
577 Sequence source(1, head);
578 try
579 {
580 do_update(replaced, replaced + 1, source.begin(), source.end());
581 }
582 catch (...)
583 {
584 delete_range(source.begin(), source.end());
585 throw;
586 }
587 }
589 void setFinal(Point const& p)
590 {
591 if ( empty() ) return;
592 Curve* tail = back().duplicate();
593 tail->setFinal(p);
594 Sequence::iterator replaced = curves_.end() - 2;
595 Sequence source(1, tail);
596 try
597 {
598 do_update(replaced, replaced + 1, source.begin(), source.end());
599 }
600 catch (...)
601 {
602 delete_range(source.begin(), source.end());
603 throw;
604 }
605 }
607 void append(Curve const &curve, Stitching stitching=NO_STITCHING) {
608 if (stitching) stitchTo(curve.initialPoint());
609 do_append(curve.duplicate());
610 }
611 void append(D2<SBasis> const &curve, Stitching stitching=NO_STITCHING) {
612 if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0]));
613 do_append(new SBasisCurve(curve));
614 }
615 void append(Path const &other, Stitching stitching=NO_STITCHING) {
616 insert(end(), other.begin(), other.end(), stitching);
617 }
619 void stitchTo(Point const &p) {
620 if (!empty() && finalPoint() != p) {
621 do_append(new StitchSegment(finalPoint(), p));
622 }
623 }
625 template <typename CurveType, typename A>
626 void appendNew(A a) {
627 do_append(new CurveType(finalPoint(), a));
628 }
630 template <typename CurveType, typename A, typename B>
631 void appendNew(A a, B b) {
632 do_append(new CurveType(finalPoint(), a, b));
633 }
635 template <typename CurveType, typename A, typename B, typename C>
636 void appendNew(A a, B b, C c) {
637 do_append(new CurveType(finalPoint(), a, b, c));
638 }
640 template <typename CurveType, typename A, typename B, typename C,
641 typename D>
642 void appendNew(A a, B b, C c, D d) {
643 do_append(new CurveType(finalPoint(), a, b, c, d));
644 }
646 template <typename CurveType, typename A, typename B, typename C,
647 typename D, typename E>
648 void appendNew(A a, B b, C c, D d, E e) {
649 do_append(new CurveType(finalPoint(), a, b, c, d, e));
650 }
652 template <typename CurveType, typename A, typename B, typename C,
653 typename D, typename E, typename F>
654 void appendNew(A a, B b, C c, D d, E e, F f) {
655 do_append(new CurveType(finalPoint(), a, b, c, d, e, f));
656 }
658 template <typename CurveType, typename A, typename B, typename C,
659 typename D, typename E, typename F,
660 typename G>
661 void appendNew(A a, B b, C c, D d, E e, F f, G g) {
662 do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g));
663 }
665 template <typename CurveType, typename A, typename B, typename C,
666 typename D, typename E, typename F,
667 typename G, typename H>
668 void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) {
669 do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h));
670 }
672 template <typename CurveType, typename A, typename B, typename C,
673 typename D, typename E, typename F,
674 typename G, typename H, typename I>
675 void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) {
676 do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i));
677 }
679 private:
680 void stitch(Sequence::iterator first_replaced,
681 Sequence::iterator last_replaced,
682 Sequence &sequence);
684 void do_update(Sequence::iterator first_replaced,
685 Sequence::iterator last_replaced,
686 Sequence::iterator first,
687 Sequence::iterator last);
689 void do_append(Curve *curve);
691 static void delete_range(Sequence::iterator first, Sequence::iterator last);
693 void check_continuity(Sequence::iterator first_replaced,
694 Sequence::iterator last_replaced,
695 Sequence::iterator first,
696 Sequence::iterator last);
698 Sequence curves_;
699 ClosingSegment *final_;
700 bool closed_;
702 }; // end class Path
704 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
705 Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
706 for(unsigned i = 1; i < paths.size(); i++) {
707 ret.concat(paths[i].toPwSb());
708 }
709 return ret;
710 }
712 inline
713 Coord nearest_point(Point const& p, Path const& c)
714 {
715 return c.nearestPoint(p);
716 }
718 } // end namespace Geom
720 namespace std {
722 template <>
723 inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
724 {
725 a.swap(b);
726 }
728 } // end namespace std
731 #endif // SEEN_GEOM_PATH_H
736 /*
737 Local Variables:
738 mode:c++
739 c-file-style:"stroustrup"
740 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
741 indent-tabs-mode:nil
742 fill-column:99
743 End:
744 */
745 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :