8930a8a7fe05ce7a96d83b61dc7112b330dc5eb7
1 /*
2 * Path - Series of continuous curves
3 *
4 * Copyright 2007 MenTaLguY <mental@rydia.net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
13 *
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
19 *
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
24 *
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
28 */
30 #ifndef SEEN_GEOM_PATH_H
31 #define SEEN_GEOM_PATH_H
33 #include "point.h"
34 #include <iterator>
35 #include <algorithm>
36 #include <exception>
37 #include <stdexcept>
38 #include "d2.h"
39 #include "matrix.h"
40 #include "bezier.h"
41 #include "crossing.h"
43 namespace Geom {
45 class Curve;
47 struct CurveHelpers {
48 protected:
49 static int root_winding(Curve const &c, Point p);
50 };
52 class Curve : private CurveHelpers {
53 public:
54 virtual ~Curve() {}
56 virtual Point initialPoint() const = 0;
57 virtual Point finalPoint() const = 0;
59 virtual Curve *duplicate() const = 0;
61 virtual Rect boundsFast() const = 0;
62 virtual Rect boundsExact() const = 0;
63 virtual Rect boundsLocal(Interval i, unsigned deg) const = 0;
64 Rect boundsLocal(Interval i) const { return boundsLocal(i, 0); }
66 virtual std::vector<double> roots(double v, Dim2 d) const = 0;
68 virtual int winding(Point p) const { return root_winding(*this, p); }
70 //mental: review these
71 virtual Curve *portion(double f, double t) const = 0;
72 virtual Curve *reverse() const { return portion(1, 0); }
73 virtual Curve *derivative() const = 0;
75 virtual void setInitial(Point v) = 0;
76 virtual void setFinal(Point v) = 0;
78 virtual Curve *transformed(Matrix const &m) const = 0;
80 virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
81 virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
82 virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
83 virtual D2<SBasis> toSBasis() const = 0;
84 };
86 class SBasisCurve : public Curve {
87 private:
88 SBasisCurve();
89 D2<SBasis> inner;
90 public:
91 explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {}
92 explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {}
93 Curve *duplicate() const { return new SBasisCurve(*this); }
95 Point initialPoint() const { return inner.at0(); }
96 Point finalPoint() const { return inner.at1(); }
97 Point pointAt(Coord t) const { return inner.valueAt(t); }
98 std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const {
99 return inner.valueAndDerivatives(t, n);
100 }
101 double valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); }
103 void setInitial(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } }
104 void setFinal(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } }
106 Rect boundsFast() const { return bounds_fast(inner); }
107 Rect boundsExact() const { return bounds_exact(inner); }
108 Rect boundsLocal(Interval i, unsigned deg) const { return bounds_local(inner, i, deg); }
110 std::vector<double> roots(double v, Dim2 d) const { return Geom::roots(inner[d] - v); }
112 Curve *portion(double f, double t) const {
113 return new SBasisCurve(Geom::portion(inner, f, t));
114 }
116 Curve *transformed(Matrix const &m) const {
117 return new SBasisCurve(inner * m);
118 }
120 Curve *derivative() const {
121 return new SBasisCurve(Geom::derivative(inner));
122 }
124 D2<SBasis> toSBasis() const { return inner; }
126 };
128 template <unsigned order>
129 class BezierCurve : public Curve {
130 private:
131 D2<Bezier > inner;
132 public:
133 template <unsigned required_degree>
134 static void assert_degree(BezierCurve<required_degree> const *) {}
136 BezierCurve() : inner(Bezier::Order(order), Bezier::Order(order)) {
137 }
139 explicit BezierCurve(D2<Bezier > const &x) : inner(x) {}
141 BezierCurve(Bezier x, Bezier y) : inner(x, y) {}
143 // default copy
144 // default assign
146 BezierCurve(Point c0, Point c1) {
147 assert_degree<1>(this);
148 for(unsigned d = 0; d < 2; d++)
149 inner[d] = Bezier(c0[d], c1[d]);
150 }
152 BezierCurve(Point c0, Point c1, Point c2) {
153 assert_degree<2>(this);
154 for(unsigned d = 0; d < 2; d++)
155 inner[d] = Bezier(c0[d], c1[d], c2[d]);
156 }
158 BezierCurve(Point c0, Point c1, Point c2, Point c3) {
159 assert_degree<3>(this);
160 for(unsigned d = 0; d < 2; d++)
161 inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]);
162 }
164 unsigned degree() const { return order; }
166 Curve *duplicate() const { return new BezierCurve(*this); }
168 Point initialPoint() const { return inner.at0(); }
169 Point finalPoint() const { return inner.at1(); }
171 void setInitial(Point v) { setPoint(0, v); }
172 void setFinal(Point v) { setPoint(1, v); }
174 void setPoint(unsigned ix, Point v) { inner[X].setPoint(ix, v[X]); inner[Y].setPoint(ix, v[Y]); }
175 Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); }
177 Rect boundsFast() const { return bounds_fast(inner); }
178 Rect boundsExact() const { return bounds_exact(inner); }
179 Rect boundsLocal(Interval i, unsigned deg) const {
180 if(i.min() == 0 && i.max() == 1) return boundsFast();
181 if(deg == 0) return bounds_local(inner, i);
182 // TODO: UUUUUUGGGLLY
183 if(deg == 1 && order > 1) return Rect(bounds_local(Geom::derivative(inner[X]), i),
184 bounds_local(Geom::derivative(inner[Y]), i));
185 return Rect(Interval(0,0), Interval(0,0));
186 }
187 //TODO: local
189 //TODO: implement next 3 natively
190 int winding(Point p) const {
191 return SBasisCurve(toSBasis()).winding(p);
192 }
194 std::vector<double>
195 roots(double v, Dim2 d) const {
196 return (inner[d] - v).roots();
197 }
199 void setPoints(std::vector<Point> ps) {
200 for(unsigned i = 0; i <= order; i++) {
201 setPoint(i, ps[i]);
202 }
203 }
204 std::vector<Point> points() const { return bezier_points(inner); }
206 std::pair<BezierCurve<order>, BezierCurve<order> > subdivide(Coord t) const {
207 std::pair<Bezier, Bezier > sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t);
208 return std::pair<BezierCurve<order>, BezierCurve<order> >(
209 BezierCurve<order>(sx.first, sy.first),
210 BezierCurve<order>(sx.second, sy.second));
211 }
213 Curve *portion(double f, double t) const {
214 return new BezierCurve(Geom::portion(inner, f, t));
215 }
217 Curve *reverse() const {
218 return new BezierCurve(Geom::reverse(inner));
219 }
221 Curve *transformed(Matrix const &m) const {
222 BezierCurve *ret = new BezierCurve();
223 std::vector<Point> ps = points();
224 for(unsigned i = 0; i <= order; i++) ps[i] = ps[i] * m;
225 ret->setPoints(ps);
226 return ret;
227 }
229 Curve *derivative() const {
230 if(order > 1)
231 return new BezierCurve<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y]));
232 else if (order == 1) {
233 double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0];
234 if(dx == 0) return new BezierCurve<1>(Point(0,0), Point(0,0));
235 double slope = dy / dx;
236 Geom::Point pnt;
237 if(slope == 0) pnt = Geom::Point(0, 0); else pnt = Geom::Point(slope, 1./slope);
238 return new BezierCurve<1>(pnt, pnt);
239 }
240 }
242 Point pointAt(double t) const { return inner.valueAt(t); }
243 std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); }
245 double valueAt(double t, Dim2 d) const { return inner[d].valueAt(t); }
247 D2<SBasis> toSBasis() const {return inner.toSBasis(); }
249 protected:
250 BezierCurve(Point c[]) {
251 Coord x[order+1], y[order+1];
252 for(unsigned i = 0; i <= order; i++) {
253 x[i] = c[i][X]; y[i] = c[i][Y];
254 }
255 inner = Bezier(x, y);
256 }
257 };
259 // BezierCurve<0> is meaningless; specialize it out
260 template<> class BezierCurve<0> : public BezierCurve<1> { public: BezierCurve(); BezierCurve(Bezier x, Bezier y); };
262 typedef BezierCurve<1> LineSegment;
263 typedef BezierCurve<2> QuadraticBezier;
264 typedef BezierCurve<3> CubicBezier;
266 class SVGEllipticalArc : public Curve {
267 public:
268 SVGEllipticalArc() {}
270 SVGEllipticalArc(Point initial, double rx, double ry,
271 double x_axis_rotation, bool large_arc,
272 bool sweep, Point final)
273 : initial_(initial), rx_(rx), ry_(ry), x_axis_rotation_(x_axis_rotation),
274 large_arc_(large_arc), sweep_(sweep), final_(final)
275 {}
277 Curve *duplicate() const { return new SVGEllipticalArc(*this); }
279 Point initialPoint() const { return initial_; }
280 Point finalPoint() const { return final_; }
282 void setInitial(Point v) { initial_ = v; }
283 void setFinal(Point v) { final_ = v; }
285 //TODO: implement funcs
287 Rect boundsFast() const;
288 Rect boundsExact() const;
289 Rect boundsLocal(Interval i, unsigned deg) const;
291 int winding(Point p) const {
292 return SBasisCurve(toSBasis()).winding(p);
293 }
295 std::vector<double> roots(double v, Dim2 d) const;
297 inline std::pair<SVGEllipticalArc, SVGEllipticalArc>
298 subdivide(Coord t) {
299 SVGEllipticalArc a(*this), b(*this);
300 a.final_ = b.initial_ = pointAt(t);
301 return std::pair<SVGEllipticalArc, SVGEllipticalArc>(a, b);
302 }
304 Curve *portion(double f, double t) const {
305 SVGEllipticalArc *ret = new SVGEllipticalArc (*this);
306 ret->initial_ = pointAt(f);
307 ret->final_ = pointAt(t);
308 return ret;
309 }
311 Curve *reverse(double /*f*/, double /*t*/) const {
312 SVGEllipticalArc *ret = new SVGEllipticalArc (*this);
313 ret->initial_ = final_;
314 ret->final_ = initial_;
315 return ret;
316 }
318 //TODO: this next def isn't right
319 Curve *transformed(Matrix const & m) const {
320 SVGEllipticalArc *ret = new SVGEllipticalArc (*this);
321 ret->initial_ = initial_ * m;
322 ret->final_ = final_ * m;
323 return ret;
324 }
326 Curve *derivative() const { throw NotImplemented(); }
328 std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const;
330 D2<SBasis> toSBasis() const;
332 private:
333 Point initial_;
334 double rx_;
335 double ry_;
336 double x_axis_rotation_;
337 bool large_arc_;
338 bool sweep_;
339 Point final_;
340 };
342 template <typename IteratorImpl>
343 class BaseIterator
344 : public std::iterator<std::forward_iterator_tag, Curve const>
345 {
346 public:
347 BaseIterator() {}
349 // default construct
350 // default copy
352 bool operator==(BaseIterator const &other) {
353 return other.impl_ == impl_;
354 }
355 bool operator!=(BaseIterator const &other) {
356 return other.impl_ != impl_;
357 }
359 Curve const &operator*() const { return **impl_; }
360 Curve const *operator->() const { return *impl_; }
362 BaseIterator &operator++() {
363 ++impl_;
364 return *this;
365 }
367 BaseIterator operator++(int) {
368 BaseIterator old=*this;
369 ++(*this);
370 return old;
371 }
373 private:
374 BaseIterator(IteratorImpl const &pos) : impl_(pos) {}
376 IteratorImpl impl_;
377 friend class Path;
378 };
380 template <typename Iterator>
381 class DuplicatingIterator
382 : public std::iterator<std::input_iterator_tag, Curve *>
383 {
384 public:
385 DuplicatingIterator() {}
386 DuplicatingIterator(Iterator const &iter) : impl_(iter) {}
388 bool operator==(DuplicatingIterator const &other) {
389 return other.impl_ == impl_;
390 }
391 bool operator!=(DuplicatingIterator const &other) {
392 return other.impl_ != impl_;
393 }
395 Curve *operator*() const { return (*impl_)->duplicate(); }
397 DuplicatingIterator &operator++() {
398 ++impl_;
399 return *this;
400 }
401 DuplicatingIterator operator++(int) {
402 DuplicatingIterator old=*this;
403 ++(*this);
404 return old;
405 }
407 private:
408 Iterator impl_;
409 };
411 class ContinuityError : public std::runtime_error {
412 public:
413 ContinuityError() : runtime_error("non-contiguous path") {}
414 ContinuityError(std::string const &message) : runtime_error(message) {}
415 };
417 class Path {
418 private:
419 typedef std::vector<Curve *> Sequence;
421 public:
422 typedef BaseIterator<Sequence::iterator> iterator;
423 typedef BaseIterator<Sequence::const_iterator> const_iterator;
424 typedef Sequence::size_type size_type;
425 typedef Sequence::difference_type difference_type;
427 Path()
428 : final_(new LineSegment()), closed_(false)
429 {
430 curves_.push_back(final_);
431 }
433 Path(Path const &other)
434 : final_(new LineSegment()), closed_(other.closed_)
435 {
436 curves_.push_back(final_);
437 insert(begin(), other.begin(), other.end());
438 }
440 explicit Path(Point p)
441 : final_(new LineSegment(p, p)), closed_(false)
442 {
443 curves_.push_back(final_);
444 }
446 template <typename Impl>
447 Path(BaseIterator<Impl> first, BaseIterator<Impl> last, bool closed=false)
448 : closed_(closed), final_(new LineSegment())
449 {
450 curves_.push_back(final_);
451 insert(begin(), first, last);
452 }
454 virtual ~Path() {
455 delete_range(curves_.begin(), curves_.end()-1);
456 delete final_;
457 }
459 Path &operator=(Path const &other) {
460 clear();
461 insert(begin(), other.begin(), other.end());
462 close(other.closed_);
463 return *this;
464 }
466 void swap(Path &other);
468 Curve const &operator[](unsigned i) const { return *curves_[i]; }
470 iterator begin() { return curves_.begin(); }
471 iterator end() { return curves_.end()-1; }
473 Curve const &front() const { return *curves_[0]; }
474 Curve const &back() const { return *curves_[curves_.size()-2]; }
476 const_iterator begin() const { return curves_.begin(); }
477 const_iterator end() const { return curves_.end()-1; }
479 const_iterator end_open() const { return curves_.end()-1; }
480 const_iterator end_closed() const { return curves_.end(); }
481 const_iterator end_default() const {
482 return ( closed_ ? end_closed() : end_open() );
483 }
485 size_type size() const { return curves_.size()-1; }
486 size_type max_size() const { return curves_.max_size()-1; }
488 bool empty() const { return curves_.size() == 1; }
489 bool closed() const { return closed_; }
490 void close(bool closed=true) { closed_ = closed; }
492 Rect boundsFast() const;
493 Rect boundsExact() const;
495 Piecewise<D2<SBasis> > toPwSb() const {
496 Piecewise<D2<SBasis> > ret;
497 ret.push_cut(0);
498 unsigned i = 1;
499 for(const_iterator it = begin(); it != end_default(); ++it, i++) {
500 ret.push(it->toSBasis(), i);
501 }
502 return ret;
503 }
505 Path operator*(Matrix const &m) const {
506 Path ret;
507 for(const_iterator it = begin(); it != end(); ++it) {
508 Curve *temp = it->transformed(m);
509 //Possible point of discontinuity?
510 ret.append(*temp);
511 delete temp;
512 }
513 return ret;
514 }
516 Point pointAt(double t) const {
517 if(empty()) return Point(0,0);
518 double i, f = modf(t, &i);
519 if(i == size() && f == 0) { i--; }
520 assert(i >= 0 && i <= size());
521 return (*this)[unsigned(i)].pointAt(f);
522 }
524 double valueAt(double t, Dim2 d) const {
525 if(empty()) return 0;
526 double i, f = modf(t, &i);
527 if(i == size() && f == 0) { i--; }
528 assert(i >= 0 && i <= size());
529 return (*this)[unsigned(i)].valueAt(f, d);
530 }
532 std::vector<double> roots(double v, Dim2 d) const {
533 std::vector<double> res;
534 for(unsigned i = 0; i <= size(); i++) {
535 std::vector<double> temp = (*this)[i].roots(v, d);
536 for(unsigned j = 0; j < temp.size(); j++)
537 res.push_back(temp[j] + i);
538 }
539 return res;
540 }
542 void appendPortionTo(Path &p, double f, double t) const;
544 Path portion(double f, double t) const {
545 Path ret;
546 ret.close(false);
547 appendPortionTo(ret, f, t);
548 return ret;
549 }
550 Path portion(Interval i) const { return portion(i.min(), i.max()); }
552 Path reverse() const {
553 Path ret;
554 ret.close(closed_);
555 for(int i = size() - (closed_ ? 0 : 1); i >= 0; i--) {
556 //TODO: do we really delete?
557 Curve *temp = (*this)[i].reverse();
558 ret.append(*temp);
559 delete temp;
560 }
561 return ret;
562 }
564 void insert(iterator pos, Curve const &curve) {
565 Sequence source(1, curve.duplicate());
566 try {
567 do_update(pos.impl_, pos.impl_, source.begin(), source.end());
568 } catch (...) {
569 delete_range(source.begin(), source.end());
570 throw;
571 }
572 }
574 template <typename Impl>
575 void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> last)
576 {
577 Sequence source(DuplicatingIterator<Impl>(first.impl_),
578 DuplicatingIterator<Impl>(last.impl_));
579 try {
580 do_update(pos.impl_, pos.impl_, source.begin(), source.end());
581 } catch (...) {
582 delete_range(source.begin(), source.end());
583 throw;
584 }
585 }
587 void clear() {
588 do_update(curves_.begin(), curves_.end()-1,
589 curves_.begin(), curves_.begin());
590 }
592 void erase(iterator pos) {
593 do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin());
594 }
596 void erase(iterator first, iterator last) {
597 do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin());
598 }
600 void replace(iterator replaced, Curve const &curve) {
601 Sequence source(1, curve.duplicate());
602 try {
603 do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
604 } catch (...) {
605 delete_range(source.begin(), source.end());
606 throw;
607 }
608 }
610 void replace(iterator first_replaced, iterator last_replaced,
611 Curve const &curve)
612 {
613 Sequence source(1, curve.duplicate());
614 try {
615 do_update(first_replaced.impl_, last_replaced.impl_,
616 source.begin(), source.end());
617 } catch (...) {
618 delete_range(source.begin(), source.end());
619 throw;
620 }
621 }
623 template <typename Impl>
624 void replace(iterator replaced,
625 BaseIterator<Impl> first, BaseIterator<Impl> last)
626 {
627 Sequence source(DuplicatingIterator<Impl>(first.impl_),
628 DuplicatingIterator<Impl>(last.impl_));
629 try {
630 do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end());
631 } catch (...) {
632 delete_range(source.begin(), source.end());
633 throw;
634 }
635 }
637 template <typename Impl>
638 void replace(iterator first_replaced, iterator last_replaced,
639 BaseIterator<Impl> first, BaseIterator<Impl> last)
640 {
641 Sequence source(first.impl_, last.impl_);
642 try {
643 do_update(first_replaced.impl_, last_replaced.impl_,
644 source.begin(), source.end());
645 } catch (...) {
646 delete_range(source.begin(), source.end());
647 throw;
648 }
649 }
651 void start(Point p) {
652 clear();
653 final_->setPoint(0, p);
654 final_->setPoint(1, p);
655 }
657 Point initialPoint() const { return (*final_)[1]; }
658 Point finalPoint() const { return (*final_)[0]; }
660 void append(Curve const &curve);
661 void append(D2<SBasis> const &curve);
663 template <typename CurveType, typename A>
664 void appendNew(A a) {
665 do_append(new CurveType((*final_)[0], a));
666 }
668 template <typename CurveType, typename A, typename B>
669 void appendNew(A a, B b) {
670 do_append(new CurveType((*final_)[0], a, b));
671 }
673 template <typename CurveType, typename A, typename B, typename C>
674 void appendNew(A a, B b, C c) {
675 do_append(new CurveType((*final_)[0], a, b, c));
676 }
678 template <typename CurveType, typename A, typename B, typename C,
679 typename D>
680 void appendNew(A a, B b, C c, D d) {
681 do_append(new CurveType((*final_)[0], a, b, c, d));
682 }
684 template <typename CurveType, typename A, typename B, typename C,
685 typename D, typename E>
686 void appendNew(A a, B b, C c, D d, E e) {
687 do_append(new CurveType((*final_)[0], a, b, c, d, e));
688 }
690 template <typename CurveType, typename A, typename B, typename C,
691 typename D, typename E, typename F>
692 void appendNew(A a, B b, C c, D d, E e, F f) {
693 do_append(new CurveType((*final_)[0], a, b, c, d, e, f));
694 }
696 template <typename CurveType, typename A, typename B, typename C,
697 typename D, typename E, typename F,
698 typename G>
699 void appendNew(A a, B b, C c, D d, E e, F f, G g) {
700 do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g));
701 }
703 template <typename CurveType, typename A, typename B, typename C,
704 typename D, typename E, typename F,
705 typename G, typename H>
706 void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) {
707 do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h));
708 }
710 template <typename CurveType, typename A, typename B, typename C,
711 typename D, typename E, typename F,
712 typename G, typename H, typename I>
713 void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) {
714 do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h, i));
715 }
717 private:
718 void do_update(Sequence::iterator first_replaced,
719 Sequence::iterator last_replaced,
720 Sequence::iterator first,
721 Sequence::iterator last);
723 void do_append(Curve *curve);
725 void delete_range(Sequence::iterator first, Sequence::iterator last);
727 void check_continuity(Sequence::iterator first_replaced,
728 Sequence::iterator last_replaced,
729 Sequence::iterator first,
730 Sequence::iterator last);
732 Sequence curves_;
733 LineSegment *final_;
734 bool closed_;
735 };
737 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
738 Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
739 for(unsigned i = 1; i < paths.size(); i++) {
740 ret.concat(paths[i].toPwSb());
741 }
742 return ret;
743 }
745 /*
746 class PathPortion : public Curve {
747 Path *source;
748 double f, t;
749 boost::optional<Path> result;
751 public:
752 double from() const { return f; }
753 double to() const { return t; }
755 explicit PathPortion(Path *s, double fp, double tp) : source(s), f(fp), t(tp) {}
756 Curve *duplicate() const { return new PathPortion(*this); }
758 Point initialPoint() const { return source->pointAt(f); }
759 Point finalPoint() const { return source->pointAt(t); }
761 Path actualPath() {
762 if(!result) *result = source->portion(f, t);
763 return *result;
764 }
766 Rect boundsFast() const { return actualPath().boundsFast; }
767 Rect boundsExact() const { return actualPath().boundsFast; }
768 Rect boundsLocal(Interval i) const { throw NotImplemented(); }
770 std::vector<double> roots(double v, Dim2 d) const = 0;
772 virtual int winding(Point p) const { return root_winding(*this, p); }
774 virtual Curve *portion(double f, double t) const = 0;
775 virtual Curve *reverse() const { return portion(1, 0); }
777 virtual Crossings crossingsWith(Curve const & other) const;
779 virtual void setInitial(Point v) = 0;
780 virtual void setFinal(Point v) = 0;
782 virtual Curve *transformed(Matrix const &m) const = 0;
784 virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
785 virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
786 virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
787 virtual D2<SBasis> toSBasis() const = 0;
789 };
790 */
792 }
794 namespace std {
796 template <>
797 inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
798 {
799 a.swap(b);
800 }
802 }
804 #endif // SEEN_GEOM_PATH_H
806 /*
807 Local Variables:
808 mode:c++
809 c-file-style:"stroustrup"
810 c-file-offsets:((innamespace . 0)(substatement-open . 0))
811 indent-tabs-mode:nil
812 c-brace-offset:0
813 fill-column:99
814 End:
815 */
816 // vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 :