savoir si une coordonnées est dans un polygone

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

savoir si une coordonnées est dans un polygone

Message par Thyphoon »

je partage avec vous un code que j'ai trouvé et adapté au purebasic
Je crois que comtois avait posté un code similaire mais je ne l'ai pas retrouvé.
ça vous permet de savoir si un point est dans un polygone ou non (quelques soit le nombre de point)
2 méthodes différentes pour tester sont implémentées
The Crossing Number ou The Winding Number, vous pouvez switcher d'un mode a un autre avec [TAB]
Il y a aussi 2 formes en mémoire [F1] et [F2]
et pour finir vous pouvez rajouter un point avec un CLIC Gauche , et effacer tout les points avec un CLIC Droit !

Bon, par contre si vous avez une idée pour améliorer tout ça n’hésitez pas ...

Code : Tout sélectionner

NewList V.point()
; Source : http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm#wn_PinPolygon%28%29

;===================================================================
;-                          isLeft
;isLeft(): tests If a point is Left|On|Right of an infinite line.
;    Input:  three points P0, P1, And P2
;    Return: >0 For P2 left of the line through P0 And P1
;            =0 For P2 on the line
;            <0 For P2 right of the line
;    See: the January 2001 Algorithm "Area of 2D and 3D Triangles and Polygons"
;inline int

Procedure isLeft(*p0.point,*p1.point,*p2.point)
  ProcedureReturn ( (*p1\x - *P0\x) * (*p2\y - *P0\y) - (*P2\x - *P0\x) * (*p1\y - *P0\y) );
EndProcedure

;===================================================================
;-                          The Winding Number
; wn_PnPoly(): winding number test For a point in a polygon
;      Input:   P = a point,
;               V[] = vertex points of a polygon V[n+1] With V[n]=V[0]
;      Return:  wn = the winding number (=0 only If P is outside V[])
;===================================================================

Procedure wn_PnPoly( *P.point,List polylist.point())
  Define    wn.l = 0                  ;the winding number counter
  Define pa.point, pb.point
  ;loop through all edges of the polygon
  For i=0 To ListSize(polylist())-1
    SelectElement(polylist(),i)
    pa\x=polylist()\x
    pa\y=polylist()\y
    ;si on arrive a la fin de la liste on prend comme point i+1 le premier point
    If i=ListSize(polylist())-1
      SelectElement(polylist(),0)
    Else  
      SelectElement(polylist(),i+1)
    EndIf  
    pb\x=polylist()\x
    pb\y=polylist()\y
    
    If (pa\y <= *P\y)                 ; start y <= *P\y
      If (pb\y > *P\y)                ; an upward crossing
        If (isLeft( pa, pb, *P) > 0)  ; P left of edge
          wn+1                        ; have a valid up intersect
        EndIf
      EndIf
    Else                              ; start y > *P\y (no test needed)
      If (pb\y <= *P\y)               ; a downward crossing
        If (isLeft( pa, pb, *P) < 0)  ; P right of edge
          wn-1                        ; have a valid down intersect
        EndIf
      EndIf
      
    EndIf
  Next
  ProcedureReturn Wn
EndProcedure

;===================================================================
;-                        The Crossing Number
; cn_PnPoly(): crossing number test For a point in a polygon
;      Input:   P = a point,
;               V[] = vertex points of a polygon V[n+1] With V[n]=V[0]
;      Return:  0 = outside, 1 = inside
; This code is patterned after [Franklin, 2000]
;===================================================================
Procedure cn_PnPoly( *P.point,List polylist.point())
  cn.l = 0                              ;the crossing number counter
  Define pa.point, pb.point
  ; loop through all edges of the polygon
  For i=0 To ListSize(polylist())-1    ; edge from V[i] To V[i+1]
    SelectElement(polylist(),i)
    pa\x=polylist()\x
    pa\y=polylist()\y
    ;si on arrive a la fin de la liste on prend comme point i+1 le premier point
    If i=ListSize(polylist())-1
      SelectElement(polylist(),0)
    Else  
      SelectElement(polylist(),i+1)
    EndIf  
    pb\x=polylist()\x
    pb\y=polylist()\y
    If (((pa\y <= *P\y) And (pb\y > *P\y))  Or ((pa\y > *P\y) And (pb\y <= *P\y))) ; an upward crossing Or // a downward crossing
      ; compute the actual edge-ray intersect x-coordinate
      vt.f = (*P\y - pa\y) / (pb\y - pa\y);
      If (*P\x < pa\x + vt * (pb\x - pa\x)) ; *P\x < intersect
        cn+1;   ; a valid crossing of y=*P\y right of *P\x
      EndIf
    EndIf
  Next
  ProcedureReturn (cn&1);    // 0 if even (out), and 1 if odd (in)
