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

RemiD

#1
a new version of the code '2d linepick intersects 2d outline (made of 2d lines), with customtypes (20241116-0944):

;2d linepick intersects 2d outline (with customtype) by RemiD (20241116-0944)
;also calculates the intersection 2d point and the outline 2d normals
;sometimes a 2d 'linepick' can go through a outline because it goes between the extremities of 2 2d 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% = 854, gheight% = 480
Graphics( gwidth, gheight, 32, 2 )

SeedRnd( MilliSecs() )

Global shapescount%
Type Tshape
 Field img
 ;Field r%, g%, b%
 Field cx%, cy% ;position of entity, at the center of the image
 Field radius# ;radius of entity
 Field linescount% ;number of lines composing the outline
 Field line_sx%[25], line_sy%[25]
 Field line_ex%[25], line_ey%[25]
End Type
CreateShapes()

;2d line ( for the 2d linepick )
Global sx#, sy#, ex#, ey# ;start point and endpoint of the 2d linepick
;Global dx#, dy# ;direction of the 2d linepick
Global debug_ix%, debug_iy% ;to debug the intersection 2d point
Global debug_inx%, debug_iny% ;to debug the intersection 2d normal

;for function LineIntersectsLine()
Global intersectx#, intersecty#

;for function LineNormals()
Global normal1x#, normal1y#
Global normal2x#, normal2y#

;to store the shapes to consider (near enough from the start of the 2d linepick)
;we use this customtype list because in a game there are usually different lists of different entities,
;and we want to consider only the near enough entities which can be obstacles, but then be able to retrieve their list and handle.
Global tempscount%
Type Ttemp
 Field list$ ;list of entity
 Field h% ;handle of entity
End Type

;to store the 2d lines of the outlines, which intersected with the 2d linepick
Global ilinescount%
Type Tiline
 Field parentlist$ ;list of parent entity (if there are different customtype lists)
 Field parenth% ;handle of parent entity (in the list )
 Field sx#, sy#, ex#, ey# ;start 2d point, end 2d point of the 2d line
 Field ix#, iy# ;intersection 2d point, if intersected
 Field inx#, iny# ;2d normal, if intersected ( pointing outwards of the outline of the shape )
End Type

Main()

End()

Function Main()

 Repeat

  UpdateShapes()

  If( MouseHit(1)=1 ) ;if mouse left hit

   ;delete all temps
   For tem.Ttemp = Each Ttemp
    Delete( tem ) : tempscount = tempscount - 1   
   Next

   ;color all shapes for debugging (in grey)
   For sha.Tshape = Each Tshape
    SetBuffer( ImageBuffer( sha\img ) )
    Color( 120, 120, 120 ) : Rect( 0, 0, 100, 100 )
   Next

   ;define the 2d linepick properties (in this case, from sx, sy to +90 in the chosen direction dx, dy )
   sx = MouseX() :  sy = MouseY()
   vx# = Rnd(-1,+1) : vy# = Rnd(-1,+1)
   vlength# =  Sqr( ( vx * vx ) + ( vy * vy ) )
   dx# = vx / vLength : dy# = vy / vlength
   ;ex = sx+dx*90 : ey = sy+dy*90

   ;determine which shapes are in range and must be considered
   For sha.Tshape = Each Tshape
    dist# = Distance2D( sx, sy, sha\cx, sha\cy )
    If( dist < sha\radius + 90 ) ;90 is the length of the 2d linepick
     ;consider this shape
     tem.Ttemp = New Ttemp : tempscount = tempscount + 1
     tem\list = "SHA" : tem\h = Handle( sha )
     ;color this shape for debugging (in lightblue)
     SetBuffer( ImageBuffer( sha\img ) )
     Color( 120, 120, 240 ) : Rect( 0, 0, 100, 100 )
    EndIf
   Next

   ;throw a 2d linepick on the considered shapes
   pickh% = twodLinepick( sx, sy, dx*90, dy*90 ) ;90 is the length of the 2d linepick
   ;if something picked
   If( pickh > 0 )
    ili.Tiline = Object.Tiline( pickh )
    ;get the picked list of the shape, get the picked handle of the shape
    pickparentlist$ = ili\parentlist : pickparenth% = ili\parenth
    ;get the intersection 2d point (to then draw it)
    debug_ix = ili\ix : debug_iy = ili\iy
    ;get the intersection 2d normal (to then draw it)
    debug_inx = ili\inx : debug_iny = ili\iny
    ;color this shape for debugging (in lightmagenta )
    If( pickparentlist = "SHA" )
     sha.Tshape = Object.Tshape( pickparenth )   
     SetBuffer( ImageBuffer( sha\img ) )
     Color( 240, 120, 240 ) : Rect( 0, 0, 100, 100 )
    EndIf
   ;else if nothing picked
   Else If( pickh = 0 )
    ;do nothing
   EndIf

  EndIf

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

  DrawShapes()

  ;draw the 2d line of the 2d linepick (in blue)
  Color( 060, 060, 240 ) : Line( sx, sy, ex, ey )

  ;draw the start point of the 2d linepick (in blue)
  Color( 060, 060 , 240 ) : Rect( sx-2, sy-2, 4, 4, True )

  If( ilinescount > 0 )
   ;draw the intersected 2d point (in magenta)
   Color( 240, 000, 240 ) : Rect( debug_ix-1, debug_iy-1, 2, 2, True )
   ;draw the intersected 2d normal (in magenta)
   Color( 240, 000, 240 ) : Line( debug_ix, debug_iy, debug_ix+debug_inx*10, debug_iy+debug_iny*10 )
  EndIf

  Color( 240, 240, 240 ) : CText( tempscount, gwidth/2, 0 )

  Flip(1)

 Until( KeyDown(1)=1 )

End Function

Function CText( textstr$, px%, py% )

 Text( px, py, textstr, False, False )

End Function

Function CreateShapes()
 
 For n% = 1 To 32 Step+1
  twidth% = Rand( 10, 100 )  : theight% = Rand( 10, 100 )
  sha.Tshape = New Tshape : shapescount = shapescount + 1
  sha\img = CreateImage( twidth, theight )
  SetBuffer( ImageBuffer( sha\img ) )
  Color( 120, 120, 120 ) : Rect( 0, 0, twidth, theight )
  sha\cx = Rand( 0+twidth/2+10, gwidth-twidth/2-10 ) : sha\cy = Rand( 0+theight/2+10, gheight-theight/2-10 )
  If( twidth = theight ) : sha\radius = Diag( twidth ) / 2 ;if width = height, radius = diag of width / 2
  Else If( twidth > theight ) : sha\radius = Diag( twidth ) / 2 ;if width > height, radius = diag of width / 2
  Else If( twidth < theight ) : sha\radius = Diag( theight ) / 2 ;if width < height, radius = diag of height / 2
  EndIf 
  ;DebugLog( sha\radius )
  ;the positions of the points of the line are related to the center of the shape / image
  sha\linescount = sha\linescount + 1 : sha\line_sx[1] = -twidth/2 : sha\line_sy[1] = -theight/2 : sha\line_ex[1] = +twidth/2 : sha\line_ey[1] = -theight/2
  sha\linescount = sha\linescount + 1 : sha\line_sx[2] = -twidth/2 : sha\line_sy[2] = +theight/2 : sha\line_ex[2] = +twidth/2 : sha\line_ey[2] = +theight/2
  sha\linescount = sha\linescount + 1 : sha\line_sx[3] = -twidth/2 : sha\line_sy[3] = -theight/2 : sha\line_ex[3] = -twidth/2 : sha\line_ey[3] = +theight/2
  sha\linescount = sha\linescount + 1 : sha\line_sx[4] = +twidth/2 : sha\line_sy[4] = -theight/2 : sha\line_ex[4] = +twidth/2 : sha\line_ey[4] = +theight/2
 Next

End Function

Function UpdateShapes()

 ;to change the positions of the shapes randomly
 If( KeyHit(56)=1 ) ;if key alt hit

  For sha.Tshape = Each Tshape
   sha\cx = Rand( 0+ImageWidth(sha\img)/2+10, gwidth-ImageWidth(sha\img)/2-10 ) : sha\cy = Rand( 0+ImageHeight(sha\img)/2+10, gheight-ImageHeight(sha\img)/2-10 )
   ;color the shape for debugging (in grey)
   SetBuffer( ImageBuffer( sha\img ) )
   Color( 120, 120, 120 ) : Rect( 0, 0, 100, 100 )
  Next

 EndIf

End Function

Function DrawShapes()

 For sha.Tshape = Each Tshape

  ;fraw the shape
  DrawImage( sha\img, sha\cx-ImageWidth(sha\img)/2, sha\cy-ImageHeight(sha\img)/2 )

  ;draw the 2d lines of the outline
  Color( 240, 240, 240 )
  For i% = 1 To sha\linescount Step+1
   Line( sha\cx+sha\line_sx[i], sha\cy+sha\line_sy[i], sha\cx+sha\line_ex[i], sha\cy+sha\line_ey[i] )
  Next

 Next

End Function

Function Diag#( SideLength# )

 Diag# = Sqr( (SideLength * SideLength) + (SideLength * SideLength) )
 Return Diag

End Function

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

Function twodLinepick%( sx%, sy%, vx#, vy# )

 ;handle of the intersected line, which will be returned, if there is one
 sh% = 0

 ;delete all intersecteds 2d lines
 For ili.Tiline= Each Tiline
  Delete( ili ) : ilinescount = ilinescount - 1
 Next

 ;calculate end 2d point of the 2d linepick
 ex = sx + vx : ey = sy + vy

 ;for all the considered shapes
 For tem.Ttemp = Each Ttemp
 
  If( tem\list = "SHA" )
 
   sha.Tshape = Object.Tshape( tem\h )

   ;calculate if the 2d linepick intersects with a 2d line of the 2d outline
   For li% = 1 To sha\linescount Step+1
    result% = LineIntersectsLine( sx, sy, ex, ey, sha\cx+sha\line_sx[li], sha\cy+sha\line_sy[li],  sha\cx+sha\line_ex[li],  sha\cy+sha\line_ey[li] )
    ;if yes
    If( result = True )
     ;store the intersected 2d line properties
     ili.Tiline = New Tiline : ilinescount = ilinescount + 1
     ili\parentlist = "SHA" : ili\parenth = Handle( sha )
     ili\sx = sha\line_sx[li] : ili\sy = sha\line_sy[li] : ili\ex = sha\line_ex[li] : ili\ey = sha\line_ey[li]
     ili\ix = intersectx : ili\iy = intersecty
    EndIf
   Next

  EndIf
 
 Next

 ;if the 2d linepick intersected with some 2d lines of the 2d outlines
 If( ilinescount > 0 )
  ;calculate which is the nearest intersection point, and the nearest intersected 2d line
  currdist# = 100000
  For ili.Tiline = Each Tiline
   dist# = Distance2D( sx, sy, ili\ix, ili\iy )
   If( dist < currdist )
    sh = Handle( ili )
    currdist = dist
   EndIf
  Next
  ;select this nearest intersected 2d line
  ili.Tiline = Object.Tiline( sh )
  ;calculate the 2 2d normals of the nearest intersected 2d line
  LineNormals( ili\sx, ili\sy, ili\ex, ili\ey )
  ;choose the 2d normal pointing outwards (project a point along the normal and choose the nearest point / normal from the start point of the 2d linepick)
  dist1# = Distance2D( sx, sy, ili\ix+Normal1x*10, ili\iy+Normal1y*10 )
  dist2# = Distance2D( sx, sy, ili\ix+Normal2x*10, ili\iy+Normal2y*10 )
  If( dist1 < dist2 )
   ;choose normal1
   ili\inx = Normal1x : ili\iny = Normal1y
  Else If( dist2 < dist1 )
   ;choose normal2
   ili\inx = Normal2x : ili\iny = Normal2y
  EndIf
 EndIf

 Return sh

End Function