Examples Delphi

VARIOUS ROUTINES USED IN A GRAPHICS APP WRITTEN BY RDE:
THEY ARE LIKELY TO REQUIRE ADAPTATION TO BE MADE TO WORK
WITH WHATEVER (point and line) DATA STRUCTURES ARE PRESENT
IN YOUR PARTICULAR APP
-BUT THE ALGORITHMS ARE KOSHER
Richard
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TListsManager.GetNearestLineToClickPos(clickX, clickY: Integer): Integer;
//CURRENTLY NOT CALLED
{this is what's known in graphics programming circles as 'PICKING'...}
{This function is generically useful although it is most appropriate in
a situation where we have a three-layer heirarchy of data structures:
1) a 'display wireframe' [called here the displayMatrix] which is a projection
of 3D co-ordinate data from the 'reference wireframe' [see 2 below] onto the 2D
world of the screen 2) a 'reference wireframe' whose co-ordinate sets DON'T
undergo all of the transformations that we might apply to the display wireframe.
This reference wireframe [called ptMatrix here] is a stripped-down data set
using pretty much exclusively COORDINATE data taken from the data structure on
the bottom layer, 3) the 'Entity data' layer. See notes elsewhere for more
detail, but suffice it to say here that one of the beauties of this arrangement
is that we can ALSO use a 'wireFrameLines' array (where we keep track of INDEXES
into the two point matrices [for line endpoints]) and whatever changes we
make to our lines, in terms of length, angle, etc etc, we can still reference
the same line entity on all three levels by virtue of the index which remains
the same...}
var
slope : Real;
XRealPrime : Real;
YRealPrime : Real;
dSquared : Real;
endPt1Idx : Integer;
endPt2Idx : Integer;
X1 : Real;
X2 : Real;
Y1 : Real;
Y2 : Real;
lineIdx : Integer;
distEndPt1Sqr: Real;
distEndPt2Sqr: Real;
lineDistSqr : Real;
//not used anymore: we just select the NEAREST line instead...
//insideSelRadius: Boolean;
smallestDistSquared: Real;
nearestLineIdx : Integer;
begin
nearestLineIdx := -1;
smallestDistSquared := InitialValue;
//UNcomment me
//next line spurious
//iterate through whatever LINES data
//structure you have got to work with-
//this code has been copied from
//elsewhere and needs adapting...
for lineIdx := 0 to 1 do
//for lineIdx := 0 to (linesNumber - 1) do
begin
//UNcomment me
//endPt1Idx := wFrameLines[lineIdx].endpt1;
//endPt2Idx := wFrameLines[lineIdx].endpt2;
//X1 := displayMatrix[endPt1Idx].x;
//Y1 := displayMatrix[endPt1Idx].y;
//X2 := displayMatrix[endPt2Idx].x;
//Y2 := displayMatrix[endPt2Idx].y;
lineDistSqr := (X2 - X1)*(X2 - X1)+(Y2 - Y1)*(Y2 - Y1);
distEndPt1Sqr := (ClickX - X1)*(ClickX - X1)+(ClickY - Y1)*(ClickY - Y1);
distEndPt2Sqr := (ClickX - X2)*(ClickX - X2)+(ClickY - Y2)*(ClickY - Y2);
if (distEndPt1Sqr > lineDistSqr) or (distEndPt2Sqr > lineDistSqr) then
begin
continue;
end;
if ((X2 - X1) = 0) or ((Y2 - Y1) = 0) then
begin
if ((X2 - X1) = 0) then
begin
dSquared := (ClickX - X1) * (ClickX - X1);
end
else
begin
dSquared := (ClickY - Y1) * (ClickY - Y1);
end;
end
else
begin
slope := (Y2 - Y1) / (X2 - X1);
XRealPrime := (ClickY - Y1 + slope * X1 + ClickX / slope) /
(slope + 1.0 / slope);
YRealPrime := Y1 + slope * ((ClickY - Y1 + ClickX / slope - X1 / slope)/
(slope + 1.0 / slope));
dSquared := (ClickX - XRealPrime) * (ClickX - XRealPrime) +
(ClickY - YRealPrime) * (ClickY - YRealPrime);
end;
(*
//commented-out code here found the FIRST line only
//whereas code below finds the VERY nearest
//(without bothering with any sort of selection radius)
if (dSquared <= selectionRadius) then
begin
insideSelRadius := True;
{here we only bother with the first selectable entity that we find
(rather than trying to catch ALL entity that are inside the
clicking radius) but, if the first one we find is not the entity
that the user intends to select 'it's tough': they'll have to find
a better way of picking it (eg by rotating the viewpoint, etc etc)...}
break;
end;
*)
if dSquared < smallestDistSquared then
begin
smallestDistSquared := dSquared;
nearestLineIdx := lineIdx;
end;
end; //end looping through all lines
//UNcomment me
//next line spurious
if (nearestLineIdx > 1) then
//if (nearestLineIdx > linesNumber) then
begin
Result := -1;
end
else Result := nearestLineIdx;
end;
///////////////////////////////////////////////////////////////////////////////////////////////
function TListsManager.GetPtToPtDistance2D(ptOne, ptTwo: TPoint3D): Real;
//find the distance 'by the shortest route' between the two points
//passed in. The formula used below is the 'basic'[!] formula known
//to all[?] as Pythagoras' theorem (where you find the length of the
//hypotenuse of the triangle that has the two points at each end of
//the hypotenuse, and where the horizontal and vertical sides are
//parallel to the x and y axes)...
var
distSquared: Real;
begin
distSquared := (((ptOne.x - ptTwo.x) * (ptOne.x - ptTwo.x)) +
((ptOne.y - ptTwo.y) * (ptOne.y - ptTwo.y)));
Result := sqrt(distSquared);
//IMPORTANT -if we use the z values, later, we must
//code a 3D version of the same algorithm:
//-simple: find the
//sqr root of X squared plus Y squared plus Z squared...
end;
///////////////////////////////////////////////////////////////////
function TListsManager.GetNearestPtToClickPos(X, Y: Real): Integer;
//CURRENTLY NOT CALLED
//see also GetNearestLineToClickPos(). This is what's known in graphics
//programming circles as 'PICKING'. Here we return the index of the Step POINT
//nearest to the x,y coordinate passed in...
//NOTE THAT WHILE THIS CODE (and a few subsequent not-called functions) MIGHT
//BE USEFUL AT SOME POINT (since they implement a 'proper' 'picking' algorithm)
//CURRENTLY WE DON'T NEED TO GO DOWN THAT ROAD. See IsScrPtInsideStep() and
//GetStepUnderMouseIndex() below, where, when ascertaining which Step the user
//has clicked on, we just check to see if the click is 'within the area
//enclosed by the Step perimiter lines' (with a simple algorithm)...
var
thisDistSquared : Real;
smallestDistSquared: Real;
X1 : Real;
Y1 : Real;
ptIdx : Integer;
ptsNumber : Integer;
begin
smallestDistSquared := InitialValue;
Result := -1;
//iterate through whatever POINTS data
//structure you have got to work with-
//this code has been copied from the
//'Fox' project and needs adapting...
ptsNumber := 69; //edit me
for ptIdx := 0 to (ptsNumber) do
begin
//X1 := displayMatrix[ptIdx].x;
//Y1 := displayMatrix[ptIdx].y;
thisDistSquared := (X1 - X) * (X1 - X) + (Y1 - Y) * (Y1 - Y);
if thisDistSquared < smallestDistSquared then
begin
smallestDistSquared := thisDistSquared;
Result := PtIdx;
end;
end;
end;
//////////////////////////////////////////////////////////////////////////////////
function TListsManager.GetNearestLineEndToClickPos(LineIdx, XClick, YClick : Integer): Integer;
//CURRENTLY NOT CALLED
{return the number of the endpoint (1 or 2) of the line that is closest to
the user mouse position. Note that here we use a simple algorithm that uses
whichever is the smallest value, the x distance or the y distance from the
click point to a line end, and then works with that, rather than doing a
full 'Pythagoras' algorithm to find the distance...}
var
endPt1Idx : Integer;
endPt2Idx : Integer;
X1 : Integer;
X2 : Integer;
Y1 : Integer;
Y2 : Integer;
//distanceX1: Integer;
//distanceY1: Integer;
//distanceX2: Integer;
//distanceY2: Integer;
xDistToEnd1 : Integer;
yDistToEnd1 : Integer;
xDistToEnd2 : Integer;
yDistToEnd2 : Integer;
distToEnd1: Real;
distToEnd2: Real;
ptNum : Integer;
begin
ptNum := -1;
if (lineIdx >= 0) then
begin
//UNcomment me
//but SUBSTITUTE THE DATA STRUCTURES USED
//IN this PROGRAM for displayMatrix etc etc
//endPt1Idx := wFrameLines[lineIdx].endpt1;
//endPt2Idx := wFrameLines[lineIdx].endpt2;
//X1 := Round(displayMatrix[endPt1Idx].x);
//Y1 := Round(displayMatrix[endPt1Idx].y);
//X2 := Round(displayMatrix[endPt2Idx].x);
//Y2 := Round(displayMatrix[endPt2Idx].y);
if (XClick > X1) then
xDistToEnd1 := (XClick - X1)
else
xDistToEnd1 := (X1 - XClick);
if (YClick > Y1) then
yDistToEnd1 := (YClick - Y1)
else
yDistToEnd1 := (Y1 - YClick);
if (XClick > X2) then
xDistToEnd2 := (XClick - X2)
else
xDistToEnd2 := (X2 - XClick);
if (YClick > Y2) then
yDistToEnd2 := (YClick - Y2)
else
yDistToEnd2 := (Y2 - YClick);
distToEnd1 := sqrt((xDistToEnd1 * xDistToEnd1) + (yDistToEnd1 * yDistToEnd1));
distToEnd2 := sqrt((xDistToEnd2 * xDistToEnd2) + (yDistToEnd2 * yDistToEnd2));
if (distToEnd1 >= distToEnd2) then ptNum := 2;
if (distToEnd2 >= distToEnd1) then ptNum := 1;
end;
Result := ptNum;
end;