Jump to content
Developer Wiki and Function Reference Links ×

Which Side of Line, User Click


PeterT

Recommended Posts

Is there an easy way to determine which side of a line a user has clicked on?

I am currently trying to do it by getting the angle of the line, then determining the 180? sweep between the positive and negative directions of the line, then getting the click point and comparing the angle between this point and the centerpoint of my line. If this click point angle falls within the sweep angle of my line, I will know which side ithe click is on.

I am getting a little fouled up though, with the relatoionship of positive and negative REAL variables versus positive and negative angle values.

Is there an easier way to do this, or does anyone have some insight that might help me figure this out? Any ideas appreciated.

Link to comment
Is there an easier way to do this, or does anyone have some insight that might help me figure this out?

Easier to understand, or easier to implement? I think the angle way may be easier to understand, but harder to implement when you cross the ?180? boundary. Even with positive degrees/radians, there is a 0/360?, or 0/2Pi boundary to contend with.

I prefer to use vectors and the cross product to determine 2D rotation. It may not be easier to understand, but it is easier to implement, especially with the following code.

Enjoy,

Raymond

procedure XProd;
{ Show whether a user-selected Point is to the Right or Left of a user-drawn Line. }
{ Your vantage point is standing at point P1 and looking at point P2. }
VAR
P1, P2, P3 :Point;

 function InARow (P1, P2, P3: Point): Boolean;
 { Returns TRUE if the angle from line P1-P2 to point P3 is collinear. }
 Begin
	 InARow := ((P1.x - P2.x) * (P3.y - P2.y) - (P3.x - P2.x) * (P1.y - P2.y)) = 0;
 End;		{ InARow }


 function RotateCCW (P1, P2, P3: Point): Boolean;
 { Returns TRUE if the angle from line P1-P2 to point P3 is CCW. }
 Begin
	 RotateCCW := ((P1.x - P2.x) * (P3.y - P2.y) - (P3.x - P2.x) * (P1.y - P2.y)) < 0;
 End;		{ RotateCCW }


BEGIN
{Interactively draw a line and display it. }
GetLine(P1.x, P1.y, P2.x, P2.y);
MoveTo(P1.x, P1.y);
LineTo(P2.x, P2.y);
Redraw;

{ Get a point to compare to the line. }
GetPt(P3.x, P3.y);

{ Herald in the answer and display it for all to see! }
SysBeep;
if InARow(P1, P2, P3) then AlrtDialog('You clicked ON the line.')
else if RotateCCW (P1, P2, P3) then AlrtDialog('You clicked on the LEFT side of the line.')
else AlrtDialog('You clicked on the RIGHT side of the line');

{ Clean up - throw away the line. }
DelObject(H);
END;
RUN(XProd);

Link to comment

Thanks Raymond,

That is a very short and clean piece of code that does exactly what I wanted.

( I added the H variable and the H:= LNewObj to get the cleanup to execute)

I guess I need to brush up on Vectors, I have not used them before. The formula seems to get a bit clearer after staring at it for a while. Are there any other Vector formulas I should be aware of? That one sure seems useful.

As I get more familiar with the VectorScript language, and more familiar with the available procedures, the challange of scripting seems to shift towards figuring out what formulas to use to manipulate the data in the script.

Thanks for the insight.

Link to comment

Hi Peter,

You're welcome. Sorry about the dangling H. I had "H := LNewObj;" in there earlier then opted to lose the assignment for the following. It should read:

DelObject(LNewObj);

Either way works. I tend toward minimalism whenever it is convenient.

The forumlae are really expanded versions of U x V or CrossProduct(U, V) where U and V are defined from the three points P1, P2 & P3.

By using the expanded versions I forego calculating U, V & W. But if you want to try it, declare P1, P2 & P3 as type Vector instead of type Point along with vectors U, V & W.

The answer for crosproduct in 2D math is always in the Z direction or the returned vector. If the Z component is positive the rotation is CCW; if it's negative, CW; if it's zero, then collinear. The magnitude is unimportant in this case.

VAR

P1, P2, P3, U, V, W :Vector;

...

function InARow (P1, P2, P3: Vector): Boolean;

...

function RotateCCW (P1, P2, P3: Vector): Boolean;

...

{ longhand }

U := P2 - P1;

V := P3 - P1;

W := crossproduct(U, V);

{ or minimally }

W := crossproduct(P2-P1, P3-P1);

{ the answer }

message(W.z); { test Z component for +, -, or 0 }

To answer your question, "Are there any other Vector formulas I should be aware of?", the short answer is YES. It would be difficult to give a rough overview of the field. Suffice it to say that all computer graphics are based on vectors and matrices. The obvious recommendation is to also become familiar with Unit, Norm and DotProduct. Unit scales a vector to length of 1, and Norm returns the length of a vector (it's always positive). So, Norm(Unit(V)) is always 1 (unless V has zero length). DotProduct can be used to indicate if two lines/vectors are parallel or perpendicular.

if (DotProduct(Unit(U), Unit(V) = 1) then { U & V are parallel }

if (DotProduct(Unit(U), Unit(V) = 0) then { U & V are perpendicular }

If you have a more specific question in the future it may be easier to answer.

Glad I could help,

Raymond

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...