xref: /haiku/headers/libs/agg/agg_conv_curve.h (revision 97dfeb96704e5dbc5bec32ad7b21379d0125e031)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // classes conv_curve
17 //
18 //----------------------------------------------------------------------------
19 
20 #ifndef AGG_CONV_CURVE_INCLUDED
21 #define AGG_CONV_CURVE_INCLUDED
22 
23 #include "agg_basics.h"
24 #include "agg_curves.h"
25 
26 #include <cmath>
27 
28 
29 namespace agg
30 {
31 
32 
33     //---------------------------------------------------------------conv_curve
34     // Curve converter class. Any path storage can have Bezier curves defined
35     // by their control points. There're two types of curves supported: curve3
36     // and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control
37     // point. Curve4 has 2 control points (4 points in total) and can be used
38     // to interpolate more complicated curves. Curve4, unlike curve3 can be used
39     // to approximate arcs, both circular and elliptical. Curves are approximated
40     // with straight lines and one of the approaches is just to store the whole
41     // sequence of vertices that approximate our curve. It takes additional
42     // memory, and at the same time the consecutive vertices can be calculated
43     // on demand.
44     //
45     // Initially, path storages are not suppose to keep all the vertices of the
46     // curves (although, nothing prevents us from doing so). Instead, path_storage
47     // keeps only vertices, needed to calculate a curve on demand. Those vertices
48     // are marked with special commands. So, if the path_storage contains curves
49     // (which are not real curves yet), and we render this storage directly,
50     // all we will see is only 2 or 3 straight line segments (for curve3 and
51     // curve4 respectively). If we need to see real curves drawn we need to
52     // include this class into the conversion pipeline.
53     //
54     // Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4
55     // and converts these vertices into a move_to/line_to sequence.
56     //-----------------------------------------------------------------------
57     template<class VertexSource,
58              class Curve3=curve3,
59              class Curve4=curve4> class conv_curve
60     {
61     public:
62         typedef Curve3 curve3_type;
63         typedef Curve4 curve4_type;
64         typedef conv_curve<VertexSource, Curve3, Curve4> self_type;
65 
66         conv_curve(VertexSource& source) :
67           m_source(&source), m_last_x(0.0), m_last_y(0.0) {}
68         void attach(VertexSource& source) { m_source = &source; }
69 
70         void approximation_method(curve_approximation_method_e v)
71         {
72             m_curve3.approximation_method(v);
73             m_curve4.approximation_method(v);
74         }
75 
76         curve_approximation_method_e approximation_method() const
77         {
78             return m_curve4.approximation_method();
79         }
80 
81         void approximation_scale(double s)
82         {
83             m_curve3.approximation_scale(s);
84             m_curve4.approximation_scale(s);
85         }
86 
87         double approximation_scale() const
88         {
89             return m_curve4.approximation_scale();
90         }
91 
92         void angle_tolerance(double v)
93         {
94             m_curve3.angle_tolerance(v);
95             m_curve4.angle_tolerance(v);
96         }
97 
98         double angle_tolerance() const
99         {
100             return m_curve4.angle_tolerance();
101         }
102 
103         void cusp_limit(double v)
104         {
105             m_curve3.cusp_limit(v);
106             m_curve4.cusp_limit(v);
107         }
108 
109         double cusp_limit() const
110         {
111             return m_curve4.cusp_limit();
112         }
113 
114         void     rewind(unsigned path_id);
115         unsigned vertex(double* x, double* y);
116 
117     private:
118         conv_curve(const self_type&);
119         const self_type& operator = (const self_type&);
120 
121         VertexSource* m_source;
122         double        m_last_x;
123         double        m_last_y;
124         curve3_type   m_curve3;
125         curve4_type   m_curve4;
126     };
127 
128 
129 
130     //------------------------------------------------------------------------
131     template<class VertexSource, class Curve3, class Curve4>
132     void conv_curve<VertexSource, Curve3, Curve4>::rewind(unsigned path_id)
133     {
134         m_source->rewind(path_id);
135         m_last_x = 0.0;
136         m_last_y = 0.0;
137         m_curve3.reset();
138         m_curve4.reset();
139     }
140 
141 
142     //------------------------------------------------------------------------
143     template<class VertexSource, class Curve3, class Curve4>
144     unsigned conv_curve<VertexSource, Curve3, Curve4>::vertex(double* x, double* y)
145     {
146         if(!is_stop(m_curve3.vertex(x, y)))
147         {
148             m_last_x = *x;
149             m_last_y = *y;
150             return path_cmd_line_to;
151         }
152 
153         if(!is_stop(m_curve4.vertex(x, y)))
154         {
155             m_last_x = *x;
156             m_last_y = *y;
157             return path_cmd_line_to;
158         }
159 
160         double ct2_x = 0;
161         double ct2_y = 0;
162         double end_x = 0;
163         double end_y = 0;
164 
165         unsigned cmd = m_source->vertex(x, y);
166         switch(cmd)
167         {
168         case path_cmd_curve3:
169             m_source->vertex(&end_x, &end_y);
170 
171 			if (!std::isnan(m_last_x) && !std::isnan(m_last_y) && !std::isnan(*x)
172 				&& !std::isnan(*y) && !std::isnan(end_x) && !std::isnan(end_y)) {
173 				m_curve3.init(m_last_x, m_last_y,
174 						*x,       *y,
175 						end_x,     end_y);
176 
177 				m_curve3.vertex(x, y);    // First call returns path_cmd_move_to
178 				m_curve3.vertex(x, y);    // This is the first vertex of the curve
179 			}
180             cmd = path_cmd_line_to;
181             break;
182 
183         case path_cmd_curve4:
184             m_source->vertex(&ct2_x, &ct2_y);
185             m_source->vertex(&end_x, &end_y);
186 
187 			if (!std::isnan(m_last_x) && !std::isnan(m_last_y) && !std::isnan(*x)
188 				&& !std::isnan(*y) && !std::isnan(end_x) && !std::isnan(end_y)) {
189 				m_curve4.init(m_last_x, m_last_y,
190 						*x,       *y,
191 						ct2_x,    ct2_y,
192 						end_x,    end_y);
193 
194 				m_curve4.vertex(x, y);    // First call returns path_cmd_move_to
195 				m_curve4.vertex(x, y);    // This is the first vertex of the curve
196 			}
197             cmd = path_cmd_line_to;
198             break;
199         }
200         m_last_x = *x;
201         m_last_y = *y;
202         return cmd;
203     }
204 
205 
206 }
207 
208 
209 
210 #endif
211