Page 1 of 1
Any ideas? (intersection with a line)
Posted: Sat Sep 24, 2005 4:04 pm
by Fleath//
Yep, I'm still lurking and posting my questions *cough*
To sum up what I'm doing this time, I'm making a small drawing application that's intended to draw lines onto a grid. This is just for my own random use, an experiment.
I've got everything to draw by storing the starting x/y and the ending x/y of everything in a linked list and drawing from that.
What I'm intending to do now is make it so when you right click/right click and drag anywhere over a line, it'll be deleted from the linked list, and thus the image.
To do this, I need to be able to take the x/y coordinates of the mouse, find out if any lines intersect that point, find their position on the list, and remove them.
Can anyone offer a suggestion on how to do this? A push in the right direction or a suggestion on a better way to go about it, anything's welcome.
Posted: Sat Sep 24, 2005 4:27 pm
by srod
***deleted first post!***
**edit**
A more accurate way would be to iterate through the list and determine the shortest distance of the point (x, y) -which hold the mouse coordinates - from the underlying line. When complete, select the line which yielded the shortest distance and if this particular distance is 'very small', then assume that the user intended to click this line.
For each line then, calculate the gradient of the line (call this value m).
The distance of (x, y) from the line with gradient m and with starting point (a, b) is given by (y - mx - b + ma) / sqrt(1 + m^2).
I could hack up an example later on if you wish.
Posted: Sat Sep 24, 2005 4:59 pm
by netmaestro
There is one way to approach it that requires almost no effort at all, but it depends upon all the lines being different colours. All you have to do is test for a left mouse click in your main loop, if you get it do:
Code: Select all
StartDrawing(WindowOutput()) ;or screen or whatever
If point(mouseX(),mouseY()) <> #BackgroundColor ;whatever you define that to be
;find the colour in the list and remove the element
Endif
StopDrawing()
Note that you can have lines that are visually the same color but numerically are different. For example, rgb(255,0,0) will not be distinguishable by the naked eye from rgb(250,0,0) but you can have six separate colors defined in between.
Posted: Wed Sep 28, 2005 2:26 am
by Fleath//
Thanks for the responses, sorry it took so long for me to reply.
srod's plan seems to fit what I'm trying to do, I have all the lines layed out in a linked list.
How would I go about calculating the gradient of a line from a starting x/y and and ending x/y? do the mx and ma values relate to this?
EDIT:
I found;
gradient = (y2-y1) / (x2-x1)
but the mx and ma values?

Posted: Wed Sep 28, 2005 2:15 pm
by srod
Sorry I haven't time to hack up some code for you at the moment.
The gradient of the line segment joining (a, b) to (x, y) is given by (y-b)/(x-a).
Take care when calculating this because if the line is vertical, then (x-a) will be zero and the gradient calculation will attempt to divide by zero. Treat this case separately. To get the distance of a point from a vertical line simply subtract the x-coordinate of the point from any point on the line.
Hope this helps.
**EDIT**
Sorry, by ma I simply mean the value of the gradient 'm', multiplied by the value of 'a' etc.
Posted: Wed Sep 28, 2005 2:32 pm
by netmaestro
The gradient thing is good, but don't forget one wrinkle: If the user clicks on an intersection of two lines, more than one line will meet the test. You have to know the "depth" of the lines so you can remove the topmost line, that is what will make sense to the user.
Posted: Wed Sep 28, 2005 3:50 pm
by Fleath//
Thank you both for your responses, I've got it set up how I want now *nod*
It detects the nearest line, then chooses the line that is the latest on the list (being the most recently drawn), and removes it. Perfect.
Posted: Thu Sep 29, 2005 10:17 am
by srod
Forget one thing, although I presume you've figured this out. The distance formula above will sometimes return a negative distance (depending upon which side of the line the point lies). Simply take the ABSolute value etc.
Posted: Wed Nov 30, 2005 12:35 pm
by einander
Got on this one a bit late. Hope it's useful for someone out there.
Updated for PB 4.20
Code: Select all
;Get intersection point
;by einander - PB 3.94
;november 30 - 2005
;Updated for PB 4.20
;June 9 - 2008
Procedure GetIntersectionPoint(X,Y,X1,Y1,A,b,c,d,*P.POINT)
Width1=X1-X : Height1=Y1-Y
Width2=c-A : Height2=d-b
If Width1 : Diag1.f=Height1/Width1
Else : Diag1.f=0
EndIf
If Width2 : Diag2.f=Height2/Width2
Else : Diag2.f=0
EndIf
A1.f=Y-Diag1*X : A2.f=b-Diag2*A : A3.f=Diag1-Diag2
If A3 : xCross.f=-(A1-A2)/A3
Else : xCross.f=0
EndIf
yCross.f=A1+Diag1*xCross
If(X-xCross)*(xCross-X1)<0 Or (A-xCross)*(xCross-c)<0 Or (Y-yCross)*(yCross-Y1)<0 Or (b-yCross)*(yCross-d)<0
ProcedureReturn 0
EndIf
*P\X=Round(xCross,1):*P\Y=Round(yCross,1)
ProcedureReturn 1
EndProcedure
;Test it <<<<<<<<<<<<<<<<<<<<<<<<<<
hwnd = OpenWindow(0, 0, 0,0,0 ,"Line Intersection", #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE)
LoadFont(1,"arial",16)
StartDrawing(WindowOutput(0))
CreateGadgetList(hwnd)
Wi=WindowWidth(0) : He=WindowHeight(0)
TextGadget(0,0,He-30,400,30,"",#PB_Text_Border )
SetGadgetFont(0,FontID(1))
Repeat
Box(0,0,Wi,He,0)
X=Random(Wi) : Y=Random(He) : X1=Wi : Y1=Random(He)
A=Random(Wi) : b=0 : c=Random(Wi) : d=He
DrawingMode(4)
LineXY(X,Y,X1,Y1,#Blue) : LineXY(A,b,c,d,#Red)
If GetIntersectionPoint(X,Y,X1,Y1,A,b,c,d,@P.POINT)
Circle(P\X,P\Y,6,#Magenta)
SetGadgetText(0," Intersection at "+Str(P\X)+" "+Str(P\Y)+" - Press <SPC>")
Else
SetGadgetText(0," No Intersection - Press <SPC>")
EndIf
Repeat
Ev=WaitWindowEvent()
If Ev= #PB_Event_CloseWindow : End :EndIf
Until Ev=#WM_KEYDOWN
If EventwParam()=27 : End:EndIf
DrawingMode(1)
ForEver
End