Code

Merge from fe-moved
[inkscape.git] / src / 2geom / hvlinesegment.h
1 /**
2  * \file
3  * \brief  Horizontal and Vertical Line Segment
4  *
5  * Copyright 2008  Marco Cecchetti <mrcekets at gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  */
32 #ifndef _2GEOM_HVLINESEGMENT_H_
33 #define _2GEOM_HVLINESEGMENT_H_
36 #include <2geom/bezier-curve.h>
39 namespace Geom
40 {
42 class HLineSegment : public Curve
43 {
44   public:
45     HLineSegment()
46     {}
48     HLineSegment(Coord _x0, Coord _x1, Coord _y)
49         : m_line_seg(Point(_x0, _y), Point(_x1, _y))
50     {
51     }
53     HLineSegment(Point const& _p, double _length)
54         : m_line_seg(_p, Point(_p[X] + _length, _p[Y]))
55     {
56     }
58     HLineSegment(Point const& _p0, Point const& _p1)
59         : m_line_seg(_p0, _p1)
60     {
61         if ( _p0[Y] != _p1[Y] )
62         {
63             THROW_RANGEERROR("HLineSegment::HLineSegment passed points should "
64                              "have the same Y value");
65         }
66     }
68     Curve* duplicate() const
69     {
70         return new HLineSegment(*this);
71     }
73     bool isDegenerate() const
74     {
75         return m_line_seg.isDegenerate();
76     }
78     Point initialPoint() const
79     {
80         return m_line_seg.initialPoint();
81     }
83     Point finalPoint() const
84     {
85         return m_line_seg.finalPoint();
86     }
88     Coord getY()
89     {
90         return initialPoint()[Y];
91     }
93     void setInitial(Point _p)
94     {
95         m_line_seg.setInitial( Point(_p[X], initialPoint()[Y]) );
96     }
98     void setFinal(Point _p)
99     {
100         m_line_seg.setFinal( Point(_p[X], finalPoint()[Y]) );
101     }
103     void setX0(Coord _x)
104     {
105         m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
106     }
108     void setX1(Coord _x)
109     {
110         m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
111     }
113     void setY(Coord _y)
114     {
115         m_line_seg.setInitial( Point(initialPoint()[X], _y) );
116         m_line_seg.setFinal( Point(finalPoint()[X], _y) );
117     }
119     virtual OptRect boundsFast() const
120     {
121         return boundsExact();
122     }
124     virtual OptRect boundsExact() const
125     {
126         return Rect( initialPoint(), finalPoint() );
127     }
129     virtual OptRect boundsLocal(OptInterval i, unsigned deg) const
130     {
131         return m_line_seg.boundsLocal(i, deg);
132     }
134     int winding(Point p) const
135     {
136         return m_line_seg.winding(p);
137     }
139     std::vector<double>
140     roots(double v, Dim2 d) const
141     {
142         if (d < 0 || d > 1)
143         {
144             THROW_RANGEERROR("dimension argument out of range");
145         }
146         std::vector<double> result;
147         if (d == X)
148         {
149             if ( v >= initialPoint()[X] && v <= finalPoint()[X] )
150             {
151                 double t = 0;
152                 if (!isDegenerate())
153                     t = (v - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
154                 result.push_back(t);
155             }
156         }
157         else
158         {
159             if (v == initialPoint()[Y])
160             {
161                 if (!isDegenerate())
162                     THROW_INFINITESOLUTIONS(0);
163                 result.push_back(0);
164             }
165         }
166         return result;
167     }
169     double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
170     {
171         if ( from > to ) std::swap(from, to);
172         double xfrom = pointAt(from)[X];
173         double xto = pointAt(to)[X];
174         if ( xfrom > xto )
175         {
176             std::swap(xfrom, xto);
177             std::swap(from, to);
178         }
179         if ( p[X] > xfrom && p[X] < xto )
180         {
181             return (p[X] - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
182         }
183         else if ( p[X] <= xfrom )
184             return from;
185         else
186             return to;
187     }
189     std::pair<HLineSegment, HLineSegment> subdivide(Coord t) const
190     {
191         std::pair<HLineSegment, HLineSegment> result;
192         Point p = pointAt(t);
193         result.first.setInitial(initialPoint());
194         result.first.setFinal(p);
195         result.second.setInitial(p);
196         result.second.setFinal(finalPoint());
197         return result;
198     }
200     Curve* portion(double f, double t) const
201     {
202         Point ip = pointAt(f);
203         Point ep = pointAt(t);
204         return new HLineSegment(ip[X], ep[X], ip[Y]);
205     }
207     Curve* reverse() const
208     {
209         return
210         new HLineSegment(finalPoint()[X], initialPoint()[X], initialPoint()[Y]);
211     }
213     Curve* transformed(Matrix const & m) const
214     {
215         Point ip = initialPoint() * m;
216         Point ep = finalPoint() * m;
217         if (m.onlyScaleAndTranslation()) {
218             return new HLineSegment(ip[X], ep[X], ip[Y]);
219         } else {
220             return new LineSegment(ip, ep);
221         }
222     }
224     Curve* derivative() const
225     {
226         double x = finalPoint()[X] - initialPoint()[X];
227         return new HLineSegment(x, x, 0);
228     }
230     Point pointAt(double t) const
231     {
232         if ( t < 0 || t > 1 )
233             THROW_RANGEERROR("domain parameter out of range");
234         double x = initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
235         return Point(x, initialPoint()[Y]);
236     }
238     double valueAt(double t, Dim2 d) const
239     {
240         if (d < 0 || d > 1)
241         {
242             THROW_RANGEERROR("dimension argument out of range");
243         }
244         if ( t < 0 || t > 1 )
245             THROW_RANGEERROR("domain parameter out of range");
247         if (d == Y) return initialPoint()[Y];
249         return initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
250     }
252     std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
253     {
254         std::vector<Point> result;
255         result.push_back(pointAt(t));
256         if (n > 0)
257         {
258             double x = finalPoint()[X] - initialPoint()[X];
259             result.push_back( Point(x, 0) );
260         }
261         if (n > 1)
262         {
263             /* higher order derivatives are zero,
264              * so the other n-1 vector elements are (0,0) */
265             result.insert( result.end(), n-1, Point(0, 0) );
266         }
267         return result;
268     }
270     D2<SBasis> toSBasis() const
271     {
272         return m_line_seg.toSBasis();
273     }
275   private:
276     LineSegment m_line_seg;
278 };  // end class HLineSegment
281 class VLineSegment : public Curve
283   public:
284     VLineSegment()
285     {}
287     VLineSegment(Coord _x, Coord _y0, Coord _y1)
288         : m_line_seg(Point(_x, _y0), Point(_x, _y1))
289     {
290     }
292     VLineSegment(Point const& _p, double _length)
293         : m_line_seg(_p, Point(_p[X], _p[Y] + _length))
294     {
295     }
297     VLineSegment(Point const& _p0, Point const& _p1)
298         : m_line_seg(_p0, _p1)
299     {
300         if ( _p0[X] != _p1[X] )
301         {
302             THROW_RANGEERROR("VLineSegment::VLineSegment passed points should "
303                              "have the same X value");
304         }
305     }
307     Curve* duplicate() const
308     {
309         return new VLineSegment(*this);
310     }
312     bool isDegenerate() const
313     {
314         return m_line_seg.isDegenerate();
315     }
317     Point initialPoint() const
318     {
319         return m_line_seg.initialPoint();
320     }
322     Point finalPoint() const
323     {
324         return m_line_seg.finalPoint();
325     }
327     Coord getX()
328     {
329         return initialPoint()[X];
330     }
332     void setInitial(Point _p)
333     {
334         m_line_seg.setInitial( Point(initialPoint()[X], _p[Y]) );
335     }
337     void setFinal(Point _p)
338     {
339         m_line_seg.setFinal( Point(finalPoint()[X], _p[Y]) );
340     }
342     void setY0(Coord _y)
343     {
344         m_line_seg.setInitial( Point(initialPoint()[X], _y) );
345     }
347     void setY1(Coord _y)
348     {
349         m_line_seg.setFinal( Point(finalPoint()[Y], _y) );
350     }
352     void setX(Coord _x)
353     {
354         m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
355         m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
356     }
358     virtual OptRect boundsFast() const
359     {
360         return boundsExact();
361     }
363     virtual OptRect boundsExact() const
364     {
365         return Rect( initialPoint(), finalPoint() );
366     }
368     virtual OptRect boundsLocal(OptInterval i, unsigned deg) const
369     {
370         return m_line_seg.boundsLocal(i, deg);
371     }
373     int winding(Point p) const
374     {
375         return m_line_seg.winding(p);
376     }
378     std::vector<double>
379     roots(double v, Dim2 d) const
380     {
381         if (d < 0 || d > 1)
382         {
383             THROW_RANGEERROR("dimension argument out of range");
384         }
385         std::vector<double> result;
386         if (d == Y)
387         {
388             if ( v >= initialPoint()[Y] && v <= finalPoint()[Y] )
389             {
390                 double t = 0;
391                 if (!isDegenerate())
392                     t = (v - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
393                 result.push_back(t);
394             }
395         }
396         else
397         {
398             if (v == initialPoint()[X])
399             {
400                 if (!isDegenerate())
401                     THROW_INFINITESOLUTIONS(0);
402                 result.push_back(0);
403             }
404         }
405         return result;
406     }
408     double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
409     {
410         if ( from > to ) std::swap(from, to);
411         double yfrom = pointAt(from)[Y];
412         double yto = pointAt(to)[Y];
413         if (yfrom > yto)
414         {
415             std::swap(yfrom, yto);
416             std::swap(from, to);
417         }
418         if ( p[Y] > yfrom && p[Y] < yto )
419         {
420             return (p[Y] - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
421         }
422         else if ( p[Y] <= yfrom )
423             return from;
424         else
425             return to;
426     }
428     std::pair<VLineSegment, VLineSegment> subdivide(Coord t) const
429     {
430         std::pair<VLineSegment, VLineSegment> result;
431         Point p = pointAt(t);
432         result.first.setInitial(initialPoint());
433         result.first.setFinal(p);
434         result.second.setInitial(p);
435         result.second.setFinal(finalPoint());
436         return result;
437     }
439     Curve* portion(double f, double t) const
440     {
441         Point ip = pointAt(f);
442         Point ep = pointAt(t);
443         return new VLineSegment(ip[X], ip[Y], ep[Y]);
444     }
446     Curve* reverse() const
447     {
448         return
449         new VLineSegment(initialPoint()[X], finalPoint()[Y], initialPoint()[Y]);
450     }
452     Curve* transformed(Matrix const & m) const
453     {
454         Point ip = initialPoint() * m;
455         Point ep = finalPoint() * m;
456         if (m.onlyScaleAndTranslation()) {
457             return new VLineSegment(ip[X], ip[Y], ep[Y]);
458         } else {
459             return new LineSegment(ip, ep);
460         }
461     }
463     Curve* derivative() const
464     {
465         double y = finalPoint()[Y] - initialPoint()[Y];
466         return new VLineSegment(0, y, y);
467     }
469     Point pointAt(double t) const
470     {
471         if ( t < 0 || t > 1 )
472             THROW_RANGEERROR("domain parameter out of range");
473         double y = initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
474         return Point(initialPoint()[X], y);
475     }
477     double valueAt(double t, Dim2 d) const
478     {
479         if (d < 0 || d > 1)
480         {
481             THROW_RANGEERROR("dimension argument out of range");
482         }
483         if ( t < 0 || t > 1 )
484             THROW_RANGEERROR("domain parameter out of range");
486         if (d == X) return initialPoint()[X];
488         return initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
489     }
491     std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
492     {
493         std::vector<Point> result;
494         result.push_back(pointAt(t));
495         if (n > 0)
496         {
497             double y = finalPoint()[Y] - initialPoint()[Y];
498             result.push_back( Point(0, y) );
499         }
500         if (n > 1)
501         {
502             /* higher order derivatives are zero,
503              * so the other n-1 vector elements are (0,0) */
504             result.insert( result.end(), n-1, Point(0, 0) );
505         }
506         return result;
507     }
509     D2<SBasis> toSBasis() const
510     {
511         return m_line_seg.toSBasis();
512     }
514   private:
515     LineSegment m_line_seg;
517 }; // end class VLineSegment
521 }  // end namespace Geom
524 #endif // _2GEOM_HVLINESEGMENT_H_
527 /*
528   Local Variables:
529   mode:c++
530   c-file-style:"stroustrup"
531   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
532   indent-tabs-mode:nil
533   fill-column:99
534   End:
535 */
536 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :