Anti-Grain Geometry Tutorial
agg_curves.h
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:
38  curve3_inc() :
39  m_num_steps(0), m_step(0), m_scale(1.0) { }
40 
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 
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 
54  void approximation_method(curve_approximation_method_e) {}
55  curve_approximation_method_e approximation_method() const { return curve_inc; }
56 
57  void approximation_scale(double s);
58  double approximation_scale() const;
59 
60  void angle_tolerance(double) {}
61  double angle_tolerance() const { return 0.0; }
62 
63  void cusp_limit(double) {}
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:
97  curve3_div() :
98  m_approximation_scale(1.0),
99  m_angle_tolerance(0.0),
100  m_count(0)
101  {}
102 
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 
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 
118  void approximation_method(curve_approximation_method_e) {}
119  curve_approximation_method_e approximation_method() const { return curve_div; }
120 
121  void approximation_scale(double s) { m_approximation_scale = s; }
122  double approximation_scale() const { return m_approximation_scale; }
123 
124  void angle_tolerance(double a) { m_angle_tolerance = a; }
125  double angle_tolerance() const { return m_angle_tolerance; }
126 
127  void cusp_limit(double) {}
128  double cusp_limit() const { return 0.0; }
129 
130  void rewind(unsigned)
131  {
132  m_count = 0;
133  }
134 
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
168  {
169  double cp[8];
170  curve4_points() {}
171  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  }
179  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
195  {
196  public:
197  curve4_inc() :
198  m_num_steps(0), m_step(0), m_scale(1.0) { }
199 
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 
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 
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 
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 
226  void approximation_method(curve_approximation_method_e) {}
227  curve_approximation_method_e approximation_method() const { return curve_inc; }
228 
229  void approximation_scale(double s);
230  double approximation_scale() const;
231 
232  void angle_tolerance(double) {}
233  double angle_tolerance() const { return 0.0; }
234 
235  void cusp_limit(double) {}
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
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
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
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
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
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
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
375  {
376  public:
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 
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 
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 
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 
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 
415  void approximation_method(curve_approximation_method_e) {}
416 
417  curve_approximation_method_e approximation_method() const
418  {
419  return curve_div;
420  }
421 
422  void approximation_scale(double s) { m_approximation_scale = s; }
423  double approximation_scale() const { return m_approximation_scale; }
424 
425  void angle_tolerance(double a) { m_angle_tolerance = a; }
426  double angle_tolerance() const { return m_angle_tolerance; }
427 
428  void cusp_limit(double v)
429  {
430  m_cusp_limit = (v == 0.0) ? 0.0 : pi - v;
431  }
432 
433  double cusp_limit() const
434  {
435  return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit;
436  }
437 
438  void rewind(unsigned)
439  {
440  m_count = 0;
441  }
442 
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:
477  curve3() : m_approximation_method(curve_div) {}
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 
486  void reset()
487  {
488  m_curve_inc.reset();
489  m_curve_div.reset();
490  }
491 
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 
506  void approximation_method(curve_approximation_method_e v)
507  {
508  m_approximation_method = v;
509  }
510 
511  curve_approximation_method_e approximation_method() const
512  {
513  return m_approximation_method;
514  }
515 
516  void approximation_scale(double s)
517  {
518  m_curve_inc.approximation_scale(s);
519  m_curve_div.approximation_scale(s);
520  }
521 
522  double approximation_scale() const
523  {
524  return m_curve_inc.approximation_scale();
525  }
526 
527  void angle_tolerance(double a)
528  {
529  m_curve_div.angle_tolerance(a);
530  }
531 
532  double angle_tolerance() const
533  {
534  return m_curve_div.angle_tolerance();
535  }
536 
537  void cusp_limit(double v)
538  {
539  m_curve_div.cusp_limit(v);
540  }
541 
542  double cusp_limit() const
543  {
544  return m_curve_div.cusp_limit();
545  }
546 
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 
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:
582  curve4() : m_approximation_method(curve_div) {}
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 
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 
598  void reset()
599  {
600  m_curve_inc.reset();
601  m_curve_div.reset();
602  }
603 
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 
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 
624  void approximation_method(curve_approximation_method_e v)
625  {
626  m_approximation_method = v;
627  }
628 
629  curve_approximation_method_e approximation_method() const
630  {
631  return m_approximation_method;
632  }
633 
634  void approximation_scale(double s)
635  {
636  m_curve_inc.approximation_scale(s);
637  m_curve_div.approximation_scale(s);
638  }
639  double approximation_scale() const { return m_curve_inc.approximation_scale(); }
640 
641  void angle_tolerance(double v)
642  {
643  m_curve_div.angle_tolerance(v);
644  }
645 
646  double angle_tolerance() const
647  {
648  return m_curve_div.angle_tolerance();
649  }
650 
651  void cusp_limit(double v)
652  {
653  m_curve_div.cusp_limit(v);
654  }
655 
656  double cusp_limit() const
657  {
658  return m_curve_div.cusp_limit();
659  }
660 
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 
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
Definition: agg_arc.cpp:24