mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 05:43:40 +02:00
885 lines
21 KiB
ObjectPascal
885 lines
21 KiB
ObjectPascal
//
|
|
// AggPas 2.4 RM3 Demo application
|
|
// Note: Press F1 key on run to see more info about this demo
|
|
//
|
|
// Paths: src;src\ctrl;src\svg;src\util;src\platform\win;expat-wrap
|
|
//
|
|
program
|
|
bezier_div ;
|
|
|
|
uses
|
|
Math ,SysUtils ,
|
|
|
|
agg_basics ,
|
|
agg_platform_support ,
|
|
|
|
agg_color ,
|
|
agg_pixfmt ,
|
|
agg_pixfmt_rgb ,
|
|
|
|
agg_ctrl ,
|
|
agg_slider_ctrl ,
|
|
agg_rbox_ctrl ,
|
|
agg_cbox_ctrl ,
|
|
agg_bezier_ctrl ,
|
|
|
|
agg_renderer_base ,
|
|
agg_renderer_scanline ,
|
|
agg_rasterizer_scanline_aa ,
|
|
agg_scanline ,
|
|
agg_scanline_u ,
|
|
agg_render_scanlines ,
|
|
agg_renderer_outline_aa ,
|
|
agg_renderer_outline_image ,
|
|
|
|
agg_conv_transform ,
|
|
agg_conv_stroke ,
|
|
agg_conv_dash ,
|
|
agg_pattern_filters_rgba ,
|
|
agg_arc ,
|
|
agg_array ,
|
|
agg_curves ,
|
|
agg_bezier_arc ,
|
|
agg_vertex_sequence ,
|
|
agg_math ,
|
|
agg_math_stroke ,
|
|
agg_path_storage ,
|
|
agg_gsv_text ,
|
|
agg_ellipse ;
|
|
|
|
{$I agg_mode.inc }
|
|
{$I- }
|
|
const
|
|
flip_y = true;
|
|
|
|
type
|
|
curve_point_ptr = ^curve_point;
|
|
curve_point = object
|
|
x ,y ,dist ,mu : double;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(x1 ,y1 ,mu1 : double ); overload;
|
|
|
|
end;
|
|
|
|
the_application = object(platform_support )
|
|
m_ctrl_color : aggclr;
|
|
|
|
m_curve1 : bezier_ctrl;
|
|
|
|
m_angle_tolerance ,
|
|
m_approximation_scale ,
|
|
m_cusp_limit ,
|
|
m_width : slider_ctrl;
|
|
|
|
m_show_points ,
|
|
m_show_outline : cbox_ctrl;
|
|
m_curve_type ,
|
|
m_case_type ,
|
|
m_inner_join ,
|
|
m_line_join ,
|
|
m_line_cap : rbox_ctrl;
|
|
|
|
m_cur_case_type : int;
|
|
|
|
constructor Construct(format_ : pix_format_e; flip_y_ : boolean );
|
|
destructor Destruct;
|
|
|
|
function measure_time(curve : curve_ptr ) : double;
|
|
function find_point (path : pod_deque_ptr; dist : double; i ,j : unsigned_ptr ) : boolean;
|
|
|
|
function calc_max_error(curve : curve_ptr; scale : double; max_angle_error : double_ptr ) : double;
|
|
|
|
procedure on_draw; virtual;
|
|
|
|
procedure on_key(x ,y : int; key ,flags : unsigned ); virtual;
|
|
procedure on_ctrl_change; virtual;
|
|
|
|
end;
|
|
|
|
{ BEZIER4_POINT }
|
|
procedure bezier4_point(
|
|
x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 ,mu : double;
|
|
x ,y : double_ptr );
|
|
var
|
|
mum1 ,mum13 ,mu3 : double;
|
|
|
|
begin
|
|
mum1 :=1 - mu;
|
|
mum13:=mum1 * mum1 * mum1;
|
|
mu3 :=mu * mu * mu;
|
|
|
|
x^:=mum13 * x1 + 3 * mu * mum1 * mum1 * x2 + 3 * mu * mu * mum1 * x3 + mu3 * x4;
|
|
y^:=mum13 * y1 + 3 * mu * mum1 * mum1 * y2 + 3 * mu * mu * mum1 * y3 + mu3 * y4;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve_point.Construct;
|
|
begin
|
|
x :=0;
|
|
y :=0;
|
|
dist:=0;
|
|
mu :=0;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor curve_point.Construct(x1 ,y1 ,mu1 : double );
|
|
begin
|
|
x :=x1;
|
|
y :=y1;
|
|
dist:=0;
|
|
mu :=mu1;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor the_application.Construct;
|
|
begin
|
|
inherited Construct(format_ ,flip_y_ );
|
|
|
|
m_ctrl_color.ConstrDbl(0 ,0.3 ,0.5 ,0.8 );
|
|
|
|
m_angle_tolerance.Construct (5.0 ,5.0 ,240.0 ,12.0 ,not flip_y_ );
|
|
m_approximation_scale.Construct(5.0 ,17 + 5.0 , 240.0 ,17 + 12.0 ,not flip_y_ );
|
|
m_cusp_limit.Construct (5.0 ,17 + 17 + 5.0 ,240.0 ,17 + 17 + 12.0 ,not flip_y_ );
|
|
m_width.Construct (245.0 ,5.0 ,495.0 ,12.0 ,not flip_y_ );
|
|
m_show_points.Construct (250.0 ,15 + 5 ,'Show Points' ,not flip_y_ );
|
|
m_show_outline.Construct (250.0 ,30 + 5 ,'Show Stroke Outline' ,not flip_y_ );
|
|
m_curve_type.Construct (535.0 ,5.0 ,535.0 + 115.0 ,55.0 ,not flip_y_ );
|
|
m_case_type.Construct (535.0 ,60.0 ,535.0 + 115.0 ,195.0 ,not flip_y_ );
|
|
m_inner_join.Construct (535.0 ,200.0 ,535.0 + 115.0 ,290.0 ,not flip_y_ );
|
|
m_line_join.Construct (535.0 ,295.0 ,535.0 + 115.0 ,385.0 ,not flip_y_ );
|
|
m_line_cap.Construct (535.0 ,395.0 ,535.0 + 115.0 ,455.0 ,not flip_y_ );
|
|
|
|
m_cur_case_type:=-1;
|
|
|
|
m_curve1.Construct;
|
|
m_curve1.line_color_(@m_ctrl_color );
|
|
|
|
m_curve1.curve_(170 ,424 ,13 ,87 ,488 ,423 ,26 ,333 );
|
|
//m_curve1.curve_(26.000 ,333.000 ,276.000 ,126.000 ,402.000 ,479.000 ,26.000 ,333.000 ); // Loop with p1==p4
|
|
//m_curve1.curve_(378.000 ,439.000 ,378.000 ,497.000 ,487.000 ,432.000 ,14.000 ,338.000 ); // Narrow loop
|
|
//m_curve1.curve_(288.000 ,283.000 ,232.000 ,89.000 ,66.000 ,197.000 ,456.000 ,241.000 ); // Loop
|
|
//m_curve1.curve_(519.000 ,142.000 ,97.000 ,147.000 ,69.000 ,147.000 ,30.000 ,144.000 ); // Almost straight
|
|
//m_curve1.curve_(100 ,100 ,200 ,100 ,100 ,200 ,200 ,200 ); // A "Z" case
|
|
//m_curve1.curve_(150 ,150 ,350 ,150 ,150 ,150 ,350 ,150 ); // Degenerate
|
|
//m_curve1.curve_(409 ,330 ,300 ,200 ,200 ,200 ,401 ,263 ); // Strange cusp
|
|
//m_curve1.curve_(129 ,233 ,172 ,320 ,414 ,253 ,344 ,236 ); // Curve cap
|
|
//m_curve1.curve_(100 ,100 ,100 ,200 ,100 ,100 ,110 ,100 ); // A "boot"
|
|
//m_curve1.curve_(225 ,150 ,60 ,150 ,460 ,150 ,295 ,150 ); // 2----1----4----3
|
|
//m_curve1.curve_(162.2 ,248.801 ,162.2 ,248.801 ,266 ,284 ,394 ,335 ); // Coinciding 1-2
|
|
//m_curve1.curve_(162.200 ,248.801 ,162.200 ,248.801 ,257.000 ,301.000 ,394.000 ,335.000 ); // Coinciding 1-2
|
|
//m_curve1.curve_(394.000 ,335.000 ,257.000 ,301.000 ,162.200 ,248.801 ,162.200 ,248.801 ); // Coinciding 3-4
|
|
//m_curve1.curve_(84.200000 ,302.80100 ,84.200000 ,302.80100 ,79.000000 ,292.40100 ,97.001000 ,304.40100 ); // From tiger.svg
|
|
//m_curve1.curve_(97.001000 ,304.40100 ,79.000000 ,292.40100 ,84.200000 ,302.80100 ,84.200000 ,302.80100 ); // From tiger.svg opposite dir
|
|
//m_curve1.curve_(475 ,157 ,200 ,100 ,453 ,100 ,222 ,157 ); // Cusp, failure for Adobe SVG
|
|
|
|
add_ctrl(@m_curve1 );
|
|
|
|
m_curve1.no_transform;
|
|
|
|
m_angle_tolerance.label_('Angle Tolerance=%.0f deg' );
|
|
m_angle_tolerance.range_(0 ,90 );
|
|
m_angle_tolerance.value_(15 );
|
|
|
|
add_ctrl(@m_angle_tolerance );
|
|
|
|
m_angle_tolerance.no_transform;
|
|
|
|
m_approximation_scale.label_('Approximation Scale=%.3f' );
|
|
m_approximation_scale.range_(0.1 ,5 );
|
|
m_approximation_scale.value_(1.0 );
|
|
|
|
add_ctrl(@m_approximation_scale );
|
|
|
|
m_approximation_scale.no_transform;
|
|
|
|
m_cusp_limit.label_('Cusp Limit=%.0f deg' );
|
|
m_cusp_limit.range_(0 ,90);
|
|
m_cusp_limit.value_(0 );
|
|
|
|
add_ctrl(@m_cusp_limit );
|
|
|
|
m_cusp_limit.no_transform;
|
|
|
|
m_width.label_('Width=%.2f' );
|
|
m_width.range_(0.0 ,100 );
|
|
m_width.value_(50.0 );
|
|
|
|
add_ctrl(@m_width );
|
|
|
|
m_width.no_transform;
|
|
|
|
add_ctrl(@m_show_points );
|
|
|
|
m_show_points.no_transform;
|
|
m_show_points.status_(true );
|
|
|
|
add_ctrl(@m_show_outline );
|
|
|
|
m_show_outline.no_transform;
|
|
m_show_outline.status_(true );
|
|
|
|
m_curve_type.add_item ('Incremental' );
|
|
m_curve_type.add_item ('Subdiv' );
|
|
m_curve_type.cur_item_(1 );
|
|
|
|
add_ctrl(@m_curve_type );
|
|
|
|
m_curve_type.no_transform;
|
|
|
|
m_case_type.text_size_ (7 );
|
|
m_case_type.text_thickness_(1.0 );
|
|
|
|
m_case_type.add_item('Random' );
|
|
m_case_type.add_item('13---24' );
|
|
m_case_type.add_item('Smooth Cusp 1' );
|
|
m_case_type.add_item('Smooth Cusp 2' );
|
|
m_case_type.add_item('Real Cusp 1' );
|
|
m_case_type.add_item('Real Cusp 2' );
|
|
m_case_type.add_item('Fancy Stroke' );
|
|
m_case_type.add_item('Jaw' );
|
|
m_case_type.add_item('Ugly Jaw' );
|
|
|
|
add_ctrl(@m_case_type );
|
|
|
|
m_case_type.no_transform;
|
|
|
|
m_inner_join.text_size_(8 );
|
|
|
|
m_inner_join.add_item ('Inner Bevel' );
|
|
m_inner_join.add_item ('Inner Miter' );
|
|
m_inner_join.add_item ('Inner Jag' );
|
|
m_inner_join.add_item ('Inner Round' );
|
|
m_inner_join.cur_item_(3 );
|
|
|
|
add_ctrl(@m_inner_join );
|
|
|
|
m_inner_join.no_transform;
|
|
|
|
m_line_join.text_size_(8 );
|
|
|
|
m_line_join.add_item ('Miter Join' );
|
|
m_line_join.add_item ('Miter Revert' );
|
|
m_line_join.add_item ('Miter Round' );
|
|
m_line_join.add_item ('Round Join' );
|
|
m_line_join.add_item ('Bevel Join' );
|
|
m_line_join.cur_item_(1 );
|
|
|
|
add_ctrl(@m_line_join );
|
|
|
|
m_line_join.no_transform;
|
|
|
|
m_line_cap.text_size_(8 );
|
|
|
|
m_line_cap.add_item ('Butt Cap' );
|
|
m_line_cap.add_item ('Square Cap' );
|
|
m_line_cap.add_item ('Round Cap' );
|
|
m_line_cap.cur_item_(0 );
|
|
|
|
add_ctrl(@m_line_cap );
|
|
|
|
m_line_cap.no_transform;
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor the_application.Destruct;
|
|
begin
|
|
inherited Destruct;
|
|
|
|
m_angle_tolerance.Destruct;
|
|
m_approximation_scale.Destruct;
|
|
m_cusp_limit.Destruct;
|
|
m_width.Destruct;
|
|
m_show_points.Destruct;
|
|
m_show_outline.Destruct;
|
|
m_curve_type.Destruct;
|
|
m_case_type.Destruct;
|
|
m_inner_join.Destruct;
|
|
m_line_join.Destruct;
|
|
m_line_cap.Destruct;
|
|
m_curve1.Destruct;
|
|
|
|
end;
|
|
|
|
{ MEASURE_TIME }
|
|
function the_application.measure_time;
|
|
var
|
|
i : int;
|
|
|
|
x ,y : double;
|
|
|
|
begin
|
|
start_timer;
|
|
|
|
for i:=0 to 99 do
|
|
begin
|
|
curve.init4(
|
|
m_curve1._x1 ,m_curve1._y1 ,
|
|
m_curve1._x2 ,m_curve1._y2 ,
|
|
m_curve1._x3 ,m_curve1._y3 ,
|
|
m_curve1._x4 ,m_curve1._y4 );
|
|
|
|
curve.rewind(0 );
|
|
|
|
while not is_stop(curve.vertex(@x ,@y ) ) do;
|
|
|
|
end;
|
|
|
|
result:=elapsed_time * 10;
|
|
|
|
end;
|
|
|
|
{ FIND_POINT }
|
|
function the_application.find_point;
|
|
var
|
|
k : int;
|
|
|
|
begin
|
|
j^:=path.size - 1;
|
|
i^:=0;
|
|
|
|
while j^ - i^ > 1 do
|
|
begin
|
|
k:=shr_int32(i^ + j^ ,1 );
|
|
|
|
if dist < vertex_dist_ptr(path.array_operator(k ) ).dist then
|
|
j^:=k
|
|
else
|
|
i^:=k;
|
|
|
|
end;
|
|
|
|
result:=true;
|
|
|
|
end;
|
|
|
|
{ CALC_MAX_ERROR }
|
|
function the_application.calc_max_error;
|
|
var
|
|
cmd ,i ,idx1 ,idx2 : unsigned;
|
|
|
|
x ,y ,curve_dist ,mu ,reference_dist ,max_error ,err ,aerr ,a1 ,a2 ,da : double;
|
|
|
|
curve_points ,reference_points : pod_deque;
|
|
|
|
vd : vertex_dist;
|
|
cp : curve_point;
|
|
|
|
begin
|
|
curve_points.Construct (sizeof(vertex_dist ) ,8 );
|
|
reference_points.Construct(sizeof(curve_point ) ,8 );
|
|
|
|
curve.approximation_scale_(m_approximation_scale._value * scale );
|
|
|
|
curve.init4(
|
|
m_curve1._x1 ,m_curve1._y1 ,
|
|
m_curve1._x2 ,m_curve1._y2 ,
|
|
m_curve1._x3 ,m_curve1._y3 ,
|
|
m_curve1._x4 ,m_curve1._y4 );
|
|
|
|
curve.rewind(0 );
|
|
|
|
vd.dist:=0;
|
|
|
|
cmd:=curve.vertex(@x ,@y );
|
|
|
|
while not is_stop(cmd ) do
|
|
begin
|
|
if is_vertex(cmd ) then
|
|
begin
|
|
vd.x:=x;
|
|
vd.y:=y;
|
|
|
|
curve_points.add(@vd );
|
|
|
|
end;
|
|
|
|
cmd:=curve.vertex(@x ,@y );
|
|
|
|
end;
|
|
|
|
curve_dist:=0;
|
|
|
|
i:=1;
|
|
|
|
while i < curve_points.size do
|
|
begin
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).dist:=curve_dist;
|
|
|
|
curve_dist:=
|
|
curve_dist +
|
|
calc_distance(
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).x ,
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).y ,
|
|
vertex_dist_ptr(curve_points.array_operator(i ) ).x ,
|
|
vertex_dist_ptr(curve_points.array_operator(i ) ).y );
|
|
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
vertex_dist_ptr(curve_points.array_operator(curve_points.size - 1 ) ).dist:=curve_dist;
|
|
|
|
for i:=0 to 4095 do
|
|
begin
|
|
mu:=i / 4095.0;
|
|
|
|
bezier4_point(
|
|
m_curve1._x1 , m_curve1._y1 ,
|
|
m_curve1._x2 , m_curve1._y2 ,
|
|
m_curve1._x3 , m_curve1._y3 ,
|
|
m_curve1._x4 , m_curve1._y4 ,
|
|
mu ,@x ,@y );
|
|
|
|
cp.Construct(x ,y ,mu );
|
|
|
|
reference_points.add(@cp );
|
|
|
|
end;
|
|
|
|
reference_dist:=0;
|
|
|
|
i:=1;
|
|
|
|
while i < reference_points.size do
|
|
begin
|
|
curve_point_ptr(reference_points.array_operator(i - 1 ) ).dist:=reference_dist;
|
|
|
|
reference_dist:=
|
|
reference_dist +
|
|
calc_distance(
|
|
curve_point_ptr(reference_points.array_operator(i - 1 ) ).x ,
|
|
curve_point_ptr(reference_points.array_operator(i - 1 ) ).y ,
|
|
curve_point_ptr(reference_points.array_operator(i ) ).x ,
|
|
curve_point_ptr(reference_points.array_operator(i ) ).y );
|
|
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
curve_point_ptr(reference_points.array_operator(reference_points.size - 1 ) ).dist:=reference_dist;
|
|
|
|
idx1:=0;
|
|
idx2:=1;
|
|
|
|
max_error:=0;
|
|
|
|
i:=0;
|
|
|
|
while i < reference_points.size do
|
|
begin
|
|
if find_point(
|
|
@curve_points ,
|
|
curve_point_ptr(reference_points.array_operator(i ) ).dist ,
|
|
@idx1 ,@idx2 ) then
|
|
begin
|
|
err:=
|
|
Abs(
|
|
calc_line_point_distance(
|
|
vertex_dist_ptr(curve_points.array_operator(idx1 ) ).x ,
|
|
vertex_dist_ptr(curve_points.array_operator(idx1 ) ).y ,
|
|
vertex_dist_ptr(curve_points.array_operator(idx2 ) ).x ,
|
|
vertex_dist_ptr(curve_points.array_operator(idx2 ) ).y ,
|
|
curve_point_ptr(reference_points.array_operator(i ) ).x ,
|
|
curve_point_ptr(reference_points.array_operator(i ) ).y ) );
|
|
|
|
if err > max_error then
|
|
max_error:=err;
|
|
|
|
end;
|
|
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
aerr:=0;
|
|
|
|
i:=2;
|
|
|
|
while i < curve_points.size do
|
|
begin
|
|
a1:=
|
|
ArcTan2(
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).y -
|
|
vertex_dist_ptr(curve_points.array_operator(i - 2 ) ).y ,
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).x -
|
|
vertex_dist_ptr(curve_points.array_operator(i - 2 ) ).x );
|
|
|
|
a2:=
|
|
ArcTan2(
|
|
vertex_dist_ptr(curve_points.array_operator(i ) ).y -
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).y ,
|
|
vertex_dist_ptr(curve_points.array_operator(i ) ).x -
|
|
vertex_dist_ptr(curve_points.array_operator(i - 1 ) ).x );
|
|
|
|
da:=Abs(a1 - a2 );
|
|
|
|
if da >= pi then
|
|
da:=2 * pi - da;
|
|
|
|
if da > aerr then
|
|
aerr:=da;
|
|
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
max_angle_error^:=aerr * 180.0 / pi;
|
|
|
|
result:=max_error * scale;
|
|
|
|
curve_points.Destruct;
|
|
reference_points.Destruct;
|
|
|
|
end;
|
|
|
|
{ ON_DRAW }
|
|
procedure the_application.on_draw;
|
|
var
|
|
ren_base : renderer_base;
|
|
rgba : aggclr;
|
|
|
|
pf : pixel_formats;
|
|
ren : renderer_scanline_aa_solid;
|
|
ras : rasterizer_scanline_aa;
|
|
sl : scanline_u8;
|
|
|
|
path : path_storage;
|
|
curve : curve4;
|
|
stroke ,
|
|
stroke2 : conv_stroke;
|
|
|
|
ell : ellipse;
|
|
buf : array[0..511 ] of char;
|
|
|
|
t : gsv_text;
|
|
pt : conv_stroke;
|
|
|
|
cmd ,num_points1 : unsigned;
|
|
|
|
x ,y ,curve_time ,
|
|
|
|
max_angle_error_01 ,
|
|
max_angle_error_1 ,
|
|
max_angle_error1 ,
|
|
max_angle_error_10 ,
|
|
max_angle_error_100 ,
|
|
|
|
max_error_01 ,
|
|
max_error_1 ,
|
|
max_error1 ,
|
|
max_error_10 ,
|
|
max_error_100 : double;
|
|
|
|
a : ellipse;
|
|
|
|
begin
|
|
// Initialize structures
|
|
pixfmt_bgr24(pf ,rbuf_window );
|
|
|
|
ren_base.Construct(@pf );
|
|
rgba.ConstrDbl (1.0 ,1.0 ,0.95 );
|
|
ren_base.clear (@rgba );
|
|
|
|
ren.Construct(@ren_base );
|
|
|
|
ras.Construct;
|
|
sl.Construct;
|
|
|
|
// Render Curve
|
|
path.Construct;
|
|
|
|
curve_time:=0;
|
|
|
|
path.remove_all;
|
|
curve.Construct;
|
|
|
|
curve.approximation_method_(curve_approximation_method_e(m_curve_type._cur_item ) );
|
|
curve.approximation_scale_ (m_approximation_scale._value );
|
|
|
|
curve.angle_tolerance_(deg2rad(m_angle_tolerance._value ) );
|
|
curve.cusp_limit_ (deg2rad(m_cusp_limit._value ) );
|
|
|
|
curve_time:=measure_time(@curve );
|
|
|
|
max_angle_error_01 :=0;
|
|
max_angle_error_1 :=0;
|
|
max_angle_error1 :=0;
|
|
max_angle_error_10 :=0;
|
|
max_angle_error_100:=0;
|
|
max_error_01 :=0;
|
|
max_error_1 :=0;
|
|
max_error1 :=0;
|
|
max_error_10 :=0;
|
|
max_error_100 :=0;
|
|
|
|
max_error_01 :=calc_max_error(@curve ,0.01 ,@max_angle_error_01 );
|
|
max_error_1 :=calc_max_error(@curve ,0.1 ,@max_angle_error_1 );
|
|
max_error1 :=calc_max_error(@curve ,1 ,@max_angle_error1 );
|
|
max_error_10 :=calc_max_error(@curve ,10 ,@max_angle_error_10 );
|
|
max_error_100:=calc_max_error(@curve ,100 ,@max_angle_error_100 );
|
|
|
|
curve.approximation_scale_(m_approximation_scale._value );
|
|
curve.angle_tolerance_ (deg2rad(m_angle_tolerance._value ) );
|
|
curve.cusp_limit_ (deg2rad(m_cusp_limit._value ) );
|
|
|
|
curve.init4(
|
|
m_curve1._x1 ,m_curve1._y1 ,
|
|
m_curve1._x2 ,m_curve1._y2 ,
|
|
m_curve1._x3 ,m_curve1._y3 ,
|
|
m_curve1._x4 ,m_curve1._y4 );
|
|
|
|
path.add_path(@curve ,0 ,false );
|
|
|
|
stroke.Construct(@path );
|
|
stroke.width_ (m_width._value );
|
|
|
|
stroke.line_join_ (m_line_join._cur_item );
|
|
stroke.line_cap_ (m_line_cap._cur_item );
|
|
stroke.inner_join_ (m_inner_join._cur_item );
|
|
stroke.inner_miter_limit_(1.01 );
|
|
|
|
ras.add_path (@stroke );
|
|
rgba.ConstrDbl (0 ,0.5 ,0 ,0.5 );
|
|
ren.color_ (@rgba );
|
|
render_scanlines(@ras ,@sl ,@ren );
|
|
|
|
// Render internal points
|
|
num_points1:=0;
|
|
|
|
path.rewind(0 );
|
|
|
|
cmd:=path.vertex(@x ,@y );
|
|
|
|
while not is_stop(cmd ) do
|
|
begin
|
|
if m_show_points._status then
|
|
begin
|
|
ell.Construct(x ,y ,1.5 ,1.5 ,8 );
|
|
|
|
ras.add_path (@ell );
|
|
rgba.ConstrDbl (0 ,0 ,0 ,0.5 );
|
|
ren.color_ (@rgba );
|
|
render_scanlines(@ras ,@sl ,@ren );
|
|
|
|
end;
|
|
|
|
inc(num_points1 );
|
|
|
|
cmd:=path.vertex(@x ,@y );
|
|
|
|
end;
|
|
|
|
// Render outline
|
|
if m_show_outline._status then
|
|
begin
|
|
// Draw a stroke of the stroke to see the internals
|
|
stroke2.Construct(@stroke );
|
|
ras.add_path (@stroke2 );
|
|
rgba.ConstrDbl (0 ,0 ,0 ,0.5 );
|
|
ren.color_ (@rgba);
|
|
render_scanlines (@ras ,@sl ,@ren );
|
|
|
|
end;
|
|
|
|
// Check ellipse and arc for the number of points
|
|
{a.Construct (100 ,100 ,m_width.value ,m_width.value ,0 );
|
|
ras.add_path (@a );
|
|
rgba.ConstrDbl (0.5 ,0 ,0 ,0.5 );
|
|
ren.color (@rgba );
|
|
render_scanlines(@ras ,@sl ,@ren );
|
|
|
|
a.rewind(0 );
|
|
|
|
cmd:=a.vertex(@x ,@ y);
|
|
|
|
while not is_stop(cmd ) do
|
|
begin
|
|
if is_vertex(cmd ) then
|
|
begin
|
|
ell.Construct (x ,y ,1.5 ,1.5 ,8 );
|
|
ras.add_path (@ell );
|
|
rgba.ConstrDbl (0 ,0 ,0 ,0.5 );
|
|
ren.color (@rgba );
|
|
render_scanlines(@ras ,@sl ,@ren );
|
|
|
|
end;
|
|
|
|
cmd:=a.vertex(@x ,@y );
|
|
|
|
end;{}
|
|
|
|
// Render text
|
|
t.Construct;
|
|
t.size_(8.0 );
|
|
|
|
pt.Construct (@t );
|
|
pt.line_cap_ (round_cap );
|
|
pt.line_join_(round_join );
|
|
pt.width_ (1.5 );
|
|
|
|
sprintf(@buf[0 ] ,'Num Points=%d ' ,num_points1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'Time=%.2fmks'#13#13 ,curve_time );
|
|
sprintf(@buf[StrLen(@buf ) ] ,' Dist Error: x0.01=%.5f ' ,max_error_01 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x0.1=%.5f ' ,max_error_1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x1=%.5f ' ,max_error1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x10=%.5f ' ,max_error_10 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x100=%.5f'#13#13 ,max_error_100 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'Angle Error: x0.01=%.1f ' ,max_angle_error_01 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x0.1=%.1f ' ,max_angle_error_1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x1=%.1f ' ,max_angle_error1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x10=%.1f ' ,max_angle_error_10 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'x100=%.1f' ,max_angle_error_100 );
|
|
|
|
t.start_point_(10.0 ,85.0 );
|
|
t.text_ (@buf[0 ] );
|
|
|
|
ras.add_path (@pt );
|
|
rgba.ConstrDbl (0 ,0 ,0 );
|
|
ren.color_ (@rgba );
|
|
render_scanlines(@ras ,@sl ,@ren );
|
|
|
|
// Render the controls
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_curve1 );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_angle_tolerance );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_approximation_scale );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_cusp_limit );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_width );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_show_points );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_show_outline );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_curve_type );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_case_type );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_inner_join );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_line_join );
|
|
render_ctrl(@ras ,@sl ,@ren ,@m_line_cap );
|
|
|
|
// Free AGG resources
|
|
ras.Destruct;
|
|
sl.Destruct;
|
|
|
|
path.Destruct;
|
|
curve.Destruct;
|
|
stroke.Destruct;
|
|
stroke2.Destruct;
|
|
|
|
t.Destruct;
|
|
pt.Destruct;
|
|
|
|
end;
|
|
|
|
{ ON_KEY }
|
|
procedure the_application.on_key;
|
|
var
|
|
fd : text;
|
|
buf : array[0..255 ] of char;
|
|
|
|
begin
|
|
if key = byte(' ' ) then
|
|
begin
|
|
AssignFile(fd ,'coord' );
|
|
rewrite (fd );
|
|
|
|
sprintf(@buf[0 ] ,'%.3f, ' ,m_curve1._x1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._y1 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._x2 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._y2 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._x3 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._y3 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f, ' ,m_curve1._x4 );
|
|
sprintf(@buf[StrLen(@buf ) ] ,'%.3f' ,m_curve1._y4 );
|
|
|
|
write(fd ,PChar(@buf[0 ] ) );
|
|
close(fd );
|
|
|
|
end;
|
|
|
|
if key = key_f1 then
|
|
message_(
|
|
'Demonstration of new methods of Bezier curve approximation. You can compare '#13 +
|
|
'the old, incremental method with adaptive De Casteljau''s subdivion. The new '#13 +
|
|
'method uses two criteria to stop subdivision: estimation of distance and estimation '#13 +
|
|
'of angle. It gives us perfectly smooth result even for very sharp turns and loops. '#13#13 +
|
|
'How to play with:'#13#13 +
|
|
'Use the mouse to change the shape of the curve.'#13 +
|
|
'Press the spacebar to dump the curve''s coordinates into the "coord" file.' +
|
|
#13#13'Note: F2 key saves current "screenshot" file in this demo''s directory. ' );
|
|
|
|
end;
|
|
|
|
{ ON_CTRL_CHANGE }
|
|
procedure the_application.on_ctrl_change;
|
|
var
|
|
w ,h : int;
|
|
|
|
begin
|
|
if m_case_type._cur_item <> m_cur_case_type then
|
|
begin
|
|
case m_case_type._cur_item of
|
|
0 : //m_case_type.add_item("Random");
|
|
begin
|
|
w:=trunc(_width - 120 );
|
|
h:=trunc(_height - 80 );
|
|
|
|
m_curve1.curve_(
|
|
Random($7fff ) mod w ,Random($7fff ) mod h + 80 ,
|
|
Random($7fff ) mod w ,Random($7fff ) mod h + 80 ,
|
|
Random($7fff ) mod w ,Random($7fff ) mod h + 80 ,
|
|
Random($7fff ) mod w ,Random($7fff ) mod h + 80 );
|
|
|
|
end;
|
|
|
|
1 : //m_case_type.add_item("13---24");
|
|
m_curve1.curve_(150 ,150 ,350 ,150 ,150 ,150 ,350 ,150 );
|
|
|
|
2 : //m_case_type.add_item("Smooth Cusp 1");
|
|
m_curve1.curve_(50 ,142 ,483 ,251 ,496 ,62 ,26 ,333 );
|
|
|
|
3 : //m_case_type.add_item("Smooth Cusp 2");
|
|
m_curve1.curve_(50 ,142 ,484 ,251 ,496 ,62 ,26 ,333 );
|
|
|
|
4 : //m_case_type.add_item("Real Cusp 1");
|
|
m_curve1.curve_(100 ,100 ,300 ,200 ,200 ,200 ,200 ,100 );
|
|
|
|
5 : //m_case_type.add_item("Real Cusp 2");
|
|
m_curve1.curve_(475 ,157 ,200 ,100 ,453 ,100 ,222 ,157 );
|
|
|
|
6 : //m_case_type.add_item("Fancy Stroke");
|
|
begin
|
|
m_curve1.curve_(129 ,233 ,32 ,283 ,258 ,285 ,159 ,232 );
|
|
m_width.value_ (100 );
|
|
|
|
end;
|
|
|
|
7 : //m_case_type.add_item("Jaw");
|
|
m_curve1.curve_(100 ,100 ,300 ,200 ,264 ,286 ,264 ,284 );
|
|
|
|
8 : //m_case_type.add_item("Ugly Jaw");
|
|
m_curve1.curve_(100 ,100 ,413 ,304 ,264 ,286 ,264 ,284 );
|
|
|
|
end;
|
|
|
|
force_redraw;
|
|
|
|
m_cur_case_type:=m_case_type._cur_item;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
VAR
|
|
app : the_application;
|
|
|
|
BEGIN
|
|
app.Construct(pix_format_bgr24 ,flip_y );
|
|
app.caption_ ('AGG Example (F1-Help)' );
|
|
|
|
if app.init(655 ,520 ,window_resize ) then
|
|
app.run;
|
|
|
|
app.Destruct;
|
|
|
|
END. |