Code

update 2geom
[inkscape.git] / src / 2geom / hvlinesegment.h
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         {}
46         
47         HLineSegment(Coord _x0, Coord _x1, Coord _y)
48                 : m_line_seg(Point(_x0, _y), Point(_x1, _y))
49         {
50         }
51         
52         HLineSegment(Point const& _p, double _length)
53                 : m_line_seg(_p, Point(_p[X] + _length, _p[Y]))
54         {
55         }
56         
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         }
66         
67         Curve* duplicate() const
68         {
69                 return new HLineSegment(*this);
70         }
71         
72         bool isDegenerate() const
73         {
74                 return m_line_seg.isDegenerate();
75         }
76         
77         Point initialPoint() const
78         {
79                 return m_line_seg.initialPoint();
80         }
81         
82         Point finalPoint() const 
83         {
84                 return m_line_seg.finalPoint();
85         }
86         
87         Coord getY()
88         {
89                 return initialPoint()[Y];
90         }
91         
92         void setInitial(Point _p) 
93         { 
94                 m_line_seg.setInitial( Point(_p[X], initialPoint()[Y]) ); 
95         }
96         
97         void setFinal(Point _p) 
98         { 
99                 m_line_seg.setFinal( Point(_p[X], finalPoint()[Y]) ); 
100         }
101         
102         void setX0(Coord _x)
103         {
104                 m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
105         }
106         
107         void setX1(Coord _x)
108         {
109                 m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
110         }
111         
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         }
122         
123         Rect boundsExact() const
124         {
125                 return Rect( initialPoint(), finalPoint() );
126         }
127         
128         Rect boundsLocal(Interval i, unsigned deg) const
129         {
130                 return m_line_seg.boundsLocal(i, deg);
131         }
132         
133         int winding(Point p) const
134         {
135                 return m_line_seg.winding(p);
136         }
137         
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         }
167         
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         }
187         
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         }
198         
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         }
205         
206         Curve* reverse() const
207         {
208                 return 
209                 new HLineSegment(finalPoint()[X], initialPoint()[X], initialPoint()[Y]);
210         }
211         
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         }
218         
219         Curve* derivative() const
220         {
221                 double x = finalPoint()[X] - initialPoint()[X];
222                 return new HLineSegment(x, x, 0);
223         }
224         
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         }
232         
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");
241                 
242                 if (d == Y) return initialPoint()[Y];
243                 
244                 return initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
245         }
246         
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         }
259         
260         D2<SBasis> toSBasis() const
261         {
262                 return m_line_seg.toSBasis();
263         }
264         
265   private:
266         LineSegment m_line_seg;
267         
268 };  // end class HLineSegment
271 class VLineSegment : public Curve
273   public:
274         VLineSegment()
275         {}
276         
277         VLineSegment(Coord _x, Coord _y0, Coord _y1)
278                 : m_line_seg(Point(_x, _y0), Point(_x, _y1))
279         {
280         }
281         
282         VLineSegment(Point const& _p, double _length)
283                 : m_line_seg(_p, Point(_p[X], _p[Y] + _length))
284         {
285         }
286         
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         }
296         
297         Curve* duplicate() const
298         {
299                 return new VLineSegment(*this);
300         }
301         
302         bool isDegenerate() const
303         {
304                 return m_line_seg.isDegenerate();
305         }
306         
307         Point initialPoint() const
308         {
309                 return m_line_seg.initialPoint();
310         }
311         
312         Point finalPoint() const 
313         {
314                 return m_line_seg.finalPoint();
315         }
316         
317         Coord getX()
318         {
319                 return initialPoint()[X];
320         }
321         
322         void setInitial(Point _p) 
323         { 
324                 m_line_seg.setInitial( Point(initialPoint()[X], _p[Y]) ); 
325         }
326         
327         void setFinal(Point _p) 
328         { 
329                 m_line_seg.setFinal( Point(finalPoint()[X], _p[Y]) ); 
330         }
331         
332         void setY0(Coord _y)
333         {
334                 m_line_seg.setInitial( Point(initialPoint()[X], _y) );
335         }
336         
337         void setY1(Coord _y)
338         {
339                 m_line_seg.setFinal( Point(finalPoint()[Y], _y) );
340         }
341         
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         }
352         
353         Rect boundsExact() const
354         {
355                 return Rect( initialPoint(), finalPoint() );
356         }
357         
358         Rect boundsLocal(Interval i, unsigned deg) const
359         {
360                 return m_line_seg.boundsLocal(i, deg);
361         }
362         
363         int winding(Point p) const
364         {
365                 return m_line_seg.winding(p);
366         }
367         
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         }
397         
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         }
417         
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         }
428         
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         }
435         
436         Curve* reverse() const
437         {
438                 return 
439                 new VLineSegment(initialPoint()[X], finalPoint()[Y], initialPoint()[Y]);
440         }
441         
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         }
448         
449         Curve* derivative() const
450         {
451                 double y = finalPoint()[Y] - initialPoint()[Y];
452                 return new VLineSegment(0, y, y);
453         }
454         
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         }
462         
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");
471                 
472                 if (d == X) return initialPoint()[X];
473                 
474                 return initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
475         }
476         
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         }
489         
490         D2<SBasis> toSBasis() const
491         {
492                 return m_line_seg.toSBasis();
493         }
494         
495   private:
496         LineSegment m_line_seg;
497         
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 :