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