1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 // Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com)
5 //
6 // Permission to copy, use, modify, sell and distribute this software
7 // is granted provided this copyright notice appears in all copies.
8 // This software is provided "as is" without express or implied
9 // warranty, and with no claim as to its suitability for any purpose.
10 //
11 //----------------------------------------------------------------------------
12 // Contact: mcseem@antigrain.com
13 //          mcseemagg@yahoo.com
14 //          http://www.antigrain.com
15 //----------------------------------------------------------------------------
16 
17 #ifndef AGG_CURVES_INCLUDED
18 #define AGG_CURVES_INCLUDED
19 
20 #include "agg_array.h"
21 
22 namespace agg
23 {
24 
25     // See Implementation agg_curves.cpp
26 
27     //--------------------------------------------curve_approximation_method_e
28     enum curve_approximation_method_e
29     {
30         curve_inc,
31         curve_div
32     };
33 
34     //--------------------------------------------------------------curve3_inc
35     class curve3_inc
36     {
37     public:
curve3_inc()38         curve3_inc() :
39           m_num_steps(0), m_step(0), m_scale(1.0) { }
40 
curve3_inc(double x1,double y1,double x2,double y2,double x3,double y3)41         curve3_inc(double x1, double y1,
42                    double x2, double y2,
43                    double x3, double y3) :
44             m_num_steps(0), m_step(0), m_scale(1.0)
45         {
46             init(x1, y1, x2, y2, x3, y3);
47         }
48 
reset()49         void reset() { m_num_steps = 0; m_step = -1; }
50         void init(double x1, double y1,
51                   double x2, double y2,
52                   double x3, double y3);
53 
approximation_method(curve_approximation_method_e)54         void approximation_method(curve_approximation_method_e) {}
approximation_method()55         curve_approximation_method_e approximation_method() const { return curve_inc; }
56 
57         void approximation_scale(double s);
58         double approximation_scale() const;
59 
angle_tolerance(double)60         void angle_tolerance(double) {}
angle_tolerance()61         double angle_tolerance() const { return 0.0; }
62 
cusp_limit(double)63         void cusp_limit(double) {}
cusp_limit()64         double cusp_limit() const { return 0.0; }
65 
66         void     rewind(unsigned path_id);
67         unsigned vertex(double* x, double* y);
68 
69     private:
70         int      m_num_steps;
71         int      m_step;
72         double   m_scale;
73         double   m_start_x;
74         double   m_start_y;
75         double   m_end_x;
76         double   m_end_y;
77         double   m_fx;
78         double   m_fy;
79         double   m_dfx;
80         double   m_dfy;
81         double   m_ddfx;
82         double   m_ddfy;
83         double   m_saved_fx;
84         double   m_saved_fy;
85         double   m_saved_dfx;
86         double   m_saved_dfy;
87     };
88 
89 
90 
91 
92 
93     //-------------------------------------------------------------curve3_div
94     class curve3_div
95     {
96     public:
curve3_div()97         curve3_div() :
98             m_approximation_scale(1.0),
99             m_angle_tolerance(0.0),
100             m_count(0)
101         {}
102 
curve3_div(double x1,double y1,double x2,double y2,double x3,double y3)103         curve3_div(double x1, double y1,
104                    double x2, double y2,
105                    double x3, double y3) :
106             m_approximation_scale(1.0),
107             m_angle_tolerance(0.0),
108             m_count(0)
109         {
110             init(x1, y1, x2, y2, x3, y3);
111         }
112 
reset()113         void reset() { m_points.remove_all(); m_count = 0; }
114         void init(double x1, double y1,
115                   double x2, double y2,
116                   double x3, double y3);
117 
approximation_method(curve_approximation_method_e)118         void approximation_method(curve_approximation_method_e) {}
approximation_method()119         curve_approximation_method_e approximation_method() const { return curve_div; }
120 
approximation_scale(double s)121         void approximation_scale(double s) { m_approximation_scale = s; }
approximation_scale()122         double approximation_scale() const { return m_approximation_scale;  }
123 
angle_tolerance(double a)124         void angle_tolerance(double a) { m_angle_tolerance = a; }
angle_tolerance()125         double angle_tolerance() const { return m_angle_tolerance;  }
126 
cusp_limit(double)127         void cusp_limit(double) {}
cusp_limit()128         double cusp_limit() const { return 0.0; }
129 
rewind(unsigned)130         void rewind(unsigned)
131         {
132             m_count = 0;
133         }
134 
vertex(double * x,double * y)135         unsigned vertex(double* x, double* y)
136         {
137             if(m_count >= m_points.size()) return path_cmd_stop;
138             const point_d& p = m_points[m_count++];
139             *x = p.x;
140             *y = p.y;
141             return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
142         }
143 
144     private:
145         void bezier(double x1, double y1,
146                     double x2, double y2,
147                     double x3, double y3);
148         void recursive_bezier(double x1, double y1,
149                               double x2, double y2,
150                               double x3, double y3,
151                               unsigned level);
152 
153         double               m_approximation_scale;
154         double               m_distance_tolerance_square;
155         double               m_angle_tolerance;
156         unsigned             m_count;
157         pod_bvector<point_d> m_points;
158     };
159 
160 
161 
162 
163 
164 
165 
166     //-------------------------------------------------------------curve4_points
167     struct curve4_points
168     {
169         double cp[8];
curve4_pointscurve4_points170         curve4_points() {}
curve4_pointscurve4_points171         curve4_points(double x1, double y1,
172                       double x2, double y2,
173                       double x3, double y3,
174                       double x4, double y4)
175         {
176             cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2;
177             cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4;
178         }
initcurve4_points179         void init(double x1, double y1,
180                   double x2, double y2,
181                   double x3, double y3,
182                   double x4, double y4)
183         {
184             cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2;
185             cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4;
186         }
187         double  operator [] (unsigned i) const { return cp[i]; }
188         double& operator [] (unsigned i)       { return cp[i]; }
189     };
190 
191 
192 
193     //-------------------------------------------------------------curve4_inc
194     class curve4_inc
195     {
196     public:
curve4_inc()197         curve4_inc() :
198             m_num_steps(0), m_step(0), m_scale(1.0) { }
199 
curve4_inc(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)200         curve4_inc(double x1, double y1,
201                    double x2, double y2,
202                    double x3, double y3,
203                    double x4, double y4) :
204             m_num_steps(0), m_step(0), m_scale(1.0)
205         {
206             init(x1, y1, x2, y2, x3, y3, x4, y4);
207         }
208 
curve4_inc(const curve4_points & cp)209         curve4_inc(const curve4_points& cp) :
210             m_num_steps(0), m_step(0), m_scale(1.0)
211         {
212             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
213         }
214 
reset()215         void reset() { m_num_steps = 0; m_step = -1; }
216         void init(double x1, double y1,
217                   double x2, double y2,
218                   double x3, double y3,
219                   double x4, double y4);
220 
init(const curve4_points & cp)221         void init(const curve4_points& cp)
222         {
223             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
224         }
225 
approximation_method(curve_approximation_method_e)226         void approximation_method(curve_approximation_method_e) {}
approximation_method()227         curve_approximation_method_e approximation_method() const { return curve_inc; }
228 
229         void approximation_scale(double s);
230         double approximation_scale() const;
231 
angle_tolerance(double)232         void angle_tolerance(double) {}
angle_tolerance()233         double angle_tolerance() const { return 0.0; }
234 
cusp_limit(double)235         void cusp_limit(double) {}
cusp_limit()236         double cusp_limit() const { return 0.0; }
237 
238         void     rewind(unsigned path_id);
239         unsigned vertex(double* x, double* y);
240 
241     private:
242         int      m_num_steps;
243         int      m_step;
244         double   m_scale;
245         double   m_start_x;
246         double   m_start_y;
247         double   m_end_x;
248         double   m_end_y;
249         double   m_fx;
250         double   m_fy;
251         double   m_dfx;
252         double   m_dfy;
253         double   m_ddfx;
254         double   m_ddfy;
255         double   m_dddfx;
256         double   m_dddfy;
257         double   m_saved_fx;
258         double   m_saved_fy;
259         double   m_saved_dfx;
260         double   m_saved_dfy;
261         double   m_saved_ddfx;
262         double   m_saved_ddfy;
263     };
264 
265 
266 
267     //-------------------------------------------------------catrom_to_bezier
catrom_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)268     inline curve4_points catrom_to_bezier(double x1, double y1,
269                                           double x2, double y2,
270                                           double x3, double y3,
271                                           double x4, double y4)
272     {
273         // Trans. matrix Catmull-Rom to Bezier
274         //
275         //  0       1       0       0
276         //  -1/6    1       1/6     0
277         //  0       1/6     1       -1/6
278         //  0       0       1       0
279         //
280         return curve4_points(
281             x2,
282             y2,
283             (-x1 + 6*x2 + x3) / 6,
284             (-y1 + 6*y2 + y3) / 6,
285             ( x2 + 6*x3 - x4) / 6,
286             ( y2 + 6*y3 - y4) / 6,
287             x3,
288             y3);
289     }
290 
291 
292     //-----------------------------------------------------------------------
293     inline curve4_points
catrom_to_bezier(const curve4_points & cp)294     catrom_to_bezier(const curve4_points& cp)
295     {
296         return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3],
297                                 cp[4], cp[5], cp[6], cp[7]);
298     }
299 
300 
301 
302     //-----------------------------------------------------ubspline_to_bezier
ubspline_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)303     inline curve4_points ubspline_to_bezier(double x1, double y1,
304                                             double x2, double y2,
305                                             double x3, double y3,
306                                             double x4, double y4)
307     {
308         // Trans. matrix Uniform BSpline to Bezier
309         //
310         //  1/6     4/6     1/6     0
311         //  0       4/6     2/6     0
312         //  0       2/6     4/6     0
313         //  0       1/6     4/6     1/6
314         //
315         return curve4_points(
316             (x1 + 4*x2 + x3) / 6,
317             (y1 + 4*y2 + y3) / 6,
318             (4*x2 + 2*x3) / 6,
319             (4*y2 + 2*y3) / 6,
320             (2*x2 + 4*x3) / 6,
321             (2*y2 + 4*y3) / 6,
322             (x2 + 4*x3 + x4) / 6,
323             (y2 + 4*y3 + y4) / 6);
324     }
325 
326 
327     //-----------------------------------------------------------------------
328     inline curve4_points
ubspline_to_bezier(const curve4_points & cp)329     ubspline_to_bezier(const curve4_points& cp)
330     {
331         return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3],
332                                   cp[4], cp[5], cp[6], cp[7]);
333     }
334 
335 
336 
337 
338     //------------------------------------------------------hermite_to_bezier
hermite_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)339     inline curve4_points hermite_to_bezier(double x1, double y1,
340                                            double x2, double y2,
341                                            double x3, double y3,
342                                            double x4, double y4)
343     {
344         // Trans. matrix Hermite to Bezier
345         //
346         //  1       0       0       0
347         //  1       0       1/3     0
348         //  0       1       0       -1/3
349         //  0       1       0       0
350         //
351         return curve4_points(
352             x1,
353             y1,
354             (3*x1 + x3) / 3,
355             (3*y1 + y3) / 3,
356             (3*x2 - x4) / 3,
357             (3*y2 - y4) / 3,
358             x2,
359             y2);
360     }
361 
362 
363 
364     //-----------------------------------------------------------------------
365     inline curve4_points
hermite_to_bezier(const curve4_points & cp)366     hermite_to_bezier(const curve4_points& cp)
367     {
368         return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3],
369                                  cp[4], cp[5], cp[6], cp[7]);
370     }
371 
372 
373     //-------------------------------------------------------------curve4_div
374     class curve4_div
375     {
376     public:
curve4_div()377         curve4_div() :
378             m_approximation_scale(1.0),
379             m_angle_tolerance(0.0),
380             m_cusp_limit(0.0),
381             m_count(0)
382         {}
383 
curve4_div(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)384         curve4_div(double x1, double y1,
385                    double x2, double y2,
386                    double x3, double y3,
387                    double x4, double y4) :
388             m_approximation_scale(1.0),
389             m_angle_tolerance(0.0),
390             m_cusp_limit(0.0),
391             m_count(0)
392         {
393             init(x1, y1, x2, y2, x3, y3, x4, y4);
394         }
395 
curve4_div(const curve4_points & cp)396         curve4_div(const curve4_points& cp) :
397             m_approximation_scale(1.0),
398             m_angle_tolerance(0.0),
399             m_count(0)
400         {
401             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
402         }
403 
reset()404         void reset() { m_points.remove_all(); m_count = 0; }
405         void init(double x1, double y1,
406                   double x2, double y2,
407                   double x3, double y3,
408                   double x4, double y4);
409 
init(const curve4_points & cp)410         void init(const curve4_points& cp)
411         {
412             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
413         }
414 
approximation_method(curve_approximation_method_e)415         void approximation_method(curve_approximation_method_e) {}
416 
approximation_method()417         curve_approximation_method_e approximation_method() const
418         {
419             return curve_div;
420         }
421 
approximation_scale(double s)422         void approximation_scale(double s) { m_approximation_scale = s; }
approximation_scale()423         double approximation_scale() const { return m_approximation_scale;  }
424 
angle_tolerance(double a)425         void angle_tolerance(double a) { m_angle_tolerance = a; }
angle_tolerance()426         double angle_tolerance() const { return m_angle_tolerance;  }
427 
cusp_limit(double v)428         void cusp_limit(double v)
429         {
430             m_cusp_limit = (v == 0.0) ? 0.0 : pi - v;
431         }
432 
cusp_limit()433         double cusp_limit() const
434         {
435             return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit;
436         }
437 
rewind(unsigned)438         void rewind(unsigned)
439         {
440             m_count = 0;
441         }
442 
vertex(double * x,double * y)443         unsigned vertex(double* x, double* y)
444         {
445             if(m_count >= m_points.size()) return path_cmd_stop;
446             const point_d& p = m_points[m_count++];
447             *x = p.x;
448             *y = p.y;
449             return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
450         }
451 
452     private:
453         void bezier(double x1, double y1,
454                     double x2, double y2,
455                     double x3, double y3,
456                     double x4, double y4);
457 
458         void recursive_bezier(double x1, double y1,
459                               double x2, double y2,
460                               double x3, double y3,
461                               double x4, double y4,
462                               unsigned level);
463 
464         double               m_approximation_scale;
465         double               m_distance_tolerance_square;
466         double               m_angle_tolerance;
467         double               m_cusp_limit;
468         unsigned             m_count;
469         pod_bvector<point_d> m_points;
470     };
471 
472 
473     //-----------------------------------------------------------------curve3
474     class curve3
475     {
476     public:
curve3()477         curve3() : m_approximation_method(curve_div) {}
curve3(double x1,double y1,double x2,double y2,double x3,double y3)478         curve3(double x1, double y1,
479                double x2, double y2,
480                double x3, double y3) :
481             m_approximation_method(curve_div)
482         {
483             init(x1, y1, x2, y2, x3, y3);
484         }
485 
reset()486         void reset()
487         {
488             m_curve_inc.reset();
489             m_curve_div.reset();
490         }
491 
init(double x1,double y1,double x2,double y2,double x3,double y3)492         void init(double x1, double y1,
493                   double x2, double y2,
494                   double x3, double y3)
495         {
496             if(m_approximation_method == curve_inc)
497             {
498                 m_curve_inc.init(x1, y1, x2, y2, x3, y3);
499             }
500             else
501             {
502                 m_curve_div.init(x1, y1, x2, y2, x3, y3);
503             }
504         }
505 
approximation_method(curve_approximation_method_e v)506         void approximation_method(curve_approximation_method_e v)
507         {
508             m_approximation_method = v;
509         }
510 
approximation_method()511         curve_approximation_method_e approximation_method() const
512         {
513             return m_approximation_method;
514         }
515 
approximation_scale(double s)516         void approximation_scale(double s)
517         {
518             m_curve_inc.approximation_scale(s);
519             m_curve_div.approximation_scale(s);
520         }
521 
approximation_scale()522         double approximation_scale() const
523         {
524             return m_curve_inc.approximation_scale();
525         }
526 
angle_tolerance(double a)527         void angle_tolerance(double a)
528         {
529             m_curve_div.angle_tolerance(a);
530         }
531 
angle_tolerance()532         double angle_tolerance() const
533         {
534             return m_curve_div.angle_tolerance();
535         }
536 
cusp_limit(double v)537         void cusp_limit(double v)
538         {
539             m_curve_div.cusp_limit(v);
540         }
541 
cusp_limit()542         double cusp_limit() const
543         {
544             return m_curve_div.cusp_limit();
545         }
546 
rewind(unsigned path_id)547         void rewind(unsigned path_id)
548         {
549             if(m_approximation_method == curve_inc)
550             {
551                 m_curve_inc.rewind(path_id);
552             }
553             else
554             {
555                 m_curve_div.rewind(path_id);
556             }
557         }
558 
vertex(double * x,double * y)559         unsigned vertex(double* x, double* y)
560         {
561             if(m_approximation_method == curve_inc)
562             {
563                 return m_curve_inc.vertex(x, y);
564             }
565             return m_curve_div.vertex(x, y);
566         }
567 
568     private:
569         curve3_inc m_curve_inc;
570         curve3_div m_curve_div;
571         curve_approximation_method_e m_approximation_method;
572     };
573 
574 
575 
576 
577 
578     //-----------------------------------------------------------------curve4
579     class curve4
580     {
581     public:
curve4()582         curve4() : m_approximation_method(curve_div) {}
curve4(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)583         curve4(double x1, double y1,
584                double x2, double y2,
585                double x3, double y3,
586                double x4, double y4) :
587             m_approximation_method(curve_div)
588         {
589             init(x1, y1, x2, y2, x3, y3, x4, y4);
590         }
591 
curve4(const curve4_points & cp)592         curve4(const curve4_points& cp) :
593             m_approximation_method(curve_div)
594         {
595             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
596         }
597 
reset()598         void reset()
599         {
600             m_curve_inc.reset();
601             m_curve_div.reset();
602         }
603 
init(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)604         void init(double x1, double y1,
605                   double x2, double y2,
606                   double x3, double y3,
607                   double x4, double y4)
608         {
609             if(m_approximation_method == curve_inc)
610             {
611                 m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4);
612             }
613             else
614             {
615                 m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4);
616             }
617         }
618 
init(const curve4_points & cp)619         void init(const curve4_points& cp)
620         {
621             init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
622         }
623 
approximation_method(curve_approximation_method_e v)624         void approximation_method(curve_approximation_method_e v)
625         {
626             m_approximation_method = v;
627         }
628 
approximation_method()629         curve_approximation_method_e approximation_method() const
630         {
631             return m_approximation_method;
632         }
633 
approximation_scale(double s)634         void approximation_scale(double s)
635         {
636             m_curve_inc.approximation_scale(s);
637             m_curve_div.approximation_scale(s);
638         }
approximation_scale()639         double approximation_scale() const { return m_curve_inc.approximation_scale(); }
640 
angle_tolerance(double v)641         void angle_tolerance(double v)
642         {
643             m_curve_div.angle_tolerance(v);
644         }
645 
angle_tolerance()646         double angle_tolerance() const
647         {
648             return m_curve_div.angle_tolerance();
649         }
650 
cusp_limit(double v)651         void cusp_limit(double v)
652         {
653             m_curve_div.cusp_limit(v);
654         }
655 
cusp_limit()656         double cusp_limit() const
657         {
658             return m_curve_div.cusp_limit();
659         }
660 
rewind(unsigned path_id)661         void rewind(unsigned path_id)
662         {
663             if(m_approximation_method == curve_inc)
664             {
665                 m_curve_inc.rewind(path_id);
666             }
667             else
668             {
669                 m_curve_div.rewind(path_id);
670             }
671         }
672 
vertex(double * x,double * y)673         unsigned vertex(double* x, double* y)
674         {
675             if(m_approximation_method == curve_inc)
676             {
677                 return m_curve_inc.vertex(x, y);
678             }
679             return m_curve_div.vertex(x, y);
680         }
681 
682     private:
683         curve4_inc m_curve_inc;
684         curve4_div m_curve_div;
685         curve_approximation_method_e m_approximation_method;
686     };
687 
688 
689 
690 
691 }
692 
693 #endif
694