tiny 2d line "class" and 2d Point inside a quad example
Posted: Mon Nov 29, 2010 5:31 pm
Hi,
I've been a fan of Froggerprogger's 3d Vector Procedures for quite some time now. In some point I needed also plain 2d lines and so here is my implementation.
One could easily create Turtle-style graphics with these.
This 2d line "class" includes also an example is for testing whether a mouse pointer is inside the quadrangle area or not. It has worked well so far, but I'm more concerned about the speed.
I'm using this routine quite intensively in one 3d application which is based on Sprite3D and TransformSprite3D(...) commands. This is also why the points have to be given in the certain order (clockwise).
One morning I started wondering whether there is any faster solution for this?
Greetings for all,
Kapslok
I've been a fan of Froggerprogger's 3d Vector Procedures for quite some time now. In some point I needed also plain 2d lines and so here is my implementation.
One could easily create Turtle-style graphics with these.
This 2d line "class" includes also an example is for testing whether a mouse pointer is inside the quadrangle area or not. It has worked well so far, but I'm more concerned about the speed.
Code: Select all
EnableExplicit
; Tiny 2d Line "class" for PureBasic users (25.11.2010)
;
; And a mousepick - example
;
; by Kapslok
#Deg2Rad = 0.01745329
#Rad2Deg = 57.2957795
Structure Line2D
x.f
y.f
x2.f
y2.f
EndStructure
Procedure.l DefineLine(*line.Line2D, x.f, y.f, x2.f, y2.f)
*line\x = x
*line\y = y
*line\x2 = x2
*line\y2 = y2
ProcedureReturn *line
EndProcedure
Procedure.f GetLineLength(*line.Line2D)
ProcedureReturn Sqr(Pow(*line\x-*line\x2,2)+Pow(*line\y-*line\y2,2))
EndProcedure
Procedure.f GetLineAngle(*line.Line2D)
Static x1.f, y1.f, temp.f
x1 = *line\x2 - *line\x
y1 = *line\y2 - *line\y
If y1=0
If x1<0 : ProcedureReturn 180 : Else : ProcedureReturn 0 : EndIf
EndIf
If x1=0
If y1<0 : ProcedureReturn 90 : Else : ProcedureReturn 270 : EndIf
EndIf
temp = ATan(y1 / x1) * #Rad2Deg
If y1 <= 0
If temp <= 0
temp * -1
Else
temp = 180 - temp
EndIf
Else
If temp < 0
temp = 180 - temp
Else
temp = 360 - temp
EndIf
EndIf
ProcedureReturn temp
EndProcedure
Procedure.l RotateLine(*line.Line2D,angle.f)
Static dx.f,dy.f
dx.f=*line\x2 - *line\x
dy.f=*line\y2 - *line\y
angle * #Deg2Rad
*line\x2 = Cos(angle) * dx - Sin(angle)*dy + *line\x
*line\y2 = Sin(angle) * dx + Cos(angle)*dy + *line\y
ProcedureReturn *line
EndProcedure
;
; Here is the actual code, which utilizes the previous
; "class"
Procedure TestMousePick(Xmouse,Ymouse,x1,y1,x2,y2,x3,y3,x4,y4)
Static rot.f, llen.f
Static MyLin.Line2D
Static PickLin.Line2D
; Is the pointer on the window?
If Xmouse<0 : ProcedureReturn 0 : EndIf
; Another quick way out?
If Xmouse<x1 And Xmouse<x2 And Xmouse<x3 And Xmouse<x4
ProcedureReturn 0
EndIf
If Xmouse>x1 And Xmouse>x2 And Xmouse>x3 And Xmouse>x4
ProcedureReturn 0
EndIf
If Ymouse>y1 And Ymouse>y2 And Ymouse>y3 And Ymouse>y4
ProcedureReturn 0
EndIf
If Ymouse<y1 And Ymouse<y2 And Ymouse<y3 And Ymouse<y4
ProcedureReturn 0
EndIf
; Some coordinates match... let's do more exact inspection
; One rotation for each side of the quadrangle
DefineLine(@MyLin,x1,y1,x2,y2)
DefineLine(@PickLin,x1,y1,Xmouse,Ymouse)
rot=GetLineAngle(@MyLin)
RotateLine(@PickLin,rot)
llen=GetLineLength(@MyLin)
If PickLin\y2<y1
ProcedureReturn 0
EndIf
DefineLine(@MyLin,x2,y2,x3,y3)
DefineLine(@PickLin,x2,y2,Xmouse,Ymouse)
rot=GetLineAngle(@MyLin)
RotateLine(@PickLin,rot)
llen=GetLineLength(@MyLin)
If PickLin\y2<y2
ProcedureReturn 0
EndIf
DefineLine(@MyLin,x3,y3,x4,y4)
DefineLine(@PickLin,x3,y3,Xmouse,Ymouse)
rot=GetLineAngle(@MyLin)
RotateLine(@PickLin,rot)
llen=GetLineLength(@MyLin)
If PickLin\y2<y3
ProcedureReturn 0
EndIf
DefineLine(@MyLin,x4,y4,x1,y1)
DefineLine(@PickLin,x4,y4,Xmouse,Ymouse)
rot=GetLineAngle(@MyLin)
RotateLine(@PickLin,rot)
llen=GetLineLength(@MyLin)
If PickLin\y2<y4
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
OpenWindow(0,0,0,800,600,"Point Inside Quadrangle",#PB_Window_ScreenCentered | #PB_Window_SystemMenu )
Define x1=550,y1=130,x2=700,y2=400,x3=220,y3=300,x4=250,y4=250
Define ev
Repeat
ev = WindowEvent()
Delay(20)
If StartDrawing(WindowOutput(0))
If TestMousePick(WindowMouseX(0),WindowMouseY(0),x1,y1,x2,y2,x3,y3,x4,y4)
FrontColor(RGB(200,20,20))
Else
FrontColor(RGB(20,200,20))
EndIf
LineXY(x1,y1,x2,y2)
LineXY(x3,y3,x2,y2)
LineXY(x3,y3,x4,y4)
LineXY(x1,y1,x4,y4)
StopDrawing()
EndIf
Until ev = #PB_Event_CloseWindow
One morning I started wondering whether there is any faster solution for this?
Greetings for all,
Kapslok