Polygone convexe

Partagez votre expérience de PureBasic avec les autres utilisateurs.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Polygone convexe

Message par comtois »

Code : Tout sélectionner

;Comtois 16/02/05
;Construction d'un polygone convexe
;Les points peuvent être déplacés à la souris

;-Include
Declare Erreur(Message$)
Declare TracePolygone()
Declare AffPoints(*P.point,mem)
Declare TestPoint(x1,Y1,X2,Y2,d)
Declare PolygoneConvexe()

Global ScreenHeight.l,ScreenWidth.l
If ExamineDesktops()
  ScreenWidth = DesktopWidth(0)
  ScreenHeight = DesktopHeight(0)
Else
  Erreur("Euh ?")
EndIf

#Nbpoints=15
NewList ListPoint.point()
NewList Polygone.point()
Point.point
DiametreSelection=6
For i=1 To #Nbpoints
  AddElement(ListPoint()) 
  ListPoint()\x=Random(ScreenWidth-1)
  ListPoint()\y=Random(ScreenHeight-1)
Next  
;-Initialisation
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  

;-Boucle
Repeat
  While WindowEvent():Wend
  ClearScreen(0, 0, 0)
  ExamineKeyboard()
  ExamineMouse()
  ;Les points peuvent être déplacés 
  If MouseButton(1)
    If MemPoint>=0
      SelectElement(ListPoint(),MemPoint)
      ListPoint()\x = MouseX()
      ListPoint()\y = MouseY()
      EndIf
  Else
    MemPoint=-1
  EndIf
  ForEach ListPoint()
    If TestPoint(MouseX(),MouseY(),ListPoint()\x,ListPoint()\y,DiametreSelection)
      MemPoint=ListIndex(ListPoint())
      Break
    EndIf
  Next  
  ;Place le point à tester sous la souris
  Point\x=MouseX()
  Point\y=MouseY()
  ;Affiche le tout
  PolygoneConvexe()
  AffPoints(@Point,MemPoint)
  TracePolygone()
  FlipBuffers()
  Delay(1)
Until KeyboardPushed(#PB_Key_Escape) 
End

;-Procedures
Procedure Erreur(Message$)
  MessageRequester( "Erreur" , Message$ , 0 ) 
  End 
EndProcedure
Procedure PolygoneConvexe()
  If CountList(ListPoint())<2
    ProcedureReturn #False
  EndIf
  ;Trouve le point le plus bas dans la liste des points
  FirstElement(ListPoint())
  *Min.point=ListPoint()
  *bas.point=*Min
  ForEach ListPoint()
    *p0.point=ListPoint()
    ;Mémorise le point le plus bas , ou le plus à gauche s'il y a égalité
    If (*p0\y<*Min\y) Or ((*p0\y=*Min\y) And (*p0\x<*Min\x))
      *Min=*p0
      *bas=ListPoint()
    EndIf
  Next  
  ;Initialise la liste pour le contour convexe
  ClearList(Polygone())
  ;Effectue la progression de Jarvis pour calculer le contour
  *p0=*bas
  Repeat
    ;Insertion du nouveau p0 dans le contour convexe
    If AddElement(Polygone())=0
      Erreur("plus de mémoire pour ajouter un élément dans polygone")
    Else  
      Polygone()\x=*p0\x
      Polygone()\y=*p0\y
    EndIf
    ;Trouve le point pc dans le sens des aiguilles d'une montre
    cpt=0
    ForEach ListPoint()
      *pi.point=ListPoint()
      ;Saute p0 
      If *pi=*p0
        Continue
      EndIf
      ;Compte les points explorés
      cpt+1
      ;On suppose que le premier point à explorer est dans le sens des aiguilles d'une montre 
      If cpt=1
        *pc.point=ListPoint()
        Continue
      EndIf
      ;Teste si pi est dans le sens des aiguilles d'une montre par rapport à pc
      z=(((*pi\x - *p0\x) * (*pc\y - *p0\y)) - ((*pi\y - *p0\y) * (*pc\x - *p0\x))) 
      If z > 0
        ;pi est dans le sens des aiguilles d'une montre par rapport à pc
        *pc=*pi
      ElseIf z=0
        ;Si pi et pc sont colinéaires , on choisit le plus éloigné de p0
        longueurpi = Pow(*pi\x - *p0\x, 2.0) + Pow(*pi\y - *p0\y, 2.0)
        longueurpc = Pow(*pc\x - *p0\x, 2.0) + Pow(*pc\y - *p0\y, 2.0)
        If longueurpi > longueurpc
          *pc=*pi
        EndIf
      EndIf  
    Next
    ;Cherche le point suivant
    *p0=*pc
  Until *p0=*bas
EndProcedure
Procedure TracePolygone()
  CouleurPolygone=RGB(0,255,0)
  StartDrawing(ScreenOutput())
  SelectElement(Polygone(),0)
  *mem0.point=Polygone()
  *mem.point=Polygone()
  While NextElement(Polygone())
    LineXY(*mem\x,*mem\y,Polygone()\x,Polygone()\y,CouleurPolygone)
    *mem=Polygone()
  Wend  
  LineXY(*mem0\x,*mem0\y,*mem\x,*mem\y,CouleurPolygone)
  StopDrawing()
EndProcedure
Procedure AffPoints(*P.point,mem)
  CouleurCurseur=RGB(255,255,255)
  CouleurPoint=RGB(255,0,0)
  StartDrawing(ScreenOutput())
    ForEach ListPoint()
      Circle(ListPoint()\x,ListPoint()\y,4,CouleurPoint)
    Next
    ;/Affiche le point
  If mem>=0
    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)
  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
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure
Dernière modification par comtois le jeu. 17/févr./2005 16:36, modifié 1 fois.
Oliv
Messages : 2117
Inscription : mer. 21/janv./2004 18:39