EndProcedure



;===================================================================
;- TEST
;===================================================================
If InitSprite()
  If InitKeyboard() And InitMouse()
    winMain = OpenWindow(#PB_Any,0,0,800,600,"Press [Esc] to close",#PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    OpenWindowedScreen(WindowID(winMain), 0, 0,800,600, 1, 0, 0)
    UsePNGImageDecoder()
    UseJPEGImageDecoder()
    SetFrameRate(60)
  EndIf
Else
  MessageRequester("","Unable to initsprite") :
EndIf

Define pa.point, pb.point ; pa et pb pour tracer un segment du polygone
Define col.l=RGB(0,0,0) ;
Define EventID.l,mode.b,result.l
Repeat
  Delay(1)
  EventID = WindowEvent()
  ExamineKeyboard()
  ExamineMouse()
  ClearScreen(col)
  
  ;pour switcher du mode The Crossing Number
  If KeyboardPushed(#PB_Key_Tab)
    mode=1-mode
    Delay(200)
  EndIf
  
  If MouseButton(#PB_MouseButton_Left)
    AddElement(V())
    v()\x=MouseX()
    v()\y=MouseY()
    Delay(200)
  EndIf
  
  If MouseButton(#PB_MouseButton_Right)
    ClearList(v())
    Delay(200)
  EndIf
  
  
  If KeyboardPushed(#PB_Key_F1)
    ClearList(V())
    For z=0 To 18:angle=(360/19)*z:AddElement(V()):V()\x=400+200*Cos(Radian(angle)):V()\y=300+200*Sin(Radian(angle)):Next
    AddElement(V()):V()\x=400:V()\y=300
  EndIf
  
  If KeyboardPushed(#PB_Key_F2)
    ClearList(V())
    
    AddElement(V()):V()\x=300:V()\y=250:n+1
    AddElement(V()):V()\x=350:V()\y=250:n+1
    AddElement(V()):V()\x=80:V()\y=10:n+1
    AddElement(V()):V()\x=450:V()\y=250:n+1
    AddElement(V()):V()\x=400:V()\y=300:n+1
    AddElement(V()):V()\x=450:V()\y=280:n+1
    AddElement(V()):V()\x=280:V()\y=400:n+1
    AddElement(V()):V()\x=340:V()\y=280:n+1
  EndIf
  
  StartDrawing(ScreenOutput())
  For i=0 To ListSize(V())-1
    SelectElement(V(),i)
    pa\x=V()\x
    pa\y=V()\y
    ;si on arrive a la fin de la liste on prend comme point i+1 le premier point
    If i=ListSize(V())-1
      SelectElement(V(),0)
    Else  
      SelectElement(V(),i+1)
    EndIf  
    pb\x=V()\x
    pb\y=V()\y
    
    LineXY(pa\x,pa\y,pb\x,pb\y,#Green)
    Circle(pa\x,pa\y,5,#Red)
    
  Next
  Circle(MouseX(),MouseY(),5,#Blue)
  
  
  P.point
  P\x=MouseX()
  P\y=MouseY()
  Select Mode
    Case 0
      modetxt.s="mode : The Crossing Number" 
      result=cn_PnPoly(P,V())
    Case 1
      modetxt.s="mode : The Winding Number"
      result=wn_PnPoly(P,V())
  EndSelect
  If result<>0
    modetxt.s+" return : "+Str(result)+" Vous êtes dans le polygone !"
    col=RGB(0,0,0)
  Else
    modetxt.s+" return : "+Str(result)+" Vous n'êtes pas dans le polygone !"
    col=RGB(50,50,50)
  EndIf
  DrawText(0,0,"[Tab] switch Crossing/Winding [F1][F2] polygone [Left mouse button] Add Point [Right mouse button] clear All Point")
  DrawText((800-TextWidth(modetxt))/2,20,modetxt.s) 

  StopDrawing()
  FlipBuffers()
Until KeyboardReleased(#PB_Key_Escape) Or EventID = #PB_Event_CloseWindow
Dernière modification par Thyphoon le jeu. 16/juin/2011 13:26, modifié 2 fois.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: savoir si une coordonnées est dans un polygone

Message par djes »

Ecran noir...
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

djes a écrit :Ecran noir...
Oui c'est a toi de dessiner le Polygone ! :P (clic gauche de la souris) le curseur est dessiné part un point bleu ! dit moi si ça marche.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: savoir si une coordonnées est dans un polygone

Message par djes »

J'avais un petit souci sur mon poste ^^
Sinon, l'algo ne fonctionne pas très bien. Au début je croyais que c'était un problème polygone formes concaves/convexes, mais non, même avec des formes relativement simples, il se trompe souvent :/
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

djes a écrit :J'avais un petit souci sur mon poste ^^
Sinon, l'algo ne fonctionne pas très bien. Au début je croyais que c'était un problème polygone formes concaves/convexes, mais non, même avec des formes relativement simples, il se trompe souvent :/
Alors là je comprends pas .... je teste cet algo depuis 2 jours jamais eu de souci !
si en retour tu as quelques choses différent de 0 c'est que tu es dedans.
Si tu as un exemple de forme qui pose problème dit le moi car pour l'instant j'ai jamais eu de problème quelques soit la forme
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

Thyphoon a écrit :
djes a écrit :J'avais un petit souci sur mon poste ^^
Sinon, l'algo ne fonctionne pas très bien. Au début je croyais que c'était un problème polygone formes concaves/convexes, mais non, même avec des formes relativement simples, il se trompe souvent :/
Alors là je comprends pas .... je teste cet algo depuis 2 jours jamais eu de souci !
si en retour tu as quelques choses différent de 0 c'est que tu es dedans.
Si tu as un exemple de forme qui pose problème dit le moi car pour l'instant j'ai jamais eu de problème quelques soit la forme
EDIT:EFFECTIVEMENT j'ai trouvé un cas qui pose problème ... je regarde
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: savoir si une coordonnées est dans un polygone

Message par djes »

Image
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

lollllllll dur tu as complétement raison ....
donc les algos donné là
http://softsurfer.com/Archive/algorithm ... ygon%28%29
sont mauvais ! :o(
Je vais voir si je peux comprendre ce qui cloche ...

Merci beaucoup en tout cas djes !!
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

voilà j'ai crois que j'ai trouvé la solution... les calculs sont bon, mais le gars qui a pondu les algos a oublier de boucler le calcul (le dernier point part rapport au premier)

vous pouvez testez et me dire si vous trouvez un bug !
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Le Soldat Inconnu »

Pour moi, ça marche :D
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

Ouf ça me rassure !
je vais peut être nettoyer un peu le code et le reposter tout propre et commenté
a oui j'ai oublié de dire que vous pouvez appuyer sur F1 ou F2 j'ai mis 2 formes prédéfinit !
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: savoir si une coordonnées est dans un polygone

Message par djes »

Nickel, merci! :)
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

de rien :D ! ça me fait toujours plaisir de partager quelques choses que j'ai réussi a faire :P (même si je n'ai rien inventé l'algo n'est pas de moi :roll: )

j'ai édité le programme du premier post ! j'utilise une liste au lieu d'un tableau pour dessiner le polygone. et 2 méthodes sont implémentées :The Crossing Number et The Winding Number, vous pouvez switcher d'un mode a un autre avec [TAB]
et pour rappel, il y a aussi 2 formes en mémoire [F1] et [F2]
et pour finir vous pouvez rajouter un point avec un CLIC Gauche , et effacer tout les points avec un CLIC Droit !

Voilà ! normalement tout dois marcher. Si vous avez des suggestions d'amélioration, d’optimisation n’hésitez pas !
Avatar de l’utilisateur
GallyHC
Messages : 1708
Inscription : lun. 17/déc./2007 12:44

Re: savoir si une coordonnées est dans un polygone

Message par GallyHC »

Bonjour,

J’avais teste cette aprem et je suis reste perplexe sur le code, mais après les tests que je viens de faire une seule chose me viens à l’esprit bravo il est bien sympa ce code.

Cordialement
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: savoir si une coordonnées est dans un polygone

Message par Thyphoon »

GallyHC a écrit :Bonjour,

J’avais teste cette aprem et je suis reste perplexe sur le code, mais après les tests que je viens de faire une seule chose me viens à l’esprit bravo il est bien sympa ce code.

Cordialement
GallyHC
Merci ! :D Bon faut avouer qu'avant que je nettoie le code c'était plutôt crade :P apres pour l'algo, il est pas de moi, j'ai juste adapté et corrigé une petite erreur ! :wink:
Moi ça me sert pour faire les zones/boutons pour un jeu d'aventure et ça marche vraiment bien !
Répondre