Dessiner un triangle rempli

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Dessiner un triangle rempli

Message par Dr. Dri »

Code : Tout sélectionner

Procedure Swap(*a.l, *b.l, size.l)
  If *a=0 Or *b=0 Or size<1
    ProcedureReturn 0
  EndIf

  *c.l = AllocateMemory(size)
  If *c=0 : ProcedureReturn 0 : EndIf
 
  CopyMemory(*a, *c, size)
  CopyMemory(*b, *a, size)
  CopyMemory(*c, *b, size)
 
  FreeMemory(*c)

  ProcedureReturn 1
EndProcedure

Procedure Sgn(x)
  If x>0
    ProcedureReturn 1
  ElseIf x<0
    ProcedureReturn -1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure FilledTriangle(x1, y1, x2, y2, x3, y3, couleur)

  If y1>y2
    Swap(@x1, @x2, 4)
    Swap(@y1, @y2, 4)
  EndIf
  If y1>y3
    Swap(@x1, @x3, 4)
    Swap(@y1, @y3, 4)
  EndIf
  If y2>y3
    Swap(@x2, @x3, 4)
    Swap(@y2, @y3, 4)
  EndIf
  
  dx1 = x3-x1 : dy1 = y3-y1 : sgn1 = Sgn(dx1)
  dx2 = x2-x1 : dy2 = y2-y1 : sgn2 = Sgn(dx2)
  dx3 = x3-x2 : dy3 = y3-y2 : sgn3 = Sgn(dx3)
  dx1 = Abs(dx1)
  dx2 = Abs(dx2)
  dx3 = Abs(dx3)
  
  err1 = 0
  err2 = 0
  err3 = 0
  
  xl = x1
  xr = x1
  
  If y1<>y2
    For y=y1 To y2
      If y>=0
      
        LineXY(xl, y, xr, y, couleur)
        
        err1 + dx1
        While err1>dy1
          xl + sgn1
          err1 - dy1
        Wend
        
        err2 + dx2
        While err2>dy2
          xr + sgn2
          err2 - dy2
        Wend
      
      EndIf
    Next y
  EndIf
  
  If y1<>y2
    For y=y2 To y3
      If y>=0
      
        LineXY(xl, y, xr, y, couleur)
        
        err1 + dx1
        While err1>dy1
          xl + sgn1
          err1 - dy1
        Wend
        
        err3 + dx3
        While err3>dy3
          xr + sgn3
          err3 - dy3
        Wend
      
      EndIf
    Next y
  EndIf
  
EndProcedure

;- Debut du programme
OpenWindow(1, 100, 100, 300, 200, #PB_Window_MinimizeGadget, "")

max=40
dessine = 0

If StartDrawing(WindowOutput())
  Box(0, 0, 300, 200, RGB(255, 255, 255))
  StopDrawing()
EndIf

Repeat
  
  x1 = Random(299)
  y1 = Random(199)
  x2 = Random(299)
  y2 = Random(199)
  x3 = Random(299)
  y3 = Random(199)
  
  r = Random(255)
  g = Random(255)
  b = Random(255)
  
  If dessine<max
    If StartDrawing(WindowOutput())
      FilledTriangle(x1, y1, x2, y2, x3, y3, RGB(r, g, b))
      StopDrawing()
    EndIf
    dessine+1
  EndIf
  
  event = WindowEvent()
Until event=#PB_Event_CloseWindow
Dri
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

un truc tout bête

simplement dessiner les lignes entres chaque points puis faire un remplissage au centre du triangle, non ?

je vais faire un exemple
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)]
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

@Dri: c'est tres rapide !! :D
mais t'a vraiment pas trouvé plus simple ?? 8O

c'est pas Dri qu'il fallai prendre comme pseudo , c'est pierre de Rosette !! :D
je comprend jamais rien a tes codes !! :lol: :lol:
Avatar de l’utilisateur
Chris
Messages : 3731
Inscription : sam. 24/janv./2004 14:54
Contact :

Message par Chris »

Dobro a écrit :@Dri: c'est tres rapide !! :D
mais t'a vraiment pas trouvé plus simple ?? 8O

c'est pas Dri qu'il fallai prendre comme pseudo , c'est pierre de Rosette !! :D
je comprend jamais rien a tes codes !! :lol: :lol:
T'est pas le seul. :lol:
J'ai beau chercher les commentaires, je trouve rien :wink:
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

ah euh oué c'est pas commenté
j'ai pas mal galéré pour le faire (ca risque de me servir)

le but est de se baser sur l'algo de tracés de ligne de bresenham
(jvais pas vous faire un court là dessus ^^ je capte pas à 100%)

donc le principe c'est de trier les points du plus haut au plus bas
(la partie avec les swap)

ensuite on trace le triangle avec des lignes horizontales en partant de haut en bas

avec un triangle quelconque ca donne à peu pres ca :

Code : Tout sélectionner

         A




                   B



C
donc on part du y de A à celui de B
en tracant des lignes horizonatles (on calcule x gauche et droite, c'est bresenham)
ensuite une fois arrivé à B on poursuit jusqu'au y de C

voila pour les grandes lignes

Sinon pour ce qui est d'utiliser la fonction fill
c'est toujours risqué... étant donné qu'il y a tout de même d'autres points de diverses couleurs là où le triangle est censé arriver... j'ai pas trouvé moins compliqué (ou plus simple de mon point de vue ^^) pour etre certain que le triangle soit tracé completement...

Dri
Psycode
Messages : 131
Inscription : lun. 23/août/2004 18:47
Localisation : Jupiter ?

Message par Psycode »

...
Dernière modification par Psycode le ven. 03/sept./2004 17:34, modifié 1 fois.
Wait And See...
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

le résultat est joli ^^
la mienne n'utilise pas de réel 8)

Dri
Psycode
Messages : 131
Inscription : lun. 23/août/2004 18:47
Localisation : Jupiter ?

Message par Psycode »

Héhéhé :lol:

Dri, faisons un concours. Lancons nous un chalenge et voyons qui fait le code le plus optimisé ! :wink:
Wait And See...
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

lol
l'optimisation c'est pas mon truc ^^
déjà j'ai pondu ca avec du mal ^^

Dri

PS. je ferais au moins des tests de vitesse pour comparer nos codes si t'en pond un avec un triangle uni et sans bordure (comme le mien)
Psycode
Messages : 131
Inscription : lun. 23/août/2004 18:47
Localisation : Jupiter ?

Routine de tracage de triangles pleins

Message par Psycode »

...
Dernière modification par Psycode le ven. 03/sept./2004 17:34, modifié 2 fois.
Wait And See...
crisot
Messages : 98
Inscription : lun. 30/août/2004 21:03

Message par crisot »

Je vous fourni la mienne, pour ceux qui en ont besoin. La première version est semie optimisée, mais surtout, très compacte, claire et lisible. Facile à adapter et à passer en procédure. Il suffit de rempli les tableaux X() et Y() avec les points qu'on veux.


Code : Tout sélectionner

#Window = 0 
#Width = 640
#Height = 480 
#Timer = 0 

;* Initialisation de DirectX *;
If InitSprite() = 0 Or InitKeyboard() = 0 
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0) 
  CloseWindow(#Window) : End 
EndIf 

;* Ouverture de la fenêtre et de l'écran *;
hwnd = OpenWindow(#Window, 0, 0, #Width, #Height, #PB_Window_TitleBar | #PB_Window_ScreenCentered, "") 
OpenWindowedScreen(hwnd, 0, 0, #Width, #Height, 0, 0, 0) 

ClearScreen(0, 0, 0) 




;*********************************************;

;* 3 pixels au pif *;

Dim X(2) : Dim Y(2)
For i=0 To 2: X(i)=Random(#Width-1) : Y(i)=Random(#Height-1) : Next

;* On tri les points (cette partie n'est pas optimale, mais ça suffira bien) *;

T=65535 : B=0 : BI=0
For i=0 To 2 : Y=Y(i) : If Y<T : T=Y : BI=i : EndIf : If Y>B : B=Y : EndIf : Next

XA.f=X(BI) : Y1=Y(BI) : BI=BI+1 : If BI=3 : BI=0 : EndIf
X2.f=X(BI) : Y2=Y(BI) : BI=BI+1 : If BI=3 : BI=0 : EndIf
X3.f=X(BI) : Y3=Y(BI) : XB.f=XA

;* On trace *;

PA1.f = (X2-XA)/((Y2-Y1)) : PB1.f = (X3-XA)/((Y3-Y1)) : PC.f = (X3-X2)/((Y3-Y2))

If Y2<Y3 : HALF=Y2 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y3: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y1=Y2 : XA = X2: EndIf           ;* cas particulier à ne pas oublier *;
If Y1=Y3 : XB = X3: EndIf           ;* cas particulier à ne pas oublier *;

StartDrawing(ScreenOutput()) 
For i=T To HALF-1 : LineXY(XA, i, XB, i, 16777215) 
XA=XA+PA1 : XB=XB+PB1 : Next
For i=HALF To B : LineXY(XA, i, XB, i, 16777215) 
XA=XA+PA2 : XB=XB+PB2 : Next 
StopDrawing()

FlipBuffers() 

;*********************************************;






;* On quite ! *;

;End
Repeat  
  ExamineKeyboard() 
  While WindowEvent() : Wend 
  If KeyboardPushed(#PB_Key_Escape) : quit = 1 : EndIf 
Until quit = 1 
End


Et voici la deuxième version, qui est en fait la meme, mais optimisée, sans les DIM que PB ne semble pas trop apprécier. Elle est plus longue mais nettement plus rapide, et encore un peu optimisable, mais j'ai préféré ne pas aller plus loin sinon après ça ne ressemble plus à rien

Code : Tout sélectionner

#Window = 0 
#Width = 640
#Height = 480 
#Timer = 0 

;* Initialisation de DirectX *;
If InitSprite() = 0 Or InitKeyboard() = 0 
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0) 
  CloseWindow(#Window) : End 
EndIf 

;* Ouverture de la fenêtre et de l'écran *;
hwnd = OpenWindow(#Window, 0, 0, #Width, #Height, #PB_Window_TitleBar | #PB_Window_ScreenCentered, "") 
OpenWindowedScreen(hwnd, 0, 0, #Width, #Height, 0, 0, 0) 

ClearScreen(0, 0, 0) 

StartDrawing(ScreenOutput()) 






;********************************;

;* 3 pixels au pif *;

X0=Random(#Width-1)
Y0=Random(#Height-1)
X1=Random(#Width-1)
Y1=Random(#Height-1)
X2=Random(#Width-1)
Y2=Random(#Height-1)

;* Recherche du point le plus haut et le plus bat *;

T=Y0 : B=Y0 : CAS=0
If Y1<T : T=Y1 : CAS=1 : EndIf : If Y1>B : B=Y1 : EndIf
If Y2<T : T=Y2 : CAS=2 : EndIf : If Y2>B : B=Y2 : EndIf

;* Calcul des pentes dans les 3 cas possibles *;

If CAS=0
XA.f=X0 : XB.f=X0
PA1.f = (X1-X0)/(Y1-Y0) : PB1.f = (X2-X0)/(Y2-Y0) : PC.f = (X2-X1)/(Y2-Y1)
If Y1<Y2 : HALF=Y1 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y2: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y0=Y1 : XA = X1: EndIf           ;* cas particulier à ne pas oublier *;
If Y0=Y2 : XB = X2: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

If CAS=1
XA.f=X1 : XB.f=X1
PA1.f = (X2-X1)/(Y2-Y1) : PB1.f = (X0-X1)/(Y0-Y1) : PC.f = (X0-X2)/(Y0-Y2)
If Y2<Y0 : HALF=Y2 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y0: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y1=Y2 : XA = X2: EndIf           ;* cas particulier à ne pas oublier *;
If Y1=Y0 : XB = X0: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

If CAS=2
XA.f=X2 : XB.f=X2
PA1.f = (X0-X2)/(Y0-Y2) : PB1.f = (X1-X2)/(Y1-Y2) : PC.f = (X1-X0)/(Y1-Y0)
If Y0<Y1 : HALF=Y0 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y1: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y2=Y0 : XA = X0: EndIf           ;* cas particulier à ne pas oublier *;
If Y2=Y1 : XB = X1: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

;* Traçage *;

For i=T To HALF-1 : LineXY(XA, i, XB, i, 16777215)
XA=XA+PA1 : XB=XB+PB1 : Next
For i=HALF To B : LineXY(XA, i, XB, i, 16777215)
XA=XA+PA2 : XB=XB+PB2 : Next 

;********************************;






;* On quite ! *;

StopDrawing()
FlipBuffers() 

Repeat  
  ExamineKeyboard() 
  While WindowEvent() : Wend 
  If KeyboardPushed(#PB_Key_Escape) : quit = 1 : EndIf 
Until quit = 1 
End


En fait j'ai fais ça en 20 minutes suite à une mise au défit par Psycode... A vous de juger ;) C'est mon premier programme en PB qu'hier soir encore je ne connaissais pas, habituellement je programme pas en basic, mais en tout cas celui ci est prometeur ;)
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

ça va surement etre le mien le plus court et le plus rapide :D
et le plus convivial car on peut choisir l'angle de l'orientation du triangle,l'ouverture en degres du sommet,et l'emplacement dans l'ecran ainsi que la couleur de la ligne de pourtour
et tout ça grace au sinus et cosinus !!
j'y ai passé l'apres-midi mais voila !

par contre j'ai pas chercher a la remplir !! mais un bon fill area bien plaçé !! :D


...............
:lol: :lol:
Dernière modification par Backup le dim. 17/juil./2011 18:01, modifié 1 fois.
crisot
Messages : 98
Inscription : lun. 30/août/2004 21:03

Message par crisot »

tu triche, tu fais un linexy d'un point à un autre :) La question était le remplissage ici, et un fill area n'overwritte pas les pixels isolés :)
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

bah !! la routine est interressante quand meme non ? :D

apres tout ça reste un triangle !! :lol: :lol: plein de vide !! :lol:
Psycode
Messages : 131
Inscription : lun. 23/août/2004 18:47
Localisation : Jupiter ?

Message par Psycode »

...
Dernière modification par Psycode le ven. 03/sept./2004 17:34, modifié 1 fois.
Wait And See...
Répondre