2
2
* Path - Series of continuous curves
4
* Copyright 2007 MenTaLguY <mental@rydia.net>
6
* This library is free software; you can redistribute it and/or
5
* MenTaLguY <mental@rydia.net>
6
* Marco Cecchetti <mrcekets at gmail.com>
8
* Copyright 2007-2008 authors
10
* This library is free software; you can redistribute it and/or
7
11
* modify it either under the terms of the GNU Lesser General Public
8
12
* License version 2.1 as published by the Free Software Foundation
9
13
* (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
14
* Public License Version 1.1 (the "MPL"). If you do not alter this
11
15
* notice, a recipient may use your version of this file under either
12
16
* the MPL or the LGPL.
14
18
* 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
19
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
20
* 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
21
* You should have received a copy of the MPL along with this library
18
22
* in the file COPYING-MPL-1.1
20
24
* The contents of this file are subject to the Mozilla Public License
21
25
* Version 1.1 (the "License"); you may not use this file except in
22
26
* compliance with the License. You may obtain a copy of the License at
23
27
* http://www.mozilla.org/MPL/
25
29
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
30
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
31
* the specific language governing rights and limitations.
36
int CurveHelpers::root_winding(Curve const &c, Point p) {
37
std::vector<double> ts = c.roots(p[Y], Y);
39
if(ts.empty()) return 0;
41
double const fudge = 0.01; //fudge factor used on first and last
43
std::sort(ts.begin(), ts.end());
45
// winding determined by crossings at roots
48
double pt = ts.front() - fudge;
49
for ( std::vector<double>::iterator ti = ts.begin()
54
if ( t <= 0. || t >= 1. ) continue; //skip endpoint roots
55
if ( c.valueAt(t, X) > p[X] ) { // root is ray intersection
57
std::vector<double>::iterator next = ti;
60
if(next == ts.end()) nt = t + fudge; else nt = *next;
62
// Check before in time and after in time for positions
63
// Currently we're using the average times between next and previous segs
64
Cmp after_to_ray = cmp(c.valueAt((t + nt) / 2, Y), p[Y]);
65
Cmp before_to_ray = cmp(c.valueAt((t + pt) / 2, Y), p[Y]);
66
// if y is included, these will have opposite values, giving order.
67
Cmp dt = cmp(after_to_ray, before_to_ray);
68
if(dt != EQUAL_TO) //Should always be true, but yah never know..
37
#include <2geom/path.h>
41
using namespace Geom::PathInternal;
46
OptRect Path::boundsFast() const {
48
if (empty()) return bounds;
49
bounds=front().boundsFast();
50
const_iterator iter = begin();
51
if ( iter != end() ) {
52
for ( ++iter; iter != end() ; ++iter ) {
53
bounds.unionWith(iter->boundsFast());
77
void Path::swap(Path &other) {
78
std::swap(curves_, other.curves_);
79
std::swap(closed_, other.closed_);
80
std::swap(*final_, *other.final_);
81
curves_[curves_.size()-1] = final_;
82
other.curves_[other.curves_.size()-1] = other.final_;
85
Rect Path::boundsFast() const {
86
Rect bounds=front().boundsFast();
87
for ( const_iterator iter=++begin(); iter != end() ; ++iter ) {
88
bounds.unionWith(iter->boundsFast());
93
Rect Path::boundsExact() const {
94
Rect bounds=front().boundsExact();
95
for ( const_iterator iter=++begin(); iter != end() ; ++iter ) {
96
bounds.unionWith(iter->boundsExact());
59
OptRect Path::boundsExact() const {
61
if (empty()) return bounds;
62
bounds=front().boundsExact();
63
const_iterator iter = begin();
64
if ( iter != end() ) {
65
for ( ++iter; iter != end() ; ++iter ) {
66
bounds.unionWith(iter->boundsExact());
109
//This assumes that you can't be perfect in your t-vals, and as such, tweaks the start
80
Path &Path::operator*=(Matrix const &m) {
82
Sequence::iterator last = get_curves().end() - 1;
83
Sequence::iterator it;
85
for (it = get_curves().begin() ; it != last ; ++it) {
86
*it = boost::shared_ptr<Curve>((*it)->transformed(m));
87
if ( it != get_curves().begin() && (*it)->initialPoint() != prev ) {
88
THROW_CONTINUITYERROR();
90
prev = (*it)->finalPoint();
92
for ( int i = 0 ; i < 2 ; ++i ) {
93
final_->setPoint(i, (*final_)[i] * m);
95
if (get_curves().size() > 1) {
96
if ( front().initialPoint() != initialPoint() || back().finalPoint() != finalPoint() ) {
97
THROW_CONTINUITYERROR();
104
Path::allNearestPoints(Point const& _point, double from, double to) const
106
if ( from > to ) std::swap(from, to);
107
const Path& _path = *this;
108
unsigned int sz = _path.size();
109
if ( _path.closed() ) ++sz;
110
if ( from < 0 || to > sz )
112
THROW_RANGEERROR("[from,to] interval out of bounds");
114
double sif, st = modf(from, &sif);
115
double eif, et = modf(to, &eif);
116
unsigned int si = static_cast<unsigned int>(sif);
117
unsigned int ei = static_cast<unsigned int>(eif);
130
std::vector<double> all_nearest =
131
_path[si].allNearestPoints(_point, st, et);
132
for ( unsigned int i = 0; i < all_nearest.size(); ++i )
134
all_nearest[i] = si + all_nearest[i];
138
std::vector<double> all_t;
139
std::vector< std::vector<double> > all_np;
140
all_np.push_back( _path[si].allNearestPoints(_point, st) );
141
std::vector<unsigned int> ni;
145
= distanceSq( _point, _path[si].pointAt( all_np.front().front() ) );
146
Rect bb(Geom::Point(0,0),Geom::Point(0,0));
147
for ( unsigned int i = si + 1; i < ei; ++i )
149
bb = *(_path[i].boundsFast());
150
dsq = distanceSq(_point, bb);
151
if ( mindistsq < dsq ) continue;
152
all_t = _path[i].allNearestPoints(_point);
153
dsq = distanceSq( _point, _path[i].pointAt( all_t.front() ) );
154
if ( mindistsq > dsq )
157
all_np.push_back(all_t);
162
else if ( mindistsq == dsq )
164
all_np.push_back(all_t);
168
bb = *(_path[ei].boundsFast());
169
dsq = distanceSq(_point, bb);
170
if ( mindistsq >= dsq )
172
all_t = _path[ei].allNearestPoints(_point, 0, et);
173
dsq = distanceSq( _point, _path[ei].pointAt( all_t.front() ) );
174
if ( mindistsq > dsq )
176
for ( unsigned int i = 0; i < all_t.size(); ++i )
178
all_t[i] = ei + all_t[i];
182
else if ( mindistsq == dsq )
184
all_np.push_back(all_t);
188
std::vector<double> all_nearest;
189
for ( unsigned int i = 0; i < all_np.size(); ++i )
191
for ( unsigned int j = 0; j < all_np[i].size(); ++j )
193
all_nearest.push_back( ni[i] + all_np[i][j] );
196
all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()),
202
Path::nearestPointPerCurve(Point const& _point) const
204
//return a single nearest point for each curve in this path
205
std::vector<double> np;
206
const Path& _path = *this;
207
for (Sequence::const_iterator it = _path.get_curves().begin() ; it != _path.get_curves().end()-1 ; ++it)
208
//for (std::vector<Path>::const_iterator it = _path.begin(); it != _path.end(), ++it){
210
np.push_back((*it)->nearestPoint(_point));
215
double Path::nearestPoint(Point const &_point, double from, double to, double *distance_squared) const
217
if ( from > to ) std::swap(from, to);
218
const Path& _path = *this;
219
unsigned int sz = _path.size();
220
if ( _path.closed() ) ++sz;
221
if ( from < 0 || to > sz )
223
THROW_RANGEERROR("[from,to] interval out of bounds");
225
double sif, st = modf(from, &sif);
226
double eif, et = modf(to, &eif);
227
unsigned int si = static_cast<unsigned int>(sif);
228
unsigned int ei = static_cast<unsigned int>(eif);
229
if(sz == 0) {// naked moveto
230
if (distance_squared != NULL)
231
*distance_squared = distanceSq(_point, _path.initialPoint());
246
double nearest = _path[si].nearestPoint(_point, st, et);
247
if (distance_squared != NULL)
248
*distance_squared = distanceSq(_point, _path[si].pointAt(nearest));
253
double nearest = _path[si].nearestPoint(_point, st);
254
unsigned int ni = si;
256
double mindistsq = distanceSq(_point, _path[si].pointAt(nearest));
257
Rect bb(Geom::Point(0,0),Geom::Point(0,0));
258
for ( unsigned int i = si + 1; i < ei; ++i )
260
bb = *(_path[i].boundsFast());
261
dsq = distanceSq(_point, bb);
262
if ( mindistsq <= dsq ) continue;
263
t = _path[i].nearestPoint(_point);
264
dsq = distanceSq(_point, _path[i].pointAt(t));
265
if ( mindistsq > dsq )
272
bb = *(_path[ei].boundsFast());
273
dsq = distanceSq(_point, bb);
274
if ( mindistsq > dsq )
276
t = _path[ei].nearestPoint(_point, 0, et);
277
dsq = distanceSq(_point, _path[ei].pointAt(t));
278
if ( mindistsq > dsq )
286
if (distance_squared != NULL)
287
*distance_squared = mindistsq;
110
292
void Path::appendPortionTo(Path &ret, double from, double to) const {
111
assert(from >= 0 && to >= 0);
293
if (!(from >= 0 && to >= 0)) {
294
THROW_RANGEERROR("from and to must be >=0 in Path::appendPortionTo");
112
296
if(to == 0) to = size()+0.999999;
113
297
if(from == to) { return; }
126
310
Curve *fromv = fromi->portion(ff, 1.);
127
311
//fromv->setInitial(ret.finalPoint());
312
ret.append(*fromv, STITCH_DISCONTINUOUS);
132
316
const_iterator ender = end();
133
317
if(ender->initialPoint() == ender->finalPoint()) ender++;
134
ret.insert(ret.end(), ++fromi, ender);
135
ret.insert(ret.end(), begin(), toi);
318
ret.insert(ret.end(), ++fromi, ender, STITCH_DISCONTINUOUS);
319
ret.insert(ret.end(), begin(), toi, STITCH_DISCONTINUOUS);
137
ret.insert(ret.end(), ++fromi, toi);
321
ret.insert(ret.end(), ++fromi, toi, STITCH_DISCONTINUOUS);
139
323
Curve *tov = toi->portion(0., tf);
324
ret.append(*tov, STITCH_DISCONTINUOUS);
144
const double eps = .1;
146
void Path::append(Curve const &curve) {
147
if ( curves_.front() != final_ && !are_near(curve.initialPoint(), (*final_)[0], eps) ) {
148
throwContinuityError();
150
do_append(curve.duplicate());
153
void Path::append(D2<SBasis> const &curve) {
154
if ( curves_.front() != final_ ) {
155
for ( int i = 0 ; i < 2 ; ++i ) {
156
if ( !are_near(curve[i][0][0], (*final_)[0][i], eps) ) {
157
throwContinuityError();
161
do_append(new SBasisCurve(curve));
164
328
void Path::do_update(Sequence::iterator first_replaced,
165
329
Sequence::iterator last_replaced,
166
330
Sequence::iterator first,
167
Sequence::iterator last)
331
Sequence::iterator last)
169
333
// note: modifies the contents of [first,last)
171
334
check_continuity(first_replaced, last_replaced, first, last);
172
delete_range(first_replaced, last_replaced);
173
335
if ( ( last - first ) == ( last_replaced - first_replaced ) ) {
174
336
std::copy(first, last, first_replaced);
176
338
// this approach depends on std::vector's behavior WRT iterator stability
177
curves_.erase(first_replaced, last_replaced);
178
curves_.insert(first_replaced, first, last);
339
get_curves().erase(first_replaced, last_replaced);
340
get_curves().insert(first_replaced, first, last);
181
if ( curves_.front() != final_ ) {
343
if ( get_curves().front().get() != final_ ) {
182
344
final_->setPoint(0, back().finalPoint());
183
345
final_->setPoint(1, front().initialPoint());
187
void Path::do_append(Curve *curve) {
188
if ( curves_.front() == final_ ) {
349
void Path::do_append(Curve *c) {
350
boost::shared_ptr<Curve> curve(c);
351
if ( get_curves().front().get() == final_ ) {
189
352
final_->setPoint(1, curve->initialPoint());
354
if (curve->initialPoint() != finalPoint()) {
355
THROW_CONTINUITYERROR();
191
curves_.insert(curves_.end()-1, curve);
358
get_curves().insert(get_curves().end()-1, curve);
192
359
final_->setPoint(0, curve->finalPoint());
195
void Path::delete_range(Sequence::iterator first, Sequence::iterator last) {
196
for ( Sequence::iterator iter=first ; iter != last ; ++iter ) {
362
void Path::stitch(Sequence::iterator first_replaced,
363
Sequence::iterator last_replaced,
366
if (!source.empty()) {
367
if ( first_replaced != get_curves().begin() ) {
368
if ( (*first_replaced)->initialPoint() != source.front()->initialPoint() ) {
369
Curve *stitch = new StitchSegment((*first_replaced)->initialPoint(),
370
source.front()->initialPoint());
371
source.insert(source.begin(), boost::shared_ptr<Curve>(stitch));
374
if ( last_replaced != (get_curves().end()-1) ) {
375
if ( (*last_replaced)->finalPoint() != source.back()->finalPoint() ) {
376
Curve *stitch = new StitchSegment(source.back()->finalPoint(),
377
(*last_replaced)->finalPoint());
378
source.insert(source.end(), boost::shared_ptr<Curve>(stitch));
381
} else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) {
382
if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) {
383
Curve *stitch = new StitchSegment((*(last_replaced-1))->finalPoint(),
384
(*first_replaced)->initialPoint());
385
source.insert(source.begin(), boost::shared_ptr<Curve>(stitch));
204
393
Sequence::iterator last)
206
395
if ( first != last ) {
207
if ( first_replaced != curves_.begin() ) {
208
if ( !are_near( (*first_replaced)->initialPoint(), (*first)->initialPoint(), eps ) ) {
209
throwContinuityError();
212
if ( last_replaced != (curves_.end()-1) ) {
213
if ( !are_near( (*(last_replaced-1))->finalPoint(), (*(last-1))->finalPoint(), eps ) ) {
214
throwContinuityError();
217
} else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()-1) {
218
if ( !are_near((*first_replaced)->initialPoint(), (*(last_replaced-1))->finalPoint(), eps ) ) {
219
throwContinuityError();
396
if ( first_replaced != get_curves().begin() ) {
397
if ( (*first_replaced)->initialPoint() != (*first)->initialPoint() ) {
398
THROW_CONTINUITYERROR();
401
if ( last_replaced != (get_curves().end()-1) ) {
402
if ( (*(last_replaced-1))->finalPoint() != (*(last-1))->finalPoint() ) {
403
THROW_CONTINUITYERROR();
406
} else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) {
407
if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) {
408
THROW_CONTINUITYERROR();
224
Rect SVGEllipticalArc::boundsFast() const {
225
throwNotImplemented();
227
Rect SVGEllipticalArc::boundsExact() const {
228
throwNotImplemented();
230
Rect SVGEllipticalArc::boundsLocal(Interval i, unsigned deg) const {
231
throwNotImplemented();
234
std::vector<Point> SVGEllipticalArc::pointAndDerivatives(Coord t, unsigned n) const {
235
throwNotImplemented();
238
std::vector<double> SVGEllipticalArc::roots(double v, Dim2 d) const {
239
throwNotImplemented();
242
D2<SBasis> SVGEllipticalArc::toSBasis() const {
243
return D2<SBasis>(Linear(initial_[X], final_[X]), Linear(initial_[Y], final_[Y]));
413
} // end namespace Geom
251
418
c-file-style:"stroustrup"
252
c-file-offsets:((innamespace . 0)(substatement-open . 0))
419
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
253
420
indent-tabs-mode:nil
257
vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 :
424
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :