Code

414d69755870dbb6b6eba09dd468ceb2a187c99b
[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  */
34 #ifndef SEEN_GEOM_PATH_H
35 #define SEEN_GEOM_PATH_H
37 #include "point.h"
38 #include "angle.h"
39 #include <iterator>
40 #include <algorithm>
41 #include "exception.h"
42 #include "d2.h"
43 #include "matrix.h"
44 #include "bezier.h"
45 #include "crossing.h"
46 #include "utils.h"
48 namespace Geom {
50 class Curve;
52 struct CurveHelpers {
53 protected:
54   static int root_winding(Curve const &c, Point p);
55 };
57 class Curve : private CurveHelpers {
58 public:
59   virtual ~Curve() {}
61   virtual Point initialPoint() const = 0;
62   virtual Point finalPoint() const = 0;
64   virtual bool isDegenerate() const = 0;
66   virtual Curve *duplicate() const = 0;
68   virtual Rect boundsFast() const = 0;
69   virtual Rect boundsExact() const = 0;
70   virtual Rect boundsLocal(Interval i, unsigned deg) const = 0;
71   Rect boundsLocal(Interval i) const { return boundsLocal(i, 0); }
73   virtual std::vector<double> roots(double v, Dim2 d) const = 0;
75   virtual int winding(Point p) const { return root_winding(*this, p); }
77   //mental: review these
78   virtual Curve *portion(double f, double t) const = 0;
79   virtual Curve *reverse() const { return portion(1, 0); }
80   virtual Curve *derivative() const = 0;
82   virtual void setInitial(Point v) = 0;
83   virtual void setFinal(Point v) = 0;
85   virtual Curve *transformed(Matrix const &m) const = 0;
87   virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
88   virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
89   virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
90   virtual D2<SBasis> toSBasis() const = 0;
91 };
93 class SBasisCurve : public Curve {
94 private:
95   SBasisCurve();
96   D2<SBasis> inner;
97 public:
98   explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {}
99   explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {}
100   Curve *duplicate() const { return new SBasisCurve(*this); }
102   Point initialPoint() const    { return inner.at0(); }
103   Point finalPoint() const      { return inner.at1(); }
104   bool isDegenerate() const     { return inner.isConstant(); }
105   Point pointAt(Coord t) const  { return inner.valueAt(t); }
106   std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const {
107       return inner.valueAndDerivatives(t, n);
108   }
109   double valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); }
111   void setInitial(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } }
112   void setFinal(Point v)   { for(unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } }
114   Rect boundsFast() const  { return bounds_fast(inner); }
115   Rect boundsExact() const { return bounds_exact(inner); }
116   Rect boundsLocal(Interval i, unsigned deg) const { return bounds_local(inner, i, deg); }
118   std::vector<double> roots(double v, Dim2 d) const { return Geom::roots(inner[d] - v); }
120   Curve *portion(double f, double t) const {
121     return new SBasisCurve(Geom::portion(inner, f, t));
122   }
124   Curve *transformed(Matrix const &m) const {
125     return new SBasisCurve(inner * m);
126   }
128   Curve *derivative() const {
129     return new SBasisCurve(Geom::derivative(inner));
130   }
132   D2<SBasis> toSBasis() const { return inner; }
134 };
136 template <unsigned order>
137 class BezierCurve : public Curve {
138 private:
139   D2<Bezier > inner;
140 public:
141   template <unsigned required_degree>
142   static void assert_degree(BezierCurve<required_degree> const *) {}
144   BezierCurve() : inner(Bezier::Order(order), Bezier::Order(order)) {
145   }
147   explicit BezierCurve(D2<Bezier > const &x) : inner(x) {}
149   BezierCurve(Bezier x, Bezier y) : inner(x, y) {}
151   // default copy
152   // default assign
154   BezierCurve(Point c0, Point c1) {
155     assert_degree<1>(this);
156     for(unsigned d = 0; d < 2; d++)
157         inner[d] = Bezier(c0[d], c1[d]);
158   }
160   BezierCurve(Point c0, Point c1, Point c2) {
161     assert_degree<2>(this);
162     for(unsigned d = 0; d < 2; d++)
163         inner[d] = Bezier(c0[d], c1[d], c2[d]);
164   }
166   BezierCurve(Point c0, Point c1, Point c2, Point c3) {
167     assert_degree<3>(this);
168     for(unsigned d = 0; d < 2; d++)
169         inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]);
170   }
172   unsigned degree() const { return order; }
174   Curve *duplicate() const { return new BezierCurve(*this); }
176   Point initialPoint() const { return inner.at0(); }
177   Point finalPoint() const { return inner.at1(); }
179   bool isDegenerate() const { return inner.isConstant(); }
181   void setInitial(Point v) { setPoint(0, v); }
182   void setFinal(Point v)   { setPoint(1, v); }
184   void setPoint(unsigned ix, Point v) { inner[X].setPoint(ix, v[X]); inner[Y].setPoint(ix, v[Y]); }
185   Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); }
187   Rect boundsFast() const { return bounds_fast(inner); }
188   Rect boundsExact() const { return bounds_exact(inner); }
189   Rect boundsLocal(Interval i, unsigned deg) const {
190       if(i.min() == 0 && i.max() == 1) return boundsFast();
191       if(deg == 0) return bounds_local(inner, i);
192       // TODO: UUUUUUGGGLLY
193       if(deg == 1 && order > 1) return Rect(bounds_local(Geom::derivative(inner[X]), i),
194                                             bounds_local(Geom::derivative(inner[Y]), i));
195       return Rect(Interval(0,0), Interval(0,0));
196   }
197 //TODO: local
199 //TODO: implement next 3 natively
200   int winding(Point p) const {
201     return SBasisCurve(toSBasis()).winding(p);
202   }
204   std::vector<double>
205   roots(double v, Dim2 d) const {
206       return (inner[d] - v).roots();
207   }
209   void setPoints(std::vector<Point> ps) {
210     for(unsigned i = 0; i <= order; i++) {
211       setPoint(i, ps[i]);
212     }
213   }
214   std::vector<Point> points() const { return bezier_points(inner); }
216   std::pair<BezierCurve<order>, BezierCurve<order> > subdivide(Coord t) const {
217     std::pair<Bezier, Bezier > sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t);
218     return std::pair<BezierCurve<order>, BezierCurve<order> >(
219                BezierCurve<order>(sx.first, sy.first),
220                BezierCurve<order>(sx.second, sy.second));
221   }
223   Curve *portion(double f, double t) const {
224     return new BezierCurve(Geom::portion(inner, f, t));
225   }
227   Curve *reverse() const {
228     return new BezierCurve(Geom::reverse(inner));
229   }
231   Curve *transformed(Matrix const &m) const {
232     BezierCurve *ret = new BezierCurve();
233     std::vector<Point> ps = points();
234     for(unsigned i = 0;  i <= order; i++) ps[i] = ps[i] * m;
235     ret->setPoints(ps);
236     return ret;
237   }
239   Curve *derivative() const {
240      if(order > 1)
241         return new BezierCurve<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y]));
242      else if (order == 1) {
243         double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0];
244         return new BezierCurve<1>(Point(dx,dy),Point(dx,dy));
245      }
246   }
248   Point pointAt(double t) const { return inner.valueAt(t); }
249   std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); }
251   double valueAt(double t, Dim2 d) const { return inner[d].valueAt(t); }
253   D2<SBasis> toSBasis() const {return inner.toSBasis(); }
255 protected:
256   BezierCurve(Point c[]) {
257     Coord x[order+1], y[order+1];
258     for(unsigned i = 0; i <= order; i++) {
259         x[i] = c[i][X]; y[i] = c[i][Y];
260     }
261     inner = Bezier(x, y);
262   }
263 };
265 // BezierCurve<0> is meaningless; specialize it out
266 template<> class BezierCurve<0> : public BezierCurve<1> { public: BezierCurve(); BezierCurve(Bezier x, Bezier y); };
268 typedef BezierCurve<1> LineSegment;
269 typedef BezierCurve<2> QuadraticBezier;
270 typedef BezierCurve<3> CubicBezier;
275 class SVGEllipticalArc : public Curve
277   public:
278         SVGEllipticalArc()
279         {}
280         
281     SVGEllipticalArc( Point _initial_point, double _rx, double _ry,
282                       double _rot_angle, bool _large_arc, bool _sweep,
283                       Point _final_point
284                     )
285         : m_initial_point(_initial_point), m_final_point(_final_point),
286           m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle),
287           m_large_arc(_large_arc), m_sweep(_sweep)
288     {
289         //assert( (ray(X) >= 0) && (ray(Y) >= 0) );
290         if ( are_near(initialPoint(), finalPoint()) )
291         {
292             m_start_angle = m_end_angle = 0;
293             m_center = initialPoint();
294         }
295         else
296         {
297             calculate_center_and_extreme_angles();
298         }
299     }
300           
301         Curve* duplicate() const
302         {
303                 return new SVGEllipticalArc(*this);
304         }
305         
306     double center(Dim2 i) const
307     {
308         return m_center[i];
309     }
311     Point center() const
312     {
313         return m_center;
314     }
316     Point initialPoint() const
317     {
318         return m_initial_point;
319     }
321     Point finalPoint() const
322     {
323         return m_final_point;
324     }
326     double start_angle() const
327     {
328         return m_start_angle;
329     }
331     double end_angle() const
332     {
333         return m_end_angle;
334     }
336     double ray(Dim2 i) const
337     {
338         return (i == 0) ? m_rx : m_ry;
339     }
341     bool large_arc_flag() const
342     {
343         return m_large_arc;
344     }
346     bool sweep_flag() const
347     {
348         return m_sweep;
349     }
351     double rotation_angle() const
352     {
353         return m_rot_angle;
354     }
356     void setInitial( const Point _point)
357     {
358         m_initial_point = _point;
359         calculate_center_and_extreme_angles();
360     }
362     void setFinal( const Point _point)
363     {
364         m_final_point = _point;
365         calculate_center_and_extreme_angles();
366     }
368     void setExtremes( const Point& _initial_point, const Point& _final_point )
369     {
370         m_initial_point = _initial_point;
371         m_final_point = _final_point;
372         calculate_center_and_extreme_angles();
373     }
375     bool isDegenerate() const
376     {
377         return are_near(initialPoint(), finalPoint());
378     }
379     
380     // TODO: native implementation of the following methods
381     Rect boundsFast() const
382     {
383         return SBasisCurve(toSBasis()).boundsFast();
384     }
385   
386     Rect boundsExact() const
387     {
388         return SBasisCurve(toSBasis()).boundsExact();
389     }
390     
391     Rect boundsLocal(Interval i, unsigned int deg) const
392     {
393         return SBasisCurve(toSBasis()).boundsLocal(i, deg);
394     }
395     
396     std::vector<double> roots(double v, Dim2 d) const
397     {
398         return SBasisCurve(toSBasis()).roots(v, d);
399     }
400     
401     int winding(Point p) const
402     {
403         return SBasisCurve(toSBasis()).winding(p);
404     }
405     
406     Curve *derivative() const
407     {
408         return SBasisCurve(toSBasis()).derivative();
409     }
410     
411     Curve *transformed(Matrix const &m) const
412     {
413         return SBasisCurve(toSBasis()).transformed(m);
414     }
415     
416     std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
417     {
418         return SBasisCurve(toSBasis()).pointAndDerivatives(t, n);
419     }
420     
421     D2<SBasis> toSBasis() const;
422     
423     double valueAt(Coord t, Dim2 d) const;
425     Point pointAt(Coord t) const
426     {
427         Coord tt = from_01_to_02PI(t);
428         double sin_rot_angle = std::sin(rotation_angle());
429         double cos_rot_angle = std::cos(rotation_angle());
430         Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle,
431                  -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle,
432                   center(X),              center(Y) );
433         Point p( std::cos(tt), std::sin(tt) );
434         return p * m;
435     }
437     std::pair<SVGEllipticalArc, SVGEllipticalArc>
438     subdivide(Coord t) const
439     {
440         SVGEllipticalArc* arc1 = static_cast<SVGEllipticalArc*>(portion(0, t));
441         SVGEllipticalArc* arc2 = static_cast<SVGEllipticalArc*>(portion(t, 1));
442         assert( arc1 != NULL && arc2 != NULL);
443         std::pair<SVGEllipticalArc, SVGEllipticalArc> arc_pair(*arc1, *arc2);        
444         delete arc1;
445         delete arc2;
446         return arc_pair;
447     }
449     Curve* portion(double f, double t) const;
450     
451     // the arc is the same but traversed in the opposite direction
452     Curve* reverse() const
453     {
454         SVGEllipticalArc* rarc = new SVGEllipticalArc( *this );
455         rarc->m_sweep = !m_sweep;
456         rarc->m_initial_point = m_final_point;
457         rarc->m_final_point = m_initial_point;
458         rarc->m_start_angle = m_end_angle;
459         rarc->m_end_angle = m_start_angle;
460         return rarc;
461     }
463   private:
464     double sweep_angle() const
465     {
466         Coord d = end_angle() - start_angle();
467         if ( !sweep_flag() ) d = -d;
468         if ( d < 0 )
469             d += 2*M_PI;
470         return d;
471     }
473     Coord from_01_to_02PI(Coord t) const;
475     void calculate_center_and_extreme_angles() throw(RangeError);
476     
477   private:
478     Point m_initial_point, m_final_point;
479     double m_rx, m_ry, m_rot_angle;
480     bool m_large_arc, m_sweep;
481     double m_start_angle, m_end_angle;
482     Point m_center;
483     
484 }; // end class SVGEllipticalArc
489 template <typename IteratorImpl>
490 class BaseIterator
491 : public std::iterator<std::forward_iterator_tag, Curve const>
493 public:
494   BaseIterator() {}
496   // default construct
497   // default copy
499   bool operator==(BaseIterator const &other) {
500     return other.impl_ == impl_;
501   }
502   bool operator!=(BaseIterator const &other) {
503     return other.impl_ != impl_;
504   }
506   Curve const &operator*() const { return **impl_; }
507   Curve const *operator->() const { return *impl_; }
509   BaseIterator &operator++() {
510     ++impl_;
511     return *this;
512   }
514   BaseIterator operator++(int) {
515     BaseIterator old=*this;
516     ++(*this);
517     return old;
518   }
520 private:
521   BaseIterator(IteratorImpl const &pos) : impl_(pos) {}
523   IteratorImpl impl_;
524   friend class Path;
525 };
527 template <typename Iterator>
528 class DuplicatingIterator
529 : public std::iterator<std::input_iterator_tag, Curve *>
531 public:
532   DuplicatingIterator() {}
533   DuplicatingIterator(Iterator const &iter) : impl_(iter) {}
535   bool operator==(DuplicatingIterator const &other) {
536     return other.impl_ == impl_;
537   }
538   bool operator!=(DuplicatingIterator const &other) {
539     return other.impl_ != impl_;
540   }
542   Curve *operator*() const { return (*impl_)->duplicate(); }
544   DuplicatingIterator &operator++() {
545     ++impl_;
546     return *this;
547   }
548   DuplicatingIterator operator++(int) {
549     DuplicatingIterator old=*this;
550     ++(*this);
551     return old;
552   }
554 private:
555   Iterator impl_;
556 };
558 class Path {
559 private:
560   typedef std::vector<Curve *> Sequence;
562 public:
563   typedef BaseIterator<Sequence::iterator> iterator;
564   typedef BaseIterator<Sequence::const_iterator> const_iterator;
565   typedef Sequence::size_type size_type;
566   typedef Sequence::difference_type difference_type;
568   Path()
569   : final_(new LineSegment()), closed_(false)
570   {
571     curves_.push_back(final_);
572   }
574   Path(Path const &other)
575   : final_(new LineSegment()), closed_(other.closed_)
576   {
577     curves_.push_back(final_);
578     insert(begin(), other.begin(), other.end());
579   }
581   explicit Path(Point p)
582   : final_(new LineSegment(p, p)), closed_(false)
583   {
584     curves_.push_back(final_);
585   }
587   template <typename Impl>
588   Path(BaseIterator<Impl> first, BaseIterator<Impl> last, bool closed=false)
589   : closed_(closed), final_(new LineSegment())
590   {
591     curves_.push_back(final_);
592     insert(begin(), first, last);
593   }
595   virtual ~Path() {
596       delete_range(curves_.begin(), curves_.end()-1);
597       delete final_;
598   }
600   Path &operator=(Path const &other) {
601     clear();
602     insert(begin(), other.begin(), other.end());
603     close(other.closed_);
604     return *this;
605   }
607   void swap(Path &other);
609   Curve const &operator[](unsigned i) const { return *curves_[i]; }
611   iterator begin() { return curves_.begin(); }
612   iterator end() { return curves_.end()-1; }
614   Curve const &front() const { return *curves_[0]; }
615   Curve const &back() const { return *curves_[curves_.size()-2]; }
617   const_iterator begin() const { return curves_.begin(); }
618   const_iterator end() const { return curves_.end()-1; }
620   const_iterator end_open() const { return curves_.end()-1; }
621   const_iterator end_closed() const { return curves_.end(); }
622   const_iterator end_default() const {
623     return ( closed_ ? end_closed() : end_open() );
624   }
626   size_type size() const { return curves_.size()-1; }
627   size_type max_size() const { return curves_.max_size()-1; }
629   bool empty() const { return curves_.size() == 1; }
630   bool closed() const { return closed_; }
631   void close(bool closed=true) { closed_ = closed; }
633   Rect boundsFast() const;
634   Rect boundsExact() const;
636   Piecewise<D2<SBasis> > toPwSb() const {
637     Piecewise<D2<SBasis> > ret;
638     ret.push_cut(0);
639     unsigned i = 1;
640     // pw<d2<>> is always open. so if path is closed, add closing segment as well to pwd2.
641     for(const_iterator it = begin(); it != end_default(); ++it) {
642       if (!it->isDegenerate()) {
643         ret.push(it->toSBasis(), i++);
644       }
645     }
646     return ret;
647   }
649   Path operator*(Matrix const &m) const {
650     Path ret;
651     for(const_iterator it = begin(); it != end(); ++it) {
652       Curve *temp = it->transformed(m);
653       //Possible point of discontinuity?
654       ret.append(*temp);
655       delete temp;
656     }
657     return ret;
658   }
660   Point pointAt(double t) const {
661     if(empty()) return Point(0,0);
662     double i, f = modf(t, &i);
663     if(i == size() && f == 0) { i--; }
664     assert(i >= 0 && i <= size());
665     return (*this)[unsigned(i)].pointAt(f);
666   }
668   double valueAt(double t, Dim2 d) const {
669     if(empty()) return 0;
670     double i, f = modf(t, &i);
671     if(i == size() && f == 0) { i--; }
672     assert(i >= 0 && i <= size());
673     return (*this)[unsigned(i)].valueAt(f, d);
674   }
676   std::vector<double> roots(double v, Dim2 d) const {
677     std::vector<double> res;
678     for(unsigned i = 0; i <= size(); i++) {
679       std::vector<double> temp = (*this)[i].roots(v, d);
680       for(unsigned j = 0; j < temp.size(); j++)
681         res.push_back(temp[j] + i);
682     }
683     return res;
684   }
686   void appendPortionTo(Path &p, double f, double t) const;
688   Path portion(double f, double t) const {
689     Path ret;
690     ret.close(false);
691     appendPortionTo(ret, f, t);
692     return ret;
693   }
694   Path portion(Interval i) const { return portion(i.min(), i.max()); }
696   Path reverse() const {
697     Path ret;
698     ret.close(closed_);
699     for(int i = size() - (closed_ ? 0 : 1); i >= 0; i--) {
700       //TODO: do we really delete?
701       Curve *temp = (*this)[i].reverse();
702       ret.append(*temp);
703       delete temp;
704     }
705     return ret;
706   }
708   void insert(iterator pos, Curve const &curve) {
709     Sequence source(1, curve.duplicate());
710     try {
711       do_update(pos.impl_, pos.impl_, source.begin(), source.end());
712     } catch (...) {
713       delete_range(source.begin(), source.end());
714       throw;
715     }
716   }
718   template <typename Impl>
719   void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> last)
720   {
721     Sequence source(DuplicatingIterator<Impl>(first.impl_),
722                     DuplicatingIterator<Impl>(last.impl_));
723     try {
724       do_update(pos.impl_, pos.impl_, source.begin(), source.end());
725     } catch (...) {
726       delete_range(source.begin(), source.end());
727       throw;
728     }
729   }
731   void clear() {
732     do_update(curves_.begin(), curves_.end()-1,
733               curves_.begin(), curves_.begin());
734   }
736   void erase(iterator pos) {
737     do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin());
738   }
740   void erase(iterator first, iterator last) {
741     do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin());
742   }
744   void replace(iterator replaced, Curve const &curve) {
745     Sequence source(1, curve.duplicate());
746     try {
747       do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
748     } catch (...) {
749       delete_range(source.begin(), source.end());
750       throw;
751     }
752   }
754   void replace(iterator first_replaced, iterator last_replaced,
755                Curve const &curve)
756   {
757     Sequence source(1, curve.duplicate());
758     try {
759       do_update(first_replaced.impl_, last_replaced.impl_,
760                 source.begin(), source.end());
761     } catch (...) {
762       delete_range(source.begin(), source.end());
763       throw;
764     }
765   }
767   template <typename Impl>
768   void replace(iterator replaced,
769                BaseIterator<Impl> first, BaseIterator<Impl> last)
770   {
771     Sequence source(DuplicatingIterator<Impl>(first.impl_),
772                     DuplicatingIterator<Impl>(last.impl_));
773     try {
774       do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
775     } catch (...) {
776       delete_range(source.begin(), source.end());
777       throw;
778     }
779   }
781   template <typename Impl>
782   void replace(iterator first_replaced, iterator last_replaced,
783                BaseIterator<Impl> first, BaseIterator<Impl> last)
784   {
785     Sequence source(first.impl_, last.impl_);
786     try {
787       do_update(first_replaced.impl_, last_replaced.impl_,
788                 source.begin(), source.end());
789     } catch (...) {
790       delete_range(source.begin(), source.end());
791       throw;
792     }
793   }
795   void start(Point p) {
796     clear();
797     final_->setPoint(0, p);
798     final_->setPoint(1, p);
799   }
801   Point initialPoint() const { return (*final_)[1]; }
802   Point finalPoint() const { return (*final_)[0]; }
804   void append(Curve const &curve);
805   void append(D2<SBasis> const &curve);
807   template <typename CurveType, typename A>
808   void appendNew(A a) {
809     do_append(new CurveType((*final_)[0], a));
810   }
812   template <typename CurveType, typename A, typename B>
813   void appendNew(A a, B b) {
814     do_append(new CurveType((*final_)[0], a, b));
815   }
817   template <typename CurveType, typename A, typename B, typename C>
818   void appendNew(A a, B b, C c) {
819     do_append(new CurveType((*final_)[0], a, b, c));
820   }
822   template <typename CurveType, typename A, typename B, typename C,
823                                 typename D>
824   void appendNew(A a, B b, C c, D d) {
825     do_append(new CurveType((*final_)[0], a, b, c, d));
826   }
828   template <typename CurveType, typename A, typename B, typename C,
829                                 typename D, typename E>
830   void appendNew(A a, B b, C c, D d, E e) {
831     do_append(new CurveType((*final_)[0], a, b, c, d, e));
832   }
834   template <typename CurveType, typename A, typename B, typename C,
835                                 typename D, typename E, typename F>
836   void appendNew(A a, B b, C c, D d, E e, F f) {
837     do_append(new CurveType((*final_)[0], a, b, c, d, e, f));
838   }
840   template <typename CurveType, typename A, typename B, typename C,
841                                 typename D, typename E, typename F,
842                                 typename G>
843   void appendNew(A a, B b, C c, D d, E e, F f, G g) {
844     do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g));
845   }
847   template <typename CurveType, typename A, typename B, typename C,
848                                 typename D, typename E, typename F,
849                                 typename G, typename H>
850   void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) {
851     do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h));
852   }
854   template <typename CurveType, typename A, typename B, typename C,
855                                 typename D, typename E, typename F,
856                                 typename G, typename H, typename I>
857   void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) {
858     do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h, i));
859   }
861 private:
862   void do_update(Sequence::iterator first_replaced,
863                  Sequence::iterator last_replaced,
864                  Sequence::iterator first,
865                  Sequence::iterator last);
867   void do_append(Curve *curve);
869   void delete_range(Sequence::iterator first, Sequence::iterator last);
871   void check_continuity(Sequence::iterator first_replaced,
872                         Sequence::iterator last_replaced,
873                         Sequence::iterator first,
874                         Sequence::iterator last);
876   Sequence curves_;
877   LineSegment *final_;
878   bool closed_;
879 };
881 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
882     Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
883     for(unsigned i = 1; i < paths.size(); i++) {
884         ret.concat(paths[i].toPwSb());
885     }
886     return ret;
889 /*
890 class PathPortion : public Curve {
891   Path *source;
892   double f, t;
893   boost::optional<Path> result;
895   public:
896   double from() const { return f; }
897   double to() const { return t; }
899   explicit PathPortion(Path *s, double fp, double tp) : source(s), f(fp), t(tp) {}
900   Curve *duplicate() const { return new PathPortion(*this); }
902   Point initialPoint() const { return source->pointAt(f); }
903   Point finalPoint() const { return source->pointAt(t); }
905   Path actualPath() {
906     if(!result) *result = source->portion(f, t);
907     return *result;
908   }
910   Rect boundsFast() const { return actualPath().boundsFast; }
911   Rect boundsExact() const { return actualPath().boundsFast; }
912   Rect boundsLocal(Interval i) const { throwNotImplemented(); }
914   std::vector<double> roots(double v, Dim2 d) const = 0;
916   virtual int winding(Point p) const { return root_winding(*this, p); }
918   virtual Curve *portion(double f, double t) const = 0;
919   virtual Curve *reverse() const { return portion(1, 0); }
921   virtual Crossings crossingsWith(Curve const & other) const;
923   virtual void setInitial(Point v) = 0;
924   virtual void setFinal(Point v) = 0;
926   virtual Curve *transformed(Matrix const &m) const = 0;
928   virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
929   virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
930   virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
931   virtual D2<SBasis> toSBasis() const = 0;
933 };
934 */
938 namespace std {
940 template <>
941 inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
943   a.swap(b);
948 #endif // SEEN_GEOM_PATH_H
950 /*
951   Local Variables:
952   mode:c++
953   c-file-style:"stroustrup"
954   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
955   indent-tabs-mode:nil
956   fill-column:99
957   End:
958 */
959 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :