mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-10 03:12:39 +02:00
1930 lines
35 KiB
ObjectPascal
1930 lines
35 KiB
ObjectPascal
//----------------------------------------------------------------------------
|
|
// Anti-Grain Geometry - Version 2.4 (Public License)
|
|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
|
// Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com)
|
|
//
|
|
// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
|
|
// Pascal Port By: Milan Marusinec alias Milano
|
|
// milan@marusinec.sk
|
|
// http://www.aggpas.org
|
|
// Copyright (c) 2005-2006
|
|
//
|
|
// Permission to copy, use, modify, sell and distribute this software
|
|
// is granted provided this copyright notice appears in all copies.
|
|
// This software is provided "as is" without express or implied
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// Contact: mcseem@antigrain.com
|
|
// mcseemagg@yahoo.com
|
|
// http://www.antigrain.com
|
|
//
|
|
// [Pascal Port History] -----------------------------------------------------
|
|
//
|
|
// 12.02.2006-Milano: Unit port establishment
|
|
//
|
|
{ agg_curves.pas }
|
|
unit
|
|
agg_curves ;
|
|
|
|
INTERFACE
|
|
|
|
{$I agg_mode.inc }
|
|
|
|
uses
|
|
Math ,
|
|
agg_basics ,
|
|
agg_array ,
|
|
agg_vertex_source ;
|
|
|
|
{ TYPES DEFINITION }
|
|
type
|
|
curve_approximation_method_e = (curve_inc ,curve_div );
|
|
|
|
curve_ptr = ^curve;
|
|
curve = object(vertex_source )
|
|
procedure reset; virtual; abstract;
|
|
procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
|
|
procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual; abstract;
|
|
function _approximation_method : curve_approximation_method_e; virtual; abstract;
|
|
|
|
procedure approximation_scale_(s : double ); virtual; abstract;
|
|
function _approximation_scale : double; virtual; abstract;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual; abstract;
|
|
function _angle_tolerance : double; virtual; abstract;
|
|
|
|
procedure cusp_limit_(v : double ); virtual; abstract;
|
|
function _cusp_limit : double; virtual; abstract;
|
|
|
|
end;
|
|
|
|
curve3_inc = object(curve )
|
|
m_num_steps ,
|
|
m_step : int;
|
|
|
|
m_scale ,
|
|
m_start_x ,
|
|
m_start_y ,
|
|
m_end_x ,
|
|
m_end_y ,
|
|
|
|
m_fx ,
|
|
m_fy ,
|
|
m_dfx ,
|
|
m_dfy ,
|
|
m_ddfx ,
|
|
m_ddfy ,
|
|
|
|
m_saved_fx ,
|
|
m_saved_fy ,
|
|
m_saved_dfx ,
|
|
m_saved_dfy : double;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
|
|
|
|
procedure reset; virtual;
|
|
procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
end;
|
|
|
|
curve3_div = object(curve )
|
|
m_approximation_scale ,
|
|
m_distance_tolerance_square ,
|
|
m_distance_tolerance_manhattan ,
|
|
m_angle_tolerance : double;
|
|
|
|
m_count : unsigned;
|
|
m_points : pod_deque;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
|
|
destructor Destruct; virtual;
|
|
|
|
procedure reset; virtual;
|
|
procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
procedure bezier (x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double );
|
|
procedure recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double; level : unsigned );
|
|
|
|
end;
|
|
|
|
curve4_points_ptr = ^curve4_points;
|
|
curve4_points = object
|
|
cp : array[0..7 ] of double;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
|
|
|
|
procedure init(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
|
|
function array_operator (i : unsigned ) : double;
|
|
function array_operator_ptr(i : unsigned ) : double_ptr;
|
|
|
|
end;
|
|
|
|
curve4_inc = object(curve )
|
|
m_num_steps ,
|
|
m_step : int;
|
|
|
|
m_scale ,
|
|
m_start_x ,
|
|
m_start_y ,
|
|
m_end_x ,
|
|
m_end_y ,
|
|
|
|
m_fx ,
|
|
m_fy ,
|
|
m_dfx ,
|
|
m_dfy ,
|
|
m_ddfx ,
|
|
m_ddfy ,
|
|
m_dddfx ,
|
|
m_dddfy ,
|
|
|
|
m_saved_fx ,
|
|
m_saved_fy ,
|
|
m_saved_dfx ,
|
|
m_saved_dfy ,
|
|
m_saved_ddfx ,
|
|
m_saved_ddfy : double;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
|
|
constructor Construct(cp : curve4_points_ptr ); overload;
|
|
|
|
procedure reset; virtual;
|
|
procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
|
|
procedure init (cp : curve4_points_ptr );
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
end;
|
|
|
|
curve4_div = object(curve )
|
|
m_approximation_scale ,
|
|
m_distance_tolerance_square ,
|
|
m_distance_tolerance_manhattan ,
|
|
|
|
m_angle_tolerance ,
|
|
m_cusp_limit : double;
|
|
|
|
m_count : unsigned;
|
|
m_points : pod_deque;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
|
|
constructor Construct(cp : curve4_points_ptr ); overload;
|
|
destructor Destruct; virtual;
|
|
|
|
procedure reset; virtual;
|
|
procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
|
|
procedure init (cp : curve4_points_ptr );
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
procedure bezier (x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
procedure recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double; level : unsigned );
|
|
|
|
end;
|
|
|
|
curve3_ptr = ^curve3;
|
|
curve3 = object(curve )
|
|
m_curve_inc : curve3_inc;
|
|
m_curve_div : curve3_div;
|
|
|
|
m_approximation_method : curve_approximation_method_e;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); overload;
|
|
destructor Destruct; virtual;
|
|
|
|
procedure reset; virtual;
|
|
procedure init3(x1 ,y1 ,x2, y2 ,x3 ,y3 : double ); virtual;
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
end;
|
|
|
|
curve4_ptr = ^curve4;
|
|
curve4 = object(curve )
|
|
m_curve_inc : curve4_inc;
|
|
m_curve_div : curve4_div;
|
|
|
|
m_approximation_method : curve_approximation_method_e;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); overload;
|
|
constructor Construct(cp : curve4_points_ptr ); overload;
|
|
destructor Destruct; virtual;
|
|
|
|
procedure reset; virtual;
|
|
procedure init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double ); virtual;
|
|
procedure init (cp : curve4_points_ptr );
|
|
|
|
procedure approximation_method_(v : curve_approximation_method_e ); virtual;
|
|
function _approximation_method : curve_approximation_method_e; virtual;
|
|
|
|
procedure approximation_scale_(s : double ); virtual;
|
|
function _approximation_scale : double; virtual;
|
|
|
|
procedure angle_tolerance_(a : double ); virtual;
|
|
function _angle_tolerance : double; virtual;
|
|
|
|
procedure cusp_limit_(v : double ); virtual;
|
|
function _cusp_limit : double; virtual;
|
|
|
|
procedure rewind(path_id : unsigned ); virtual;
|
|
function vertex(x ,y : double_ptr ) : unsigned; virtual;
|
|
|
|
end;
|
|
|
|
{ GLOBAL PROCEDURES }
|
|
function catrom_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
|
|
function catrom_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
|
|
|
|
function ubspline_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
|
|
function ubspline_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
|
|
|
|
function hermite_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points; overload;
|
|
function hermite_to_bezier(cp : curve4_points_ptr ) : curve4_points; overload;
|
|
|
|
|
|
IMPLEMENTATION
|
|
{ LOCAL VARIABLES & CONSTANTS }
|
|
const
|
|
curve_distance_epsilon = 1e-30;
|
|
curve_collinearity_epsilon = 1e-30;
|
|
curve_angle_tolerance_epsilon = 0.01;
|
|
curve_recursion_limit = 32;
|
|
|
|
{ UNIT IMPLEMENTATION }
|
|
{ CATROM_TO_BEZIER }
|
|
function catrom_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
|
|
begin
|
|
// Trans. matrix Catmull-Rom to Bezier
|
|
//
|
|
// 0 1 0 0
|
|
// -1/6 1 1/6 0
|
|
// 0 1/6 1 -1/6
|
|
// 0 0 1 0
|
|
//
|
|
result.Construct(
|
|
x2 ,
|
|
y2 ,
|
|
(-x1 + 6 * x2 + x3 ) / 6 ,
|
|
(-y1 + 6 * y2 + y3 ) / 6 ,
|
|
( x2 + 6 * x3 - x4 ) / 6 ,
|
|
( y2 + 6 * y3 - y4 ) / 6 ,
|
|
x3 ,
|
|
y3 );
|
|
|
|
end;
|
|
|
|
{ CATROM_TO_BEZIER }
|
|
function catrom_to_bezier(cp : curve4_points_ptr ) : curve4_points;
|
|
begin
|
|
result:=
|
|
catrom_to_bezier(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ UBSPLINE_TO_BEZIER }
|
|
function ubspline_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
|
|
begin
|
|
// Trans. matrix Uniform BSpline to Bezier
|
|
//
|
|
// 1/6 4/6 1/6 0
|
|
// 0 4/6 2/6 0
|
|
// 0 2/6 4/6 0
|
|
// 0 1/6 4/6 1/6
|
|
//
|
|
result.Construct(
|
|
(x1 + 4 * x2 + x3 ) / 6 ,
|
|
(y1 + 4 * y2 + y3 ) / 6 ,
|
|
(4 * x2 + 2 * x3 ) / 6 ,
|
|
(4 * y2 + 2 * y3 ) / 6 ,
|
|
(2 * x2 + 4 * x3 ) / 6 ,
|
|
(2 * y2 + 4 * y3 ) / 6 ,
|
|
(x2 + 4 * x3 + x4 ) / 6 ,
|
|
(y2 + 4 * y3 + y4 ) / 6 );
|
|
|
|
end;
|
|
|
|
{ UBSPLINE_TO_BEZIER }
|
|
function ubspline_to_bezier(cp : curve4_points_ptr ) : curve4_points;
|
|
begin
|
|
result:=
|
|
ubspline_to_bezier(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ HERMITE_TO_BEZIER }
|
|
function hermite_to_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ) : curve4_points;
|
|
begin
|
|
// Trans. matrix Hermite to Bezier
|
|
//
|
|
// 1 0 0 0
|
|
// 1 0 1/3 0
|
|
// 0 1 0 -1/3
|
|
// 0 1 0 0
|
|
//
|
|
result.Construct(
|
|
x1 ,
|
|
y1 ,
|
|
(3 * x1 + x3 ) / 3 ,
|
|
(3 * y1 + y3 ) / 3 ,
|
|
(3 * x2 - x4 ) / 3 ,
|
|
(3 * y2 - y4 ) / 3 ,
|
|
x2 ,
|
|
y2 );
|
|
|
|
end;
|
|
|
|
{ HERMITE_TO_BEZIER }
|
|
function hermite_to_bezier(cp : curve4_points_ptr ) : curve4_points;
|
|
begin
|
|
result:=
|
|
hermite_to_bezier(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ INIT3 }
|
|
procedure curve.init3;
|
|
begin
|
|
end;
|
|
|
|
{ INIT4 }
|
|
procedure curve.init4;
|
|
begin
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3_inc.Construct;
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=0;
|
|
m_scale :=1.0;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3_inc.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=0;
|
|
m_scale :=1.0;
|
|
|
|
init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve3_inc.reset;
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=-1;
|
|
|
|
end;
|
|
|
|
{ INIT3 }
|
|
procedure curve3_inc.init3;
|
|
var
|
|
dx1 ,dy1 ,dx2 ,dy2 ,len ,tmpx ,tmpy ,
|
|
subdivide_step ,subdivide_step2 : double;
|
|
|
|
begin
|
|
m_start_x:=x1;
|
|
m_start_y:=y1;
|
|
m_end_x :=x3;
|
|
m_end_y :=y3;
|
|
|
|
dx1:=x2 - x1;
|
|
dy1:=y2 - y1;
|
|
dx2:=x3 - x2;
|
|
dy2:=y3 - y2;
|
|
|
|
len:=Sqrt(dx1 * dx1 + dy1 * dy1 ) + Sqrt(dx2 * dx2 + dy2 * dy2 );
|
|
|
|
m_num_steps:=trunc(len * 0.25 * m_scale );
|
|
|
|
if m_num_steps < 4 then
|
|
m_num_steps:=4;
|
|
|
|
subdivide_step :=1.0 / m_num_steps;
|
|
subdivide_step2:=subdivide_step * subdivide_step;
|
|
|
|
tmpx:=(x1 - x2 * 2.0 + x3 ) * subdivide_step2;
|
|
tmpy:=(y1 - y2 * 2.0 + y3 ) * subdivide_step2;
|
|
|
|
m_saved_fx:=x1;
|
|
m_fx :=x1;
|
|
m_saved_fy:=y1;
|
|
m_fy :=y1;
|
|
|
|
m_saved_dfx:=tmpx + (x2 - x1 ) * (2.0 * subdivide_step );
|
|
m_dfx :=m_saved_dfx;
|
|
m_saved_dfy:=tmpy + (y2 - y1 ) * (2.0 * subdivide_step );
|
|
m_dfy :=m_saved_dfy;
|
|
|
|
m_ddfx:=tmpx * 2.0;
|
|
m_ddfy:=tmpy * 2.0;
|
|
|
|
m_step:=m_num_steps;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve3_inc.approximation_method_;
|
|
begin
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve3_inc._approximation_method;
|
|
begin
|
|
result:=curve_inc;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve3_inc.approximation_scale_;
|
|
begin
|
|
m_scale:=s;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve3_inc._approximation_scale;
|
|
begin
|
|
result:=m_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve3_inc.angle_tolerance_;
|
|
begin
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve3_inc._angle_tolerance;
|
|
begin
|
|
result:=0.0;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve3_inc.cusp_limit_;
|
|
begin
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve3_inc._cusp_limit;
|
|
begin
|
|
result:=0.0;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve3_inc.rewind;
|
|
begin
|
|
if m_num_steps = 0 then
|
|
begin
|
|
m_step:=-1;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
m_step:=m_num_steps;
|
|
m_fx :=m_saved_fx;
|
|
m_fy :=m_saved_fy;
|
|
m_dfx :=m_saved_dfx;
|
|
m_dfy :=m_saved_dfy;
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve3_inc.vertex;
|
|
begin
|
|
if m_step < 0 then
|
|
begin
|
|
result:=path_cmd_stop;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_step = m_num_steps then
|
|
begin
|
|
x^:=m_start_x;
|
|
y^:=m_start_y;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_move_to;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_step = 0 then
|
|
begin
|
|
x^:=m_end_x;
|
|
y^:=m_end_y;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_line_to;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
m_fx :=m_fx + m_dfx;
|
|
m_fy :=m_fy + m_dfy;
|
|
m_dfx:=m_dfx + m_ddfx;
|
|
m_dfy:=m_dfy + m_ddfy;
|
|
|
|
x^:=m_fx;
|
|
y^:=m_fy;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_line_to;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3_div.Construct;
|
|
begin
|
|
m_points.Construct(sizeof(point_type ) );
|
|
|
|
m_approximation_scale:=1.0;
|
|
m_angle_tolerance :=0.0;
|
|
m_count :=0;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3_div.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
|
|
begin
|
|
m_points.Construct(sizeof(point_type ) );
|
|
|
|
m_approximation_scale:=1.0;
|
|
m_angle_tolerance :=0.0;
|
|
m_count :=0;
|
|
|
|
init3(x1 ,y1 ,x2, y2 ,x3 ,y3 );
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor curve3_div.Destruct;
|
|
begin
|
|
m_points.Destruct;
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve3_div.reset;
|
|
begin
|
|
m_points.remove_all;
|
|
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ INIT3 }
|
|
procedure curve3_div.init3;
|
|
begin
|
|
m_points.remove_all;
|
|
|
|
m_distance_tolerance_square :=0.5 / m_approximation_scale;
|
|
m_distance_tolerance_square :=m_distance_tolerance_square * m_distance_tolerance_square;
|
|
m_distance_tolerance_manhattan:=4.0 / m_approximation_scale;
|
|
|
|
bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
|
|
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve3_div.approximation_method_;
|
|
begin
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve3_div._approximation_method;
|
|
begin
|
|
result:=curve_div;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve3_div.approximation_scale_;
|
|
begin
|
|
if s = 0 then
|
|
m_approximation_scale:=0.00001
|
|
else
|
|
m_approximation_scale:=s;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve3_div._approximation_scale;
|
|
begin
|
|
result:=m_approximation_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve3_div.angle_tolerance_;
|
|
begin
|
|
m_angle_tolerance:=a;
|
|
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve3_div._angle_tolerance;
|
|
begin
|
|
result:=m_angle_tolerance;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve3_div.cusp_limit_;
|
|
begin
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve3_div._cusp_limit;
|
|
begin
|
|
result:=0.0;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve3_div.rewind;
|
|
begin
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve3_div.vertex;
|
|
var
|
|
p : point_type_ptr;
|
|
|
|
begin
|
|
if m_count >= m_points.size then
|
|
begin
|
|
result:=path_cmd_stop;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
p:=m_points.array_operator(m_count );
|
|
|
|
inc(m_count );
|
|
|
|
x^:=p.x;
|
|
y^:=p.y;
|
|
|
|
if m_count = 1 then
|
|
result:=path_cmd_move_to
|
|
else
|
|
result:=path_cmd_line_to;
|
|
|
|
end;
|
|
|
|
{ BEZIER }
|
|
procedure curve3_div.bezier;
|
|
var
|
|
pt : point_type;
|
|
|
|
begin
|
|
pt.x:=x1;
|
|
pt.y:=y1;
|
|
|
|
m_points.add(@pt );
|
|
|
|
recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,0 );
|
|
|
|
pt.x:=x3;
|
|
pt.y:=y3;
|
|
|
|
m_points.add(@pt );
|
|
|
|
end;
|
|
|
|
{ RECURSIVE_BEZIER }
|
|
procedure curve3_div.recursive_bezier;
|
|
var
|
|
x12 ,y12 ,x23 ,y23 ,x123 ,y123 ,dx ,dy ,d ,da : double;
|
|
|
|
pt : point_type;
|
|
|
|
begin
|
|
if level > curve_recursion_limit then
|
|
exit;
|
|
|
|
// Calculate all the mid-points of the line segments
|
|
x12 :=(x1 + x2 ) / 2;
|
|
y12 :=(y1 + y2 ) / 2;
|
|
x23 :=(x2 + x3 ) / 2;
|
|
y23 :=(y2 + y3 ) / 2;
|
|
x123:=(x12 + x23 ) / 2;
|
|
y123:=(y12 + y23 ) / 2;
|
|
|
|
dx:=x3 - x1;
|
|
dy:=y3 - y1;
|
|
d :=Abs((x2 - x3 ) * dy - (y2 - y3 ) * dx );
|
|
|
|
if d > curve_collinearity_epsilon then
|
|
// Regular care
|
|
if d * d <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
|
|
begin
|
|
// If the curvature doesn't exceed the distance_tolerance value
|
|
// we tend to finish subdivisions.
|
|
if m_angle_tolerance < curve_angle_tolerance_epsilon then
|
|
begin
|
|
pt.x:=x123;
|
|
pt.y:=y123;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Angle & Cusp Condition
|
|
da:=Abs(ArcTan2(y3 - y2 ,x3 - x2 ) - ArcTan2(y2 - y1 ,x2 - x1 ) );
|
|
|
|
if da >= pi then
|
|
da:=2 * pi - da;
|
|
|
|
if da < m_angle_tolerance then
|
|
begin
|
|
// Finally we can stop the recursion
|
|
pt.x:=x123;
|
|
pt.y:=y123;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end
|
|
else
|
|
else
|
|
if Abs(x1 + x3 - x2 - x2 ) + Abs(y1 + y3 - y2 - y2 ) <= m_distance_tolerance_manhattan then
|
|
begin
|
|
pt.x:=x123;
|
|
pt.y:=y123;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Continue subdivision
|
|
recursive_bezier(x1 ,y1 ,x12 ,y12 ,x123 ,y123 ,level + 1 );
|
|
recursive_bezier(x123 ,y123 ,x23 ,y23 ,x3 ,y3 ,level + 1 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_points.Construct;
|
|
begin
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_points.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
begin
|
|
cp[0 ]:=x1;
|
|
cp[1 ]:=y1;
|
|
cp[2 ]:=x2;
|
|
cp[3 ]:=y2;
|
|
cp[4 ]:=x3;
|
|
cp[5 ]:=y3;
|
|
cp[6 ]:=x4;
|
|
cp[7 ]:=y4;
|
|
|
|
end;
|
|
|
|
{ INIT }
|
|
procedure curve4_points.init;
|
|
begin
|
|
cp[0 ]:=x1;
|
|
cp[1 ]:=y1;
|
|
cp[2 ]:=x2;
|
|
cp[3 ]:=y2;
|
|
cp[4 ]:=x3;
|
|
cp[5 ]:=y3;
|
|
cp[6 ]:=x4;
|
|
cp[7 ]:=y4;
|
|
|
|
end;
|
|
|
|
{ ARRAY_OPERATOR }
|
|
function curve4_points.array_operator;
|
|
begin
|
|
result:=cp[i ];
|
|
|
|
end;
|
|
|
|
{ ARRAY_OPERATOR_PTR }
|
|
function curve4_points.array_operator_ptr;
|
|
begin
|
|
result:=@cp[i ];
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_inc.Construct;
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=0;
|
|
m_scale :=1.0;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_inc.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=0;
|
|
m_scale :=1.0;
|
|
|
|
init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_inc.Construct(cp : curve4_points_ptr );
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=0;
|
|
m_scale :=1.0;
|
|
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve4_inc.reset;
|
|
begin
|
|
m_num_steps:=0;
|
|
m_step :=-1;
|
|
|
|
end;
|
|
|
|
{ INIT4 }
|
|
procedure curve4_inc.init4;
|
|
var
|
|
dx1 ,dy1 ,dx2 ,dy2 ,dx3 ,dy3 ,len ,
|
|
|
|
subdivide_step ,
|
|
subdivide_step2 ,
|
|
subdivide_step3 ,
|
|
|
|
pre1 ,pre2 ,pre4 ,pre5 ,tmp1x ,tmp1y ,tmp2x ,tmp2y : double;
|
|
|
|
begin
|
|
m_start_x:=x1;
|
|
m_start_y:=y1;
|
|
m_end_x :=x4;
|
|
m_end_y :=y4;
|
|
|
|
dx1:=x2 - x1;
|
|
dy1:=y2 - y1;
|
|
dx2:=x3 - x2;
|
|
dy2:=y3 - y2;
|
|
dx3:=x4 - x3;
|
|
dy3:=y4 - y3;
|
|
|
|
len:=
|
|
Sqrt(dx1 * dx1 + dy1 * dy1 ) +
|
|
Sqrt(dx2 * dx2 + dy2 * dy2 ) +
|
|
Sqrt(dx3 * dx3 + dy3 * dy3 );
|
|
|
|
m_num_steps:=trunc(len * 0.25 * m_scale );
|
|
|
|
if m_num_steps < 4 then
|
|
m_num_steps:=4;
|
|
|
|
subdivide_step :=1.0 / m_num_steps;
|
|
subdivide_step2:=subdivide_step * subdivide_step;
|
|
subdivide_step3:=subdivide_step * subdivide_step * subdivide_step;
|
|
|
|
pre1:=3.0 * subdivide_step;
|
|
pre2:=3.0 * subdivide_step2;
|
|
pre4:=6.0 * subdivide_step2;
|
|
pre5:=6.0 * subdivide_step3;
|
|
|
|
tmp1x:=x1 - x2 * 2.0 + x3;
|
|
tmp1y:=y1 - y2 * 2.0 + y3;
|
|
|
|
tmp2x:=(x2 - x3 ) * 3.0 - x1 + x4;
|
|
tmp2y:=(y2 - y3 ) * 3.0 - y1 + y4;
|
|
|
|
m_saved_fx:=x1;
|
|
m_fx :=x1;
|
|
m_saved_fy:=y1;
|
|
m_fy :=y1;
|
|
|
|
m_saved_dfx:=(x2 - x1 ) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3;
|
|
m_dfx :=m_saved_dfx;
|
|
m_saved_dfy:=(y2 - y1 ) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3;
|
|
m_dfy :=m_saved_dfy;
|
|
|
|
m_saved_ddfx:=tmp1x * pre4 + tmp2x * pre5;
|
|
m_ddfx :=m_saved_ddfx;
|
|
m_saved_ddfy:=tmp1y * pre4 + tmp2y * pre5;
|
|
m_ddfy :=m_saved_ddfy;
|
|
|
|
m_dddfx:=tmp2x * pre5;
|
|
m_dddfy:=tmp2y * pre5;
|
|
|
|
m_step:=m_num_steps;
|
|
|
|
end;
|
|
|
|
{ INIT }
|
|
procedure curve4_inc.init;
|
|
begin
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve4_inc.approximation_method_;
|
|
begin
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve4_inc._approximation_method;
|
|
begin
|
|
result:=curve_inc;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve4_inc.approximation_scale_;
|
|
begin
|
|
m_scale:=s;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve4_inc._approximation_scale;
|
|
begin
|
|
result:=m_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve4_inc.angle_tolerance_;
|
|
begin
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve4_inc._angle_tolerance;
|
|
begin
|
|
result:=0.0;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve4_inc.cusp_limit_;
|
|
begin
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve4_inc._cusp_limit;
|
|
begin
|
|
result:=0.0;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve4_inc.rewind;
|
|
begin
|
|
if m_num_steps = 0 then
|
|
begin
|
|
m_step:=-1;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
m_step:=m_num_steps;
|
|
m_fx :=m_saved_fx;
|
|
m_fy :=m_saved_fy;
|
|
m_dfx :=m_saved_dfx;
|
|
m_dfy :=m_saved_dfy;
|
|
m_ddfx:=m_saved_ddfx;
|
|
m_ddfy:=m_saved_ddfy;
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve4_inc.vertex;
|
|
begin
|
|
if m_step < 0 then
|
|
begin
|
|
result:=path_cmd_stop;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_step = m_num_steps then
|
|
begin
|
|
x^:=m_start_x;
|
|
y^:=m_start_y;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_move_to;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_step = 0 then
|
|
begin
|
|
x^:=m_end_x;
|
|
y^:=m_end_y;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_line_to;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
m_fx :=m_fx + m_dfx;
|
|
m_fy :=m_fy + m_dfy;
|
|
m_dfx :=m_dfx + m_ddfx;
|
|
m_dfy :=m_dfy + m_ddfy;
|
|
m_ddfx:=m_ddfx + m_dddfx;
|
|
m_ddfy:=m_ddfy + m_dddfy;
|
|
|
|
x^:=m_fx;
|
|
y^:=m_fy;
|
|
|
|
dec(m_step );
|
|
|
|
result:=path_cmd_line_to;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_div.Construct;
|
|
begin
|
|
m_points.Construct(sizeof(point_type ) );
|
|
|
|
m_approximation_scale:=1.0;
|
|
m_angle_tolerance :=0.0;
|
|
|
|
m_cusp_limit:=0.0;
|
|
m_count :=0;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_div.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
begin
|
|
m_points.Construct(sizeof(point_type ) );
|
|
|
|
m_approximation_scale:=1.0;
|
|
m_angle_tolerance :=0.0;
|
|
|
|
m_cusp_limit:=0.0;
|
|
m_count :=0;
|
|
|
|
init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4_div.Construct(cp : curve4_points_ptr );
|
|
begin
|
|
m_points.Construct(sizeof(point_type ) );
|
|
|
|
m_approximation_scale:=1.0;
|
|
m_angle_tolerance :=0.0;
|
|
|
|
m_cusp_limit:=0.0;
|
|
m_count :=0;
|
|
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor curve4_div.Destruct;
|
|
begin
|
|
m_points.Destruct;
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve4_div.reset;
|
|
begin
|
|
m_points.remove_all;
|
|
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ INIT4 }
|
|
procedure curve4_div.init4;
|
|
begin
|
|
m_points.remove_all;
|
|
|
|
m_distance_tolerance_square :=0.5 / m_approximation_scale;
|
|
m_distance_tolerance_square :=m_distance_tolerance_square * m_distance_tolerance_square;
|
|
m_distance_tolerance_manhattan:=4.0 / m_approximation_scale;
|
|
|
|
bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 );
|
|
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ INIT }
|
|
procedure curve4_div.init;
|
|
begin
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve4_div.approximation_method_;
|
|
begin
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve4_div._approximation_method;
|
|
begin
|
|
result:=curve_div;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve4_div.approximation_scale_;
|
|
begin
|
|
if s = 0 then
|
|
m_approximation_scale:=0.00001
|
|
else
|
|
m_approximation_scale:=s;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve4_div._approximation_scale;
|
|
begin
|
|
result:=m_approximation_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve4_div.angle_tolerance_;
|
|
begin
|
|
m_angle_tolerance:=a;
|
|
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve4_div._angle_tolerance;
|
|
begin
|
|
result:=m_angle_tolerance;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve4_div.cusp_limit_;
|
|
begin
|
|
if v = 0.0 then
|
|
m_cusp_limit:=0.0
|
|
else
|
|
m_cusp_limit:=pi - v;
|
|
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve4_div._cusp_limit;
|
|
begin
|
|
if m_cusp_limit = 0.0 then
|
|
result:=0.0
|
|
else
|
|
result:=pi - m_cusp_limit;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve4_div.rewind;
|
|
begin
|
|
m_count:=0;
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve4_div.vertex;
|
|
var
|
|
p : point_type_ptr;
|
|
|
|
begin
|
|
if m_count >= m_points.size then
|
|
begin
|
|
result:=path_cmd_stop;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
p:=m_points.array_operator(m_count );
|
|
|
|
inc(m_count );
|
|
|
|
x^:=p.x;
|
|
y^:=p.y;
|
|
|
|
if m_count = 1 then
|
|
result:=path_cmd_move_to
|
|
else
|
|
result:=path_cmd_line_to;
|
|
|
|
end;
|
|
|
|
{ BEZIER }
|
|
procedure curve4_div.bezier;
|
|
var
|
|
pt : point_type;
|
|
|
|
begin
|
|
pt.x:=x1;
|
|
pt.y:=y1;
|
|
|
|
m_points.add(@pt );
|
|
|
|
recursive_bezier(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 ,0 );
|
|
|
|
pt.x:=x4;
|
|
pt.y:=y4;
|
|
|
|
m_points.add(@pt );
|
|
|
|
end;
|
|
|
|
{ RECURSIVE_BEZIER }
|
|
procedure curve4_div.recursive_bezier;
|
|
var
|
|
x12 ,y12 ,x23 ,y23 ,x34 ,y34 ,x123 ,y123 ,x234 ,y234 ,x1234 ,y1234 ,
|
|
|
|
dx ,dy ,d2 ,d3 ,da1 ,da2 ,a23 : double;
|
|
|
|
pt : point_type;
|
|
|
|
begin
|
|
if level > curve_recursion_limit then
|
|
exit;
|
|
|
|
// Calculate all the mid-points of the line segments
|
|
x12 :=(x1 + x2 ) / 2;
|
|
y12 :=(y1 + y2 ) / 2;
|
|
x23 :=(x2 + x3 ) / 2;
|
|
y23 :=(y2 + y3 ) / 2;
|
|
x34 :=(x3 + x4 ) / 2;
|
|
y34 :=(y3 + y4 ) / 2;
|
|
x123 :=(x12 + x23 ) / 2;
|
|
y123 :=(y12 + y23 ) / 2;
|
|
x234 :=(x23 + x34 ) / 2;
|
|
y234 :=(y23 + y34 ) / 2;
|
|
x1234:=(x123 + x234 ) / 2;
|
|
y1234:=(y123 + y234 ) / 2;
|
|
|
|
// Try to approximate the full cubic curve by a single straight line
|
|
dx:=x4 - x1;
|
|
dy:=y4 - y1;
|
|
|
|
d2:=Abs((x2 - x4 ) * dy - (y2 - y4 ) * dx );
|
|
d3:=Abs((x3 - x4 ) * dy - (y3 - y4 ) * dx );
|
|
|
|
case ((int(d2 > curve_collinearity_epsilon) shl 1 ) +
|
|
int(d3 > curve_collinearity_epsilon ) ) of
|
|
// All collinear OR p1==p4
|
|
0 :
|
|
if Abs(x1 + x3 - x2 - x2 ) +
|
|
Abs(y1 + y3 - y2 - y2 ) +
|
|
Abs(x2 + x4 - x3 - x3 ) +
|
|
Abs(y2 + y4 - y3 - y3 ) <= m_distance_tolerance_manhattan then
|
|
begin
|
|
pt.x:=x1234;
|
|
pt.y:=y1234;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// p1,p2,p4 are collinear, p3 is considerable
|
|
1 :
|
|
if d3 * d3 <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
|
|
begin
|
|
if m_angle_tolerance < curve_angle_tolerance_epsilon then
|
|
begin
|
|
pt.x:=x23;
|
|
pt.y:=y23;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Angle Condition
|
|
da1:=Abs(ArcTan2(y4 - y3 ,x4 - x3 ) - ArcTan2(y3 - y2 ,x3 - x2 ) );
|
|
|
|
if da1 >= pi then
|
|
da1:=2 * pi - da1;
|
|
|
|
if da1 < m_angle_tolerance then
|
|
begin
|
|
pt.x:=x2;
|
|
pt.y:=y2;
|
|
|
|
m_points.add(@pt );
|
|
|
|
pt.x:=x3;
|
|
pt.y:=y3;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_cusp_limit <> 0.0 then
|
|
if da1 > m_cusp_limit then
|
|
begin
|
|
pt.x:=x3;
|
|
pt.y:=y3;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
// p1,p3,p4 are collinear, p2 is considerable
|
|
2 :
|
|
if d2 * d2 <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
|
|
begin
|
|
if m_angle_tolerance < curve_angle_tolerance_epsilon then
|
|
begin
|
|
pt.x:=x23;
|
|
pt.y:=y23;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Angle Condition
|
|
da1:=Abs(ArcTan2(y3 - y2 ,x3 - x2 ) - ArcTan2(y2 - y1 ,x2 - x1 ) );
|
|
|
|
if da1 >= pi then
|
|
da1:=2 * pi - da1;
|
|
|
|
if da1 < m_angle_tolerance then
|
|
begin
|
|
pt.x:=x2;
|
|
pt.y:=y2;
|
|
|
|
m_points.add(@pt );
|
|
|
|
pt.x:=x3;
|
|
pt.y:=y3;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_cusp_limit <> 0.0 then
|
|
if da1 > m_cusp_limit then
|
|
begin
|
|
pt.x:=x2;
|
|
pt.y:=y2;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
// Regular care
|
|
3 :
|
|
if (d2 + d3 ) * (d2 + d3 ) <= m_distance_tolerance_square * (dx * dx + dy * dy ) then
|
|
begin
|
|
// If the curvature doesn't exceed the distance_tolerance value
|
|
// we tend to finish subdivisions.
|
|
if m_angle_tolerance < curve_angle_tolerance_epsilon then
|
|
begin
|
|
pt.x:=x23;
|
|
pt.y:=y23;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Angle & Cusp Condition
|
|
a23:=ArcTan2(y3 - y2 ,x3 - x2 );
|
|
da1:=Abs(a23 - ArcTan2(y2 - y1 ,x2 - x1 ) );
|
|
da2:=Abs(ArcTan2(y4 - y3 ,x4 - x3 ) - a23 );
|
|
|
|
if da1 >= pi then
|
|
da1:=2 * pi - da1;
|
|
|
|
if da2 >= pi then
|
|
da2:=2 * pi - da2;
|
|
|
|
if da1 + da2 < m_angle_tolerance then
|
|
begin
|
|
// Finally we can stop the recursion
|
|
pt.x:=x23;
|
|
pt.y:=y23;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if m_cusp_limit <> 0.0 then
|
|
begin
|
|
if da1 > m_cusp_limit then
|
|
begin
|
|
pt.x:=x2;
|
|
pt.y:=y2;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if da2 > m_cusp_limit then
|
|
begin
|
|
pt.x:=x3;
|
|
pt.y:=y3;
|
|
|
|
m_points.add(@pt );
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
// Continue subdivision
|
|
recursive_bezier(x1 ,y1 ,x12 ,y12 ,x123 ,y123 ,x1234 ,y1234 ,level + 1 );
|
|
recursive_bezier(x1234 ,y1234 ,x234 ,y234 ,x34 ,y34 ,x4 ,y4 ,level + 1 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3.Construct;
|
|
begin
|
|
m_curve_inc.Construct;
|
|
m_curve_div.Construct;
|
|
|
|
m_approximation_method:=curve_div;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve3.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 : double );
|
|
begin
|
|
m_curve_inc.Construct;
|
|
m_curve_div.Construct;
|
|
|
|
m_approximation_method:=curve_div;
|
|
|
|
init3(x1 ,y1 ,x2, y2 ,x3 ,y3 );
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor curve3.Destruct;
|
|
begin
|
|
m_curve_div.Destruct;
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve3.reset;
|
|
begin
|
|
m_curve_inc.reset;
|
|
m_curve_div.reset;
|
|
|
|
end;
|
|
|
|
{ INIT3 }
|
|
procedure curve3.init3;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
m_curve_inc.init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 )
|
|
else
|
|
m_curve_div.init3(x1 ,y1 ,x2 ,y2 ,x3 ,y3 );
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve3.approximation_method_;
|
|
begin
|
|
m_approximation_method:=v;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve3._approximation_method;
|
|
begin
|
|
result:=m_approximation_method;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve3.approximation_scale_;
|
|
begin
|
|
m_curve_inc.approximation_scale_(s );
|
|
m_curve_div.approximation_scale_(s );
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve3._approximation_scale;
|
|
begin
|
|
result:=m_curve_inc._approximation_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve3.angle_tolerance_;
|
|
begin
|
|
m_curve_div.angle_tolerance_(a );
|
|
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve3._angle_tolerance;
|
|
begin
|
|
result:=m_curve_div._angle_tolerance;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve3.cusp_limit_;
|
|
begin
|
|
m_curve_div.cusp_limit_(v );
|
|
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve3._cusp_limit;
|
|
begin
|
|
result:=m_curve_div._cusp_limit;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve3.rewind;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
m_curve_inc.rewind(path_id )
|
|
else
|
|
m_curve_div.rewind(path_id )
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve3.vertex;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
result:=m_curve_inc.vertex(x ,y )
|
|
else
|
|
result:=m_curve_div.vertex(x ,y );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4.Construct;
|
|
begin
|
|
m_curve_inc.Construct;
|
|
m_curve_div.Construct;
|
|
|
|
m_approximation_method:=curve_div;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4.Construct(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 : double );
|
|
begin
|
|
m_curve_inc.Construct;
|
|
m_curve_div.Construct;
|
|
|
|
m_approximation_method:=curve_div;
|
|
|
|
init4(x1 ,y1 ,x2, y2 ,x3 ,y3 ,x4 ,y4 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve4.Construct(cp : curve4_points_ptr );
|
|
begin
|
|
m_curve_inc.Construct;
|
|
m_curve_div.Construct;
|
|
|
|
m_approximation_method:=curve_div;
|
|
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor curve4.Destruct;
|
|
begin
|
|
m_curve_div.Destruct;
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure curve4.reset;
|
|
begin
|
|
m_curve_inc.reset;
|
|
m_curve_div.reset;
|
|
|
|
end;
|
|
|
|
{ INIT4 }
|
|
procedure curve4.init4;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
m_curve_inc.init4(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 )
|
|
else
|
|
m_curve_div.init4(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 );
|
|
|
|
end;
|
|
|
|
{ INIT }
|
|
procedure curve4.init;
|
|
begin
|
|
init4(
|
|
cp.array_operator(0 ) ,
|
|
cp.array_operator(1 ) ,
|
|
cp.array_operator(2 ) ,
|
|
cp.array_operator(3 ) ,
|
|
cp.array_operator(4 ) ,
|
|
cp.array_operator(5 ) ,
|
|
cp.array_operator(6 ) ,
|
|
cp.array_operator(7 ) );
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_METHOD_ }
|
|
procedure curve4.approximation_method_;
|
|
begin
|
|
m_approximation_method:=v;
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_METHOD }
|
|
function curve4._approximation_method;
|
|
begin
|
|
result:=m_approximation_method;
|
|
|
|
end;
|
|
|
|
{ APPROXIMATION_SCALE_ }
|
|
procedure curve4.approximation_scale_;
|
|
begin
|
|
m_curve_inc.approximation_scale_(s );
|
|
m_curve_div.approximation_scale_(s );
|
|
|
|
end;
|
|
|
|
{ _APPROXIMATION_SCALE }
|
|
function curve4._approximation_scale;
|
|
begin
|
|
result:=m_curve_inc._approximation_scale;
|
|
|
|
end;
|
|
|
|
{ ANGLE_TOLERANCE_ }
|
|
procedure curve4.angle_tolerance_;
|
|
begin
|
|
m_curve_div.angle_tolerance_(a );
|
|
|
|
end;
|
|
|
|
{ _ANGLE_TOLERANCE }
|
|
function curve4._angle_tolerance;
|
|
begin
|
|
result:=m_curve_div._angle_tolerance;
|
|
|
|
end;
|
|
|
|
{ CUSP_LIMIT_ }
|
|
procedure curve4.cusp_limit_;
|
|
begin
|
|
m_curve_div.cusp_limit_(v );
|
|
|
|
end;
|
|
|
|
{ _CUSP_LIMIT }
|
|
function curve4._cusp_limit;
|
|
begin
|
|
result:=m_curve_div._cusp_limit;
|
|
|
|
end;
|
|
|
|
{ REWIND }
|
|
procedure curve4.rewind;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
m_curve_inc.rewind(path_id )
|
|
else
|
|
m_curve_div.rewind(path_id );
|
|
|
|
end;
|
|
|
|
{ VERTEX }
|
|
function curve4.vertex;
|
|
begin
|
|
if m_approximation_method = curve_inc then
|
|
result:=m_curve_inc.vertex(x ,y )
|
|
else
|
|
result:=m_curve_div.vertex(x ,y );
|
|
|
|
end;
|
|
|
|
END.
|
|
|