|
Polygon expansion / contraction |
|
|
download Delphi project
download program
This Delphi project shows expansion and contraction of polygons.
Below is a picture of the project at work:
The grey lines are the original polygon, the black lines form the contracted polygon.
The process uses basic vector operations. So, I start with a brief explanation.
Vector geometry in a plane.
A vector (V) in 2D is a line segment defined by dx and dy (horizontal and vertical distances).
Vector addition
Multiplication by a scalar
Equation of a line
Intersection of lines
Parallel shift
Vector direction
(in radians)
Left and Right orientation
Left picture: counterclockwise (CCW). Right: clockwise (CW).
Expansion algorithm
A right shift of vectors is needed if
- the polygon is CW oriented and
- expansion is required
or
- polygon is CW oriented and
- contraction is requested
In other cases a left shift must take place.
The new points are the intersections of the shifted vectors.
Before expansion, the vector list is created from the list of points.
The angles between connecting vectors are summed to know CW or CCW orientation.
Using the vector list, the new points are calculated.
The program
const offset = 0.025; //displacement
pi05 = 0.5*pi;
pi15 = 1.5*pi;
pi2 = 2*pi;
Vector direction
function VDir(deltaX,deltaY : single) : single;
//return direction of vector in radians
//(+,0) = 0; (0,+) = 0.5pi ; (-,0) = pi ; (0,-) = 1.5pi
begin
if deltaX = 0 then
begin
if deltaY > 0 then result := pi05 else result := pi15;
exit;
end;
result := arctan((deltaY)/(deltaX));
if deltaX < 0 then result := result + pi;
if result < 0 then result := result + pi2;
end;
Angle between vectors
function V12angle(dir1,dir2 : single) : single;
//return angle between vectors v1,v2 in radians
begin
result := dir2 - dir1;
if result > pi then result := result-pi2
else if result < -pi then result := result+pi2;
end;
Summing the angles
function SumAngles : single;
var i : byte;
begin
result := 0;
for i := 1 to vcount-1 do
result := result + V12Angle(vectorlist[i].dir,vectorlist[i+1].dir);
result := result + V12Angle(vectorlist[vcount].dir,vectorlist[1].dir);
end;
Data formats
Const maxpoint = 40;
type Tvector = record
x,y : single;
dx,dy : single;
dir : single; //direction 0..+-pi
modulus : single;
end;
TVectorList = array[1..maxpoint] of TVector;
TFpoint = record
x : single;
y : single;
end;
TFpoints = array[1..maxpoint] of TFpoint;
var Fpoints : TFpoints; //in interface
pcount : byte; //number of points
vectorlist : TVectorlist;//in implementation
vcount : byte; //number of vectors
Vector shifting
procedure shiftvector(var v : Tvector; R : boolean);
//R : true for right shift
var dd,m: single;
begin
if R then m := 1 else m := -1;
with v do
begin
dd := offset/modulus;
x := x+dd*dy*m;
y := y-dd*dx*m;
end;
end;
Form and buttons
The polygon is painted on a bitmap which is copied to form1.paintbox1.
Units
Unit1 holds the procedures for drawing and the event handlers.
The poly_unit takes care of the polygon specific procedures and data.
The clock_unit supplies a microseconds clock to measure processing time and
control the expansion speed.
For details please refer to the source code.
Operations
drawing a polygon
[draw] button down.
- mouse DOWN on paintbox and move
- mouse UP to end.
modify a polygon
[modify] button down
- mouse DOWN on point and move
- mouse UP to stop
[undo] : remove last added vector.
[clear] : erase polygon
[save] : polygon is stored and remains drawn in grey.
[reload]: restore saved polygon.
|