Il existe un algo spécifique pour savoir si un point est dans un polygone, qu'il soit convexe ou concave.
Fait une recherche avec "algorithm inside polygon"
Dans ma collection de code recueilli dans les forums, j'ai ça:
Code : Tout sélectionner
Structure point_f
x.f
y.f
EndStructure
Procedure inpoly(*p.point_f, List poly.point_f())
Protected.point_f new, old, lp, rp
Protected inside
If ListSize(poly()) < 3: ProcedureReturn 0: EndIf
LastElement(poly()): old = poly()
ForEach poly()
;find leftmost endpoint 'lp' and the rightmost endpoint 'rp' based on x value
If poly()\x > old\x
lp = old
rp = poly()
Else
lp = poly()
rp = old
EndIf
If lp\x < *p\x And *p\x <= rp\x And (*p\y - lp\y) * (rp\x - lp\x) < (rp\y - lp\y) * (*p\x - lp\x)
inside = ~inside
EndIf
old = poly()
Next
ProcedureReturn inside & 1
EndProcedure
If InitSprite()
If InitKeyboard() And InitMouse()
OpenWindow(0, 0, 0, 800, 600, "Press [Esc] to close, [Left mouse button] Add Point, [Right mouse button] Clear All Points.", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 1, 0, 0)
SetFrameRate(60)
EndIf
Else
MessageRequester("", "Unable to initsprite"): End
EndIf
NewList v.point_f()
Define.point_f pvp, mp
Define Col, EventID, mode.b, modetxt.s
Repeat
Delay(1)
EventID = WindowEvent()
ExamineKeyboard()
ExamineMouse()
ClearScreen(Col)
mp\x = MouseX()
mp\y = MouseY()
If MouseButton(#PB_MouseButton_Left)
AddElement(v())
v()\x = mp\x
v()\y = mp\y
Delay(100)
EndIf
If MouseButton(#PB_MouseButton_Right)
ClearList(v())
Delay(100)
EndIf
StartDrawing(ScreenOutput())
If LastElement(v())
pvp = v()
ForEach v()
LineXY(pvp\x, pvp\y, v()\x, v()\y, RGB(0, $FF, 0)) ;Green
Circle(pvp\x, pvp\y, 5, RGB($FF, 0, 0)) ;Red
pvp = v()
Next
EndIf
Circle(MouseX(), MouseY(), 5, RGB($C0, $C0, $FF)) ;LightBlue
If inpoly(mp, v())
modetxt = "You are in the polygon."
Col = RGB(0, 0, 0)
Else
modetxt = "You are not in the polygon."
Col = RGB($50, $50, $50)
EndIf
DrawText((800 - TextWidth(modetxt)) / 2, 0, modetxt)
StopDrawing()
FlipBuffers()
Until KeyboardReleased(#PB_Key_Escape) Or EventID = #PB_Event_CloseWindow
Avec rotation:
Code : Tout sélectionner
; Author : comtois
; Date : 20/04/2007
; Code de collision avec un rectangle en rotation... d'apres un code de comtois
; http://www.purebasic.fr/french/viewtopic.php?t = 1960
Structure Rectangle
X.l ; Coordonée Central X
Y.l ; Coordonée Central Y
R.l ; Demi Diagonal du Rectangle
Angle.l ; Angle de Rotation
X1.l
Y1.l
X2.l
Y2.l
X3.l
Y3.l
X4.l
Y4.l
EndStructure
Global Rect.Rectangle
Rect\X = 400
Rect\Y = 300
Rect\R = 150
If InitSprite() = 0 Or InitKeyboard()= 0 Or InitMouse()= 0 Or InitSound()= 0
MessageRequester("Error", "DirectX 7+ is needed.", 0)
End
EndIf
OpenWindow(0, 0, 0, 800, 600, "Planete Alien ", #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)
Procedure Drawrect()
LineXY(Rect\X1, Rect\Y1, Rect\X2, Rect\Y2, RGB(255, 255, 255))
LineXY(Rect\X2, Rect\Y2, Rect\X3, Rect\Y3, RGB(255, 255, 255))
LineXY(Rect\X3, Rect\Y3, Rect\X4, Rect\Y4, RGB(255, 255, 255))
LineXY(Rect\X4, Rect\Y4, Rect\X1, Rect\Y1, RGB(255, 255, 255))
Circle(Rect\X1, Rect\Y1, 10, RGB(255, 0, 0))
Circle(Rect\X2, Rect\Y2, 10, RGB(255, 0, 0))
Circle(Rect\X3, Rect\Y3, 10, RGB(255, 0, 0))
Circle(Rect\X4, Rect\Y4, 10, RGB(255, 0, 0))
EndProcedure
Procedure Signe(a.l)
If a>0
ProcedureReturn 1
ElseIf a = 0
ProcedureReturn 0
Else
ProcedureReturn - 1
EndIf
EndProcedure
Procedure Coli()
; Test la collision du point avec le triangle
; pour en savoir plus http://tanopah.jo.free.fr/seconde/region.html
; Plan 1
mx = MouseX() : my = MouseY()
xu1 = Rect\X2 - Rect\X1: yu1 = Rect\Y2 - Rect\Y1
c1 = Rect\Y1*xu1 - Rect\X1*yu1
P1 = Rect\X3*yu1 - Rect\Y3*xu1 + c1
AX1 = Mx*yu1 - My*xu1 + c1
; Plan 2
xu2 = Rect\X3 - Rect\X2: yu2 = Rect\Y3 - Rect\Y2
c2 = Rect\Y2*xu2 - Rect\X2*yu2
P2 = Rect\X1*yu2 - Rect\Y1*xu2 + c2
AX2 = Mx*yu2 - My*xu2 + c2
; Plan 3
xu3 = Rect\X4 - Rect\X3: yu3 = Rect\Y4 - Rect\Y3
c3 = Rect\Y3*xu3 - Rect\X3*yu3
P3 = Rect\X1*yu3 - Rect\Y1*xu3 + c3
AX3 = Mx*yu3 - My*xu3 + c3
; Plan 4
xu4 = Rect\X1 - Rect\X4: yu4 = Rect\Y1 - Rect\Y4
c4 = Rect\Y4*xu4 - Rect\X4*yu4
P4 = Rect\X3*yu4 - Rect\Y3*xu4 + c4
AX4 = Mx*yu4 - My*xu4 + c4
If Signe(AX1)= Signe(P1) And Signe(AX2)= Signe(P2) And Signe(AX3)= Signe(P3) And Signe(AX4)= Signe(P4)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
#DEG=#PI/180
Repeat
ExamineMouse()
ExamineKeyboard()
Rect\X = 400 + 100*Sin(Rect\Angle*#DEG)
Rect\Y = 300 + 100*Cos(Rect\Angle*#DEG)
Rect\Angle + 1
If Rect\Angle>360: Rect\Angle = 0: EndIf
Rect\X1 = Rect\X + Rect\R*Cos((Rect\Angle - 25)*#DEG)
Rect\Y1 = Rect\Y + Rect\R*Sin((Rect\Angle - 25)*#DEG)
Rect\X2 = Rect\X + Rect\R*Cos((Rect\Angle + 25)*#DEG)
Rect\Y2 = Rect\Y + Rect\R*Sin((Rect\Angle + 25)*#DEG)
Rect\X3 = Rect\X + Rect\R*Cos((Rect\Angle + 180 - 25)*#DEG)
Rect\Y3 = Rect\Y + Rect\R*Sin((Rect\Angle + 180 - 25)*#DEG)
Rect\X4 = Rect\X + Rect\R*Cos((Rect\Angle - 180 + 25)*#DEG)
Rect\Y4 = Rect\Y + Rect\R*Sin((Rect\Angle - 180 + 25)*#DEG)
; Si ma souris passe dans le rectangle
If Coli()
ClearScreen(#Blue)
Else
ClearScreen(0)
EndIf
StartDrawing(ScreenOutput())
Drawrect()
Circle(MouseX(), MouseY(), 10, RGB(0, 255, 0))
StopDrawing()
Delay(1)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Rapide avec 2 cercles
Code : Tout sélectionner
Procedure Circles_Faster_Collision(cx1.f, cy1.f, radius1.f, cx2.f, cy2.f, radius2.f)
dCenter.f =(cx2 - cx1) *(cx2 - cx1) +(cy2 - cy1) *(cy2 - cy1)
dRadius.f =(radius1 + radius2) *(radius1 + radius2)
If dCenter <= dRadius
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure Circles_Fast_Collision(cx1.f, cy1.f, radius1.f, cx2.f, cy2.f, radius2.f)
d.f = Sqr((cx2 - cx1) *(cx2 - cx1) +(cy2 - cy1) *(cy2 - cy1))
If d <= radius1 + radius2
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure Circles_Collision(x1.f, y1.f, r1.f, x2.f, y2.f, r2.f)
dx.f =(x1 - x2)
dy.f =(y1 - y2)
If Abs(dx) <= r1 And Abs(dy) <= r1
ProcedureReturn #True
EndIf
If dx = 0 And dy = 0
ProcedureReturn #True
Else
dxdy.f = dx / dy
N.f =(r2 * r2 - r1 * r1 - x2 * x2 + x1 * x1 - y2 * y2 + y1 * y1) /(2 *(y1 - y2))
A.f = dxdy * dxdy + 1
B.f = 2 * y1 * dxdy - 2 * N * dxdy - 2 * x1
C.f =(x1 * x1 + y1 * y1 + N * N - r1 * r1 - 2 * y1 * N)
Delta.f = B * B - 4 * A * C
If Delta < 0
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndIf
EndProcedure
ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)
ScreenDepth = 32
If InitSprite() And InitMouse() And InitKeyboard()
If OpenScreen(ScreenWidth, ScreenHeight, ScreenDepth, "")
Quit = #False
Repeat
FlipBuffers()
ClearScreen($000000)
ExamineKeyboard()
ExamineMouse()
MouseX = MouseX()
MouseY = MouseY()
If KeyboardPushed(#PB_Key_Escape) : Quit = #True : EndIf
StartDrawing(ScreenOutput())
DrawingMode(4)
If Circles_Faster_Collision(ScreenWidth / 2, ScreenHeight / 2, 200, MouseX, MouseY, 200)
Color = #Red
Else
Color = #White
EndIf
Circle(ScreenWidth / 2, ScreenHeight / 2, 200, Color)
Circle(MouseX, MouseY, 200, Color)
StopDrawing()
Until Quit
EndIf
EndIf
End
Avec des ellipses:
Code : Tout sélectionner
Procedure SpriteCollisionLocation(Sprite1.l, x1.l, y1.l, Sprite2.l, x2.l, y2.l, *location.POINTS)
Protected w1.l, h1.l, w2.l, h2.l
Protected xl.l, xr.l, yt.l, yb.l
Protected x.l, y.l, u.l, v.l, yy.l, vv.l
Protected i.l, j.l, cx.l, cy.l, nb.l, collision.l
w1 = SpriteWidth(Sprite1)
h1 = SpriteHeight(Sprite1)
w2 = SpriteWidth(Sprite2)
h2 = SpriteHeight(Sprite2)
collision = #True
If x1 < x2
If(x1 + w1) > x2
xl = x2
u = 0
x = xl - x1
Else
collision = #False
EndIf
Else
If(x2 + w2) > x1
xl = x1
x = 0
u = xl - x2
Else
collision = #False
EndIf
EndIf
If y1 < y2
If(y1 + h1) > y2
yt = y2
v = 0
y = yt - y1
Else
collision = #False
EndIf
Else
If(y2 + h2) > y1
yt = y1
y = 0
v = yt - y2
Else
collision = #False
EndIf
EndIf
If collision = #True
If(x1 + w1) <(x2 + w2)
xr = x1 + w1
Else
xr = x2 + w2
EndIf
If(y1 + h1) <(y2 + h2)
yb = y1 + h1
Else
yb = y2 + h2
EndIf
xr - 1
yb - 1
w1 - 1
h1 - 1
w2 - 1
h2 - 1
EndIf
If collision = #True
Dim pt1.l(w1, h1)
If StartDrawing( SpriteOutput(Sprite1) )
For i = xl To xr
For j = yt To yb
pt1(i - xl + x, j - yt + y) = Point(i - xl + x, j - yt + y)
Next j
Next i
StopDrawing()
Else
collision = #False
EndIf
EndIf
If collision = #True
Dim pt2.l(w2, h2)
If StartDrawing( SpriteOutput(Sprite2) )
For i = xl To xr
For j = yt To yb
pt2(i - xl + u, j - yt + v) = Point(i - xl + u, j - yt + v)
Next j
Next i
StopDrawing()
Else
collision = #False
EndIf
EndIf
If collision = #True
yy = y
vv = v
For i = xl To xr
y = yy
v = vv
For j = yt To yb
If pt1(x, y) And pt2(u, v)
cx + i
cy + j
nb + 1
EndIf
y + 1
v + 1
Next j
x + 1
u + 1
Next i
If nb > 0 And *location
*location\x = cx / nb
*location\y = cy / nb
EndIf
EndIf
ProcedureReturn nb
EndProcedure
InitSprite()
InitMouse()
InitKeyboard()
x = 500
y = 500
If OpenScreen(1024, 768, 16, "")
TransparentSpriteColor(#PB_Default, $000000)
CreateSprite(0, 320, 240)
CreateSprite(1, 60, 60)
CreateSprite(2, 3, 3)
If StartDrawing( SpriteOutput(0) )
Ellipse(160, 120, 160, 120, $0000FF)
Ellipse(160, 120, 80, 60, $000000)
StopDrawing()
EndIf
If StartDrawing( SpriteOutput(1) )
Circle( 0, 30, 30, $00FF00)
Circle(60, 30, 30, $00FF00)
Circle(30, 30, 20, $000000)
StopDrawing()
EndIf
If StartDrawing( SpriteOutput(2) )
Box(0, 0, 3, 3, $FF0000)
StopDrawing()
EndIf
Repeat
ExamineMouse()
ExamineKeyboard()
ClearScreen($000000)
x + MouseDeltaX()
y + MouseDeltaY()
DisplayTransparentSprite(0, 80, 80)
DisplayTransparentSprite(1, x, y)
If SpriteCollisionLocation(0, 80, 80, 1, x, y, @Location.POINTS)
DisplaySprite(2, Location\x - 1, Location\y - 1)
EndIf
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
CloseScreen()
EndIf
Dans un triangle:
Code : Tout sélectionner
; Comtois 05/02/05
; Détection d'un point dans un triangle
;-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) = 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 Triangle
X1.l
Y1.l
X2.l
Y2.l
X3.l
Y3.l
EndStructure
Procedure Erreur(Message$)
MessageRequester( "Erreur" , Message$ , 0 )
End
EndProcedure
Procedure Signe(a.l)
If a>0
ProcedureReturn 1
ElseIf a = 0
ProcedureReturn 0
Else
ProcedureReturn - 1
EndIf
EndProcedure
Procedure CollisionTriangle(*T.Triangle, *P.point)
; Test la collision du point avec le triangle
; pour en savoir plus http://tanopah.jo.free.fr/seconde/region.html
; Plan 1
xu1 =*T\X2 -*T\X1: yu1 =*T\Y2 -*T\Y1
c1 =*T\Y1*xu1 -*T\X1*yu1
P1 =*T\X3*yu1 -*T\Y3*xu1 + c1
AX1 =*P\x*yu1 -*P\y*xu1 + c1
; Plan 2
xu2 =*T\X3 -*T\X2: yu2 =*T\Y3 -*T\Y2
c2 =*T\Y2*xu2 -*T\X2*yu2
P2 =*T\X1*yu2 -*T\Y1*xu2 + c2
AX2 =*P\x*yu2 -*P\y*xu2 + c2
; Plan 3
xu3 =*T\X1 -*T\X3: yu3 =*T\Y1 -*T\Y3
c3 =*T\Y3*xu3 -*T\X3*yu3
P3 =*T\X2*yu3 -*T\Y2*xu3 + c3
AX3 =*P\x*yu3 -*P\y*xu3 + c3
If Signe(AX1)= Signe(P1) And Signe(AX2)= Signe(P2) And Signe(AX3)= Signe(P3)
Resultat =#True
EndIf
ProcedureReturn Resultat
EndProcedure
Procedure AffPoints(*T.Triangle, *P.point, mem)
StartDrawing(ScreenOutput())
;/Affiche le triangle
Circle(*T\X1, *T\Y1, 4, RGB(255, 0, 0))
Circle(*T\X2, *T\Y2, 4, RGB(255, 0, 0))
Circle(*T\X3, *T\Y3, 4, RGB(255, 0, 0))
LineXY(*T\X1, *T\Y1, *T\X2, *T\Y2, RGB(255, 0, 0))
LineXY(*T\X2, *T\Y2, *T\X3, *T\Y3, RGB(255, 0, 0))
LineXY(*T\X1, *T\Y1, *T\X3, *T\Y3, RGB(255, 0, 0))
;/Affiche le point
If mem
DrawingMode(4)
Circle(*P\x, *P\y, 6, RGB(255, 255, 255))
Else
DrawingMode(0)
Circle(*P\x, *P\y, 4, RGB(255, 255, 255))
EndIf
;/Affiche une croix pour mieux suivre le déplacement du point
LineXY(*P\x, 0, *P\x, ScreenHeight - 1, RGB(255, 255, 255))
LineXY(0, *P\y, ScreenWidth - 1, *P\y, RGB(255, 255, 255))
If CollisionTriangle(*T, *P)
FrontColor(RGB(255, 255, 0))
BackColor(RGB(255, 0, 0))
texte$ = " IN "
Else
FrontColor(RGB(155, 155, 155))
BackColor(RGB(0, 255, 0))
texte$ = " OUT "
EndIf
DrawText(0, 0, texte$)
StopDrawing()
EndProcedure
Procedure TestPoint(X1, Y1, X2, Y2, d)
If X1>X2 - d And X1 And Y1>Y2 - d And Y1
ProcedureReturn #True
EndIf
ProcedureReturn Resultat
EndProcedure
Triangle.Triangle
Point.point
; Triangle modifiable à la souris
Triangle\X1 = 50
Triangle\Y1 = 50
Triangle\X2 = 200
Triangle\Y2 = 400
Triangle\X3 = 730
Triangle\Y3 = 150
; Point à tester
Point\x = 340
Point\y = 100
DiametreSelection = 6
Repeat
While WindowEvent(): Wend
ClearScreen(0)
ExamineKeyboard()
ExamineMouse()
; Le triangle est modifiable à la souris en cliquant sur un point
If MouseButton(1)
If MemPoint = 1
Triangle\X1 = MouseX()
Triangle\Y1 = MouseY()
ElseIf MemPoint = 2
Triangle\X2 = MouseX()
Triangle\Y2 = MouseY()
ElseIf MemPoint = 3
Triangle\X3 = MouseX()
Triangle\Y3 = MouseY()
EndIf
Else
MemPoint = 0
EndIf
If TestPoint(MouseX(), MouseY(), Triangle\X1, Triangle\Y1, DiametreSelection)
MemPoint = 1
ElseIf TestPoint(MouseX(), MouseY(), Triangle\X2, Triangle\Y2, DiametreSelection)
MemPoint = 2
ElseIf TestPoint(MouseX(), MouseY(), Triangle\X3, Triangle\Y3, DiametreSelection)
MemPoint = 3
EndIf
; Place le point à tester sous la souris
Point\x = MouseX()
Point\y = MouseY()
; Affiche le tout
AffPoints(@Triangle, @Point, MemPoint)
FlipBuffers()
Delay(1)
Until KeyboardPushed(#PB_Key_Escape)
M.