~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/2geom/path.h

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * \file
 
3
 * \brief  Path - Series of continuous curves
 
4
 *
 
5
 * Authors:
 
6
 *              MenTaLguY <mental@rydia.net>
 
7
 *              Marco Cecchetti <mrcekets at gmail.com>
 
8
 * 
 
9
 * Copyright 2007-2008  authors
 
10
 *
 
11
 * This library is free software; you can redistribute it and/or
 
12
 * modify it either under the terms of the GNU Lesser General Public
 
13
 * License version 2.1 as published by the Free Software Foundation
 
14
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 
15
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 
16
 * notice, a recipient may use your version of this file under either
 
17
 * the MPL or the LGPL.
 
18
 *
 
19
 * You should have received a copy of the LGPL along with this library
 
20
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
22
 * You should have received a copy of the MPL along with this library
 
23
 * in the file COPYING-MPL-1.1
 
24
 *
 
25
 * The contents of this file are subject to the Mozilla Public License
 
26
 * Version 1.1 (the "License"); you may not use this file except in
 
27
 * compliance with the License. You may obtain a copy of the License at
 
28
 * http://www.mozilla.org/MPL/
 
29
 *
 
30
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 
31
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 
32
 * the specific language governing rights and limitations.
 
33
 */
 
34
 
 
35
 
 
36
 
 
37
 
 
38
#ifndef SEEN_GEOM_PATH_H
 
39
#define SEEN_GEOM_PATH_H
 
40
 
 
41
 
 
42
#include <boost/shared_ptr.hpp>
 
43
#include <2geom/curve.h>
 
44
#include <2geom/bezier-curve.h>
 
45
 
 
46
#include <iterator>
 
47
#include <algorithm>
 
48
 
 
49
 
 
50
namespace Geom
 
51
{
 
52
 
 
53
class Path;
 
54
 
 
55
namespace PathInternal {
 
56
 
 
57
typedef std::vector<boost::shared_ptr<Curve const> > Sequence;
 
58
 
 
59
template <typename C, typename P>
 
60
class BaseIterator {
 
61
protected:
 
62
  BaseIterator() : path(NULL), index(0) {}
 
63
  BaseIterator(P *p, unsigned i) : path(p), index(i) {}
 
64
  // default copy, default assign
 
65
 
 
66
public:
 
67
  bool operator==(BaseIterator const &other) {
 
68
    return path == other.path && index == other.index;
 
69
  }
 
70
  bool operator!=(BaseIterator const &other) {
 
71
    return path != other.path || index != other.index;
 
72
  }
 
73
 
 
74
  Curve const &operator*() const { return (*path)[index]; }
 
75
  Curve const *operator->() const { return &(*path)[index]; }
 
76
  boost::shared_ptr<Curve const> get_ref() const {
 
77
    return path->get_ref_at_index(index);
 
78
  }
 
79
 
 
80
  C &operator++() {
 
81
    ++index;
 
82
    return static_cast<C &>(*this);
 
83
  }
 
84
  C operator++(int) {
 
85
    C old(static_cast<C &>(*this));
 
86
    ++(*this);
 
87
    return old;
 
88
  }
 
89
 
 
90
  C &operator--() {
 
91
    --index;
 
92
    return static_cast<C &>(*this);
 
93
  }
 
94
  C operator--(int) {
 
95
    C old(static_cast<C &>(*this));
 
96
    --(*this);
 
97
    return old;
 
98
  }
 
99
 
 
100
private:
 
101
  P *path;
 
102
  unsigned index;
 
103
 
 
104
  friend class ::Geom::Path;
 
105
};
 
106
 
 
107
class ConstIterator : public BaseIterator<ConstIterator, Path const> {
 
108
public:
 
109
  typedef BaseIterator<ConstIterator, Path const> Base;
 
110
 
 
111
  ConstIterator() : Base() {}
 
112
  // default copy, default assign
 
113
 
 
114
private:
 
115
  ConstIterator(Path const &p, unsigned i) : Base(&p, i) {}
 
116
  friend class ::Geom::Path;
 
117
};
 
118
 
 
119
class Iterator : public BaseIterator<Iterator, Path> {
 
120
public:
 
121
  typedef BaseIterator<Iterator, Path> Base;
 
122
 
 
123
  Iterator() : Base() {}
 
124
  // default copy, default assign
 
125
 
 
126
  operator ConstIterator const &() const {
 
127
    return reinterpret_cast<ConstIterator const &>(*this);
 
128
  }
 
129
 
 
130
private:
 
131
  Iterator(Path &p, unsigned i) : Base(&p, i) {}
 
132
  friend class ::Geom::Path;
 
133
};
 
134
 
 
135
}
 
136
 
 
137
/*
 
138
 * Open and closed paths: all paths, whether open or closed, store a final
 
139
 * segment which connects the initial and final endpoints of the "real"
 
140
 * path data.  While similar to the "z" in an SVG path, it exists for
 
141
 * both open and closed paths, and is not considered part of the "normal"
 
142
 * path data, which is always covered by the range [begin(), end_open()).
 
143
 * Conversely, the range [begin(), end_closed()) always contains the "extra"
 
144
 * closing segment.
 
145
 *
 
146
 * The only difference between a closed and an open path is whether
 
147
 * end_default() returns end_closed() or end_open().  The idea behind this
 
148
 * is to let any path be stroked using [begin(), end_default()), and filled
 
149
 * using [begin(), end_closed()), without requiring a separate "filled" version
 
150
 * of the path to use for filling.
 
151
 *
 
152
 * \invariant : curves_ always contains at least one segment. The last segment
 
153
 *              is always of type ClosingSegment. All constructors take care of this.
 
154
                (curves_.size() > 0) && dynamic_cast<ClosingSegment>(curves_.back())
 
155
 */
 
156
class Path {
 
157
public:
 
158
  typedef PathInternal::Sequence Sequence;
 
159
  typedef PathInternal::Iterator iterator;
 
160
  typedef PathInternal::ConstIterator const_iterator;
 
161
  typedef Sequence::size_type size_type;
 
162
  typedef Sequence::difference_type difference_type;
 
163
 
 
164
  class ClosingSegment : public LineSegment {
 
165
  public:
 
166
    ClosingSegment() : LineSegment() {}
 
167
    ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
 
168
    virtual Curve *duplicate() const { return new ClosingSegment(*this); }
 
169
    virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); }
 
170
  };
 
171
 
 
172
  enum Stitching {
 
173
    NO_STITCHING=0,
 
174
    STITCH_DISCONTINUOUS
 
175
  };
 
176
 
 
177
  class StitchSegment : public LineSegment {
 
178
  public:
 
179
    StitchSegment() : LineSegment() {}
 
180
    StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
 
181
    virtual Curve *duplicate() const { return new StitchSegment(*this); }
 
182
    virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); }
 
183
  };
 
184
 
 
185
  // Path(Path const &other) - use default copy constructor
 
186
 
 
187
  explicit Path(Point p=Point())
 
188
  : curves_(boost::shared_ptr<Sequence>(new Sequence(1, boost::shared_ptr<Curve>()))),
 
189
    final_(new ClosingSegment(p, p)),
 
190
    closed_(false)
 
191
  {
 
192
    get_curves().back() = boost::shared_ptr<Curve>(final_);
 
193
  }
 
194
 
 
195
  Path(const_iterator const &first,
 
196
       const_iterator const &last,
 
197
       bool closed=false)
 
198
  : curves_(boost::shared_ptr<Sequence>(new Sequence(seq_iter(first),
 
199
                                                     seq_iter(last)))),
 
200
    closed_(closed)
 
201
  {
 
202
    if (!get_curves().empty()) {
 
203
      final_ = new ClosingSegment(get_curves().back()->finalPoint(),
 
204
                                  get_curves().front()->initialPoint());
 
205
    } else {
 
206
      final_ = new ClosingSegment();
 
207
    }
 
208
    get_curves().push_back(boost::shared_ptr<Curve>(final_));
 
209
  }
 
210
 
 
211
  virtual ~Path() {}
 
212
  
 
213
  // Path &operator=(Path const &other) - use default assignment operator
 
214
 
 
215
  void swap(Path &other) {
 
216
    std::swap(other.curves_, curves_);
 
217
    std::swap(other.final_, final_);
 
218
    std::swap(other.closed_, closed_);
 
219
  }
 
220
 
 
221
  Curve const &operator[](unsigned i) const { return *get_curves()[i]; }
 
222
  Curve const &at_index(unsigned i) const { return *get_curves()[i]; }
 
223
  boost::shared_ptr<Curve const> get_ref_at_index(unsigned i) {
 
224
    return get_curves()[i];
 
225
  }
 
226
 
 
227
  Curve const &front() const { return *get_curves()[0]; }
 
228
  Curve const &back() const { return back_open(); }
 
229
  Curve const &back_open() const {
 
230
    if (empty()) { THROW_RANGEERROR("Path contains not enough segments"); }
 
231
    return *get_curves()[get_curves().size()-2];
 
232
  }
 
233
  Curve const &back_closed() const { return *get_curves()[get_curves().size()-1]; }
 
234
  Curve const &back_default() const {
 
235
    return ( closed_ ? back_closed() : back_open() );
 
236
  }
 
237
 
 
238
  const_iterator begin() const { return const_iterator(*this, 0); }
 
239
  const_iterator end() const { return const_iterator(*this, size()); }
 
240
  iterator begin() { return iterator(*this, 0); }
 
241
  iterator end() { return iterator(*this, size()); }
 
242
 
 
243
  const_iterator end_open() const { return const_iterator(*this, size()); }
 
244
  const_iterator end_closed() const { return const_iterator(*this, size()+1); }
 
245
  const_iterator end_default() const {
 
246
    return ( closed_ ? end_closed() : end_open() );
 
247
  }
 
248
 
 
249
  size_type size_open() const { return get_curves().size()-1; }
 
250
  size_type size_closed() const { return get_curves().size(); }
 
251
  size_type size_default() const  {
 
252
    return ( closed_ ? size_closed() : size_open() );
 
253
  }
 
254
  size_type size() const { return size_open(); }
 
255
 
 
256
  size_type max_size() const { return get_curves().max_size()-1; }
 
257
 
 
258
  bool empty() const { return (get_curves().size() == 1); }
 
259
  bool closed() const { return closed_; }
 
260
  void close(bool closed=true) { closed_ = closed; }
 
261
 
 
262
  OptRect boundsFast() const;
 
263
  OptRect boundsExact() const;
 
264
 
 
265
  Piecewise<D2<SBasis> > toPwSb() const {
 
266
    Piecewise<D2<SBasis> > ret;
 
267
    ret.push_cut(0);
 
268
    unsigned i = 1;
 
269
    bool degenerate = true;
 
270
    // pw<d2<>> is always open. so if path is closed, add closing segment as well to pwd2.
 
271
    for(const_iterator it = begin(); it != end_default(); ++it) {
 
272
      if (!it->isDegenerate()) {
 
273
        ret.push(it->toSBasis(), i++);
 
274
        degenerate = false;
 
275
      }
 
276
    }
 
277
    if (degenerate) {
 
278
      // if path only contains degenerate curves, no second cut is added
 
279
      // so we need to create at least one segment manually
 
280
      ret = Piecewise<D2<SBasis> >(initialPoint());
 
281
    }
 
282
    return ret;
 
283
  }
 
284
 
 
285
  bool operator==(Path const &other) const {
 
286
    if (this == &other) return true;
 
287
    if (closed_ != other.closed_) return false;
 
288
    return get_curves() == other.get_curves();
 
289
  }
 
290
  bool operator!=(Path const &other) const {
 
291
    return !( *this == other );
 
292
  }
 
293
 
 
294
  Path operator*(Matrix const &m) const {
 
295
    Path ret(*this);
 
296
    ret *= m;
 
297
    return ret;
 
298
  }
 
299
 
 
300
  Path &operator*=(Matrix const &m);
 
301
  
 
302
  Point pointAt(double t) const 
 
303
  {
 
304
          unsigned int sz = size();
 
305
          if ( closed() ) ++sz;
 
306
          if ( t < 0 || t > sz  )
 
307
          {
 
308
                  THROW_RANGEERROR("parameter t out of bounds");
 
309
          }
 
310
          if ( empty() ) return initialPoint(); // naked moveto
 
311
          double k, lt = modf(t, &k);
 
312
          unsigned int i = static_cast<unsigned int>(k);
 
313
          if ( i == sz ) 
 
314
          { 
 
315
                  --i;
 
316
                  lt = 1;
 
317
          }
 
318
          return (*this)[i].pointAt(lt);
 
319
  }
 
320
 
 
321
  double valueAt(double t, Dim2 d) const 
 
322
  {
 
323
          unsigned int sz = size();
 
324
          if ( closed() ) ++sz;
 
325
          if ( t < 0 || t > sz  )
 
326
          {
 
327
                  THROW_RANGEERROR("parameter t out of bounds");
 
328
          }
 
329
          if ( empty() ) return initialPoint()[d]; // naked moveto
 
330
          double k, lt = modf(t, &k);
 
331
          unsigned int i = static_cast<unsigned int>(k);
 
332
          if ( i == sz ) 
 
333
          { 
 
334
                  --i;
 
335
                  lt = 1;
 
336
          }
 
337
          return (*this)[i].valueAt(lt, d);
 
338
  }
 
339
 
 
340
  
 
341
  Point operator() (double t) const
 
342
  {
 
343
          return pointAt(t);
 
344
  }
 
345
  
 
346
  std::vector<double> roots(double v, Dim2 d) const {
 
347
    std::vector<double> res;
 
348
    for(unsigned i = 0; i <= size(); i++) {
 
349
      std::vector<double> temp = (*this)[i].roots(v, d);
 
350
      for(unsigned j = 0; j < temp.size(); j++)
 
351
        res.push_back(temp[j] + i);
 
352
    }
 
353
    return res;
 
354
  }
 
355
  
 
356
  std::vector<double> 
 
357
  allNearestPoints(Point const& _point, double from, double to) const;
 
358
  
 
359
  std::vector<double>
 
360
  allNearestPoints(Point const& _point) const
 
361
  {
 
362
          unsigned int sz = size();
 
363
          if ( closed() ) ++sz;
 
364
          return allNearestPoints(_point, 0, sz);
 
365
  }
 
366
  
 
367
  std::vector<double>
 
368
  nearestPointPerCurve(Point const& _point) const;  
 
369
  
 
370
  double nearestPoint(Point const& _point, double from, double to, double *distance_squared = NULL) const;
 
371
  
 
372
  double nearestPoint(Point const& _point, double *distance_squared = NULL) const
 
373
  {
 
374
          unsigned int sz = size();
 
375
          if ( closed() ) ++sz;
 
376
          return nearestPoint(_point, 0, sz, distance_squared);
 
377
  }
 
378
   
 
379
  void appendPortionTo(Path &p, double f, double t) const;
 
380
 
 
381
  Path portion(double f, double t) const {
 
382
    Path ret;
 
383
    ret.close(false);
 
384
    appendPortionTo(ret, f, t);
 
385
    return ret;
 
386
  }
 
387
  Path portion(Interval i) const { return portion(i.min(), i.max()); }
 
388
 
 
389
  Path reverse() const {
 
390
    Path ret(*this);
 
391
    ret.unshare();
 
392
    for ( Sequence::iterator iter = ret.get_curves().begin() ;
 
393
          iter != ret.get_curves().end()-1 ; ++iter )
 
394
    {
 
395
      *iter = boost::shared_ptr<Curve>((*iter)->reverse());
 
396
    }
 
397
    std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1);
 
398
    ret.final_ = static_cast<ClosingSegment *>(ret.final_->reverse());
 
399
    ret.get_curves().back() = boost::shared_ptr<Curve>(ret.final_);
 
400
    return ret;
 
401
  }
 
402
 
 
403
  void insert(iterator const &pos,
 
404
              Curve const &curve, Stitching stitching=NO_STITCHING)
 
405
  {
 
406
    unshare();
 
407
    Sequence::iterator seq_pos(seq_iter(pos));
 
408
    Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
 
409
    if (stitching) stitch(seq_pos, seq_pos, source);
 
410
    do_update(seq_pos, seq_pos, source.begin(), source.end());
 
411
  }
 
412
 
 
413
  void insert(iterator const &pos,
 
414
              const_iterator const &first,
 
415
              const_iterator const &last,
 
416
              Stitching stitching=NO_STITCHING)
 
417
  {
 
418
    unshare();
 
419
    Sequence::iterator seq_pos(seq_iter(pos));
 
420
    Sequence source(seq_iter(first), seq_iter(last));
 
421
    if (stitching) stitch(seq_pos, seq_pos, source);
 
422
    do_update(seq_pos, seq_pos, source.begin(), source.end());
 
423
  }
 
424
 
 
425
  void clear() {
 
426
    unshare();
 
427
    do_update(get_curves().begin(), get_curves().end()-1,
 
428
              get_curves().begin(), get_curves().begin());
 
429
  }
 
430
 
 
431
  void erase(iterator const &pos, Stitching stitching=NO_STITCHING) {
 
432
    unshare();
 
433
    Sequence::iterator seq_pos(seq_iter(pos));
 
434
    if (stitching) {
 
435
      Sequence stitched;
 
436
      stitch(seq_pos, seq_pos+1, stitched);
 
437
      do_update(seq_pos, seq_pos+1, stitched.begin(), stitched.end());
 
438
    } else {
 
439
      do_update(seq_pos, seq_pos+1, get_curves().begin(), get_curves().begin());
 
440
    }
 
441
  }
 
442
 
 
443
  void erase(iterator const &first,
 
444
             iterator const &last,
 
445
             Stitching stitching=NO_STITCHING)
 
446
  {
 
447
    unshare();
 
448
    Sequence::iterator seq_first=seq_iter(first);
 
449
    Sequence::iterator seq_last=seq_iter(last);
 
450
    if (stitching) {
 
451
      Sequence stitched;
 
452
      stitch(seq_first, seq_last, stitched);
 
453
      do_update(seq_first, seq_last, stitched.begin(), stitched.end());
 
454
    } else {
 
455
      do_update(seq_first, seq_last,
 
456
                get_curves().begin(), get_curves().begin());
 
457
    }
 
458
  }
 
459
 
 
460
  // erase last segment of path
 
461
  void erase_last() {
 
462
    erase(iterator(*this, size()-1));
 
463
  }
 
464
 
 
465
  void replace(iterator const &replaced,
 
466
               Curve const &curve,
 
467
               Stitching stitching=NO_STITCHING)
 
468
  {
 
469
    unshare();
 
470
    Sequence::iterator seq_replaced(seq_iter(replaced));
 
471
    Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
 
472
    if (stitching) stitch(seq_replaced, seq_replaced+1, source);
 
473
    do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
 
474
  }
 
475
 
 
476
  void replace(iterator const &first_replaced,
 
477
               iterator const &last_replaced,
 
478
               Curve const &curve, Stitching stitching=NO_STITCHING)
 
479
  {
 
480
    unshare();
 
481
    Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
 
482
    Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
 
483
    Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
 
484
    if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
 
485
    do_update(seq_first_replaced, seq_last_replaced,
 
486
              source.begin(), source.end());
 
487
  }
 
488
 
 
489
  void replace(iterator const &replaced,
 
490
               const_iterator const &first,
 
491
               const_iterator const &last,
 
492
               Stitching stitching=NO_STITCHING)
 
493
  {
 
494
    unshare();
 
495
    Sequence::iterator seq_replaced(seq_iter(replaced));
 
496
    Sequence source(seq_iter(first), seq_iter(last));
 
497
    if (stitching) stitch(seq_replaced, seq_replaced+1, source);
 
498
    do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
 
499
  }
 
500
 
 
501
  void replace(iterator const &first_replaced,
 
502
               iterator const &last_replaced,
 
503
               const_iterator const &first,
 
504
               const_iterator const &last,
 
505
               Stitching stitching=NO_STITCHING)
 
506
  {
 
507
    unshare();
 
508
    Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
 
509
    Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
 
510
    Sequence source(seq_iter(first), seq_iter(last));
 
511
    if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
 
512
    do_update(seq_first_replaced, seq_last_replaced,
 
513
              source.begin(), source.end());
 
514
  }
 
515
 
 
516
  void start(Point p) {
 
517
    clear();
 
518
    final_->setPoint(0, p);
 
519
    final_->setPoint(1, p);
 
520
  }
 
521
 
 
522
  Point initialPoint() const { return (*final_)[1]; }
 
523
  Point finalPoint() const { return (*final_)[0]; }
 
524
 
 
525
  void setInitial(Point const& p)
 
526
  {
 
527
          if ( empty() ) return;
 
528
          unshare();
 
529
          boost::shared_ptr<Curve> head(front().duplicate());
 
530
          head->setInitial(p);
 
531
          Sequence::iterator replaced = get_curves().begin();
 
532
          Sequence source(1, head);
 
533
          do_update(replaced, replaced + 1, source.begin(), source.end());
 
534
  }
 
535
 
 
536
  void setFinal(Point const& p)
 
537
  {
 
538
          if ( empty() ) return;
 
539
          unshare();
 
540
          boost::shared_ptr<Curve> tail(back().duplicate());
 
541
          tail->setFinal(p);
 
542
          Sequence::iterator replaced = get_curves().end() - 2;
 
543
          Sequence source(1, tail);
 
544
          do_update(replaced, replaced + 1, source.begin(), source.end());
 
545
  }
 
546
 
 
547
  void append(Curve const &curve, Stitching stitching=NO_STITCHING) {
 
548
    unshare();
 
549
    if (stitching) stitchTo(curve.initialPoint());
 
550
    do_append(curve.duplicate());
 
551
  }
 
552
  void append(D2<SBasis> const &curve, Stitching stitching=NO_STITCHING) {
 
553
    unshare();
 
554
    if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0]));
 
555
    do_append(new SBasisCurve(curve));
 
556
  }
 
557
  void append(Path const &other, Stitching stitching=NO_STITCHING) {
 
558
    insert(end(), other.begin(), other.end(), stitching);
 
559
  }
 
560
 
 
561
  void stitchTo(Point const &p) {
 
562
    if (!empty() && finalPoint() != p) {
 
563
      unshare();
 
564
      do_append(new StitchSegment(finalPoint(), p));
 
565
    }
 
566
  }
 
567
 
 
568
 
 
569
  /**
 
570
   * It is important to note that the coordinates passed to appendNew should be finite!
 
571
   * If one of the coordinates is infinite, 2geom will throw a ContinuityError exception.
 
572
   */
 
573
 
 
574
  template <typename CurveType, typename A>
 
575
  void appendNew(A a) {
 
576
    unshare();
 
577
    do_append(new CurveType(finalPoint(), a));
 
578
  }
 
579
 
 
580
  template <typename CurveType, typename A, typename B>
 
581
  void appendNew(A a, B b) {
 
582
    unshare();
 
583
    do_append(new CurveType(finalPoint(), a, b));
 
584
  }
 
585
 
 
586
  template <typename CurveType, typename A, typename B, typename C>
 
587
  void appendNew(A a, B b, C c) {
 
588
    unshare();
 
589
    do_append(new CurveType(finalPoint(), a, b, c));
 
590
  }
 
591
 
 
592
  template <typename CurveType, typename A, typename B, typename C,
 
593
                                typename D>
 
594
  void appendNew(A a, B b, C c, D d) {
 
595
    unshare();
 
596
    do_append(new CurveType(finalPoint(), a, b, c, d));
 
597
  }
 
598
 
 
599
  template <typename CurveType, typename A, typename B, typename C,
 
600
                                typename D, typename E>
 
601
  void appendNew(A a, B b, C c, D d, E e) {
 
602
    unshare();
 
603
    do_append(new CurveType(finalPoint(), a, b, c, d, e));
 
604
  }
 
605
 
 
606
  template <typename CurveType, typename A, typename B, typename C,
 
607
                                typename D, typename E, typename F>
 
608
  void appendNew(A a, B b, C c, D d, E e, F f) {
 
609
    unshare();
 
610
    do_append(new CurveType(finalPoint(), a, b, c, d, e, f));
 
611
  }
 
612
 
 
613
  template <typename CurveType, typename A, typename B, typename C,
 
614
                                typename D, typename E, typename F,
 
615
                                typename G>
 
616
  void appendNew(A a, B b, C c, D d, E e, F f, G g) {
 
617
    unshare();
 
618
    do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g));
 
619
  }
 
620
 
 
621
  template <typename CurveType, typename A, typename B, typename C,
 
622
                                typename D, typename E, typename F,
 
623
                                typename G, typename H>
 
624
  void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) {
 
625
    unshare();
 
626
    do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h));
 
627
  }
 
628
 
 
629
  template <typename CurveType, typename A, typename B, typename C,
 
630
                                typename D, typename E, typename F,
 
631
                                typename G, typename H, typename I>
 
632
  void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) {
 
633
    unshare();
 
634
    do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i));
 
635
  }
 
636
 
 
637
private:
 
638
  static Sequence::iterator seq_iter(iterator const &iter) {
 
639
    return iter.path->get_curves().begin() + iter.index;
 
640
  }
 
641
  static Sequence::const_iterator seq_iter(const_iterator const &iter) {
 
642
    return iter.path->get_curves().begin() + iter.index;
 
643
  }
 
644
 
 
645
  Sequence &get_curves() { return *curves_; }
 
646
  Sequence const &get_curves() const { return *curves_; }
 
647
 
 
648
  void unshare() {
 
649
    if (!curves_.unique()) {
 
650
      curves_ = boost::shared_ptr<Sequence>(new Sequence(*curves_));
 
651
    }
 
652
    if (!get_curves().back().unique()) {
 
653
      final_ = static_cast<ClosingSegment *>(final_->duplicate());
 
654
      get_curves().back() = boost::shared_ptr<Curve>(final_);
 
655
    }
 
656
  }
 
657
 
 
658
  void stitch(Sequence::iterator first_replaced,
 
659
              Sequence::iterator last_replaced,
 
660
              Sequence &sequence);
 
661
 
 
662
  void do_update(Sequence::iterator first_replaced,
 
663
                 Sequence::iterator last_replaced,
 
664
                 Sequence::iterator first,
 
665
                 Sequence::iterator last);
 
666
 
 
667
  // n.b. takes ownership of curve object
 
668
  void do_append(Curve *curve);
 
669
 
 
670
  void check_continuity(Sequence::iterator first_replaced,
 
671
                        Sequence::iterator last_replaced,
 
672
                        Sequence::iterator first,
 
673
                        Sequence::iterator last);
 
674
 
 
675
  boost::shared_ptr<Sequence> curves_;
 
676
  ClosingSegment *final_;
 
677
  bool closed_;
 
678
};  // end class Path
 
679
 
 
680
inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
 
681
    Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
 
682
    for(unsigned i = 1; i < paths.size(); i++) {
 
683
        ret.concat(paths[i].toPwSb());
 
684
    }
 
685
    return ret;
 
686
}
 
687
 
 
688
inline
 
689
Coord nearest_point(Point const& p, Path const& c)
 
690
{
 
691
        return c.nearestPoint(p);
 
692
}
 
693
 
 
694
}  // end namespace Geom
 
695
 
 
696
namespace std {
 
697
 
 
698
template <>
 
699
inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
 
700
{
 
701
  a.swap(b);
 
702
}
 
703
 
 
704
}  // end namespace std
 
705
 
 
706
#endif // SEEN_GEOM_PATH_H
 
707
 
 
708
 
 
709
 
 
710
 
 
711
/*
 
712
  Local Variables:
 
713
  mode:c++
 
714
  c-file-style:"stroustrup"
 
715
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
716
  indent-tabs-mode:nil
 
717
  fill-column:99
 
718
  End:
 
719
*/
 
720
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :