summaryrefslogtreecommitdiff
path: root/src/corelib/render/software/ctrl/agg_polygon_ctrl.pas
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graeme@mastermaths.co.za>2012-11-22 11:48:47 +0000
committerGraeme Geldenhuys <graeme@mastermaths.co.za>2012-11-22 11:48:47 +0000
commitaf45f95f16cee22f8f012f706f4d0a42eaeb68fa (patch)
treec572c1cc6a7d3bb12874d8f9b9363312b275e328 /src/corelib/render/software/ctrl/agg_polygon_ctrl.pas
parent9c62dfaf7217557f08a3d33b20bb302874960f87 (diff)
downloadfpGUI-af45f95f16cee22f8f012f706f4d0a42eaeb68fa.tar.xz
Fixes line ending issues
Diffstat (limited to 'src/corelib/render/software/ctrl/agg_polygon_ctrl.pas')
-rw-r--r--src/corelib/render/software/ctrl/agg_polygon_ctrl.pas1538
1 files changed, 769 insertions, 769 deletions
diff --git a/src/corelib/render/software/ctrl/agg_polygon_ctrl.pas b/src/corelib/render/software/ctrl/agg_polygon_ctrl.pas
index 881c9d60..2aa16ed7 100644
--- a/src/corelib/render/software/ctrl/agg_polygon_ctrl.pas
+++ b/src/corelib/render/software/ctrl/agg_polygon_ctrl.pas
@@ -1,769 +1,769 @@
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.4 (Public License)
-// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.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] -----------------------------------------------------
-//
-// 23.06.2006-Milano: ptrcomp adjustments
-// 23.02.2006-Milano: Unit port establishment
-//
-{ agg_polygon_ctrl.pas }
-unit
- agg_polygon_ctrl ;
-
-INTERFACE
-
-{$I agg_mode.inc }
-
-uses
- Math ,
- agg_basics ,
- agg_conv_stroke ,
- agg_ellipse ,
- agg_color ,
- agg_ctrl ,
- agg_vertex_source ;
-
-{ TYPES DEFINITION }
-type
- simple_polygon_vertex_source = object(vertex_source )
- m_polygon : double_ptr;
- m_num_points ,
- m_vertex : unsigned;
- m_roundoff ,
- m_close : boolean;
-
- constructor Construct(polygon : double_ptr; np : unsigned; roundoff : boolean = false; close : boolean = true );
-
- procedure close_(f : boolean );
- function _close : boolean;
-
- procedure rewind(path_id : unsigned ); virtual;
- function vertex(x ,y : double_ptr ) : unsigned; virtual;
-
- end;
-
- polygon_ctrl_impl = object(ctrl )
- m_polygon : double_ptr;
- m_num_points : unsigned;
-
- m_node ,
- m_edge : int;
-
- m_vs : simple_polygon_vertex_source;
- m_stroke : conv_stroke;
-
- m_ellipse : ellipse;
- m_point_radius : double;
- m_status : unsigned;
-
- m_dx ,
- m_dy : double;
-
- m_in_polygon_check : boolean;
-
- constructor Construct(np : unsigned; point_radius : double = 5 );
- destructor Destruct; virtual;
-
- function _num_points : unsigned;
-
- function _xn(n : unsigned ) : double;
- function _yn(n : unsigned ) : double;
-
- function xn_ptr(n : unsigned ) : double_ptr;
- function yn_ptr(n : unsigned ) : double_ptr;
-
- function _polygon : double_ptr;
-
- procedure line_width_(w : double );
- function _line_width : double;
-
- procedure point_radius_(r : double );
- function _point_radius : double;
-
- procedure in_polygon_check_(f : boolean );
- function _in_polygon_check : boolean;
-
- procedure close_(f : boolean );
- function _close : boolean;
-
- // Vertex source interface
- function num_paths : unsigned; virtual;
- procedure rewind(path_id : unsigned ); virtual;
- function vertex(x ,y : double_ptr ) : unsigned; virtual;
-
- // Event handlers
- function in_rect(x ,y : double ) : boolean; virtual;
-
- function on_mouse_button_down(x ,y : double ) : boolean; virtual;
- function on_mouse_button_up (x ,y : double ) : boolean; virtual;
-
- function on_mouse_move(x ,y : double; button_flag : boolean ) : boolean; virtual;
- function on_arrow_keys(left ,right ,down ,up : boolean ) : boolean; virtual;
-
- // Private
- function check_edge (i : unsigned; x ,y : double ) : boolean;
- function point_in_polygon(x ,y : double ) : boolean;
-
- end;
-
- polygon_ctrl = object(polygon_ctrl_impl )
- m_color : aggclr;
-
- constructor Construct(np : unsigned; point_radius : double = 5 );
-
- procedure line_color_(c : aggclr_ptr );
-
- function _color(i : unsigned ) : aggclr_ptr; virtual;
-
- end;
-
-{ GLOBAL PROCEDURES }
-
-
-IMPLEMENTATION
-{ LOCAL VARIABLES & CONSTANTS }
-{ UNIT IMPLEMENTATION }
-{ CONSTRUCT }
-constructor simple_polygon_vertex_source.Construct;
-begin
- m_polygon :=polygon;
- m_num_points:=np;
- m_vertex :=0;
- m_roundoff :=roundoff;
- m_close :=close;
-
-end;
-
-{ CLOSE_ }
-procedure simple_polygon_vertex_source.close_;
-begin
- m_close:=f;
-
-end;
-
-{ _CLOSE }
-function simple_polygon_vertex_source._close;
-begin
- result:=m_close;
-
-end;
-
-{ REWIND }
-procedure simple_polygon_vertex_source.rewind;
-begin
- m_vertex:=0;
-
-end;
-
-{ VERTEX }
-function simple_polygon_vertex_source.vertex;
-begin
- if m_vertex > m_num_points then
- begin
- result:=path_cmd_stop;
-
- exit;
-
- end;
-
- if m_vertex = m_num_points then
- begin
- inc(m_vertex );
-
- if m_close then
- result:=path_cmd_end_poly or path_flags_close
- else
- result:=path_cmd_end_poly or 0;
-
- exit;
-
- end;
-
- x^:=double_ptr(ptrcomp(m_polygon ) + (m_vertex * 2 ) * sizeof(double ) )^;
- y^:=double_ptr(ptrcomp(m_polygon ) + (m_vertex * 2 + 1 ) * sizeof(double ) )^;
-
- if m_roundoff then
- begin
- x^:=Floor(x^ ) + 0.5;
- y^:=Floor(y^ ) + 0.5;
-
- end;
-
- inc(m_vertex );
-
- if m_vertex = 1 then
- result:=path_cmd_move_to
- else
- result:=path_cmd_line_to;
-
-end;
-
-{ CONSTRUCT }
-constructor polygon_ctrl_impl.Construct;
-begin
- inherited Construct(0 ,0 ,1 ,1 ,false );
-
- agg_getmem(pointer(m_polygon ) ,np * 2 * sizeof(double ) );
-
- m_num_points:=np;
-
- m_node:=-1;
- m_edge:=-1;
-
- m_vs.Construct (m_polygon ,m_num_points ,false );
- m_stroke.Construct(@m_vs );
- m_ellipse.Construct;
-
- m_point_radius:=point_radius;
-
- m_status:=0;
-
- m_dx:=0.0;
- m_dy:=0.0;
-
- m_in_polygon_check:=false;
-
- m_stroke.width_(1.0 );
-
-end;
-
-{ DESTRUCT }
-destructor polygon_ctrl_impl.Destruct;
-begin
- agg_freemem(pointer(m_polygon ) ,m_num_points * 2 * sizeof(double ) );
-
- m_stroke.Destruct;
-
-end;
-
-{ _NUM_POINTS }
-function polygon_ctrl_impl._num_points;
-begin
- result:=m_num_points;
-
-end;
-
-{ _XN }
-function polygon_ctrl_impl._xn;
-begin
- result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 ) * sizeof(double ) )^;
-
-end;
-
-{ _YN }
-function polygon_ctrl_impl._yn;
-begin
- result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 + 1 ) * sizeof(double ) )^;
-
-end;
-
-{ XN_PTR }
-function polygon_ctrl_impl.xn_ptr;
-begin
- result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 ) * sizeof(double ) );
-
-end;
-
-{ YN_PTR }
-function polygon_ctrl_impl.yn_ptr;
-begin
- result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 + 1 ) * sizeof(double ) );
-
-end;
-
-{ _POLYGON }
-function polygon_ctrl_impl._polygon;
-begin
- result:=m_polygon;
-
-end;
-
-{ LINE_WIDTH_ }
-procedure polygon_ctrl_impl.line_width_;
-begin
- m_stroke.width_(w );
-
-end;
-
-{ _LINE_WIDTH }
-function polygon_ctrl_impl._line_width;
-begin
- result:=m_stroke._width;
-
-end;
-
-{ POINT_RADIUS_ }
-procedure polygon_ctrl_impl.point_radius_;
-begin
- m_point_radius:=r;
-
-end;
-
-{ _POINT_RADIUS }
-function polygon_ctrl_impl._point_radius;
-begin
- result:=m_point_radius;
-
-end;
-
-{ IN_POLYGON_CHECK_ }
-procedure polygon_ctrl_impl.in_polygon_check_;
-begin
- m_in_polygon_check:=f;
-
-end;
-
-{ _IN_POLYGON_CHECK }
-function polygon_ctrl_impl._in_polygon_check;
-begin
- result:=m_in_polygon_check;
-
-end;
-
-{ CLOSE_ }
-procedure polygon_ctrl_impl.close_;
-begin
- m_vs.close_(f );
-
-end;
-
-{ _CLOSE }
-function polygon_ctrl_impl._close;
-begin
- result:=m_vs._close;
-
-end;
-
-{ NUM_PATHS }
-function polygon_ctrl_impl.num_paths;
-begin
- result:=1;
-
-end;
-
-{ REWIND }
-procedure polygon_ctrl_impl.rewind;
-begin
- m_status:=0;
-
- m_stroke.rewind(0 );
-
-end;
-
-{ VERTEX }
-function polygon_ctrl_impl.vertex;
-var
- cmd : unsigned;
- r : double;
-
-begin
- cmd:=path_cmd_stop;
- r :=m_point_radius;
-
- if m_status = 0 then
- begin
- cmd:=m_stroke.vertex(x ,y );
-
- if not is_stop(cmd ) then
- begin
- transform_xy(x ,y );
-
- result:=cmd;
-
- exit;
-
- end;
-
- if (m_node >= 0 ) and
- (m_node = m_status ) then
- r:=r * 1.2;
-
- m_ellipse.init(_xn(m_status ) ,_yn(m_status ) ,r ,r ,32 );
-
- inc(m_status );
-
- end;
-
- cmd:=m_ellipse.vertex(x ,y );
-
- if not is_stop(cmd ) then
- begin
- transform_xy(x ,y );
-
- result:=cmd;
-
- exit;
-
- end;
-
- if m_status >= m_num_points then
- begin
- result:=path_cmd_stop;
-
- exit;
-
- end;
-
- if (m_node >= 0 ) and
- (m_node = m_status ) then
- r:=r * 1.2;
-
- m_ellipse.init(_xn(m_status ) ,_yn(m_status ) ,r ,r ,32 );
-
- inc(m_status );
-
- cmd:=m_ellipse.vertex(x ,y );
-
- if not is_stop(cmd ) then
- transform_xy(x ,y );
-
- result:=cmd;
-
-end;
-
-{ IN_RECT }
-function polygon_ctrl_impl.in_rect;
-begin
- result:=false;
-
-end;
-
-{ ON_MOUSE_BUTTON_DOWN }
-function polygon_ctrl_impl.on_mouse_button_down;
-var
- i : unsigned;
- ret : boolean;
-
-begin
- ret:=false;
-
- m_node:=-1;
- m_edge:=-1;
-
- inverse_transform_xy(@x ,@y );
-
- for i:=0 to m_num_points - 1 do
- if Sqrt((x - _xn(i ) ) * (x - _xn(i ) ) + (y - _yn(i ) ) * (y - _yn(i ) ) ) < m_point_radius then
- begin
- m_dx :=x - _xn(i );
- m_dy :=y - _yn(i );
- m_node:=i;
- ret :=true;
-
- break;
-
- end;
-
- if not ret then
- for i:=0 to m_num_points - 1 do
- if check_edge(i ,x ,y ) then
- begin
- m_dx :=x;
- m_dy :=y;
- m_edge:=i;
- ret :=true;
-
- break;
-
- end;
-
- if not ret then
- if point_in_polygon(x ,y ) then
- begin
- m_dx :=x;
- m_dy :=y;
- m_node:=m_num_points;
- ret :=true;
-
- end;
-
- result:=ret;
-
-end;
-
-{ ON_MOUSE_BUTTON_UP }
-function polygon_ctrl_impl.on_mouse_button_up;
-var
- ret : boolean;
-
-begin
- ret :=(m_node >= 0 ) or (m_edge >= 0 );
- m_node:=-1;
- m_edge:=-1;
- result:=ret;
-
-end;
-
-{ ON_MOUSE_MOVE }
-function polygon_ctrl_impl.on_mouse_move;
-var
- ret : boolean;
-
- i ,n1 ,n2 : unsigned;
-
- dx ,dy : double;
-
-begin
- ret:=false;
-
- inverse_transform_xy(@x ,@y );
-
- if m_node = m_num_points then
- begin
- dx:=x - m_dx;
- dy:=y - m_dy;
-
- for i:=0 to m_num_points - 1 do
- begin
- xn_ptr(i )^:=_xn(i ) + dx;
- yn_ptr(i )^:=_yn(i ) + dy;
-
- end;
-
- m_dx:=x;
- m_dy:=y;
- ret :=true;
-
- end
- else
- if m_edge >= 0 then
- begin
- n1:=m_edge;
- n2:=(n1 + m_num_points - 1 ) mod m_num_points;
- dx:=x - m_dx;
- dy:=y - m_dy;
-
- xn_ptr(n1 )^:=_xn(n1 ) + dx;
- yn_ptr(n1 )^:=_yn(n1 ) + dy;
- xn_ptr(n2 )^:=_xn(n2 ) + dx;
- yn_ptr(n2 )^:=_yn(n2 ) + dy;
-
- m_dx:=x;
- m_dy:=y;
- ret :=true;
-
- end
- else
- if m_node >= 0 then
- begin
- xn_ptr(m_node )^:=x - m_dx;
- yn_ptr(m_node )^:=y - m_dy;
-
- ret:=true;
-
- end;
-
- result:=ret;
-
-end;
-
-{ ON_ARROW_KEYS }
-function polygon_ctrl_impl.on_arrow_keys;
-begin
- result:=false;
-
-end;
-
-{ CHECK_EDGE }
-function polygon_ctrl_impl.check_edge;
-var
- ret : boolean;
-
- n1 ,n2 : unsigned;
-
- x1 ,y1 ,x2 ,y2 ,dx ,dy ,x3 ,y3 ,x4 ,y4 ,den ,u1 ,xi ,yi : double;
-
-begin
- ret:=false;
-
- n1:=i;
- n2:=(i + m_num_points - 1 ) mod m_num_points;
- x1:=_xn(n1 );
- y1:=_yn(n1 );
- x2:=_xn(n2 );
- y2:=_yn(n2 );
-
- dx:=x2 - x1;
- dy:=y2 - y1;
-
- if Sqrt(dx * dx + dy * dy ) > 0.0000001 then
- begin
- x3:=x;
- y3:=y;
- x4:=x3 - dy;
- y4:=y3 + dx;
-
- den:=(y4 - y3 ) * (x2 - x1 ) - (x4 - x3 ) * (y2 - y1 );
- u1 :=((x4 - x3 ) * (y1 - y3 ) - (y4 - y3 ) * (x1 - x3 ) ) / den;
-
- xi:=x1 + u1 * (x2 - x1 );
- yi:=y1 + u1 * (y2 - y1 );
-
- dx:=xi - x;
- dy:=yi - y;
-
- if (u1 > 0.0 ) and
- (u1 < 1.0 ) and
- (Sqrt(dx * dx + dy * dy ) <= m_point_radius ) then
- ret:=true;
-
- end;
-
- result:=ret;
-
-end;
-
-{ POINT_IN_POLYGON }
-//======= Crossings Multiply algorithm of InsideTest ========================
-//
-// By Eric Haines, 3D/Eye Inc, erich@eye.com
-//
-// This version is usually somewhat faster than the original published in
-// Graphics Gems IV; by turning the division for testing the X axis crossing
-// into a tricky multiplication test this part of the test became faster,
-// which had the additional effect of making the test for "both to left or
-// both to right" a bit slower for triangles than simply computing the
-// intersection each time. The main increase is in triangle testing speed,
-// which was about 15% faster; all other polygon complexities were pretty much
-// the same as before. On machines where division is very expensive (not the
-// case on the HP 9000 series on which I tested) this test should be much
-// faster overall than the old code. Your mileage may (in fact, will) vary,
-// depending on the machine and the test data, but in general I believe this
-// code is both shorter and faster. This test was inspired by unpublished
-// Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
-// Related work by Samosky is in:
-//
-// Samosky, Joseph, "SectionView: A system for interactively specifying and
-// visualizing sections through three-dimensional medical image data",
-// M.S. Thesis, Department of Electrical Engineering and Computer Science,
-// Massachusetts Institute of Technology, 1993.
-//
-// Shoot a test ray along +X axis. The strategy is to compare vertex Y values
-// to the testing point's Y and quickly discard edges which are entirely to one
-// side of the test ray. Note that CONVEX and WINDING code can be added as
-// for the CrossingsTest() code; it is left out here for clarity.
-//
-// Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
-// _point_, returns 1 if inside, 0 if outside.
-function polygon_ctrl_impl.point_in_polygon;
-var
- j ,k : unsigned;
-
- yflag0 ,yflag1 ,inside_flag : int;
-
- vtx0 ,vty0 ,vtx1 ,vty1 : double;
-
-begin
- if m_num_points < 3 then
- begin
- result:=false;
-
- exit;
-
- end;
-
- if not m_in_polygon_check then
- begin
- result:=false;
-
- exit;
-
- end;
-
- vtx0:=_xn(m_num_points - 1 );
- vty0:=_yn(m_num_points - 1 );
-
-// get test bit for above/below X axis
- yflag0:=int(vty0 >= y);
-
- vtx1:=_xn(0 );
- vty1:=_yn(0 );
-
- inside_flag:=0;
-
- for j:=1 to m_num_points do
- begin
- yflag1:=int(vty1 >= y );
-
- // Check if endpoints straddle (are on opposite sides) of X axis
- // (i.e. the Y's differ); if so, +X ray could intersect this edge.
- // The old test also checked whether the endpoints are both to the
- // right or to the left of the test point. However, given the faster
- // intersection point computation used below, this test was found to
- // be a break-even proposition for most polygons and a loser for
- // triangles (where 50% or more of the edges which survive this test
- // will cross quadrants and so have to have the X intersection computed
- // anyway). I credit Joseph Samosky with inspiring me to try dropping
- // the "both left or both right" part of my code.
- if yflag0 <> yflag1 then
- // Check intersection of pgon segment with +X ray.
- // Note if >= point's X; if so, the ray hits it.
- // The division operation is avoided for the ">=" test by checking
- // the sign of the first vertex wrto the test point; idea inspired
- // by Joseph Samosky's and Mark Haigh-Hutchinson's different
- // polygon inclusion tests.
- if int((vty1 - y ) * (vtx0 - vtx1 ) >=
- (vtx1 - x ) * (vty0 - vty1 ) ) = yflag1 then
- inside_flag:=inside_flag xor 1;
-
- // Move to the next pair of vertices, retaining info as possible.
- yflag0:=yflag1;
- vtx0 :=vtx1;
- vty0 :=vty1;
-
- if j >= m_num_points then
- k:=j - m_num_points
- else
- k:=j;
-
- vtx1:=_xn(k );
- vty1:=_yn(k );
-
- end;
-
- result:=inside_flag <> 0;
-
-end;
-
-{ CONSTRUCT }
-constructor polygon_ctrl.Construct;
-begin
- inherited Construct(np ,point_radius );
-
- m_color.ConstrDbl(0.0 ,0.0 ,0.0 );
-
-end;
-
-{ LINE_COLOR_ }
-procedure polygon_ctrl.line_color_;
-begin
- m_color:=c^;
-
-end;
-
-{ _COLOR }
-function polygon_ctrl._color;
-begin
- result:=@m_color;
-
-end;
-
-END.
-
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.4 (Public License)
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.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] -----------------------------------------------------
+//
+// 23.06.2006-Milano: ptrcomp adjustments
+// 23.02.2006-Milano: Unit port establishment
+//
+{ agg_polygon_ctrl.pas }
+unit
+ agg_polygon_ctrl ;
+
+INTERFACE
+
+{$I agg_mode.inc }
+
+uses
+ Math ,
+ agg_basics ,
+ agg_conv_stroke ,
+ agg_ellipse ,
+ agg_color ,
+ agg_ctrl ,
+ agg_vertex_source ;
+
+{ TYPES DEFINITION }
+type
+ simple_polygon_vertex_source = object(vertex_source )
+ m_polygon : double_ptr;
+ m_num_points ,
+ m_vertex : unsigned;
+ m_roundoff ,
+ m_close : boolean;
+
+ constructor Construct(polygon : double_ptr; np : unsigned; roundoff : boolean = false; close : boolean = true );
+
+ procedure close_(f : boolean );
+ function _close : boolean;
+
+ procedure rewind(path_id : unsigned ); virtual;
+ function vertex(x ,y : double_ptr ) : unsigned; virtual;
+
+ end;
+
+ polygon_ctrl_impl = object(ctrl )
+ m_polygon : double_ptr;
+ m_num_points : unsigned;
+
+ m_node ,
+ m_edge : int;
+
+ m_vs : simple_polygon_vertex_source;
+ m_stroke : conv_stroke;
+
+ m_ellipse : ellipse;
+ m_point_radius : double;
+ m_status : unsigned;
+
+ m_dx ,
+ m_dy : double;
+
+ m_in_polygon_check : boolean;
+
+ constructor Construct(np : unsigned; point_radius : double = 5 );
+ destructor Destruct; virtual;
+
+ function _num_points : unsigned;
+
+ function _xn(n : unsigned ) : double;
+ function _yn(n : unsigned ) : double;
+
+ function xn_ptr(n : unsigned ) : double_ptr;
+ function yn_ptr(n : unsigned ) : double_ptr;
+
+ function _polygon : double_ptr;
+
+ procedure line_width_(w : double );
+ function _line_width : double;
+
+ procedure point_radius_(r : double );
+ function _point_radius : double;
+
+ procedure in_polygon_check_(f : boolean );
+ function _in_polygon_check : boolean;
+
+ procedure close_(f : boolean );
+ function _close : boolean;
+
+ // Vertex source interface
+ function num_paths : unsigned; virtual;
+ procedure rewind(path_id : unsigned ); virtual;
+ function vertex(x ,y : double_ptr ) : unsigned; virtual;
+
+ // Event handlers
+ function in_rect(x ,y : double ) : boolean; virtual;
+
+ function on_mouse_button_down(x ,y : double ) : boolean; virtual;
+ function on_mouse_button_up (x ,y : double ) : boolean; virtual;
+
+ function on_mouse_move(x ,y : double; button_flag : boolean ) : boolean; virtual;
+ function on_arrow_keys(left ,right ,down ,up : boolean ) : boolean; virtual;
+
+ // Private
+ function check_edge (i : unsigned; x ,y : double ) : boolean;
+ function point_in_polygon(x ,y : double ) : boolean;
+
+ end;
+
+ polygon_ctrl = object(polygon_ctrl_impl )
+ m_color : aggclr;
+
+ constructor Construct(np : unsigned; point_radius : double = 5 );
+
+ procedure line_color_(c : aggclr_ptr );
+
+ function _color(i : unsigned ) : aggclr_ptr; virtual;
+
+ end;
+
+{ GLOBAL PROCEDURES }
+
+
+IMPLEMENTATION
+{ LOCAL VARIABLES & CONSTANTS }
+{ UNIT IMPLEMENTATION }
+{ CONSTRUCT }
+constructor simple_polygon_vertex_source.Construct;
+begin
+ m_polygon :=polygon;
+ m_num_points:=np;
+ m_vertex :=0;
+ m_roundoff :=roundoff;
+ m_close :=close;
+
+end;
+
+{ CLOSE_ }
+procedure simple_polygon_vertex_source.close_;
+begin
+ m_close:=f;
+
+end;
+
+{ _CLOSE }
+function simple_polygon_vertex_source._close;
+begin
+ result:=m_close;
+
+end;
+
+{ REWIND }
+procedure simple_polygon_vertex_source.rewind;
+begin
+ m_vertex:=0;
+
+end;
+
+{ VERTEX }
+function simple_polygon_vertex_source.vertex;
+begin
+ if m_vertex > m_num_points then
+ begin
+ result:=path_cmd_stop;
+
+ exit;
+
+ end;
+
+ if m_vertex = m_num_points then
+ begin
+ inc(m_vertex );
+
+ if m_close then
+ result:=path_cmd_end_poly or path_flags_close
+ else
+ result:=path_cmd_end_poly or 0;
+
+ exit;
+
+ end;
+
+ x^:=double_ptr(ptrcomp(m_polygon ) + (m_vertex * 2 ) * sizeof(double ) )^;
+ y^:=double_ptr(ptrcomp(m_polygon ) + (m_vertex * 2 + 1 ) * sizeof(double ) )^;
+
+ if m_roundoff then
+ begin
+ x^:=Floor(x^ ) + 0.5;
+ y^:=Floor(y^ ) + 0.5;
+
+ end;
+
+ inc(m_vertex );
+
+ if m_vertex = 1 then
+ result:=path_cmd_move_to
+ else
+ result:=path_cmd_line_to;
+
+end;
+
+{ CONSTRUCT }
+constructor polygon_ctrl_impl.Construct;
+begin
+ inherited Construct(0 ,0 ,1 ,1 ,false );
+
+ agg_getmem(pointer(m_polygon ) ,np * 2 * sizeof(double ) );
+
+ m_num_points:=np;
+
+ m_node:=-1;
+ m_edge:=-1;
+
+ m_vs.Construct (m_polygon ,m_num_points ,false );
+ m_stroke.Construct(@m_vs );
+ m_ellipse.Construct;
+
+ m_point_radius:=point_radius;
+
+ m_status:=0;
+
+ m_dx:=0.0;
+ m_dy:=0.0;
+
+ m_in_polygon_check:=false;
+
+ m_stroke.width_(1.0 );
+
+end;
+
+{ DESTRUCT }
+destructor polygon_ctrl_impl.Destruct;
+begin
+ agg_freemem(pointer(m_polygon ) ,m_num_points * 2 * sizeof(double ) );
+
+ m_stroke.Destruct;
+
+end;
+
+{ _NUM_POINTS }
+function polygon_ctrl_impl._num_points;
+begin
+ result:=m_num_points;
+
+end;
+
+{ _XN }
+function polygon_ctrl_impl._xn;
+begin
+ result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 ) * sizeof(double ) )^;
+
+end;
+
+{ _YN }
+function polygon_ctrl_impl._yn;
+begin
+ result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 + 1 ) * sizeof(double ) )^;
+
+end;
+
+{ XN_PTR }
+function polygon_ctrl_impl.xn_ptr;
+begin
+ result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 ) * sizeof(double ) );
+
+end;
+
+{ YN_PTR }
+function polygon_ctrl_impl.yn_ptr;
+begin
+ result:=double_ptr(ptrcomp(m_polygon ) + (n * 2 + 1 ) * sizeof(double ) );
+
+end;
+
+{ _POLYGON }
+function polygon_ctrl_impl._polygon;
+begin
+ result:=m_polygon;
+
+end;
+
+{ LINE_WIDTH_ }
+procedure polygon_ctrl_impl.line_width_;
+begin
+ m_stroke.width_(w );
+
+end;
+
+{ _LINE_WIDTH }
+function polygon_ctrl_impl._line_width;
+begin
+ result:=m_stroke._width;
+
+end;
+
+{ POINT_RADIUS_ }
+procedure polygon_ctrl_impl.point_radius_;
+begin
+ m_point_radius:=r;
+
+end;
+
+{ _POINT_RADIUS }
+function polygon_ctrl_impl._point_radius;
+begin
+ result:=m_point_radius;
+
+end;
+
+{ IN_POLYGON_CHECK_ }
+procedure polygon_ctrl_impl.in_polygon_check_;
+begin
+ m_in_polygon_check:=f;
+
+end;
+
+{ _IN_POLYGON_CHECK }
+function polygon_ctrl_impl._in_polygon_check;
+begin
+ result:=m_in_polygon_check;
+
+end;
+
+{ CLOSE_ }
+procedure polygon_ctrl_impl.close_;
+begin
+ m_vs.close_(f );
+
+end;
+
+{ _CLOSE }
+function polygon_ctrl_impl._close;
+begin
+ result:=m_vs._close;
+
+end;
+
+{ NUM_PATHS }
+function polygon_ctrl_impl.num_paths;
+begin
+ result:=1;
+
+end;
+
+{ REWIND }
+procedure polygon_ctrl_impl.rewind;
+begin
+ m_status:=0;
+
+ m_stroke.rewind(0 );
+
+end;
+
+{ VERTEX }
+function polygon_ctrl_impl.vertex;
+var
+ cmd : unsigned;
+ r : double;
+
+begin
+ cmd:=path_cmd_stop;
+ r :=m_point_radius;
+
+ if m_status = 0 then
+ begin
+ cmd:=m_stroke.vertex(x ,y );
+
+ if not is_stop(cmd ) then
+ begin
+ transform_xy(x ,y );
+
+ result:=cmd;
+
+ exit;
+
+ end;
+
+ if (m_node >= 0 ) and
+ (m_node = m_status ) then
+ r:=r * 1.2;
+
+ m_ellipse.init(_xn(m_status ) ,_yn(m_status ) ,r ,r ,32 );
+
+ inc(m_status );
+
+ end;
+
+ cmd:=m_ellipse.vertex(x ,y );
+
+ if not is_stop(cmd ) then
+ begin
+ transform_xy(x ,y );
+
+ result:=cmd;
+
+ exit;
+
+ end;
+
+ if m_status >= m_num_points then
+ begin
+ result:=path_cmd_stop;
+
+ exit;
+
+ end;
+
+ if (m_node >= 0 ) and
+ (m_node = m_status ) then
+ r:=r * 1.2;
+
+ m_ellipse.init(_xn(m_status ) ,_yn(m_status ) ,r ,r ,32 );
+
+ inc(m_status );
+
+ cmd:=m_ellipse.vertex(x ,y );
+
+ if not is_stop(cmd ) then
+ transform_xy(x ,y );
+
+ result:=cmd;
+
+end;
+
+{ IN_RECT }
+function polygon_ctrl_impl.in_rect;
+begin
+ result:=false;
+
+end;
+
+{ ON_MOUSE_BUTTON_DOWN }
+function polygon_ctrl_impl.on_mouse_button_down;
+var
+ i : unsigned;
+ ret : boolean;
+
+begin
+ ret:=false;
+
+ m_node:=-1;
+ m_edge:=-1;
+
+ inverse_transform_xy(@x ,@y );
+
+ for i:=0 to m_num_points - 1 do
+ if Sqrt((x - _xn(i ) ) * (x - _xn(i ) ) + (y - _yn(i ) ) * (y - _yn(i ) ) ) < m_point_radius then
+ begin
+ m_dx :=x - _xn(i );
+ m_dy :=y - _yn(i );
+ m_node:=i;
+ ret :=true;
+
+ break;
+
+ end;
+
+ if not ret then
+ for i:=0 to m_num_points - 1 do
+ if check_edge(i ,x ,y ) then
+ begin
+ m_dx :=x;
+ m_dy :=y;
+ m_edge:=i;
+ ret :=true;
+
+ break;
+
+ end;
+
+ if not ret then
+ if point_in_polygon(x ,y ) then
+ begin
+ m_dx :=x;
+ m_dy :=y;
+ m_node:=m_num_points;
+ ret :=true;
+
+ end;
+
+ result:=ret;
+
+end;
+
+{ ON_MOUSE_BUTTON_UP }
+function polygon_ctrl_impl.on_mouse_button_up;
+var
+ ret : boolean;
+
+begin
+ ret :=(m_node >= 0 ) or (m_edge >= 0 );
+ m_node:=-1;
+ m_edge:=-1;
+ result:=ret;
+
+end;
+
+{ ON_MOUSE_MOVE }
+function polygon_ctrl_impl.on_mouse_move;
+var
+ ret : boolean;
+
+ i ,n1 ,n2 : unsigned;
+
+ dx ,dy : double;
+
+begin
+ ret:=false;
+
+ inverse_transform_xy(@x ,@y );
+
+ if m_node = m_num_points then
+ begin
+ dx:=x - m_dx;
+ dy:=y - m_dy;
+
+ for i:=0 to m_num_points - 1 do
+ begin
+ xn_ptr(i )^:=_xn(i ) + dx;
+ yn_ptr(i )^:=_yn(i ) + dy;
+
+ end;
+
+ m_dx:=x;
+ m_dy:=y;
+ ret :=true;
+
+ end
+ else
+ if m_edge >= 0 then
+ begin
+ n1:=m_edge;
+ n2:=(n1 + m_num_points - 1 ) mod m_num_points;
+ dx:=x - m_dx;
+ dy:=y - m_dy;
+
+ xn_ptr(n1 )^:=_xn(n1 ) + dx;
+ yn_ptr(n1 )^:=_yn(n1 ) + dy;
+ xn_ptr(n2 )^:=_xn(n2 ) + dx;
+ yn_ptr(n2 )^:=_yn(n2 ) + dy;
+
+ m_dx:=x;
+ m_dy:=y;
+ ret :=true;
+
+ end
+ else
+ if m_node >= 0 then
+ begin
+ xn_ptr(m_node )^:=x - m_dx;
+ yn_ptr(m_node )^:=y - m_dy;
+
+ ret:=true;
+
+ end;
+
+ result:=ret;
+
+end;
+
+{ ON_ARROW_KEYS }
+function polygon_ctrl_impl.on_arrow_keys;
+begin
+ result:=false;
+
+end;
+
+{ CHECK_EDGE }
+function polygon_ctrl_impl.check_edge;
+var
+ ret : boolean;
+
+ n1 ,n2 : unsigned;
+
+ x1 ,y1 ,x2 ,y2 ,dx ,dy ,x3 ,y3 ,x4 ,y4 ,den ,u1 ,xi ,yi : double;
+
+begin
+ ret:=false;
+
+ n1:=i;
+ n2:=(i + m_num_points - 1 ) mod m_num_points;
+ x1:=_xn(n1 );
+ y1:=_yn(n1 );
+ x2:=_xn(n2 );
+ y2:=_yn(n2 );
+
+ dx:=x2 - x1;
+ dy:=y2 - y1;
+
+ if Sqrt(dx * dx + dy * dy ) > 0.0000001 then
+ begin
+ x3:=x;
+ y3:=y;
+ x4:=x3 - dy;
+ y4:=y3 + dx;
+
+ den:=(y4 - y3 ) * (x2 - x1 ) - (x4 - x3 ) * (y2 - y1 );
+ u1 :=((x4 - x3 ) * (y1 - y3 ) - (y4 - y3 ) * (x1 - x3 ) ) / den;
+
+ xi:=x1 + u1 * (x2 - x1 );
+ yi:=y1 + u1 * (y2 - y1 );
+
+ dx:=xi - x;
+ dy:=yi - y;
+
+ if (u1 > 0.0 ) and
+ (u1 < 1.0 ) and
+ (Sqrt(dx * dx + dy * dy ) <= m_point_radius ) then
+ ret:=true;
+
+ end;
+
+ result:=ret;
+
+end;
+
+{ POINT_IN_POLYGON }
+//======= Crossings Multiply algorithm of InsideTest ========================
+//
+// By Eric Haines, 3D/Eye Inc, erich@eye.com
+//
+// This version is usually somewhat faster than the original published in
+// Graphics Gems IV; by turning the division for testing the X axis crossing
+// into a tricky multiplication test this part of the test became faster,
+// which had the additional effect of making the test for "both to left or
+// both to right" a bit slower for triangles than simply computing the
+// intersection each time. The main increase is in triangle testing speed,
+// which was about 15% faster; all other polygon complexities were pretty much
+// the same as before. On machines where division is very expensive (not the
+// case on the HP 9000 series on which I tested) this test should be much
+// faster overall than the old code. Your mileage may (in fact, will) vary,
+// depending on the machine and the test data, but in general I believe this
+// code is both shorter and faster. This test was inspired by unpublished
+// Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
+// Related work by Samosky is in:
+//
+// Samosky, Joseph, "SectionView: A system for interactively specifying and
+// visualizing sections through three-dimensional medical image data",
+// M.S. Thesis, Department of Electrical Engineering and Computer Science,
+// Massachusetts Institute of Technology, 1993.
+//
+// Shoot a test ray along +X axis. The strategy is to compare vertex Y values
+// to the testing point's Y and quickly discard edges which are entirely to one
+// side of the test ray. Note that CONVEX and WINDING code can be added as
+// for the CrossingsTest() code; it is left out here for clarity.
+//
+// Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
+// _point_, returns 1 if inside, 0 if outside.
+function polygon_ctrl_impl.point_in_polygon;
+var
+ j ,k : unsigned;
+
+ yflag0 ,yflag1 ,inside_flag : int;
+
+ vtx0 ,vty0 ,vtx1 ,vty1 : double;
+
+begin
+ if m_num_points < 3 then
+ begin
+ result:=false;
+
+ exit;
+
+ end;
+
+ if not m_in_polygon_check then
+ begin
+ result:=false;
+
+ exit;
+
+ end;
+
+ vtx0:=_xn(m_num_points - 1 );
+ vty0:=_yn(m_num_points - 1 );
+
+// get test bit for above/below X axis
+ yflag0:=int(vty0 >= y);
+
+ vtx1:=_xn(0 );
+ vty1:=_yn(0 );
+
+ inside_flag:=0;
+
+ for j:=1 to m_num_points do
+ begin
+ yflag1:=int(vty1 >= y );
+
+ // Check if endpoints straddle (are on opposite sides) of X axis
+ // (i.e. the Y's differ); if so, +X ray could intersect this edge.
+ // The old test also checked whether the endpoints are both to the
+ // right or to the left of the test point. However, given the faster
+ // intersection point computation used below, this test was found to
+ // be a break-even proposition for most polygons and a loser for
+ // triangles (where 50% or more of the edges which survive this test
+ // will cross quadrants and so have to have the X intersection computed
+ // anyway). I credit Joseph Samosky with inspiring me to try dropping
+ // the "both left or both right" part of my code.
+ if yflag0 <> yflag1 then
+ // Check intersection of pgon segment with +X ray.
+ // Note if >= point's X; if so, the ray hits it.
+ // The division operation is avoided for the ">=" test by checking
+ // the sign of the first vertex wrto the test point; idea inspired
+ // by Joseph Samosky's and Mark Haigh-Hutchinson's different
+ // polygon inclusion tests.
+ if int((vty1 - y ) * (vtx0 - vtx1 ) >=
+ (vtx1 - x ) * (vty0 - vty1 ) ) = yflag1 then
+ inside_flag:=inside_flag xor 1;
+
+ // Move to the next pair of vertices, retaining info as possible.
+ yflag0:=yflag1;
+ vtx0 :=vtx1;
+ vty0 :=vty1;
+
+ if j >= m_num_points then
+ k:=j - m_num_points
+ else
+ k:=j;
+
+ vtx1:=_xn(k );
+ vty1:=_yn(k );
+
+ end;
+
+ result:=inside_flag <> 0;
+
+end;
+
+{ CONSTRUCT }
+constructor polygon_ctrl.Construct;
+begin
+ inherited Construct(np ,point_radius );
+
+ m_color.ConstrDbl(0.0 ,0.0 ,0.0 );
+
+end;
+
+{ LINE_COLOR_ }
+procedure polygon_ctrl.line_color_;
+begin
+ m_color:=c^;
+
+end;
+
+{ _COLOR }
+function polygon_ctrl._color;
+begin
+ result:=@m_color;
+
+end;
+
+END.
+