Message par Oliv »

impressionant 8O
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

Excellent!
Fred
Site Admin
Messages : 2805
Inscription : mer. 21/janv./2004 11:03

Message par Fred »

Du tres bon..
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

Terrible :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)]
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

:D
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Variation autour du thème du polygone

Message par comtois »

une variante

Code : Tout sélectionner

;Comtois 18/02/05
;Construction d'un polygone convexe

;-Include
Declare Erreur(Message$)
Declare TracePolygone()
Declare AffPoints()
Declare TestPoint(x1, Y1, X2, Y2, d)
Declare PolygoneConvexe()
Declare Repartition()

Global ScreenHeight.l, ScreenWidth.l
If ExamineDesktops()
  ScreenWidth = DesktopWidth(0)
  ScreenHeight = DesktopHeight(0)
Else
  Erreur("Euh ?")
EndIf

Structure NewPoint
  x.l
  y.l
  dx.l
  dy.l
EndStructure  

#Nbpoints = 18
#Taille = 16

NewList ListPoint.NewPoint()
NewList Polygone.NewPoint()

DiametreSelection = 6


;-Initialisation
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 
If OpenWindowedScreen( WindowID(0), 0, 0, ScreenWidth , ScreenHeight, 0, 0, 0 ) = 0 
  Erreur("Impossible d'ouvrir l'écran ") 
EndIf 
Repartition()

;-Sprite
CreateSprite(0,#Taille * 2, #Taille * 2)
StartDrawing(SpriteOutput(0))
  For i = 0 To #Taille
    Circle(#Taille, #Taille,#Taille - i, RGB(50 + i * 6, 40 + i * 6, 40 + i * 6))
  Next
StopDrawing()  

;-Boucle
Repeat
  While WindowEvent():Wend
  ClearScreen(0, 0, 0)
  ExamineKeyboard()
  ExamineMouse()
  AffPoints()
  PolygoneConvexe()
  TracePolygone()
  ForEach ListPoint()
    DisplayTransparentSprite(0,ListPoint()\x - #Taille, ListPoint()\y - #Taille)
  Next  
  FlipBuffers()
  Delay(1)
Until KeyboardPushed(#PB_Key_Escape) 
End

;-Procedures
Procedure Erreur(Message$)
  MessageRequester("Erreur", Message$, 0) 
  End 
EndProcedure
Procedure Repartition()
;Répartition des boules sur l'écran 
For i=1 To #Nbpoints
  AddElement(ListPoint()) 
  *MemPos.NewPoint = ListPoint()
  MemIndex=ListIndex(ListPoint())
  Repeat
    Collision = #False
    x = #Taille + Random(ScreenWidth - #Taille * 2)
    y = #Taille + Random(ScreenHeight - #Taille * 2)
    If CountList(ListPoint()) > 1
      ForEach ListPoint()
        If ListIndex(ListPoint()) = MemIndex
          Continue
        EndIf  
        If Sqr(Pow(ListPoint()\x - x, 2.0) + Pow(ListPoint()\y - y, 2.0)) <= #Taille * 2 
          Collision = #True
          Break
        EndIf
      Next
    EndIf
  Until Collision = #False
  SelectElement(ListPoint(), MemIndex)
  ListPoint()\x = x
  ListPoint()\y = y
  ListPoint()\dx = 2 + Random(2)
  ListPoint()\dy = 2 + Random(2)
Next
EndProcedure
Procedure PolygoneConvexe()
  If CountList(ListPoint()) < 2
    ProcedureReturn #False
  EndIf
  ;Initialise 
  *Min.NewPoint = #Null
  *p0.NewPoint  = #Null
  *pi.NewPoint  = #Null
  *pc.NewPoint  = #Null
  ;Trouve le point le plus bas dans la liste des points
  FirstElement(ListPoint())
  *Min = ListPoint()
  ForEach ListPoint()
    *p0 = ListPoint()
    ;Mémorise le point le plus bas , ou le plus à gauche s'il y a égalité
    If (*p0\y < *Min\y) Or ((*p0\y = *Min\y) And (*p0\x < *Min\x))
      *Min = *p0
    EndIf
  Next  
  ;Initialise la liste pour le contour convexe
  ClearList(Polygone())
  ;Effectue la progression de Jarvis pour calculer le contour 
  *p0 = *Min
  Repeat
    ;Insertion du nouveau p0 dans le contour convexe
    If AddElement(Polygone()) = 0
      Erreur("plus de mémoire pour ajouter un élément dans polygone")
    Else  
      Polygone()\x = *p0\x
      Polygone()\y = *p0\y
    EndIf
    ;Trouve le point pc dans le sens des aiguilles d'une montre
    *pc = #Null
    ForEach ListPoint()
      *pi = ListPoint()
      ;Saute p0 
      If *pi = *p0
        Continue
      EndIf
      ;Sélectionne le premier point 
      If *pc = #Null
        *pc = ListPoint()
        Continue
      EndIf
      ;Teste si pi est dans le sens des aiguilles d'une montre par rapport à pc
      z=(((*pi\x - *p0\x) * (*pc\y - *p0\y)) - ((*pi\y - *p0\y) * (*pc\x - *p0\x))) 
      If z > 0
        ;pi est dans le sens des aiguilles d'une montre par rapport à pc
        *pc = *pi
      ElseIf z = 0
        ;Si pi et pc sont colinéaires , on choisit le plus éloigné de p0
        longueurpi = Pow(*pi\x - *p0\x, 2.0) + Pow(*pi\y - *p0\y, 2.0)
        longueurpc = Pow(*pc\x - *p0\x, 2.0) + Pow(*pc\y - *p0\y, 2.0)
        If longueurpi > longueurpc
          *pc = *pi
        EndIf
      EndIf  
    Next
    ;Cherche le point suivant
    *p0 = *pc
  Until *p0 = *Min
EndProcedure
Procedure TracePolygone()
  CouleurPolygone = RGB(145, 155, 165)
  StartDrawing(ScreenOutput())
  SelectElement(Polygone(), 0)
  *mem0.NewPoint = Polygone()
  *mem.NewPoint  = Polygone()
  While NextElement(Polygone())
    LineXY(*mem\x, *mem\y, Polygone()\x, Polygone()\y, CouleurPolygone)
    *mem = Polygone()
  Wend  
  LineXY(*mem0\x, *mem0\y, *mem\x, *mem\y, CouleurPolygone)
  StopDrawing()
EndProcedure
Procedure.l Limite(*Valeur.LONG, Min.l, Max.l)
  If *Valeur\l < Min
    *Valeur\l = Min
    ProcedureReturn #True
  ElseIf *Valeur\l > Max
    *Valeur\l = Max
    ProcedureReturn #True
  EndIf
EndProcedure
Procedure AffPoints()
  CouleurPoint = RGB(200, 255, 0)
  Taille2 = #Taille / 2
  ForEach ListPoint()
    ListPoint()\x + ListPoint()\dx
    ListPoint()\y + ListPoint()\dy 
    If Limite(@ListPoint()\x, #Taille, ScreenWidth - #Taille)
      ListPoint()\dx * -1
    EndIf
    If Limite(@ListPoint()\y, #Taille, ScreenHeight - #Taille)
      ListPoint()\dy * -1
    EndIf
    *MemPos.NewPoint=ListPoint()
    MemIndex=ListIndex(ListPoint())
    ForEach ListPoint()
      If ListIndex(ListPoint()) = MemIndex
        Continue
      EndIf  
      ;Calcul la distance 
      Distance = Sqr(Pow(ListPoint()\x - *MemPos\x, 2.0) + Pow(ListPoint()\y - *MemPos\y, 2.0))
      If Distance <= #Taille * 2
        *MemPos\dx * -1
        *MemPos\dy * -1  
        *MemPos\x + *MemPos\dx
        *MemPos\y + *MemPos\dy 
      EndIf
    Next 
    SelectElement(ListPoint(), MemIndex)
  Next
EndProcedure
Procedure TestPoint(x1, Y1, X2, Y2, d)
  If x1 > X2 - d And x1 < X2 + d And Y1 > Y2 - d And Y1 < Y2 + d
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure
Dernière modification par comtois le sam. 19/févr./2005 23:28, modifié 3 fois.
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

Re :D
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Il y a matière à faire un bel écran de veille original! :)
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

nico a écrit :Il y a matière à faire un bel écran de veille original! :)
oui , c'est à ça que je songeais avec le dernier code ,mais c'est Dobro le spécialiste de l'écran de veille :)
Le soldat inconnu aussi , il me semble qu'il avait proposé des exemples ?
va falloir que je fasse une petite recherche.

Sinon , on peut obtenir le même résultat avec l'algorithme de Graham , je ferai peut-être un essai plus tard .

[EDIT]
En faisant des recherches sur Graham , je viens de voir qu'il y a encore mieux , le 'Quick' , bon ben , ça sera peut-être pour une prochaine fois , le temps de me documenter :)
Répondre