Source:CollisionSegments.pb


;Comtois 16/02/05
;Détection collision d'un segment avec un autre segment

;-Initialisation
Global ScreenHeight.l, ScreenWidth.l
Declare Erreur(Message$)
If ExamineDesktops()
  ScreenWidth  = DesktopWidth(0)
  ScreenHeight = DesktopHeight(0)
Else
  Erreur("Euh ?")
EndIf
If InitSprite() = 0 Or InitMouse() = 0 Or InitKeyboard()=0
  Erreur("Impossible d'initialiser DirectX 7 Ou plus")
ElseIf OpenWindow(0,0,0,ScreenWidth,ScreenHeight,#PB_Window_BorderLess,"Collision") = 0
  Erreur("Impossible de créer la fenêtre")
EndIf
;{/ouvre un écran
If OpenWindowedScreen( WindowID(0), 0, 0, ScreenWidth , ScreenHeight, 0, 0, 0 ) = 0
  Erreur("Impossible d'ouvrir l'écran ")
EndIf

Structure Segment
  P1.point
  P2.point
EndStructure

Global Box1.Segment,Box2.Segment

Procedure Erreur(Message$)
  MessageRequester( "Erreur" , Message$ , 0 )
  End
EndProcedure

Procedure.l Signe(a.l)
  If a>0
    ProcedureReturn 1
  ElseIf a=0
    ProcedureReturn 0
  Else
    ProcedureReturn -1
  EndIf
EndProcedure

Procedure.l Min(a.l,b.l)
  If a<b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure.l Max(a.l,b.l)
  If a>b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure Encadrement(*S1.Segment,*S2.Segment)
  ;Box Segment1
  Box1\P1\x = Min(*S1\P1\x, *S1\P2\x)
  Box1\P1\y = Min(*S1\P1\y, *S1\P2\y)
  Box1\P2\x = Max(*S1\P1\x, *S1\P2\x)
  Box1\P2\y = Max(*S1\P1\y, *S1\P2\y)
  ;Box Segment2
  Box2\P1\x = Min(*S2\P1\x, *S2\P2\x)
  Box2\P1\y = Min(*S2\P1\y, *S2\P2\y)
  Box2\P2\x = Max(*S2\P1\x, *S2\P2\x)
  Box2\P2\y = Max(*S2\P1\y, *S2\P2\y)
EndProcedure

Procedure CollisionSegmentSegment(*S1.Segment,*S2.Segment)
  ;Test Collision encadrement
  If Box1\P2\x >= Box2\P1\x And Box1\P1\x <= Box2\P2\x And Box1\P2\y >= Box2\P1\y And Box1\P1\y <= Box2\P2\y
    ;Test chevauchement segments
    R1.f=((*S2\P1\x-*S1\P1\x) * (*S1\P2\y-*S1\P1\y)) - ((*S2\P1\y-*S1\P1\y) * (*S1\P2\x-*S1\P1\x))
    R2.f=((*S2\P2\x-*S1\P1\x) * (*S1\P2\y-*S1\P1\y)) - ((*S2\P2\y-*S1\P1\y) * (*S1\P2\x-*S1\P1\x))
    R3.f=((*S1\P1\x-*S2\P1\x) * (*S2\P2\y-*S2\P1\y)) - ((*S1\P1\y-*S2\P1\y) * (*S2\P2\x-*S2\P1\x))
    R4.f=((*S1\P2\x-*S2\P1\x) * (*S2\P2\y-*S2\P1\y)) - ((*S1\P2\y-*S2\P1\y) * (*S2\P2\x-*S2\P1\x))
    If (Signe(R1) * Signe(R2) <= 0) And (Signe(R3) * Signe(R4) <= 0)
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
  EndIf
EndProcedure

Procedure AffPoints(*S1.Segment,*S2.Segment,*P.point,mem)
  CouleurBox      = RGB(70,70,70)
  CouleurSegment1 = RGB(255,0,0)
  CouleurSegment2 = RGB(0,255,0)
  CouleurCurseur  = RGB(255,255,255)
  StartDrawing(ScreenOutput())
  ;/Affiche le Segment1
  Circle(*S1\P1\x, *S1\P1\y, 4, CouleurSegment1)
  Circle(*S1\P2\x, *S1\P2\y, 4, CouleurSegment1)
  LineXY(*S1\P1\x, *S1\P1\y, *S1\P2\x, *S1\P2\y, CouleurSegment1)
  ;/Affiche le Segment2
  Circle(*S2\P1\x, *S2\P1\y, 4, CouleurSegment2)
  Circle(*S2\P2\x, *S2\P2\y, 4, CouleurSegment2)
  LineXY(*S2\P1\x, *S2\P1\y, *S2\P2\x, *S2\P2\y, CouleurSegment2)
  ;/Affiche le point
  If mem
    DrawingMode(4)
    Circle(*P\x, *P\y, 6, CouleurCurseur)
  Else
    DrawingMode(0)
    Circle(*P\x,*P\y, 4, CouleurCurseur)
  EndIf
  ;/Affiche une croix pour mieux suivre le déplacement du point
  LineXY(*P\x, 0, *P\x, ScreenHeight - 1, CouleurCurseur)
  LineXY(0, *P\y, ScreenWidth - 1, *P\y, CouleurCurseur)
  Locate(0, 0)
  If CollisionSegmentSegment(*S1, *S2)
    FrontColor(255, 255, 0)
    BackColor(255, 0, 0)
    texte$  =" IN "
  Else
    FrontColor(255, 255, 255)
    BackColor(0, 255, 0)
    texte$ = " OUT "
  EndIf
  DrawText(texte$)
  StopDrawing()
EndProcedure

Procedure TestPoint(X1, Y1, X2, Y2, d)
  If X1 > X2 - d And X1 < X2 + d And Y1 > Y2 - d And Y1 < Y2 + d
    Resultat = #True
  EndIf
  ProcedureReturn Resultat
EndProcedure

Segment1.Segment
Segment2.Segment
Point.point
;Segment1
Segment1\P1\x = 50
Segment1\P1\y = 50
Segment1\P2\x = 110
Segment1\P2\y = 250
;Segment2
Segment2\P1\x = 210
Segment2\P1\y = 250
Segment2\P2\x = 410
Segment2\P2\y = 350
;Point à tester
Point\x = 340
Point\y = 100
DiametreSelection=6

Repeat
  While WindowEvent() : Wend
  ClearScreen(0, 0, 0)
  ExamineKeyboard()
  ExamineMouse()
  ;Les segments sont modifiables à la souris en cliquant sur un point 
  If MouseButton(1)
    If MemPoint = 1
      Segment1\P1\x = MouseX()
      Segment1\P1\y = MouseY()
    ElseIf MemPoint = 2
      Segment1\P2\x = MouseX()
      Segment1\P2\y = MouseY()
    ElseIf MemPoint = 3
      Segment2\P1\x = MouseX()
      Segment2\P1\y = MouseY()
    ElseIf MemPoint = 4
      Segment2\P2\x = MouseX()
      Segment2\P2\y = MouseY()
    EndIf
  Else
    MemPoint = 0
  EndIf
  If TestPoint(MouseX(), MouseY(), Segment1\P1\x, Segment1\P1\y, DiametreSelection)
    MemPoint = 1
  ElseIf TestPoint(MouseX(), MouseY(), Segment1\P2\x, Segment1\P2\y, DiametreSelection)
    MemPoint = 2
  ElseIf TestPoint(MouseX(), MouseY(), Segment2\P1\x, Segment2\P1\y, DiametreSelection)
    MemPoint = 3
  ElseIf TestPoint(MouseX(), MouseY(), Segment2\P2\x, Segment2\P2\y, DiametreSelection)
    MemPoint = 4
  EndIf
  ;Place le point à tester sous la souris
  Point\x = MouseX()
  Point\y = MouseY()
  ;Affiche le tout
  Encadrement(@Segment1, @Segment2)
  AffPoints(@Segment1, @Segment2, @Point, MemPoint)
  FlipBuffers()
  Delay(1)
Until KeyboardPushed(#PB_Key_Escape)