2d 'linepick' intersects 2d outline example

Started by RemiD, November 29, 2022, 10:27:11

Previous topic - Next topic

RemiD

edit 20221130 : here is a better bcode with a 2d 'linepick' more similar to the 3d linepick (of blitz3d), and with the possibility to move (position) the shapes everywhere easily and have their outlines automatically recalculated...


;2d 'linepick' intersects 2d outline example (arbitrary shape) by RemiD (20221130)
;also calculates the intersection 2d point and the outline 2d normals
;sometimes a 2d 'linepick' can go through a 2d outline because it goes between the extremities of 2 lines of the outline,
;a simple fix would be to cast several 2d 'linepick' with a slight offset to be sure to hit the outline...

Global gwidth% = 640 : Global gheight% = 480
Graphics(gwidth,gheight,32,2)

SeedRnd(MilliSecs())

;assume that we have made a 2d shape in a drawing app

;since we have made the 2d shape, we know the 2d lines of the 2d outline
Global ShapesCount%
Dim Shape_CX%(16) : Dim Shape_CY%(16) ; center of shape
Dim Shape_LinesCount%(16)
Dim Shape_Line_Sx#(16,10) : Dim Shape_Line_Sy#(16,10) : Dim Shape_Line_Ex#(16,10) : Dim Shape_Line_Ey#(16,10) ;start point end point of each line
Dim Shape_R%(16) : Dim Shape_G%(16)  : Dim Shape_B%(16) ;color of outline
For n% = 1 To 16 Step +1
ShapesCount = ShapesCount + 1 : SI% = ShapesCount
Shape_CX(SI) = Rand(0+50, 640-1-50) : Shape_CY(SI) = Rand(0+50, 480-1-50)
Shape_LinesCount%(SI) = 10
LI% = 1 : Shape_Line_Sx(SI,LI) = 50-50 : Shape_Line_Sy(SI,LI) = 12-50 : Shape_Line_Ex(SI,LI) = 61-50 : Shape_Line_Ey(SI,LI) = 36-50
LI% = 2 : Shape_Line_Sx(SI,LI) = 62-50 : Shape_Line_Sy(SI,LI) = 36-50 : Shape_Line_Ex(SI,LI) = 87-50 : Shape_Line_Ey(SI,LI) = 26-50
LI% = 3 : Shape_Line_Sx(SI,LI) = 87-50 : Shape_Line_Sy(SI,LI) = 27-50 : Shape_Line_Ex(SI,LI) = 72-50 : Shape_Line_Ey(SI,LI) = 55-50
LI% = 4 : Shape_Line_Sx(SI,LI) = 72-50 : Shape_Line_Sy(SI,LI) = 56-50 : Shape_Line_Ex(SI,LI) = 83-50 : Shape_Line_Ey(SI,LI) = 82-50
LI% = 5 : Shape_Line_Sx(SI,LI) = 82-50 : Shape_Line_Sy(SI,LI) = 82-50 : Shape_Line_Ex(SI,LI) = 58-50 : Shape_Line_Ey(SI,LI) = 67-50
LI% = 6 : Shape_Line_Sx(SI,LI) = 57-50 : Shape_Line_Sy(SI,LI) = 67-50 : Shape_Line_Ex(SI,LI) = 29-50 : Shape_Line_Ey(SI,LI) = 87-50
LI% = 7 : Shape_Line_Sx(SI,LI) = 28-50 : Shape_Line_Sy(SI,LI) = 87-50 : Shape_Line_Ex(SI,LI) = 36-50 : Shape_Line_Ey(SI,LI) = 61-50
LI% = 8 : Shape_Line_Sx(SI,LI) = 36-50 : Shape_Line_Sy(SI,LI) = 60-50 : Shape_Line_Ex(SI,LI) = 11-50 : Shape_Line_Ey(SI,LI) = 36-50
LI% = 9 : Shape_Line_Sx(SI,LI) = 11-50 : Shape_Line_Sy(SI,LI) = 35-50 : Shape_Line_Ex(SI,LI) = 36-50 : Shape_Line_Ey(SI,LI) = 39-50
LI% = 10 : Shape_Line_Sx(SI,LI) = 37-50 : Shape_Line_Sy(SI,LI) = 38-50 : Shape_Line_Ex(SI,LI) = 49-50 : Shape_Line_Ey(SI,LI) = 12-50
Shape_R(SI) = Rand(025,250) : Shape_G(SI) = Rand(025,250) : Shape_B(SI) = Rand(025,250)
Next

;2d line (of a turning moving entity)
Global Sx# : Global Sy# : Global Ex# : Global Ey#
Global Nx# : Global Ny#

;intersection 2d point ( for function LineIntersectsLine() )
Global Intersectx# : Global Intersecty#

;2d normals ( for function LineNormals() )
Global Normal1x# : Global Normal1y#
Global Normal2x# : Global Normal2y#

Global TempsCount%
Dim Temp_Sx#(100) : Dim Temp_Sy#(100) : Dim Temp_Ex#(100) : Dim Temp_Ey#(100)
Dim Temp_Ix#(100) : Dim Temp_Iy#(100)
Dim Temp_Dist#(100)
Dim Temp_N1x#(100) : Dim Temp_N1y#(100)
Dim Temp_N2x#(100) : Dim Temp_N2y#(100)

Global TI%
Global WhichNormal%

Goto ChooseLineProperties

Repeat

If( KeyHit(56)=1 )
  ;define others positions for shapes
  For SI% = 1 To ShapesCount
   Shape_CX(SI) = Rand(0+50, 640-1-50) : Shape_CY(SI) = Rand(0+50, 480-1-50)
  Next
EndIf

If( MouseHit(1)=1 Or KeyHit(57)=1 )

  .ChooseLineProperties
  ;define another 2d line (of a turning moving entity)
  Sx = MouseX() :  Sy = MouseY()
  Vx# = Rnd(-1,+1) : Vy# = Rnd(-1,+1)
  VLength# =  Sqr( ( Vx * Vx ) + ( Vy * Vy ) )
  Nx = Vx / VLength : Ny = Vy / VLength
  Ex = Sx+Nx*100 : Ey = Sy+Ny*100

  TempsCount = 0
  For SI% = 1 To ShapesCount
   ;color shape in grey (for debug)
   Shape_R(SI) = 125 : Shape_G(SI) = 125 : Shape_B(SI) = 125
   ;check distance between start of 2d linepick and center of shape
   D# = Distance2D( Sx, Sy, Shape_Cx(SI), Shape_Cy(SI) )
   ;if shape near enough start of linepick
   If( D < 50+100 )
    ;color shape in white (for debug)
    Shape_R(SI) = 250 : Shape_G(SI) = 250 : Shape_B(SI) = 250
   
    ;check If the 2d linepick intersects with some lines of the 2d outline of the shape
    For LI% = 1 To Shape_LinesCount(SI) Step +1
     R% = LineIntersectsLine( Sx, Sy, Ex, Ey, Shape_CX(SI)+Shape_Line_SX(SI,LI), Shape_CY(SI)+Shape_Line_SY(SI,LI), Shape_CX(SI)+Shape_Line_EX(SI,LI), Shape_CY(SI)+Shape_Line_EY(SI,LI) )
     If( R = True )
      TempsCount = TempsCount  + 1 : TI% = TempsCount
      Temp_Sx(TI) =  Shape_CX(SI)+Shape_Line_SX(SI,LI) : Temp_Sy(TI) = Shape_CY(SI)+Shape_Line_SY(SI,LI) : Temp_Ex(TI) = Shape_CX(SI)+Shape_Line_EX(SI,LI) : Temp_Ey(TI) = Shape_CY(SI)+Shape_Line_EY(SI,LI)
      Temp_Ix(TI) = Intersectx : Temp_Iy(TI) = Intersecty
     EndIf
    Next
    ;if yes
    If (TempsCount > 0 )
     ;choose the nearest intersection point, and the nearest intersected line
     CurrDist# = 100000
     STI% = -1
     For TI% = 1 To TempsCount Step +1
      Temp_Dist(TI) = Distance2D( Sx, Sy, Temp_Ix(TI), Temp_Iy(TI) )
      If( Temp_Dist(TI) < CurrDist )
       STI = TI
       CurrDist = Temp_Dist(TI)
      EndIf
     Next
     TI% = STI
     ;calculate the 2 2d normals of the nearest intersected line
     LineNormals( Temp_Sx(TI), Temp_Sy(TI), Temp_Ex(TI), Temp_Ey(TI) )
     Temp_N1x(TI) = Normal1x : Temp_N1y(TI) = Normal1y
     Temp_N2x(TI) = Normal2x : Temp_N2y(TI) = Normal2y
     ;choose the 2d normal pointing outwards (project a point along the normal and choose the nearest point / normal from the start point)
     D1# = Distance2D( Sx, Sy, Temp_Ix(TI)+Temp_N1x(TI)*10, Temp_Iy(TI)+Temp_N1y(TI)*10 )
     D2# = Distance2D( Sx, Sy, Temp_Ix(TI)+Temp_N2x(TI)*10, Temp_Iy(TI)+Temp_N2y(TI)*10 )
     If( D1 < D2 )
      ;choose normal1
      WhichNormal = 1
     Else If( D2 < D1 )
      ;choose normal2
      WhichNormal = 2
     EndIf
    EndIf
   EndIf
  Next

EndIf

SetBuffer(BackBuffer())
ClsColor(000,000,000) : Cls()

;draw the 2d lines of the 2d outline
For SI% = 1 To ShapesCount Step +1
  Color( Shape_R(SI), Shape_G(SI), Shape_B(SI) )
  For LI% = 1 To Shape_LinesCount(SI) Step +1
   Line( Shape_CX(SI)+Shape_Line_SX(SI,LI), Shape_CY(SI)+Shape_Line_SY(SI,LI), Shape_CX(SI)+Shape_Line_EX(SI,LI), Shape_CY(SI)+Shape_Line_EY(SI,LI) )
  Next
Next

;draw the 2d line (of a turning moving entity)
Color(125,125,250) : Line( Sx, Sy, Ex, Ey )

;draw the start point of the 2d line (of a turning moving entity)
Color(125,125,250) : Rect( Sx-2, Sy-2, 4, 4, True )

;if the line intersect
If( TempsCount > 0 )
  ;draw the intersection 2d point
  Color(250,000,250) : Rect( Temp_Ix(TI)-2, Temp_Iy(TI)-2, 4, 4, True )
  ;draw the 2d normal of the nearest intersected line
  If( WhichNormal = 1 )
   Color(250,000,250) : Line( Temp_Ix(TI), Temp_Iy(TI), Temp_Ix(TI)+Temp_N1x(TI)*10, Temp_Iy(TI)+Temp_N1y(TI)*10 )
  Else If( WhichNormal =  2 )
   Color(250,000,250) : Line( Temp_Ix(TI), Temp_Iy(TI), Temp_Ix(TI)+Temp_N2x(TI)*10, Temp_Iy(TI)+Temp_N2y(TI)*10 )
  EndIf
EndIf

Flip()

Until( KeyHit(1)=1 )

End()

Function Distance2D#(AX#,AZ#,BX#,BZ#)

Distance2D# = Sqr( ( ( BX - AX ) * ( BX - AX ) ) + ( ( BZ - AZ ) * ( BZ - AZ ) ) )
Return Distance2D

End Function

;2d line intersects 2d line math formula by NoseKills (20141023)
Function LineIntersectsLine( p0_x#, p0_y#, p1_x#, p1_y#, p2_x#, p2_y#, p3_x#, p3_y# )

s1_x# = p1_x - p0_x     
s1_y# = p1_y - p0_y
s2_x# = p3_x - p2_x   
s2_y# = p3_y - p2_y

s# = ( -s1_y * ( p0_x - p2_x ) + s1_x * ( p0_y - p2_y ) ) / ( -s2_x * s1_y + s1_x * s2_y )
t# = ( s2_x * ( p0_y - p2_y ) - s2_y * ( p0_x - p2_x ) ) / ( -s2_x * s1_y + s1_x * s2_y )

If( s >= 0 And s <= 1 And t >= 0 And t <= 1 )
  ;intersection detected
  intersectx = p0_x + (  t * s1_x ) : intersecty = p0_y + ( t * s1_y )
  Return True
Else
  ;no intersection
  intersectx = 0 : intersecty = 0
  Return False
EndIf

End Function

;2d normals of a 2d line math formula by Stevie G (20221127)
Function LineNormals( pA_x#, pA_y#, pB_x#, pB_y# )

  ;vectorAB
  vAB_x# = pB_x - pA_x : vAB_y# = pB_y - pA_y
  ;normalizedvectorAB
  vAB_length# = Sqr( ( vAB_x * vAB_x ) + ( vAB_y * vAB_y ) )
  nAB_x# = vAB_x / vAB_length : nAB_y# = vAB_y / vAB_length

  ;one side perpendiculat normalized  vector
  Normal1x# = -nAB_y : Normal1y# = +nAB_x
  ;other side perpendicular normalized  vector
  Normal2x# = +nAB_y : Normal2y# = -nAB_x

End Function