1 /*
2 * Horizontal and Vertical Line Segment
3 *
4 * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com>
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 */
31 #ifndef _2GEOM_HVLINESEGMENT_H_
32 #define _2GEOM_HVLINESEGMENT_H_
35 #include "bezier-curve.h"
38 namespace Geom
39 {
41 class HLineSegment : public Curve
42 {
43 public:
44 HLineSegment()
45 {}
47 HLineSegment(Coord _x0, Coord _x1, Coord _y)
48 : m_line_seg(Point(_x0, _y), Point(_x1, _y))
49 {
50 }
52 HLineSegment(Point const& _p, double _length)
53 : m_line_seg(_p, Point(_p[X] + _length, _p[Y]))
54 {
55 }
57 HLineSegment(Point const& _p0, Point const& _p1)
58 : m_line_seg(_p0, _p1)
59 {
60 if ( _p0[Y] != _p1[Y] )
61 {
62 THROW_RANGEERROR("HLineSegment::HLineSegment passed points should "
63 "have the same Y value");
64 }
65 }
67 Curve* duplicate() const
68 {
69 return new HLineSegment(*this);
70 }
72 bool isDegenerate() const
73 {
74 return m_line_seg.isDegenerate();
75 }
77 Point initialPoint() const
78 {
79 return m_line_seg.initialPoint();
80 }
82 Point finalPoint() const
83 {
84 return m_line_seg.finalPoint();
85 }
87 Coord getY()
88 {
89 return initialPoint()[Y];
90 }
92 void setInitial(Point _p)
93 {
94 m_line_seg.setInitial( Point(_p[X], initialPoint()[Y]) );
95 }
97 void setFinal(Point _p)
98 {
99 m_line_seg.setFinal( Point(_p[X], finalPoint()[Y]) );
100 }
102 void setX0(Coord _x)
103 {
104 m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
105 }
107 void setX1(Coord _x)
108 {
109 m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
110 }
112 void setY(Coord _y)
113 {
114 m_line_seg.setInitial( Point(initialPoint()[X], _y) );
115 m_line_seg.setFinal( Point(finalPoint()[X], _y) );
116 }
118 Rect boundsFast() const
119 {
120 return boundsExact();
121 }
123 Rect boundsExact() const
124 {
125 return Rect( initialPoint(), finalPoint() );
126 }
128 Rect boundsLocal(Interval i, unsigned deg) const
129 {
130 return m_line_seg.boundsLocal(i, deg);
131 }
133 int winding(Point p) const
134 {
135 return m_line_seg.winding(p);
136 }
138 std::vector<double>
139 roots(double v, Dim2 d) const
140 {
141 if (d < 0 || d > 1)
142 {
143 THROW_RANGEERROR("dimension argument out of range");
144 }
145 std::vector<double> result;
146 if (d == X)
147 {
148 if ( v >= initialPoint()[X] && v <= finalPoint()[X] )
149 {
150 double t = 0;
151 if (!isDegenerate())
152 t = (v - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
153 result.push_back(t);
154 }
155 }
156 else
157 {
158 if (v == initialPoint()[Y])
159 {
160 if (!isDegenerate())
161 THROW_INFINITESOLUTIONS(0);
162 result.push_back(0);
163 }
164 }
165 return result;
166 }
168 double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
169 {
170 if ( from > to ) std::swap(from, to);
171 double xfrom = pointAt(from)[X];
172 double xto = pointAt(to)[X];
173 if ( xfrom > xto )
174 {
175 std::swap(xfrom, xto);
176 std::swap(from, to);
177 }
178 if ( p[X] > xfrom && p[X] < xto )
179 {
180 return (p[X] - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
181 }
182 else if ( p[X] <= xfrom )
183 return from;
184 else
185 return to;
186 }
188 std::pair<HLineSegment, HLineSegment> subdivide(Coord t) const
189 {
190 std::pair<HLineSegment, HLineSegment> result;
191 Point p = pointAt(t);
192 result.first.setInitial(initialPoint());
193 result.first.setFinal(p);
194 result.second.setInitial(p);
195 result.second.setFinal(finalPoint());
196 return result;
197 }
199 Curve* portion(double f, double t) const
200 {
201 Point ip = pointAt(f);
202 Point ep = pointAt(t);
203 return new HLineSegment(ip[X], ep[X], ip[Y]);
204 }
206 Curve* reverse() const
207 {
208 return
209 new HLineSegment(finalPoint()[X], initialPoint()[X], initialPoint()[Y]);
210 }
212 Curve* transformed(Matrix const & m) const
213 {
214 Point ip = initialPoint() * m;
215 Point ep = finalPoint() * m;
216 return new LineSegment(ip, ep);
217 }
219 Curve* derivative() const
220 {
221 double x = finalPoint()[X] - initialPoint()[X];
222 return new HLineSegment(x, x, 0);
223 }
225 Point pointAt(double t) const
226 {
227 if ( t < 0 || t > 1 )
228 THROW_RANGEERROR("domain parameter out of range");
229 double x = initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
230 return Point(x, initialPoint()[Y]);
231 }
233 double valueAt(double t, Dim2 d) const
234 {
235 if (d < 0 || d > 1)
236 {
237 THROW_RANGEERROR("dimension argument out of range");
238 }
239 if ( t < 0 || t > 1 )
240 THROW_RANGEERROR("domain parameter out of range");
242 if (d == Y) return initialPoint()[Y];
244 return initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
245 }
247 std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
248 {
249 std::vector<Point> result;
250 if ( n > 0)
251 result.push_back(pointAt(t));
252 if (n > 1)
253 {
254 double x = finalPoint()[X] - initialPoint()[X];
255 result.push_back( Point(x, 0) );
256 }
257 return result;
258 }
260 D2<SBasis> toSBasis() const
261 {
262 return m_line_seg.toSBasis();
263 }
265 private:
266 LineSegment m_line_seg;
268 }; // end class HLineSegment
271 class VLineSegment : public Curve
272 {
273 public:
274 VLineSegment()
275 {}
277 VLineSegment(Coord _x, Coord _y0, Coord _y1)
278 : m_line_seg(Point(_x, _y0), Point(_x, _y1))
279 {
280 }
282 VLineSegment(Point const& _p, double _length)
283 : m_line_seg(_p, Point(_p[X], _p[Y] + _length))
284 {
285 }
287 VLineSegment(Point const& _p0, Point const& _p1)
288 : m_line_seg(_p0, _p1)
289 {
290 if ( _p0[X] != _p1[X] )
291 {
292 THROW_RANGEERROR("VLineSegment::VLineSegment passed points should "
293 "have the same X value");
294 }
295 }
297 Curve* duplicate() const
298 {
299 return new VLineSegment(*this);
300 }
302 bool isDegenerate() const
303 {
304 return m_line_seg.isDegenerate();
305 }
307 Point initialPoint() const
308 {
309 return m_line_seg.initialPoint();
310 }
312 Point finalPoint() const
313 {
314 return m_line_seg.finalPoint();
315 }
317 Coord getX()
318 {
319 return initialPoint()[X];
320 }
322 void setInitial(Point _p)
323 {
324 m_line_seg.setInitial( Point(initialPoint()[X], _p[Y]) );
325 }
327 void setFinal(Point _p)
328 {
329 m_line_seg.setFinal( Point(finalPoint()[X], _p[Y]) );
330 }
332 void setY0(Coord _y)
333 {
334 m_line_seg.setInitial( Point(initialPoint()[X], _y) );
335 }
337 void setY1(Coord _y)
338 {
339 m_line_seg.setFinal( Point(finalPoint()[Y], _y) );
340 }
342 void setX(Coord _x)
343 {
344 m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
345 m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
346 }
348 Rect boundsFast() const
349 {
350 return boundsExact();
351 }
353 Rect boundsExact() const
354 {
355 return Rect( initialPoint(), finalPoint() );
356 }
358 Rect boundsLocal(Interval i, unsigned deg) const
359 {
360 return m_line_seg.boundsLocal(i, deg);
361 }
363 int winding(Point p) const
364 {
365 return m_line_seg.winding(p);
366 }
368 std::vector<double>
369 roots(double v, Dim2 d) const
370 {
371 if (d < 0 || d > 1)
372 {
373 THROW_RANGEERROR("dimension argument out of range");
374 }
375 std::vector<double> result;
376 if (d == Y)
377 {
378 if ( v >= initialPoint()[Y] && v <= finalPoint()[Y] )
379 {
380 double t = 0;
381 if (!isDegenerate())
382 t = (v - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
383 result.push_back(t);
384 }
385 }
386 else
387 {
388 if (v == initialPoint()[X])
389 {
390 if (!isDegenerate())
391 THROW_INFINITESOLUTIONS(0);
392 result.push_back(0);
393 }
394 }
395 return result;
396 }
398 double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
399 {
400 if ( from > to ) std::swap(from, to);
401 double yfrom = pointAt(from)[Y];
402 double yto = pointAt(to)[Y];
403 if (yfrom > yto)
404 {
405 std::swap(yfrom, yto);
406 std::swap(from, to);
407 }
408 if ( p[Y] > yfrom && p[Y] < yto )
409 {
410 return (p[Y] - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
411 }
412 else if ( p[Y] <= yfrom )
413 return from;
414 else
415 return to;
416 }
418 std::pair<VLineSegment, VLineSegment> subdivide(Coord t) const
419 {
420 std::pair<VLineSegment, VLineSegment> result;
421 Point p = pointAt(t);
422 result.first.setInitial(initialPoint());
423 result.first.setFinal(p);
424 result.second.setInitial(p);
425 result.second.setFinal(finalPoint());
426 return result;
427 }
429 Curve* portion(double f, double t) const
430 {
431 Point ip = pointAt(f);
432 Point ep = pointAt(t);
433 return new VLineSegment(ip[X], ip[Y], ep[Y]);
434 }
436 Curve* reverse() const
437 {
438 return
439 new VLineSegment(initialPoint()[X], finalPoint()[Y], initialPoint()[Y]);
440 }
442 Curve* transformed(Matrix const & m) const
443 {
444 Point ip = initialPoint() * m;
445 Point ep = finalPoint() * m;
446 return new LineSegment(ip, ep);
447 }
449 Curve* derivative() const
450 {
451 double y = finalPoint()[Y] - initialPoint()[Y];
452 return new VLineSegment(0, y, y);
453 }
455 Point pointAt(double t) const
456 {
457 if ( t < 0 || t > 1 )
458 THROW_RANGEERROR("domain parameter out of range");
459 double y = initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
460 return Point(initialPoint()[X], y);
461 }
463 double valueAt(double t, Dim2 d) const
464 {
465 if (d < 0 || d > 1)
466 {
467 THROW_RANGEERROR("dimension argument out of range");
468 }
469 if ( t < 0 || t > 1 )
470 THROW_RANGEERROR("domain parameter out of range");
472 if (d == X) return initialPoint()[X];
474 return initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
475 }
477 std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
478 {
479 std::vector<Point> result;
480 if ( n > 0)
481 result.push_back(pointAt(t));
482 if (n > 1)
483 {
484 double y = finalPoint()[Y] - initialPoint()[Y];
485 result.push_back( Point(0, y) );
486 }
487 return result;
488 }
490 D2<SBasis> toSBasis() const
491 {
492 return m_line_seg.toSBasis();
493 }
495 private:
496 LineSegment m_line_seg;
498 }; // end class VLineSegment
502 } // end namespace Geom
505 #endif // _2GEOM_HVLINESEGMENT_H_
508 /*
509 Local Variables:
510 mode:c++
511 c-file-style:"stroustrup"
512 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
513 indent-tabs-mode:nil
514 fill-column:99
515 End:
516 */
517 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :