Code

update to latest 2geom (rev1497)
[inkscape.git] / src / 2geom / path.h
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 <boost/shared_ptr.hpp>
42 #include <2geom/curves.h>
44 #include <iterator>
45 #include <algorithm>
48 namespace Geom
49 {
51 class Path;
53 namespace PathInternal {
55 typedef std::vector<boost::shared_ptr<Curve const> > Sequence;
57 template <typename C, typename P>
58 class BaseIterator {
59 protected:
60   BaseIterator() : path(NULL), index(0) {}
61   BaseIterator(P *p, unsigned i) : path(p), index(i) {}
62   // default copy, default assign
64 public:
65   bool operator==(BaseIterator const &other) {
66     return path == other.path && index == other.index;
67   }
68   bool operator!=(BaseIterator const &other) {
69     return path != other.path || index != other.index;
70   }
72   Curve const &operator*() const { return (*path)[index]; }
73   Curve const *operator->() const { return &(*path)[index]; }
74   boost::shared_ptr<Curve const> get_ref() const {
75     return path->get_ref_at_index(index);
76   }
78   C &operator++() {
79     ++index;
80     return static_cast<C &>(*this);
81   }
82   C operator++(int) {
83     C old(static_cast<C &>(*this));
84     ++(*this);
85     return old;
86   }
88   C &operator--() {
89     --index;
90     return static_cast<C &>(*this);
91   }
92   C operator--(int) {
93     C old(static_cast<C &>(*this));
94     --(*this);
95     return old;
96   }
98 private:
99   P *path;
100   unsigned index;
102   friend class ::Geom::Path;
103 };
105 class ConstIterator : public BaseIterator<ConstIterator, Path const> {
106 public:
107   typedef BaseIterator<ConstIterator, Path const> Base;
109   ConstIterator() : Base() {}
110   // default copy, default assign
112 private:
113   ConstIterator(Path const &p, unsigned i) : Base(&p, i) {}
114   friend class ::Geom::Path;
115 };
117 class Iterator : public BaseIterator<Iterator, Path> {
118 public:
119   typedef BaseIterator<Iterator, Path> Base;
121   Iterator() : Base() {}
122   // default copy, default assign
124   operator ConstIterator const &() const {
125     return reinterpret_cast<ConstIterator const &>(*this);
126   }
128 private:
129   Iterator(Path &p, unsigned i) : Base(&p, i) {}
130   friend class ::Geom::Path;
131 };
135 /*
136  * Open and closed paths: all paths, whether open or closed, store a final
137  * segment which connects the initial and final endpoints of the "real"
138  * path data.  While similar to the "z" in an SVG path, it exists for
139  * both open and closed paths, and is not considered part of the "normal"
140  * path data, which is always covered by the range [begin(), end_open()).
141  * Conversely, the range [begin(), end_closed()) always contains the "extra"
142  * closing segment.
143  *
144  * The only difference between a closed and an open path is whether
145  * end_default() returns end_closed() or end_open().  The idea behind this
146  * is to let any path be stroked using [begin(), end_default()), and filled
147  * using [begin(), end_closed()), without requiring a separate "filled" version
148  * of the path to use for filling.
149  *
150  * \invariant : curves_ always contains at least one segment. The last segment
151  *              is always of type ClosingSegment. All constructors take care of this.
152                 (curves_.size() > 0) && dynamic_cast<ClosingSegment>(curves_.back())
153  */
154 class Path {
155 public:
156   typedef PathInternal::Sequence Sequence;
157   typedef PathInternal::Iterator iterator;
158   typedef PathInternal::ConstIterator const_iterator;
159   typedef Sequence::size_type size_type;
160   typedef Sequence::difference_type difference_type;
162   class ClosingSegment : public LineSegment {
163   public:
164     ClosingSegment() : LineSegment() {}
165     ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
166     virtual Curve *duplicate() const { return new ClosingSegment(*this); }
167     virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); }
168   };
170   enum Stitching {
171     NO_STITCHING=0,
172     STITCH_DISCONTINUOUS
173   };
175   class StitchSegment : public LineSegment {
176   public:
177     StitchSegment() : LineSegment() {}
178     StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
179     virtual Curve *duplicate() const { return new StitchSegment(*this); }
180     virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); }
181   };
183   // Path(Path const &other) - use default copy constructor
185   explicit Path(Point p=Point())
186   : curves_(boost::shared_ptr<Sequence>(new Sequence(1, boost::shared_ptr<Curve>()))),
187     final_(new ClosingSegment(p, p)),
188     closed_(false)
189   {
190     get_curves().back() = boost::shared_ptr<Curve>(final_);
191   }
193   Path(const_iterator const &first,
194        const_iterator const &last,
195        bool closed=false)
196   : curves_(boost::shared_ptr<Sequence>(new Sequence(seq_iter(first),
197                                                      seq_iter(last)))),
198     closed_(closed)
199   {
200     if (!get_curves().empty()) {
201       final_ = new ClosingSegment(get_curves().back()->finalPoint(),
202                                   get_curves().front()->initialPoint());
203     } else {
204       final_ = new ClosingSegment();
205     }
206     get_curves().push_back(boost::shared_ptr<Curve>(final_));
207   }
209   virtual ~Path() {}
210   
211   // Path &operator=(Path const &other) - use default assignment operator
213   void swap(Path &other) {
214     std::swap(other.curves_, curves_);
215     std::swap(other.final_, final_);
216     std::swap(other.closed_, closed_);
217   }
219   Curve const &operator[](unsigned i) const { return *get_curves()[i]; }
220   Curve const &at_index(unsigned i) const { return *get_curves()[i]; }
221   boost::shared_ptr<Curve const> get_ref_at_index(unsigned i) {
222     return get_curves()[i];
223   }
225   Curve const &front() const { return *get_curves()[0]; }
226   Curve const &back() const { return back_open(); }
227   Curve const &back_open() const {
228     if (empty()) { THROW_RANGEERROR("Path contains not enough segments"); }
229     return *get_curves()[get_curves().size()-2];
230   }
231   Curve const &back_closed() const { return *get_curves()[get_curves().size()-1]; }
232   Curve const &back_default() const {
233     return ( closed_ ? back_closed() : back_open() );
234   }
236   const_iterator begin() const { return const_iterator(*this, 0); }
237   const_iterator end() const { return const_iterator(*this, size()); }
238   iterator begin() { return iterator(*this, 0); }
239   iterator end() { return iterator(*this, size()); }
241   const_iterator end_open() const { return const_iterator(*this, size()); }
242   const_iterator end_closed() const { return const_iterator(*this, size()+1); }
243   const_iterator end_default() const {
244     return ( closed_ ? end_closed() : end_open() );
245   }
247   size_type size() const { return get_curves().size()-1; }
248   size_type max_size() const { return get_curves().max_size()-1; }
250   bool empty() const { return get_curves().size() == 1; }
251   bool closed() const { return closed_; }
252   void close(bool closed=true) { closed_ = closed; }
254   Rect boundsFast() const;
255   Rect boundsExact() const;
257   Piecewise<D2<SBasis> > toPwSb() const {
258     Piecewise<D2<SBasis> > ret;
259     ret.push_cut(0);
260     unsigned i = 1;
261     bool degenerate = true;
262     // pw<d2<>> is always open. so if path is closed, add closing segment as well to pwd2.
263     for(const_iterator it = begin(); it != end_default(); ++it) {
264       if (!it->isDegenerate()) {
265         ret.push(it->toSBasis(), i++);
266         degenerate = false;
267       }
268     }
269     if (degenerate) {
270       // if path only contains degenerate curves, no second cut is added
271       // so we need to create at least one segment manually
272       ret = Piecewise<D2<SBasis> >(initialPoint());
273     }
274     return ret;
275   }
277   bool operator==(Path const &other) const {
278     if (this == &other) return true;
279     if (closed_ != other.closed_) return false;
280     return get_curves() == other.get_curves();
281   }
282   bool operator!=(Path const &other) const {
283     return !( *this == other );
284   }
286   Path operator*(Matrix const &m) const {
287     Path ret(*this);
288     ret *= m;
289     return ret;
290   }
292   Path &operator*=(Matrix const &m);
293   
294   Point pointAt(double t) const 
295   {
296           unsigned int sz = size();
297           if ( closed() ) ++sz;
298           if ( t < 0 || t > sz  )
299           {
300                   THROW_RANGEERROR("parameter t out of bounds");
301           }
302           if ( empty() ) return Point(0,0);
303           double k, lt = modf(t, &k);
304           unsigned int i = static_cast<unsigned int>(k);
305           if ( i == sz ) 
306           { 
307                   --i;
308                   lt = 1;
309           }
310           return (*this)[i].pointAt(lt);
311   }
313   double valueAt(double t, Dim2 d) const 
314   {
315           unsigned int sz = size();
316           if ( closed() ) ++sz;
317           if ( t < 0 || t > sz  )
318           {
319                   THROW_RANGEERROR("parameter t out of bounds");
320           }
321           if ( empty() ) return 0;
322           double k, lt = modf(t, &k);
323           unsigned int i = static_cast<unsigned int>(k);
324           if ( i == sz ) 
325           { 
326                   --i;
327                   lt = 1;
328           }
329           return (*this)[i].valueAt(lt, d);
330   }
332   
333   Point operator() (double t) const
334   {
335           return pointAt(t);
336   }
337   
338   std::vector<double> roots(double v, Dim2 d) const {
339     std::vector<double> res;
340     for(unsigned i = 0; i <= size(); i++) {
341       std::vector<double> temp = (*this)[i].roots(v, d);
342       for(unsigned j = 0; j < temp.size(); j++)
343         res.push_back(temp[j] + i);
344     }
345     return res;
346   }
347   
348   std::vector<double> 
349   allNearestPoints(Point const& _point, double from, double to) const;
350   
351   std::vector<double>
352   allNearestPoints(Point const& _point) const
353   {
354           unsigned int sz = size();
355           if ( closed() ) ++sz;
356           return allNearestPoints(_point, 0, sz);
357   }
358   
359   
360   double nearestPoint(Point const& _point, double from, double to) const;
361   
362   double nearestPoint(Point const& _point) const
363   {
364           unsigned int sz = size();
365           if ( closed() ) ++sz;
366           return nearestPoint(_point, 0, sz);
367   }
368    
369   void appendPortionTo(Path &p, double f, double t) const;
371   Path portion(double f, double t) const {
372     Path ret;
373     ret.close(false);
374     appendPortionTo(ret, f, t);
375     return ret;
376   }
377   Path portion(Interval i) const { return portion(i.min(), i.max()); }
379   Path reverse() const {
380     Path ret(*this);
381     ret.unshare();
382     for ( Sequence::iterator iter = ret.get_curves().begin() ;
383           iter != ret.get_curves().end()-1 ; ++iter )
384     {
385       *iter = boost::shared_ptr<Curve>((*iter)->reverse());
386     }
387     std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1);
388     ret.final_ = static_cast<ClosingSegment *>(ret.final_->reverse());
389     ret.get_curves().back() = boost::shared_ptr<Curve>(ret.final_);
390     return ret;
391   }
393   void insert(iterator const &pos,
394               Curve const &curve, Stitching stitching=NO_STITCHING)
395   {
396     unshare();
397     Sequence::iterator seq_pos(seq_iter(pos));
398     Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
399     if (stitching) stitch(seq_pos, seq_pos, source);
400     do_update(seq_pos, seq_pos, source.begin(), source.end());
401   }
403   void insert(iterator const &pos,
404               const_iterator const &first,
405               const_iterator const &last,
406               Stitching stitching=NO_STITCHING)
407   {
408     unshare();
409     Sequence::iterator seq_pos(seq_iter(pos));
410     Sequence source(seq_iter(first), seq_iter(last));
411     if (stitching) stitch(seq_pos, seq_pos, source);
412     do_update(seq_pos, seq_pos, source.begin(), source.end());
413   }
415   void clear() {
416     unshare();
417     do_update(get_curves().begin(), get_curves().end()-1,
418               get_curves().begin(), get_curves().begin());
419   }
421   void erase(iterator const &pos, Stitching stitching=NO_STITCHING) {
422     unshare();
423     Sequence::iterator seq_pos(seq_iter(pos));
424     if (stitching) {
425       Sequence stitched;
426       stitch(seq_pos, seq_pos+1, stitched);
427       do_update(seq_pos, seq_pos+1, stitched.begin(), stitched.end());
428     } else {
429       do_update(seq_pos, seq_pos+1, get_curves().begin(), get_curves().begin());
430     }
431   }
433   void erase(iterator const &first,
434              iterator const &last,
435              Stitching stitching=NO_STITCHING)
436   {
437     unshare();
438     Sequence::iterator seq_first=seq_iter(first);
439     Sequence::iterator seq_last=seq_iter(last);
440     if (stitching) {
441       Sequence stitched;
442       stitch(seq_first, seq_last, stitched);
443       do_update(seq_first, seq_last, stitched.begin(), stitched.end());
444     } else {
445       do_update(seq_first, seq_last,
446                 get_curves().begin(), get_curves().begin());
447     }
448   }
450   // erase last segment of path
451   void erase_last() {
452     erase(iterator(*this, size()-1));
453   }
455   void replace(iterator const &replaced,
456                Curve const &curve,
457                Stitching stitching=NO_STITCHING)
458   {
459     unshare();
460     Sequence::iterator seq_replaced(seq_iter(replaced));
461     Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
462     if (stitching) stitch(seq_replaced, seq_replaced+1, source);
463     do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
464   }
466   void replace(iterator const &first_replaced,
467                iterator const &last_replaced,
468                Curve const &curve, Stitching stitching=NO_STITCHING)
469   {
470     unshare();
471     Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
472     Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
473     Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
474     if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
475     do_update(seq_first_replaced, seq_last_replaced,
476               source.begin(), source.end());
477   }
479   void replace(iterator const &replaced,
480                const_iterator const &first,
481                const_iterator const &last,
482                Stitching stitching=NO_STITCHING)
483   {
484     unshare();
485     Sequence::iterator seq_replaced(seq_iter(replaced));
486     Sequence source(seq_iter(first), seq_iter(last));
487     if (stitching) stitch(seq_replaced, seq_replaced+1, source);
488     do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
489   }
491   void replace(iterator const &first_replaced,
492                iterator const &last_replaced,
493                const_iterator const &first,
494                const_iterator const &last,
495                Stitching stitching=NO_STITCHING)
496   {
497     unshare();
498     Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
499     Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
500     Sequence source(seq_iter(first), seq_iter(last));
501     if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
502     do_update(seq_first_replaced, seq_last_replaced,
503               source.begin(), source.end());
504   }
506   void start(Point p) {
507     clear();
508     final_->setPoint(0, p);
509     final_->setPoint(1, p);
510   }
512   Point initialPoint() const { return (*final_)[1]; }
513   Point finalPoint() const { return (*final_)[0]; }
515   void setInitial(Point const& p)
516   {
517           if ( empty() ) return;
518           unshare();
519           boost::shared_ptr<Curve> head(front().duplicate());
520           head->setInitial(p);
521           Sequence::iterator replaced = get_curves().begin();
522           Sequence source(1, head);
523           do_update(replaced, replaced + 1, source.begin(), source.end());
524   }
526   void setFinal(Point const& p)
527   {
528           if ( empty() ) return;
529           unshare();
530           boost::shared_ptr<Curve> tail(back().duplicate());
531           tail->setFinal(p);
532           Sequence::iterator replaced = get_curves().end() - 2;
533           Sequence source(1, tail);
534           do_update(replaced, replaced + 1, source.begin(), source.end());
535   }
537   void append(Curve const &curve, Stitching stitching=NO_STITCHING) {
538     unshare();
539     if (stitching) stitchTo(curve.initialPoint());
540     do_append(curve.duplicate());
541   }
542   void append(D2<SBasis> const &curve, Stitching stitching=NO_STITCHING) {
543     unshare();
544     if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0]));
545     do_append(new SBasisCurve(curve));
546   }
547   void append(Path const &other, Stitching stitching=NO_STITCHING) {
548     insert(end(), other.begin(), other.end(), stitching);
549   }
551   void stitchTo(Point const &p) {
552     if (!empty() && finalPoint() != p) {
553       unshare();
554       do_append(new StitchSegment(finalPoint(), p));
555     }
556   }
558   template <typename CurveType, typename A>
559   void appendNew(A a) {
560     unshare();
561     do_append(new CurveType(finalPoint(), a));
562   }
564   template <typename CurveType, typename A, typename B>
565   void appendNew(A a, B b) {
566     unshare();
567     do_append(new CurveType(finalPoint(), a, b));
568   }
570   template <typename CurveType, typename A, typename B, typename C>
571   void appendNew(A a, B b, C c) {
572     unshare();
573     do_append(new CurveType(finalPoint(), a, b, c));
574   }
576   template <typename CurveType, typename A, typename B, typename C,
577                                 typename D>
578   void appendNew(A a, B b, C c, D d) {
579     unshare();
580     do_append(new CurveType(finalPoint(), a, b, c, d));
581   }
583   template <typename CurveType, typename A, typename B, typename C,
584                                 typename D, typename E>
585   void appendNew(A a, B b, C c, D d, E e) {
586     unshare();
587     do_append(new CurveType(finalPoint(), a, b, c, d, e));
588   }
590   template <typename CurveType, typename A, typename B, typename C,
591                                 typename D, typename E, typename F>
592   void appendNew(A a, B b, C c, D d, E e, F f) {
593     unshare();
594     do_append(new CurveType(finalPoint(), a, b, c, d, e, f));
595   }
597   template <typename CurveType, typename A, typename B, typename C,
598                                 typename D, typename E, typename F,
599                                 typename G>
600   void appendNew(A a, B b, C c, D d, E e, F f, G g) {
601     unshare();
602     do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g));
603   }
605   template <typename CurveType, typename A, typename B, typename C,
606                                 typename D, typename E, typename F,
607                                 typename G, typename H>
608   void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) {
609     unshare();
610     do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h));
611   }
613   template <typename CurveType, typename A, typename B, typename C,
614                                 typename D, typename E, typename F,
615                                 typename G, typename H, typename I>
616   void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) {
617     unshare();
618     do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i));
619   }
621 private:
622   static Sequence::iterator seq_iter(iterator const &iter) {
623     return iter.path->get_curves().begin() + iter.index;
624   }
625   static Sequence::const_iterator seq_iter(const_iterator const &iter) {
626     return iter.path->get_curves().begin() + iter.index;
627   }
629   Sequence &get_curves() { return *curves_; }
630   Sequence const &get_curves() const { return *curves_; }
632   void unshare() {
633     if (!curves_.unique()) {
634       curves_ = boost::shared_ptr<Sequence>(new Sequence(*curves_));
635     }
636     if (!get_curves().back().unique()) {
637       final_ = static_cast<ClosingSegment *>(final_->duplicate());
638       get_curves().back() = boost::shared_ptr<Curve>(final_);
639     }
640   }
642   void stitch(Sequence::iterator first_replaced,
643               Sequence::iterator last_replaced,
644               Sequence &sequence);
646   void do_update(Sequence::iterator first_replaced,
647                  Sequence::iterator last_replaced,
648                  Sequence::iterator first,
649                  Sequence::iterator last);
651   // n.b. takes ownership of curve object
652   void do_append(Curve *curve);
654   void check_continuity(Sequence::iterator first_replaced,
655                         Sequence::iterator last_replaced,
656                         Sequence::iterator first,
657                         Sequence::iterator last);
659   boost::shared_ptr<Sequence> curves_;
660   ClosingSegment *final_;
661   bool closed_;
662 };  // end class Path
664 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
665     Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
666     for(unsigned i = 1; i < paths.size(); i++) {
667         ret.concat(paths[i].toPwSb());
668     }
669     return ret;
672 inline
673 Coord nearest_point(Point const& p, Path const& c)
675         return c.nearestPoint(p);
678 }  // end namespace Geom
680 namespace std {
682 template <>
683 inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
685   a.swap(b);
688 }  // end namespace std
690 #endif // SEEN_GEOM_PATH_H
695 /*
696   Local Variables:
697   mode:c++
698   c-file-style:"stroustrup"
699   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
700   indent-tabs-mode:nil
701   fill-column:99
702   End:
703 */
704 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :