1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4 (Public License)
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 // Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com)
5 //
6 // Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
7 // Pascal Port By: Milan Marusinec alias Milano
8 //                 milan@marusinec.sk
9 //                 http://www.aggpas.org
10 // Copyright (c) 2005-2006
11 //
12 // Permission to copy, use, modify, sell and distribute this software
13 // is granted provided this copyright notice appears in all copies.
14 // This software is provided "as is" without express or implied
15 // warranty, and with no claim as to its suitability for any purpose.
16 //
17 //----------------------------------------------------------------------------
18 // Contact: mcseem@antigrain.com
19 //          mcseemagg@yahoo.com
20 //          http://www.antigrain.com
21 //
22 // [Pascal Port History] -----------------------------------------------------
23 //
24 // 12.02.2006-Milano: Unit port establishment
25 //
26 { agg_curves.pas }
27 unit
28  agg_curves ;
29 
30 INTERFACE
31 
32 {$I agg_mode.inc }
33 
34 uses
35  Math ,
36  agg_basics ,
37  agg_array ,
38  agg_vertex_source ;
39 
40 { TYPES DEFINITION }
41 type
42  curve_approximation_method_e = (curve_inc ,curve_div );
43 
44  curve_ptr = ^curve;
45  curve = object(vertex_source )
46    procedure reset; virtual; abstract;
47    procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
48    procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
49 
50    procedure approximation_method_(v : curve_approximation_method_e ); virtual; abstract;
_approximation_methodnull51    function  _approximation_method : curve_approximation_method_e; virtual; abstract;
52 
53    procedure approximation_scale_(s : double ); virtual; abstract;
_approximation_scalenull54    function  _approximation_scale : double; virtual; abstract;
55 
56    procedure angle_tolerance_(a : double ); virtual; abstract;
_angle_tolerancenull57    function  _angle_tolerance : double; virtual; abstract;
58 
59    procedure cusp_limit_(v : double ); virtual; abstract;
_cusp_limitnull60    function  _cusp_limit : double; virtual; abstract;
61 
62   end;
63 
64  curve3_inc = object(curve )
65    m_num_steps ,
66    m_step      : int;
67 
68    m_scale   ,
69    m_start_x ,
70    m_start_y ,
71    m_end_x   ,
72    m_end_y   ,
73 
74    m_fx   ,
75    m_fy   ,
76    m_dfx  ,
77    m_dfy  ,
78    m_ddfx ,
79    m_ddfy ,
80 
81    m_saved_fx  ,
82    m_saved_fy  ,
83    m_saved_dfx ,
84    m_saved_dfy : double;
85 
86    constructor Construct; overload;
87    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
88 
89    procedure reset; virtual;
90    procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
91 
92    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull93    function  _approximation_method : curve_approximation_method_e; virtual;
94 
95    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull96    function  _approximation_scale : double; virtual;
97 
98    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull99    function  _angle_tolerance : double; virtual;
100 
101    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull102    function  _cusp_limit : double; virtual;
103 
104    procedure rewind(path_id : unsigned ); virtual;
vertexnull105    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
106 
107   end;
108 
109  curve3_div = object(curve )
110    m_approximation_scale          ,
111    m_distance_tolerance_square    ,
112    m_distance_tolerance_manhattan ,
113    m_angle_tolerance              : double;
114 
115    m_count  : unsigned;
116    m_points : pod_deque;
117 
118    constructor Construct; overload;
119    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
120    destructor  Destruct; virtual;
121 
122    procedure reset; virtual;
123    procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
124 
125    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull126    function  _approximation_method : curve_approximation_method_e; virtual;
127 
128    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull129    function  _approximation_scale : double; virtual;
130 
131    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull132    function  _angle_tolerance : double; virtual;
133 
134    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull135    function  _cusp_limit : double; virtual;
136 
137    procedure rewind(path_id : unsigned ); virtual;
vertexnull138    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
139 
140    procedure bezier          (x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double );
141    procedure recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double; level : unsigned );
142 
143   end;
144 
145  curve4_points_ptr = ^curve4_points;
146  curve4_points = object
147    cp : array[0..7 ] of double;
148 
149    constructor Construct; overload;
150    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
151 
152    procedure init(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
153 
array_operatornull154    function  array_operator    (i : unsigned ) : double;
array_operator_ptrnull155    function  array_operator_ptr(i : unsigned ) : double_ptr;
156 
157   end;
158 
159  curve4_inc = object(curve )
160    m_num_steps ,
161    m_step      : int;
162 
163    m_scale   ,
164    m_start_x ,
165    m_start_y ,
166    m_end_x   ,
167    m_end_y   ,
168 
169    m_fx    ,
170    m_fy    ,
171    m_dfx   ,
172    m_dfy   ,
173    m_ddfx  ,
174    m_ddfy  ,
175    m_dddfx ,
176    m_dddfy ,
177 
178    m_saved_fx   ,
179    m_saved_fy   ,
180    m_saved_dfx  ,
181    m_saved_dfy  ,
182    m_saved_ddfx ,
183    m_saved_ddfy : double;
184 
185    constructor Construct; overload;
186    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
187    constructor Construct(cp : curve4_points_ptr ); overload;
188 
189    procedure reset; virtual;
190    procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
191    procedure init (cp : curve4_points_ptr );
192 
193    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull194    function  _approximation_method : curve_approximation_method_e; virtual;
195 
196    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull197    function  _approximation_scale : double; virtual;
198 
199    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull200    function  _angle_tolerance : double; virtual;
201 
202    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull203    function  _cusp_limit : double; virtual;
204 
205    procedure rewind(path_id : unsigned ); virtual;
vertexnull206    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
207 
208   end;
209 
210  curve4_div = object(curve )
211    m_approximation_scale          ,
212    m_distance_tolerance_square    ,
213    m_distance_tolerance_manhattan ,
214 
215    m_angle_tolerance ,
216    m_cusp_limit      : double;
217 
218    m_count  : unsigned;
219    m_points : pod_deque;
220 
221    constructor Construct; overload;
222    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
223    constructor Construct(cp : curve4_points_ptr ); overload;
224    destructor  Destruct; virtual;
225 
226    procedure reset; virtual;
227    procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
228    procedure init (cp : curve4_points_ptr );
229 
230    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull231    function  _approximation_method : curve_approximation_method_e; virtual;
232 
233    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull234    function  _approximation_scale : double; virtual;
235 
236    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull237    function  _angle_tolerance : double; virtual;
238 
239    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull240    function  _cusp_limit : double; virtual;
241 
242    procedure rewind(path_id : unsigned ); virtual;
vertexnull243    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
244 
245    procedure bezier          (x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double );
246    procedure recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double; level : unsigned );
247 
248   end;
249 
250  curve3_ptr = ^curve3;
251  curve3 = object(curve )
252    m_curve_inc : curve3_inc;
253    m_curve_div : curve3_div;
254 
255    m_approximation_method : curve_approximation_method_e;
256 
257    constructor Construct; overload;
258    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
259    destructor  Destruct; virtual;
260 
261    procedure reset; virtual;
262    procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
263 
264    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull265    function  _approximation_method : curve_approximation_method_e; virtual;
266 
267    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull268    function  _approximation_scale : double; virtual;
269 
270    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull271    function  _angle_tolerance : double; virtual;
272 
273    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull274    function  _cusp_limit : double; virtual;
275 
276    procedure rewind(path_id : unsigned ); virtual;
vertexnull277    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
278 
279   end;
280 
281  curve4_ptr = ^curve4;
282  curve4 = object(curve )
283    m_curve_inc : curve4_inc;
284    m_curve_div : curve4_div;
285 
286    m_approximation_method : curve_approximation_method_e;
287 
288    constructor Construct; overload;
289    constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
290    constructor Construct(cp : curve4_points_ptr ); overload;
291    destructor  Destruct; virtual;
292 
293    procedure reset; virtual;
294    procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
295    procedure init (cp : curve4_points_ptr );
296 
297    procedure approximation_method_(v : curve_approximation_method_e ); virtual;
_approximation_methodnull298    function  _approximation_method : curve_approximation_method_e; virtual;
299 
300    procedure approximation_scale_(s : double ); virtual;
_approximation_scalenull301    function  _approximation_scale : double; virtual;
302 
303    procedure angle_tolerance_(a : double ); virtual;
_angle_tolerancenull304    function  _angle_tolerance : double; virtual;
305 
306    procedure cusp_limit_(v : double ); virtual;
_cusp_limitnull307    function  _cusp_limit : double; virtual;
308 
309    procedure rewind(path_id : unsigned ); virtual;
vertexnull310    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
311 
312   end;
313 
314 { GLOBAL PROCEDURES }
catrom_to_beziernull315  function  catrom_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
catrom_to_beziernull316  function  catrom_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
317 
ubspline_to_beziernull318  function  ubspline_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
ubspline_to_beziernull319  function  ubspline_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
320 
hermite_to_beziernull321  function  hermite_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
hermite_to_beziernull322  function  hermite_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
323 
324 
325 IMPLEMENTATION
326 { LOCAL VARIABLES & CONSTANTS }
327 const
328  curve_distance_epsilon        = 1e-30;
329  curve_collinearity_epsilon    = 1e-30;
330  curve_angle_tolerance_epsilon = 0.01;
331  curve_recursion_limit         = 32;
332 
333 { UNIT IMPLEMENTATION }
334 { CATROM_TO_BEZIER }
catrom_to_beziernull335 function catrom_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
336 begin
337 // Trans. matrix Catmull-Rom to Bezier
338 //
339 //  0       1       0       0
340 //  -1/6    1       1/6     0
341 //  0       1/6     1       -1/6
342 //  0       0       1       0
343 //
344  result.Construct(
345   x2 ,
346   y2 ,
347   (-x1 + 6 * x2 + x3 ) / 6 ,
348   (-y1 + 6 * y2 + y3 ) / 6 ,
349   ( x2 + 6 * x3 - x4 ) / 6 ,
350   ( y2 + 6 * y3 - y4 ) / 6 ,
351   x3 ,
352   y3 );
353 
354 end;
355 
356 { CATROM_TO_BEZIER }
catrom_to_beziernull357 function catrom_to_bezier(cp : curve4_points_ptr ) : curve4_points;
358 begin
359  result:=
360   catrom_to_bezier(
361    cp.array_operator(0 ) ,
362    cp.array_operator(1 ) ,
363    cp.array_operator(2 ) ,
364    cp.array_operator(3 ) ,
365    cp.array_operator(4 ) ,
366    cp.array_operator(5 ) ,
367    cp.array_operator(6 ) ,
368    cp.array_operator(7 ) );
369 
370 end;
371 
372 { UBSPLINE_TO_BEZIER }
ubspline_to_beziernull373 function ubspline_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
374 begin
375 // Trans. matrix Uniform BSpline to Bezier
376 //
377 //  1/6     4/6     1/6     0
378 //  0       4/6     2/6     0
379 //  0       2/6     4/6     0
380 //  0       1/6     4/6     1/6
381 //
382  result.Construct(
383   (x1 + 4 * x2 + x3 ) / 6 ,
384   (y1 + 4 * y2 + y3 ) / 6 ,
385   (4 * x2 + 2 * x3 ) / 6 ,
386   (4 * y2 + 2 * y3 ) / 6 ,
387   (2 * x2 + 4 * x3 ) / 6 ,
388   (2 * y2 + 4 * y3 ) / 6 ,
389   (x2 + 4 * x3 + x4 ) / 6 ,
390   (y2 + 4 * y3 + y4 ) / 6 );
391 
392 end;
393 
394 { UBSPLINE_TO_BEZIER }
ubspline_to_beziernull395 function ubspline_to_bezier(cp : curve4_points_ptr ) : curve4_points;
396 begin
397  result:=
398   ubspline_to_bezier(
399    cp.array_operator(0 ) ,
400    cp.array_operator(1 ) ,
401    cp.array_operator(2 ) ,
402    cp.array_operator(3 ) ,
403    cp.array_operator(4 ) ,
404    cp.array_operator(5 ) ,
405    cp.array_operator(6 ) ,
406    cp.array_operator(7 ) );
407 
408 end;
409 
410 { HERMITE_TO_BEZIER }
hermite_to_beziernull411 function hermite_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
412 begin
413 // Trans. matrix Hermite to Bezier
414 //
415 //  1       0       0       0
416 //  1       0       1/3     0
417 //  0       1       0       -1/3
418 //  0       1       0       0
419 //
420  result.Construct(
421   x1 ,
422   y1 ,
423   (3 * x1 + x3 ) / 3 ,
424   (3 * y1 + y3 ) / 3 ,
425   (3 * x2 - x4 ) / 3 ,
426   (3 * y2 - y4 ) / 3 ,
427   x2 ,
428   y2 );
429 
430 end;
431 
432 { HERMITE_TO_BEZIER }
hermite_to_beziernull433 function hermite_to_bezier(cp : curve4_points_ptr ) : curve4_points;
434 begin
435  result:=
436   hermite_to_bezier(
437    cp.array_operator(0 ) ,
438    cp.array_operator(1 ) ,
439    cp.array_operator(2 ) ,
440    cp.array_operator(3 ) ,
441    cp.array_operator(4 ) ,
442    cp.array_operator(5 ) ,
443    cp.array_operator(6 ) ,
444    cp.array_operator(7 ) );
445 
446 end;
447 
448 { INIT3 }
449 procedure curve.init3;
450 begin
451 end;
452 
453 { INIT4 }
454 procedure curve.init4;
455 begin
456 end;
457 
458 { CONSTRUCT }
459 constructor curve3_inc.Construct;
460 begin
461  m_num_steps:=0;
462  m_step     :=0;
463  m_scale    :=1.0;
464 
465 end;
466 
467 { CONSTRUCT }
468 constructor curve3_inc.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
469 begin
470  m_num_steps:=0;
471  m_step     :=0;
472  m_scale    :=1.0;
473 
474  init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
475 
476 end;
477 
478 { RESET }
479 procedure curve3_inc.reset;
480 begin
481  m_num_steps:=0;
482  m_step     :=-1;
483 
484 end;
485 
486 { INIT3 }
487 procedure curve3_inc.init3;
488 var
489  dx1 ,dy1 ,dx2 ,dy2 ,len ,tmpx ,tmpy ,
490  subdivide_step     ,subdivide_step2 : double;
491 
492 begin
493  m_start_x:=x1;
494  m_start_y:=y1;
495  m_end_x  :=x3;
496  m_end_y  :=y3;
497 
498  dx1:=x2 - x1;
499  dy1:=y2 - y1;
500  dx2:=x3 - x2;
501  dy2:=y3 - y2;
502 
503  len:=Sqrt(dx1 * dx1 + dy1 * dy1 ) + Sqrt(dx2 * dx2 + dy2 * dy2 );
504 
505  m_num_steps:=trunc(len * 0.25 * m_scale );
506 
507  if m_num_steps < 4 then
508   m_num_steps:=4;
509 
510  subdivide_step :=1.0 / m_num_steps;
511  subdivide_step2:=subdivide_step * subdivide_step;
512 
513  tmpx:=(x1 - x2 * 2.0 + x3 ) * subdivide_step2;
514  tmpy:=(y1 - y2 * 2.0 + y3 ) * subdivide_step2;
515 
516  m_saved_fx:=x1;
517  m_fx      :=x1;
518  m_saved_fy:=y1;
519  m_fy      :=y1;
520 
521  m_saved_dfx:=tmpx + (x2 - x1 ) * (2.0 * subdivide_step );
522  m_dfx      :=m_saved_dfx;
523  m_saved_dfy:=tmpy + (y2 - y1 ) * (2.0 * subdivide_step );
524  m_dfy      :=m_saved_dfy;
525 
526  m_ddfx:=tmpx * 2.0;
527  m_ddfy:=tmpy * 2.0;
528 
529  m_step:=m_num_steps;
530 
531 end;
532 
533 { APPROXIMATION_METHOD_ }
534 procedure curve3_inc.approximation_method_;
535 begin
536 end;
537 
538 { _APPROXIMATION_METHOD }
curve3_inc._approximation_methodnull539 function curve3_inc._approximation_method;
540 begin
541  result:=curve_inc;
542 
543 end;
544 
545 { APPROXIMATION_SCALE_ }
546 procedure curve3_inc.approximation_scale_;
547 begin
548  m_scale:=s;
549 
550 end;
551 
552 { _APPROXIMATION_SCALE }
curve3_inc._approximation_scalenull553 function curve3_inc._approximation_scale;
554 begin
555  result:=m_scale;
556 
557 end;
558 
559 { ANGLE_TOLERANCE_ }
560 procedure curve3_inc.angle_tolerance_;
561 begin
562 end;
563 
564 { _ANGLE_TOLERANCE }
curve3_inc._angle_tolerancenull565 function curve3_inc._angle_tolerance;
566 begin
567  result:=0.0;
568 
569 end;
570 
571 { CUSP_LIMIT_ }
572 procedure curve3_inc.cusp_limit_;
573 begin
574 end;
575 
576 { _CUSP_LIMIT }
curve3_inc._cusp_limitnull577 function curve3_inc._cusp_limit;
578 begin
579  result:=0.0;
580 
581 end;
582 
583 { REWIND }
584 procedure curve3_inc.rewind;
585 begin
586  if m_num_steps = 0 then
587   begin
588    m_step:=-1;
589 
590    exit;
591 
592   end;
593 
594  m_step:=m_num_steps;
595  m_fx  :=m_saved_fx;
596  m_fy  :=m_saved_fy;
597  m_dfx :=m_saved_dfx;
598  m_dfy :=m_saved_dfy;
599 
600 end;
601 
602 { VERTEX }
curve3_inc.vertexnull603 function curve3_inc.vertex;
604 begin
605  if m_step < 0 then
606   begin
607    result:=path_cmd_stop;
608 
609    exit;
610 
611   end;
612 
613  if m_step = m_num_steps then
614   begin
615    x^:=m_start_x;
616    y^:=m_start_y;
617 
618    dec(m_step );
619 
620    result:=path_cmd_move_to;
621 
622    exit;
623 
624   end;
625 
626  if m_step = 0 then
627   begin
628    x^:=m_end_x;
629    y^:=m_end_y;
630 
631    dec(m_step );
632 
633    result:=path_cmd_line_to;
634 
635    exit;
636 
637   end;
638 
639  m_fx :=m_fx + m_dfx;
640  m_fy :=m_fy + m_dfy;
641  m_dfx:=m_dfx + m_ddfx;
642  m_dfy:=m_dfy + m_ddfy;
643 
644  x^:=m_fx;
645  y^:=m_fy;
646 
647  dec(m_step );
648 
649  result:=path_cmd_line_to;
650 
651 end;
652 
653 { CONSTRUCT }
654 constructor curve3_div.Construct;
655 begin
656  m_points.Construct(sizeof(point_type ) );
657 
658  m_approximation_scale:=1.0;
659  m_angle_tolerance    :=0.0;
660  m_count              :=0;
661 
662 end;
663 
664 { CONSTRUCT }
665 constructor curve3_div.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
666 begin
667  m_points.Construct(sizeof(point_type ) );
668 
669  m_approximation_scale:=1.0;
670  m_angle_tolerance    :=0.0;
671  m_count              :=0;
672 
673  init3(x1 ,y1 ,x2, y2 ,x3 ,y3 );
674 
675 end;
676 
677 { DESTRUCT }
678 destructor curve3_div.Destruct;
679 begin
680  m_points.Destruct;
681 
682 end;
683 
684 { RESET }
685 procedure curve3_div.reset;
686 begin
687  m_points.remove_all;
688 
689  m_count:=0;
690 
691 end;
692 
693 { INIT3 }
694 procedure curve3_div.init3;
695 begin
696  m_points.remove_all;
697 
698  m_distance_tolerance_square   :=0.5 / m_approximation_scale;
699  m_distance_tolerance_square   :=m_distance_tolerance_square * m_distance_tolerance_square;
700  m_distance_tolerance_manhattan:=4.0 / m_approximation_scale;
701 
702  bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
703 
704  m_count:=0;
705 
706 end;
707 
708 { APPROXIMATION_METHOD_ }
709 procedure curve3_div.approximation_method_;
710 begin
711 end;
712 
713 { _APPROXIMATION_METHOD }
curve3_div._approximation_methodnull714 function curve3_div._approximation_method;
715 begin
716  result:=curve_div;
717 
718 end;
719 
720 { APPROXIMATION_SCALE_ }
721 procedure curve3_div.approximation_scale_;
722 begin
723  if s = 0 then
724   m_approximation_scale:=0.00001
725  else
726   m_approximation_scale:=s;
727 
728 end;
729 
730 { _APPROXIMATION_SCALE }
curve3_div._approximation_scalenull731 function curve3_div._approximation_scale;
732 begin
733  result:=m_approximation_scale;
734 
735 end;
736 
737 { ANGLE_TOLERANCE_ }
738 procedure curve3_div.angle_tolerance_;
739 begin
740  m_angle_tolerance:=a;
741 
742 end;
743 
744 { _ANGLE_TOLERANCE }
curve3_div._angle_tolerancenull745 function curve3_div._angle_tolerance;
746 begin
747  result:=m_angle_tolerance;
748 
749 end;
750 
751 { CUSP_LIMIT_ }
752 procedure curve3_div.cusp_limit_;
753 begin
754 end;
755 
756 { _CUSP_LIMIT }
curve3_div._cusp_limitnull757 function curve3_div._cusp_limit;
758 begin
759  result:=0.0;
760 
761 end;
762 
763 { REWIND }
764 procedure curve3_div.rewind;
765 begin
766  m_count:=0;
767 
768 end;
769 
770 { VERTEX }
curve3_div.vertexnull771 function curve3_div.vertex;
772 var
773  p : point_type_ptr;
774 
775 begin
776  if m_count >= m_points.size then
777   begin
778    result:=path_cmd_stop;
779 
780    exit;
781 
782   end;
783 
784  p:=m_points.array_operator(m_count );
785 
786  inc(m_count );
787 
788  x^:=p.x;
789  y^:=p.y;
790 
791  if m_count = 1 then
792   result:=path_cmd_move_to
793  else
794   result:=path_cmd_line_to;
795 
796 end;
797 
798 { BEZIER }
799 procedure curve3_div.bezier;
800 var
801  pt : point_type;
802 
803 begin
804  pt.x:=x1;
805  pt.y:=y1;
806 
807  m_points.add(@pt );
808 
809  recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,0 );
810 
811  pt.x:=x3;
812  pt.y:=y3;
813 
814  m_points.add(@pt );
815 
816 end;
817 
818 { RECURSIVE_BEZIER }
819 procedure curve3_div.recursive_bezier;
820 var
821  x12 ,y12 ,x23 ,y23 ,x123 ,y123 ,dx ,dy ,d ,da : double;
822 
823  pt : point_type;
824 
825 begin
826  if level > curve_recursion_limit then
827   exit;
828 
829 // Calculate all the mid-points of the line segments
830  x12 :=(x1 + x2 ) / 2;
831  y12 :=(y1 + y2 ) / 2;
832  x23 :=(x2 + x3 ) / 2;
833  y23 :=(y2 + y3 ) / 2;
834  x123:=(x12 + x23 ) / 2;
835  y123:=(y12 + y23 ) / 2;
836 
837  dx:=x3 - x1;
838  dy:=y3 - y1;
839  d :=Abs((x2 - x3 ) * dy - (y2 - y3 ) * dx );
840 
841  if d > curve_collinearity_epsilon then
842  // Regular care
843   if d * d <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
844    begin
845    // If the curvature doesn't exceed the distance_tolerance value
846    // we tend to finish subdivisions.
847     if m_angle_tolerance < curve_angle_tolerance_epsilon then
848      begin
849       pt.x:=x123;
850       pt.y:=y123;
851 
852       m_points.add(@pt );
853 
854       exit;
855 
856      end;
857 
858    // Angle & Cusp Condition
859     da:=Abs(ArcTan2(y3 - y2 ,x3 - x2 ) - ArcTan2(y2 - y1 ,x2 - x1 ) );
860 
861     if da >= pi then
862      da:=2 * pi - da;
863 
864     if da < m_angle_tolerance then
865      begin
866      // Finally we can stop the recursion
867       pt.x:=x123;
868       pt.y:=y123;
869 
870       m_points.add(@pt );
871 
872       exit;
873 
874      end;
875 
876    end
877   else
878  else
879   if Abs(x1 + x3 - x2 - x2 ) + Abs(y1 + y3 - y2 - y2 ) <= m_distance_tolerance_manhattan then
880    begin
881     pt.x:=x123;
882     pt.y:=y123;
883 
884     m_points.add(@pt );
885 
886     exit;
887 
888    end;
889 
890 // Continue subdivision
891  recursive_bezier(x1   ,y1   ,x12 ,y12 ,x123 ,y123 ,level + 1 );
892  recursive_bezier(x123 ,y123 ,x23 ,y23 ,x3   ,y3   ,level + 1 );
893 
894 end;
895 
896 { CONSTRUCT }
897 constructor curve4_points.Construct;
898 begin
899 end;
900 
901 { CONSTRUCT }
902 constructor curve4_points.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
903 begin
904  cp[0 ]:=x1;
905  cp[1 ]:=y1;
906  cp[2 ]:=x2;
907  cp[3 ]:=y2;
908  cp[4 ]:=x3;
909  cp[5 ]:=y3;
910  cp[6 ]:=x4;
911  cp[7 ]:=y4;
912 
913 end;
914 
915 { INIT }
916 procedure curve4_points.init;
917 begin
918  cp[0 ]:=x1;
919  cp[1 ]:=y1;
920  cp[2 ]:=x2;
921  cp[3 ]:=y2;
922  cp[4 ]:=x3;
923  cp[5 ]:=y3;
924  cp[6 ]:=x4;
925  cp[7 ]:=y4;
926 
927 end;
928 
929 { ARRAY_OPERATOR }
930 function curve4_points.array_operator;
931 begin
932  result:=cp[i ];
933 
934 end;
935 
936 { ARRAY_OPERATOR_PTR }
937 function curve4_points.array_operator_ptr;
938 begin
939  result:=@cp[i ];
940 
941 end;
942 
943 { CONSTRUCT }
944 constructor curve4_inc.Construct;
945 begin
946  m_num_steps:=0;
947  m_step     :=0;
948  m_scale    :=1.0;
949 
950 end;
951 
952 { CONSTRUCT }
953 constructor curve4_inc.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
954 begin
955  m_num_steps:=0;
956  m_step     :=0;
957  m_scale    :=1.0;
958 
959  init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
960 
961 end;
962 
963 { CONSTRUCT }
964 constructor curve4_inc.Construct(cp : curve4_points_ptr );
965 begin
966  m_num_steps:=0;
967  m_step     :=0;
968  m_scale    :=1.0;
969 
970  init4(
971   cp.array_operator(0 ) ,
972   cp.array_operator(1 ) ,
973   cp.array_operator(2 ) ,
974   cp.array_operator(3 ) ,
975   cp.array_operator(4 ) ,
976   cp.array_operator(5 ) ,
977   cp.array_operator(6 ) ,
978   cp.array_operator(7 ) );
979 
980 end;
981 
982 { RESET }
983 procedure curve4_inc.reset;
984 begin
985  m_num_steps:=0;
986  m_step     :=-1;
987 
988 end;
989 
990 { INIT4 }
991 procedure curve4_inc.init4;
992 var
993  dx1 ,dy1 ,dx2 ,dy2 ,dx3 ,dy3 ,len ,
994 
995  subdivide_step  ,
996  subdivide_step2 ,
997  subdivide_step3 ,
998 
999  pre1 ,pre2 ,pre4 ,pre5 ,tmp1x ,tmp1y ,tmp2x ,tmp2y : double;
1000 
1001 begin
1002  m_start_x:=x1;
1003  m_start_y:=y1;
1004  m_end_x  :=x4;
1005  m_end_y  :=y4;
1006 
1007  dx1:=x2 - x1;
1008  dy1:=y2 - y1;
1009  dx2:=x3 - x2;
1010  dy2:=y3 - y2;
1011  dx3:=x4 - x3;
1012  dy3:=y4 - y3;
1013 
1014  len:=
1015   Sqrt(dx1 * dx1 + dy1 * dy1 ) +
1016   Sqrt(dx2 * dx2 + dy2 * dy2 ) +
1017   Sqrt(dx3 * dx3 + dy3 * dy3 );
1018 
1019  m_num_steps:=trunc(len * 0.25 * m_scale );
1020 
1021  if m_num_steps < 4 then
1022   m_num_steps:=4;
1023 
1024  subdivide_step :=1.0 / m_num_steps;
1025  subdivide_step2:=subdivide_step * subdivide_step;
1026  subdivide_step3:=subdivide_step * subdivide_step * subdivide_step;
1027 
1028  pre1:=3.0 * subdivide_step;
1029  pre2:=3.0 * subdivide_step2;
1030  pre4:=6.0 * subdivide_step2;
1031  pre5:=6.0 * subdivide_step3;
1032 
1033  tmp1x:=x1 - x2 * 2.0 + x3;
1034  tmp1y:=y1 - y2 * 2.0 + y3;
1035 
1036  tmp2x:=(x2 - x3 ) * 3.0 - x1 + x4;
1037  tmp2y:=(y2 - y3 ) * 3.0 - y1 + y4;
1038 
1039  m_saved_fx:=x1;
1040  m_fx      :=x1;
1041  m_saved_fy:=y1;
1042  m_fy      :=y1;
1043 
1044  m_saved_dfx:=(x2 - x1 ) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3;
1045  m_dfx      :=m_saved_dfx;
1046  m_saved_dfy:=(y2 - y1 ) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3;
1047  m_dfy      :=m_saved_dfy;
1048 
1049  m_saved_ddfx:=tmp1x * pre4 + tmp2x * pre5;
1050  m_ddfx      :=m_saved_ddfx;
1051  m_saved_ddfy:=tmp1y * pre4 + tmp2y * pre5;
1052  m_ddfy      :=m_saved_ddfy;
1053 
1054  m_dddfx:=tmp2x * pre5;
1055  m_dddfy:=tmp2y * pre5;
1056 
1057  m_step:=m_num_steps;
1058 
1059 end;
1060 
1061 { INIT }
1062 procedure curve4_inc.init;
1063 begin
1064  init4(
1065   cp.array_operator(0 ) ,
1066   cp.array_operator(1 ) ,
1067   cp.array_operator(2 ) ,
1068   cp.array_operator(3 ) ,
1069   cp.array_operator(4 ) ,
1070   cp.array_operator(5 ) ,
1071   cp.array_operator(6 ) ,
1072   cp.array_operator(7 ) );
1073 
1074 end;
1075 
1076 { APPROXIMATION_METHOD_ }
1077 procedure curve4_inc.approximation_method_;
1078 begin
1079 end;
1080 
1081 { _APPROXIMATION_METHOD }
1082 function curve4_inc._approximation_method;
1083 begin
1084  result:=curve_inc;
1085 
1086 end;
1087 
1088 { APPROXIMATION_SCALE_ }
1089 procedure curve4_inc.approximation_scale_;
1090 begin
1091  m_scale:=s;
1092 
1093 end;
1094 
1095 { _APPROXIMATION_SCALE }
1096 function curve4_inc._approximation_scale;
1097 begin
1098  result:=m_scale;
1099 
1100 end;
1101 
1102 { ANGLE_TOLERANCE_ }
1103 procedure curve4_inc.angle_tolerance_;
1104 begin
1105 end;
1106 
1107 { _ANGLE_TOLERANCE }
1108 function curve4_inc._angle_tolerance;
1109 begin
1110  result:=0.0;
1111 
1112 end;
1113 
1114 { CUSP_LIMIT_ }
1115 procedure curve4_inc.cusp_limit_;
1116 begin
1117 end;
1118 
1119 { _CUSP_LIMIT }
1120 function curve4_inc._cusp_limit;
1121 begin
1122  result:=0.0;
1123 
1124 end;
1125 
1126 { REWIND }
1127 procedure curve4_inc.rewind;
1128 begin
1129  if m_num_steps = 0 then
1130   begin
1131    m_step:=-1;
1132 
1133    exit;
1134 
1135   end;
1136 
1137  m_step:=m_num_steps;
1138  m_fx  :=m_saved_fx;
1139  m_fy  :=m_saved_fy;
1140  m_dfx :=m_saved_dfx;
1141  m_dfy :=m_saved_dfy;
1142  m_ddfx:=m_saved_ddfx;
1143  m_ddfy:=m_saved_ddfy;
1144 
1145 end;
1146 
1147 { VERTEX }
1148 function curve4_inc.vertex;
1149 begin
1150  if m_step < 0 then
1151   begin
1152    result:=path_cmd_stop;
1153 
1154    exit;
1155 
1156   end;
1157 
1158  if m_step = m_num_steps then
1159   begin
1160    x^:=m_start_x;
1161    y^:=m_start_y;
1162 
1163    dec(m_step );
1164 
1165    result:=path_cmd_move_to;
1166 
1167    exit;
1168 
1169   end;
1170 
1171  if m_step = 0 then
1172   begin
1173    x^:=m_end_x;
1174    y^:=m_end_y;
1175 
1176    dec(m_step );
1177 
1178    result:=path_cmd_line_to;
1179 
1180    exit;
1181 
1182   end;
1183 
1184  m_fx  :=m_fx + m_dfx;
1185  m_fy  :=m_fy + m_dfy;
1186  m_dfx :=m_dfx + m_ddfx;
1187  m_dfy :=m_dfy + m_ddfy;
1188  m_ddfx:=m_ddfx + m_dddfx;
1189  m_ddfy:=m_ddfy + m_dddfy;
1190 
1191  x^:=m_fx;
1192  y^:=m_fy;
1193 
1194  dec(m_step );
1195 
1196  result:=path_cmd_line_to;
1197 
1198 end;
1199 
1200 { CONSTRUCT }
1201 constructor curve4_div.Construct;
1202 begin
1203  m_points.Construct(sizeof(point_type ) );
1204 
1205  m_approximation_scale:=1.0;
1206  m_angle_tolerance    :=0.0;
1207 
1208  m_cusp_limit:=0.0;
1209  m_count     :=0;
1210 
1211 end;
1212 
1213 { CONSTRUCT }
1214 constructor curve4_div.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
1215 begin
1216  m_points.Construct(sizeof(point_type ) );
1217 
1218  m_approximation_scale:=1.0;
1219  m_angle_tolerance    :=0.0;
1220 
1221  m_cusp_limit:=0.0;
1222  m_count     :=0;
1223 
1224  init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
1225 
1226 end;
1227 
1228 { CONSTRUCT }
1229 constructor curve4_div.Construct(cp : curve4_points_ptr );
1230 begin
1231  m_points.Construct(sizeof(point_type ) );
1232 
1233  m_approximation_scale:=1.0;
1234  m_angle_tolerance    :=0.0;
1235 
1236  m_cusp_limit:=0.0;
1237  m_count     :=0;
1238 
1239  init4(
1240   cp.array_operator(0 ) ,
1241   cp.array_operator(1 ) ,
1242   cp.array_operator(2 ) ,
1243   cp.array_operator(3 ) ,
1244   cp.array_operator(4 ) ,
1245   cp.array_operator(5 ) ,
1246   cp.array_operator(6 ) ,
1247   cp.array_operator(7 ) );
1248 
1249 end;
1250 
1251 { DESTRUCT }
1252 destructor curve4_div.Destruct;
1253 begin
1254  m_points.Destruct;
1255 
1256 end;
1257 
1258 { RESET }
1259 procedure curve4_div.reset;
1260 begin
1261  m_points.remove_all;
1262 
1263  m_count:=0;
1264 
1265 end;
1266 
1267 { INIT4 }
1268 procedure curve4_div.init4;
1269 begin
1270  m_points.remove_all;
1271 
1272  m_distance_tolerance_square   :=0.5 / m_approximation_scale;
1273  m_distance_tolerance_square   :=m_distance_tolerance_square * m_distance_tolerance_square;
1274  m_distance_tolerance_manhattan:=4.0 / m_approximation_scale;
1275 
1276  bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 );
1277 
1278  m_count:=0;
1279 
1280 end;
1281 
1282 { INIT }
1283 procedure curve4_div.init;
1284 begin
1285  init4(
1286   cp.array_operator(0 ) ,
1287   cp.array_operator(1 ) ,
1288   cp.array_operator(2 ) ,
1289   cp.array_operator(3 ) ,
1290   cp.array_operator(4 ) ,
1291   cp.array_operator(5 ) ,
1292   cp.array_operator(6 ) ,
1293   cp.array_operator(7 ) );
1294 
1295 end;
1296 
1297 { APPROXIMATION_METHOD_ }
1298 procedure curve4_div.approximation_method_;
1299 begin
1300 end;
1301 
1302 { _APPROXIMATION_METHOD }
1303 function curve4_div._approximation_method;
1304 begin
1305  result:=curve_div;
1306 
1307 end;
1308 
1309 { APPROXIMATION_SCALE_ }
1310 procedure curve4_div.approximation_scale_;
1311 begin
1312  if s = 0 then
1313   m_approximation_scale:=0.00001
1314  else
1315   m_approximation_scale:=s;
1316 
1317 end;
1318 
1319 { _APPROXIMATION_SCALE }
1320 function curve4_div._approximation_scale;
1321 begin
1322  result:=m_approximation_scale;
1323 
1324 end;
1325 
1326 { ANGLE_TOLERANCE_ }
1327 procedure curve4_div.angle_tolerance_;
1328 begin
1329  m_angle_tolerance:=a;
1330 
1331 end;
1332 
1333 { _ANGLE_TOLERANCE }
1334 function curve4_div._angle_tolerance;
1335 begin
1336  result:=m_angle_tolerance;
1337 
1338 end;
1339 
1340 { CUSP_LIMIT_ }
1341 procedure curve4_div.cusp_limit_;
1342 begin
1343  if v = 0.0 then
1344   m_cusp_limit:=0.0
1345  else
1346   m_cusp_limit:=pi - v;
1347 
1348 end;
1349 
1350 { _CUSP_LIMIT }
1351 function curve4_div._cusp_limit;
1352 begin
1353  if m_cusp_limit = 0.0 then
1354   result:=0.0
1355  else
1356   result:=pi - m_cusp_limit;
1357 
1358 end;
1359 
1360 { REWIND }
1361 procedure curve4_div.rewind;
1362 begin
1363  m_count:=0;
1364 
1365 end;
1366 
1367 { VERTEX }
1368 function curve4_div.vertex;
1369 var
1370  p : point_type_ptr;
1371 
1372 begin
1373  if m_count >= m_points.size then
1374   begin
1375    result:=path_cmd_stop;
1376 
1377    exit;
1378 
1379   end;
1380 
1381  p:=m_points.array_operator(m_count );
1382 
1383  inc(m_count );
1384 
1385  x^:=p.x;
1386  y^:=p.y;
1387 
1388  if m_count = 1 then
1389   result:=path_cmd_move_to
1390  else
1391   result:=path_cmd_line_to;
1392 
1393 end;
1394 
1395 { BEZIER }
1396 procedure curve4_div.bezier;
1397 var
1398  pt : point_type;
1399 
1400 begin
1401  pt.x:=x1;
1402  pt.y:=y1;
1403 
1404  m_points.add(@pt );
1405 
1406  recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 ,0 );
1407 
1408  pt.x:=x4;
1409  pt.y:=y4;
1410 
1411  m_points.add(@pt );
1412 
1413 end;
1414 
1415 { RECURSIVE_BEZIER }
1416 procedure curve4_div.recursive_bezier;
1417 var
1418  x12 ,y12 ,x23 ,y23 ,x34 ,y34 ,x123 ,y123 ,x234 ,y234 ,x1234 ,y1234 ,
1419 
1420  dx ,dy ,d2 ,d3 ,da1 ,da2 ,a23 : double;
1421 
1422  pt : point_type;
1423 
1424 begin
1425  if level > curve_recursion_limit then
1426   exit;
1427 
1428 // Calculate all the mid-points of the line segments
1429  x12  :=(x1 + x2 ) / 2;
1430  y12  :=(y1 + y2 ) / 2;
1431  x23  :=(x2 + x3 ) / 2;
1432  y23  :=(y2 + y3 ) / 2;
1433  x34  :=(x3 + x4 ) / 2;
1434  y34  :=(y3 + y4 ) / 2;
1435  x123 :=(x12 + x23 ) / 2;
1436  y123 :=(y12 + y23 ) / 2;
1437  x234 :=(x23 + x34 ) / 2;
1438  y234 :=(y23 + y34 ) / 2;
1439  x1234:=(x123 + x234 ) / 2;
1440  y1234:=(y123 + y234 ) / 2;
1441 
1442 // Try to approximate the full cubic curve by a single straight line
1443  dx:=x4 - x1;
1444  dy:=y4 - y1;
1445 
1446  d2:=Abs((x2 - x4 ) * dy - (y2 - y4 ) * dx );
1447  d3:=Abs((x3 - x4 ) * dy - (y3 - y4 ) * dx );
1448 
1449  case ((int(d2 > curve_collinearity_epsilon) shl 1 ) +
1450         int(d3 > curve_collinearity_epsilon ) ) of
1451   // All collinear OR p1==p4
1452   0 :
1453    if Abs(x1 + x3 - x2 - x2 ) +
1454       Abs(y1 + y3 - y2 - y2 ) +
1455       Abs(x2 + x4 - x3 - x3 ) +
1456       Abs(y2 + y4 - y3 - y3 ) <= m_distance_tolerance_manhattan then
1457     begin
1458      pt.x:=x1234;
1459      pt.y:=y1234;
1460 
1461      m_points.add(@pt );
1462 
1463      exit;
1464 
1465     end;
1466 
1467   // p1,p2,p4 are collinear, p3 is considerable
1468   1 :
1469    if d3 * d3 <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
1470     begin
1471      if m_angle_tolerance < curve_angle_tolerance_epsilon then
1472       begin
1473        pt.x:=x23;
1474        pt.y:=y23;
1475 
1476        m_points.add(@pt );
1477 
1478        exit;
1479 
1480       end;
1481 
1482     // Angle Condition
1483      da1:=Abs(ArcTan2(y4 - y3 ,x4 - x3 ) - ArcTan2(y3 - y2 ,x3 - x2 ) );
1484 
1485      if da1 >= pi then
1486       da1:=2 * pi - da1;
1487 
1488      if da1 < m_angle_tolerance then
1489       begin
1490        pt.x:=x2;
1491        pt.y:=y2;
1492 
1493        m_points.add(@pt );
1494 
1495        pt.x:=x3;
1496        pt.y:=y3;
1497 
1498        m_points.add(@pt );
1499 
1500        exit;
1501 
1502       end;
1503 
1504      if m_cusp_limit <> 0.0 then
1505       if da1 > m_cusp_limit then
1506        begin
1507         pt.x:=x3;
1508         pt.y:=y3;
1509 
1510         m_points.add(@pt );
1511 
1512         exit;
1513 
1514        end;
1515 
1516     end;
1517 
1518   // p1,p3,p4 are collinear, p2 is considerable
1519   2 :
1520    if d2 * d2 <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
1521     begin
1522      if m_angle_tolerance < curve_angle_tolerance_epsilon then
1523       begin
1524        pt.x:=x23;
1525        pt.y:=y23;
1526 
1527        m_points.add(@pt );
1528 
1529        exit;
1530 
1531       end;
1532 
1533     // Angle Condition
1534      da1:=Abs(ArcTan2(y3 - y2 ,x3 - x2 ) - ArcTan2(y2 - y1 ,x2 - x1 ) );
1535 
1536      if da1 >= pi then
1537       da1:=2 * pi - da1;
1538 
1539      if da1 < m_angle_tolerance then
1540       begin
1541        pt.x:=x2;
1542        pt.y:=y2;
1543 
1544        m_points.add(@pt );
1545 
1546        pt.x:=x3;
1547        pt.y:=y3;
1548 
1549        m_points.add(@pt );
1550 
1551        exit;
1552 
1553       end;
1554 
1555      if m_cusp_limit <> 0.0 then
1556       if da1 > m_cusp_limit then
1557        begin
1558         pt.x:=x2;
1559         pt.y:=y2;
1560 
1561         m_points.add(@pt );
1562 
1563         exit;
1564 
1565        end;
1566 
1567     end;
1568 
1569   // Regular care
1570   3 :
1571    if (d2 + d3 ) * (d2 + d3 ) <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
1572     begin
1573     // If the curvature doesn't exceed the distance_tolerance value
1574     // we tend to finish subdivisions.
1575      if m_angle_tolerance < curve_angle_tolerance_epsilon then
1576       begin
1577        pt.x:=x23;
1578        pt.y:=y23;
1579 
1580        m_points.add(@pt );
1581 
1582        exit;
1583 
1584       end;
1585 
1586     // Angle & Cusp Condition
1587      a23:=ArcTan2(y3 - y2 ,x3 - x2 );
1588      da1:=Abs(a23 - ArcTan2(y2 - y1 ,x2 - x1 ) );
1589      da2:=Abs(ArcTan2(y4 - y3 ,x4 - x3 ) - a23 );
1590 
1591      if da1 >= pi then
1592       da1:=2 * pi - da1;
1593 
1594      if da2 >= pi then
1595       da2:=2 * pi - da2;
1596 
1597      if da1 + da2 < m_angle_tolerance then
1598       begin
1599       // Finally we can stop the recursion
1600        pt.x:=x23;
1601        pt.y:=y23;
1602 
1603        m_points.add(@pt );
1604 
1605        exit;
1606 
1607       end;
1608 
1609      if m_cusp_limit <> 0.0 then
1610       begin
1611        if da1 > m_cusp_limit then
1612         begin
1613          pt.x:=x2;
1614          pt.y:=y2;
1615 
1616          m_points.add(@pt );
1617 
1618          exit;
1619 
1620         end;
1621 
1622        if da2 > m_cusp_limit then
1623         begin
1624          pt.x:=x3;
1625          pt.y:=y3;
1626 
1627          m_points.add(@pt );
1628 
1629          exit;
1630 
1631         end;
1632 
1633       end;
1634 
1635     end;
1636 
1637  end;
1638 
1639 // Continue subdivision
1640  recursive_bezier(x1    ,y1    ,x12  ,y12  ,x123 ,y123 ,x1234 ,y1234 ,level + 1 );
1641  recursive_bezier(x1234 ,y1234 ,x234 ,y234 ,x34  ,y34  ,x4    ,y4    ,level + 1 );
1642 
1643 end;
1644 
1645 { CONSTRUCT }
1646 constructor curve3.Construct;
1647 begin
1648  m_curve_inc.Construct;
1649  m_curve_div.Construct;
1650 
1651  m_approximation_method:=curve_div;
1652 
1653 end;
1654 
1655 { CONSTRUCT }
1656 constructor curve3.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
1657 begin
1658  m_curve_inc.Construct;
1659  m_curve_div.Construct;
1660 
1661  m_approximation_method:=curve_div;
1662 
1663  init3(x1 ,y1 ,x2, y2 ,x3 ,y3 );
1664 
1665 end;
1666 
1667 { DESTRUCT }
1668 destructor curve3.Destruct;
1669 begin
1670  m_curve_div.Destruct;
1671 
1672 end;
1673 
1674 { RESET }
1675 procedure curve3.reset;
1676 begin
1677  m_curve_inc.reset;
1678  m_curve_div.reset;
1679 
1680 end;
1681 
1682 { INIT3 }
1683 procedure curve3.init3;
1684 begin
1685  if m_approximation_method = curve_inc then
1686   m_curve_inc.init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 )
1687  else
1688   m_curve_div.init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
1689 
1690 end;
1691 
1692 { APPROXIMATION_METHOD_ }
1693 procedure curve3.approximation_method_;
1694 begin
1695  m_approximation_method:=v;
1696 
1697 end;
1698 
1699 { _APPROXIMATION_METHOD }
curve3._approximation_methodnull1700 function curve3._approximation_method;
1701 begin
1702  result:=m_approximation_method;
1703 
1704 end;
1705 
1706 { APPROXIMATION_SCALE_ }
1707 procedure curve3.approximation_scale_;
1708 begin
1709  m_curve_inc.approximation_scale_(s );
1710  m_curve_div.approximation_scale_(s );
1711 
1712 end;
1713 
1714 { _APPROXIMATION_SCALE }
curve3._approximation_scalenull1715 function curve3._approximation_scale;
1716 begin
1717  result:=m_curve_inc._approximation_scale;
1718 
1719 end;
1720 
1721 { ANGLE_TOLERANCE_ }
1722 procedure curve3.angle_tolerance_;
1723 begin
1724  m_curve_div.angle_tolerance_(a );
1725 
1726 end;
1727 
1728 { _ANGLE_TOLERANCE }
curve3._angle_tolerancenull1729 function curve3._angle_tolerance;
1730 begin
1731  result:=m_curve_div._angle_tolerance;
1732 
1733 end;
1734 
1735 { CUSP_LIMIT_ }
1736 procedure curve3.cusp_limit_;
1737 begin
1738  m_curve_div.cusp_limit_(v );
1739 
1740 end;
1741 
1742 { _CUSP_LIMIT }
curve3._cusp_limitnull1743 function curve3._cusp_limit;
1744 begin
1745  result:=m_curve_div._cusp_limit;
1746 
1747 end;
1748 
1749 { REWIND }
1750 procedure curve3.rewind;
1751 begin
1752  if m_approximation_method = curve_inc then
1753   m_curve_inc.rewind(path_id )
1754  else
1755   m_curve_div.rewind(path_id )
1756 
1757 end;
1758 
1759 { VERTEX }
curve3.vertexnull1760 function curve3.vertex;
1761 begin
1762  if m_approximation_method = curve_inc then
1763   result:=m_curve_inc.vertex(x ,y )
1764  else
1765   result:=m_curve_div.vertex(x ,y );
1766 
1767 end;
1768 
1769 { CONSTRUCT }
1770 constructor curve4.Construct;
1771 begin
1772  m_curve_inc.Construct;
1773  m_curve_div.Construct;
1774 
1775  m_approximation_method:=curve_div;
1776 
1777 end;
1778 
1779 { CONSTRUCT }
1780 constructor curve4.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
1781 begin
1782  m_curve_inc.Construct;
1783  m_curve_div.Construct;
1784 
1785  m_approximation_method:=curve_div;
1786 
1787  init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
1788 
1789 end;
1790 
1791 { CONSTRUCT }
1792 constructor curve4.Construct(cp : curve4_points_ptr );
1793 begin
1794  m_curve_inc.Construct;
1795  m_curve_div.Construct;
1796 
1797  m_approximation_method:=curve_div;
1798 
1799  init4(
1800   cp.array_operator(0 ) ,
1801   cp.array_operator(1 ) ,
1802   cp.array_operator(2 ) ,
1803   cp.array_operator(3 ) ,
1804   cp.array_operator(4 ) ,
1805   cp.array_operator(5 ) ,
1806   cp.array_operator(6 ) ,
1807   cp.array_operator(7 ) );
1808 
1809 end;
1810 
1811 { DESTRUCT }
1812 destructor curve4.Destruct;
1813 begin
1814  m_curve_div.Destruct;
1815 
1816 end;
1817 
1818 { RESET }
1819 procedure curve4.reset;
1820 begin
1821  m_curve_inc.reset;
1822  m_curve_div.reset;
1823 
1824 end;
1825 
1826 { INIT4 }
1827 procedure curve4.init4;
1828 begin
1829  if m_approximation_method = curve_inc then
1830   m_curve_inc.init4(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 )
1831  else
1832   m_curve_div.init4(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 );
1833 
1834 end;
1835 
1836 { INIT }
1837 procedure curve4.init;
1838 begin
1839  init4(
1840   cp.array_operator(0 ) ,
1841   cp.array_operator(1 ) ,
1842   cp.array_operator(2 ) ,
1843   cp.array_operator(3 ) ,
1844   cp.array_operator(4 ) ,
1845   cp.array_operator(5 ) ,
1846   cp.array_operator(6 ) ,
1847   cp.array_operator(7 ) );
1848 
1849 end;
1850 
1851 { APPROXIMATION_METHOD_ }
1852 procedure curve4.approximation_method_;
1853 begin
1854  m_approximation_method:=v;
1855 
1856 end;
1857 
1858 { _APPROXIMATION_METHOD }
curve4._approximation_methodnull1859 function curve4._approximation_method;
1860 begin
1861  result:=m_approximation_method;
1862 
1863 end;
1864 
1865 { APPROXIMATION_SCALE_ }
1866 procedure curve4.approximation_scale_;
1867 begin
1868  m_curve_inc.approximation_scale_(s );
1869  m_curve_div.approximation_scale_(s );
1870 
1871 end;
1872 
1873 { _APPROXIMATION_SCALE }
curve4._approximation_scalenull1874 function curve4._approximation_scale;
1875 begin
1876  result:=m_curve_inc._approximation_scale;
1877 
1878 end;
1879 
1880 { ANGLE_TOLERANCE_ }
1881 procedure curve4.angle_tolerance_;
1882 begin
1883  m_curve_div.angle_tolerance_(a );
1884 
1885 end;
1886 
1887 { _ANGLE_TOLERANCE }
curve4._angle_tolerancenull1888 function curve4._angle_tolerance;
1889 begin
1890  result:=m_curve_div._angle_tolerance;
1891 
1892 end;
1893 
1894 { CUSP_LIMIT_ }
1895 procedure curve4.cusp_limit_;
1896 begin
1897  m_curve_div.cusp_limit_(v );
1898 
1899 end;
1900 
1901 { _CUSP_LIMIT }
curve4._cusp_limitnull1902 function curve4._cusp_limit;
1903 begin
1904  result:=m_curve_div._cusp_limit;
1905 
1906 end;
1907 
1908 { REWIND }
1909 procedure curve4.rewind;
1910 begin
1911  if m_approximation_method = curve_inc then
1912   m_curve_inc.rewind(path_id )
1913  else
1914   m_curve_div.rewind(path_id );
1915 
1916 end;
1917 
1918 { VERTEX }
curve4.vertexnull1919 function curve4.vertex;
1920 begin
1921  if m_approximation_method = curve_inc then
1922   result:=m_curve_inc.vertex(x ,y )
1923  else
1924   result:=m_curve_div.vertex(x ,y );
1925 
1926 end;
1927 
1928 END.
1929 
1930