Trait, courbe, ligne, points tillés, etc...

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

Le dernier code est pas mal, mais effectivement ça pose quelques problèmes quand on va vite ^^, avec un interval de 10 ou 15.
Sinon, c'est assez rapide comme technique, ça peut faire une bonne base pour tracer les traits entre deux points ;).


En fait, je me demandais quelle serait la technique pour obtenir ceci :
1) je dessine sur une surface de dessin (canvas, screen, sprite, image, peu importe). J'obtiens des points que j'enregistre dans une liste/ un tableau.
2) Optionnel : je calcule une sorte de "trajectoire" pour avoir une belle courbe, la plus proche possible de l'originale, mais aussi la plus lissée possible (en gros, j'applique un peu un lissage façon courbe de bézier)
3) je trace enfin tous les traits entre les points obtenus, en fonction d'un espacement défini.
4) Je vérifie qu'ils sont bien tous à la même distance et je les corrige si besoin.

Dois-je sauvegarder une première fois tous mes points en 1), puis l'étape 2), 3). et 4)
Ou dois-je sauvegarder mes points 1), en calculant avant qu'ils sont bien à une distance proportionnelle à mon espacement 4), puis, 2) et 3) ?

D'après vous qu'elle serait la meilleure méthode (la plus rapide, ) ?
Je pencherai pour 1) 4) 2) 3). si la distance entre les points est > à mon espacement. Et 1) 3) si ce n'est pas le cas.

Qu'en pensez-vous ?
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

blendman a écrit :Le dernier code est pas mal, mais effectivement ça pose quelques problèmes quand on va vite ^^, avec un interval de 10 ou 15.
Sinon, c'est assez rapide comme technique, ça peut faire une bonne base pour tracer les traits entre deux points ;).


En fait, je me demandais quelle serait la technique pour obtenir ceci :
1) je dessine sur une surface de dessin (canvas, screen, sprite, image, peu importe). J'obtiens des points que j'enregistre dans une liste/ un tableau.
2) Optionnel : je calcule une sorte de "trajectoire" pour avoir une belle courbe, la plus proche possible de l'originale, mais aussi la plus lissée possible (en gros, j'applique un peu un lissage façon courbe de bézier)
3) je trace enfin tous les traits entre les points obtenus, en fonction d'un espacement défini.
4) Je vérifie qu'ils sont bien tous à la même distance et je les corrige si besoin.

Dois-je sauvegarder une première fois tous mes points en 1), puis l'étape 2), 3). et 4)
Ou dois-je sauvegarder mes points 1), en calculant avant qu'ils sont bien à une distance proportionnelle à mon espacement 4), puis, 2) et 3) ?

D'après vous qu'elle serait la meilleure méthode (la plus rapide, ) ?
Je pencherai pour 1) 4) 2) 3). si la distance entre les points est > à mon espacement. Et 1) 3) si ce n'est pas le cas.

Qu'en pensez-vous ?
Vérifier qu'ils sont bien à la même distance ne me semble pas adéquat/utile. Perso je partirais sur une solution de pile FIFO (un petit tableau fait l'affaire) pour avoir toujours les n derniers points correspondant aux points de contrôle d'une courbe. Il faut bien choisir le type de courbe car elle ne passe pas forcément par les points de contrôle. La distance entre les points me donnerait la "vitesse" de tracé et donc me permettrait de mieux affiner la courbe. Donc pour moi le plus important pour l'instant serait de savoir quelle fonction de courbe utiliser.

Voici un lien pour un très bon papier sur les types de courbes : http://members.chello.at/easyfilter/bresenham.pdf
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

djes a écrit :Vérifier qu'ils sont bien à la même distance ne me semble pas adéquat/utile. Perso je partirais sur une solution de pile FIFO (un petit tableau fait l'affaire) pour avoir toujours les n derniers points correspondant aux points de contrôle d'une courbe.
c'est ce que j'ai fait au départ. Mais je bloque sur l'utilisation de ce tableau ensuite, car je ne sais pas comment avoir une belle courbe.
Il faut bien choisir le type de courbe car elle ne passe pas forcément par les points de contrôle. La distance entre les points me donnerait la "vitesse" de tracé et donc me permettrait de mieux affiner la courbe. Donc pour moi le plus important pour l'instant serait de savoir quelle fonction de courbe utiliser.
JE suis bien d'accord, mais alors, quelle type de courbe dois-je utiliser ?

Un ami m'avait donné une fonction de courbe qui lissait les points tout en passant par les points de contrôle, mais il restait le problème de la distance entre les points qui ne donnait pas de jolis résultats (lorsque j'utilisai un brush image ou un circle par exemple)

Voici l'exemple en question. Là, ça fonctionne car ce sont des line, mais si je mets des circles, ça peut poser des poser avec la transparence :

Code : Tout sélectionner


; Code by Onilink (CBNA) 2011
; adapted for Purebasic 5.31 by blendman 06/2015 (for Animatoon)


; distance, direction..
Macro point_distance(x1,y1,x2,y2)   
  Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )       
EndMacro
Macro point_direction(x1,y1,x2,y2)
  ATan2((y2- y1),(x2- x1))
EndMacro




Global Dim listdot.point(0), startCurve, size
size = 5

Procedure AddDot(x1,y1)
    
  i = ArraySize(listdot())  
  
  If i >0
    
    xx = x1
    yy = y1   
    StartX = ListDot(i)\x
    StartY = ListDot(i)\y
    
    dist  = point_distance(xx,yy,StartX,StartY) 
    
    If dist >= size
      ok = 1
    EndIf  
    
  Else
    ok = 1
  EndIf
  
  
  If ok
    
    ListDot(i)\x = x1
    ListDot(i)\y = y1
    ReDim ListDot(i+1)
    
  EndIf

EndProcedure


Procedure AddArrayElement(Array liste1.point(1),x1,y1)
  
  i = ArraySize(liste1())
  liste1(i)\x = x1
  liste1(i)\y = y1
  ReDim liste1(i+1)

EndProcedure

Procedure CurveStroke()
  
  ; we get the current dot
  Dim copy.point(0)
  n = ArraySize(listdot()) - 3
  
  ; we copy it to a new array, to smooth it
  For i=0 To 3
    ReDim copy(i)
    copy(i)\x = listdot(n+i)\x
    copy(i)\y = listdot(n+i)\y  
  Next i
  
  ; smooth the dots
  Dim tmp.point(0)
  
  bx1 = (copy(0)\x + copy(1)\x)/2
  by1 = (copy(0)\y + copy(1)\y)/2
  bx2 = (copy(1)\x + copy(2)\x)/2
  by2 = (copy(1)\y + copy(2)\y)/2
  
  AddArrayElement(tmp(), bx1,by1)
  AddArrayElement(tmp(), (bx1+copy(1)\x)/2,(by1+copy(1)\y)/2)
  AddArrayElement(tmp(), (bx2+copy(1)\x)/2,(by2+copy(1)\y)/2)
  AddArrayElement(tmp(), bx2, by2)
  
  ReDim copy(0)
  
  For i= 0 To 4
    AddArrayElement(copy(),tmp(i)\x,tmp(i)\y)
  Next i
  
  ReDim tmp(0)
  
  bx1 = (copy(0)\x + copy(1)\x)/2
  by1 = (copy(0)\y + copy(1)\y)/2
  bx2 = (copy(2)\x + copy(3)\x)/2
  by2 = (copy(2)\y + copy(3)\y)/2
  bx  = (copy(1)\x + copy(2)\x)/2
  by  = (copy(1)\y + copy(2)\y)/2
  
  AddArrayElement(tmp(), copy(0)\x,copy(0)\y)
  AddArrayElement(tmp(), bx1,by1)
  AddArrayElement(tmp(), (bx+copy(1)\x)/2, (by+copy(1)\y)/2 )
  AddArrayElement(tmp(), (bx+copy(2)\x)/2, (by+copy(2)\y)/2 )
  AddArrayElement(tmp(), bx2,by2)
  AddArrayElement(tmp(), copy(3)\x,copy(3)\y)
  
  If startCurve 
    tmp(0)\x = ListDot(0)\x  
    tmp(0)\y = ListDot(0)\y  
    startCurve = 0
  EndIf
  
  ; and we can draw the result
  If StartDrawing(CanvasOutput(0))
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    For i=0 To ArraySize(tmp())-2
      LineXY(tmp(i)\x,tmp(i)\y,tmp(i+1)\x,tmp(i+1)\y,RGBA(255,0,0,255))
      
      Circle(tmp(i)\x,tmp(i)\y, 10,RGBA(0,0,0,100))
      
    Next i
          
    StopDrawing()
  EndIf
  
  FreeArray(copy())
  FreeArray(tmp())
  
EndProcedure

OpenWindow(0, 0, 0, 1024,768, "Smooth curve", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(0,0,0,1024,768)

Repeat
  
  Event       = WaitWindowEvent(1)
  EventType   = EventType()
  EventGadget = EventGadget()
  
  Select Event
    Case #PB_Event_CloseWindow
      Break
      
    Case #PB_Event_Gadget
          
      Select EventGadget
        Case 0
           If EventType = #PB_EventType_LeftButtonDown
                MouseDown  = #True
                startCurve = 1
                
              ElseIf EventType = #PB_EventType_LeftButtonUp
                MouseDown = #False
                startCurve = 0
                ReDim listdot(0)
                
              ElseIf EventType = #PB_EventType_MouseMove
                If MouseDown 
                  MouseX = GetGadgetAttribute(0,#PB_Canvas_MouseX)
                  MouseY = GetGadgetAttribute(0,#PB_Canvas_MouseY)
                  AddDot(MouseX,MouseY)
                  If ArraySize(listdot()) > 2
                    CurveStroke()
                  EndIf                  
                EndIf
                                  
              EndIf
              
      EndSelect
      
  EndSelect
    
Until Event = #PB_Event_CloseWindow
Comme tu le vois, il y a des soucis avec un cercle avec un alpha < 255. D'où l'intérêt de trouvé la distance entre les points pour que ça soit bien régulier.

Voici un lien pour un très bon papier sur les types de courbes : http://members.chello.at/easyfilter/bresenham.pdf
Merci, j'avais déjà regarder du coté de bresenham (ici : http://members.chello.at/~easyfilter/bresenham.html), je pense qu'on retrouve des choses similaires ;).

Effectivement, j'aimerais bien utiliser une courbe avec l'algo de bresenham (thickline). j'avais essayer de traduire en purebasic le code, mais il y a des choses que je ne comprenais pas :

Code : Tout sélectionner

void plotLineWidth((int x0, int y0, int x1, int y1, float wd)
{ 
   int dx = Abs(x1-x0), sx = x0 < x1 ? 1 : -1; 
   int dy = Abs(y1-y0), sy = y0 < y1 ? 1 : -1; 
   int err = dx-dy, e2, x2, y2;                          /* error value e_xy */
   float ed = dx+dy == 0 ? 1 : sqrt((float)dx*dx+(float)dy*dy);
   
   For (wd = (wd+1)/2; ; ) {                                   /* pixel loop */
      setPixelColor(x0,y0,max(0,255*(Abs(err-dx+dy)/ed-wd+1));
      e2 = err; x2 = x0;
      If (2*e2 >= -dx) {                                           /* x Step */
         For (e2 += dy, y2 = y0; e2 < ed*wd && (y1 != y2 || dx > dy); e2 += dx)
            setPixelColor(x0, y2 += sy, max(0,255*(Abs(e2)/ed-wd+1));
         If (x0 == x1) Break;
         e2 = err; err -= dy; x0 += sx; 
      } 
      If (2*e2 <= dy) {                                            /* y Step */
         For (e2 = dx-e2; e2 < ed*wd && (x1 != x2 || dx < dy); e2 += dy)
            setPixelColor(x2 += sx, y0, max(0,255*(Abs(e2)/ed-wd+1));
         If (y0 == y1) Break;
         err += dx; y0 += sy; 
      }
   }
}
Dernière modification par blendman le jeu. 25/juin/2015 17:31, modifié 1 fois.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Trouver un point entre deux points

Message par G-Rom »

Chez moi ca marche, il ne faut cependant pas d'intervalle trop petit.

Code : Tout sélectionner

OpenWindow(0,0,0,800,600,"PAINT")
CanvasGadget(0,0,0,800,600,#PB_Canvas_ClipMouse)

mx.i
my.i
paint.b = #False 



Structure Vector2f
  x.f : y.f
EndStructure

Procedure.f Distance(*a.Vector2f, *b.Vector2f)
  ProcedureReturn Sqr( ((*a\x-*b\x)*(*a\x-*b\x)) + ((*a\y-*b\y)*(*a\y-*b\y))) 
EndProcedure



PaintPos.Vector2f
OldPaintPos.Vector2f



While #True 
  
  Repeat
    event = WindowEvent()
    If event = #PB_Event_CloseWindow
      Break 2
    EndIf 
    
    If event = #PB_Event_Gadget
      
      If EventGadget() = 0
        Select EventType()
          Case #PB_EventType_MouseMove
            mx = GetGadgetAttribute(0,#PB_Canvas_MouseX)
            my = GetGadgetAttribute(0,#PB_Canvas_MouseY)
            PaintPos\x = mx
            PaintPos\y = my
          Case #PB_EventType_LeftButtonDown
            paint = #True 
          Case #PB_EventType_LeftButtonUp
            paint = #False 
            
            
        EndSelect
      EndIf 
      
    EndIf 
    
  Until event = 0
  
  
  
  If paint 
    
    interval.i = 10
    dist.f     = Distance(@PaintPos, @OldPaintPos)
    
    If(dist > interval)
      
      
      number.i = dist / interval
      
      
      If number = 1 ; slow speed
         StartDrawing(CanvasOutput(0))
           Circle(PaintPos\x,PaintPos\y,2,0)    
         StopDrawing()
        Else
          
          Direction.Vector2f
           Direction\x = OldPaintPos\x - PaintPos\x
           Direction\y = OldPaintPos\y - PaintPos\y
            
          lenght.f =  Sqr(Direction\x * Direction\x + Direction\y * Direction\y)
     
          If lenght > 0
            Direction\x / lenght
            Direction\y / lenght
          EndIf
          
          StartDrawing(CanvasOutput(0))
          For i = 0 To number-1
            
            px.d = PaintPos\x + (Direction\x*(interval*i))
            py.d = PaintPos\y + (Direction\y*(interval*i))
            Circle(px,py,2,0)   
            
          Next
          StopDrawing()
      EndIf 
      
      
      OldPaintPos\x = PaintPos\x
      OldPaintPos\y = PaintPos\y  
    EndIf
    
  EndIf 
  
Wend 
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

@G-rom :
c'est pas mal du tout (et très rapide ;)).

Mais j'ai remarqué 1 petit souci :
- si on utilise de l'alpha avec le cercle, on voit le problème que ça donne quand on dessine lentement.


Pour tester le soucis avec l'alpha, dessine vite, puis lentement :

[Edit : en commentant certaines lignes, je n'ai plus le soucis :mrgreen: punaise, la classe ]

Code : Tout sélectionner

 


OpenWindow(0,0,0,800,600,"PAINT", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(0,0,0,800,600,#PB_Canvas_ClipMouse)

mx.i
my.i
paint.b = #False



Structure Vector2f
  x.f : y.f
EndStructure

Procedure.f Distance(*a.Vector2f, *b.Vector2f)
  ProcedureReturn Sqr( ((*a\x-*b\x)*(*a\x-*b\x)) + ((*a\y-*b\y)*(*a\y-*b\y)))
EndProcedure



PaintPos.Vector2f
OldPaintPos.Vector2f

R = 10 ; rayon 

While #True
  
  Repeat
    event = WindowEvent()
    If event = #PB_Event_CloseWindow
      Break 2
    EndIf
    
    If event = #PB_Event_Gadget
      
      If EventGadget() = 0
        Select EventType()
          Case #PB_EventType_MouseMove
            mx = GetGadgetAttribute(0,#PB_Canvas_MouseX)
            my = GetGadgetAttribute(0,#PB_Canvas_MouseY)
            PaintPos\x = mx
            PaintPos\y = my
          Case #PB_EventType_LeftButtonDown
            paint = #True
            mx = GetGadgetAttribute(0,#PB_Canvas_MouseX)
            my = GetGadgetAttribute(0,#PB_Canvas_MouseY)
            OldPaintPos\x = mx
            OldPaintPos\y = my
            
          Case #PB_EventType_LeftButtonUp
            paint = #False
            
            
        EndSelect
      EndIf
      
    EndIf
    
  Until event = 0
  
  
  
  If paint
    
    interval.i = 1
    dist.f     = Distance(@PaintPos, @OldPaintPos)
    
    If(dist > interval)
      number.i = dist / interval
            
      ;If number = 1 ; slow speed
;           If StartDrawing(CanvasOutput(0))
;             DrawingMode(#PB_2DDrawing_AlphaBlend)
;             Circle(PaintPos\x,PaintPos\y,R,RGBA(0,0,0,100))   
;             StopDrawing()
;           EndIf
      ;Else
        
        Direction.Vector2f
        Direction\x = OldPaintPos\x - PaintPos\x
        Direction\y = OldPaintPos\y - PaintPos\y
        
        lenght.f =  Sqr(Direction\x * Direction\x + Direction\y * Direction\y)
        
        If lenght > 0
          Direction\x / lenght
          Direction\y / lenght
        EndIf
        
        If StartDrawing(CanvasOutput(0))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        For i = 0 To number-1
          
          px.d = PaintPos\x + (Direction\x*(interval*i))
          py.d = PaintPos\y + (Direction\y*(interval*i))            
          Circle(px,py,R,RGBA(0,0,0,10)) 
          
        Next
        StopDrawing()
        EndIf
      ;EndIf
      
      
      OldPaintPos\x = PaintPos\x
      OldPaintPos\y = PaintPos\y 
    EndIf
    
  EndIf
  
Wend 


Dernière modification par blendman le jeu. 25/juin/2015 17:46, modifié 1 fois.
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Trouver un point entre deux points

Message par falsam »

Ton code G-Rom a le même souci que le mien. Si on va trop vite avec la souris, les intervalles entres les points ne sont pas réguliers. Blendman utilisant une tablette graphique, ça sera encore plus flagrant.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

ah oui, exact, merdoum, on n'est vraiment pas loin ^^.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

Je sais bien de quoi tu parles car j'utilise tvpaint depuis vingt ans et il fait ça depuis toujours : être hyper réactif au dessin tablette, et bien lisser le tracé, y compris avec cercles, brosses, etc. Je t'ai donné les bons algos pour ça, les quelques trucs sur lesquels tu buttes sont faciles à régler si on s'y met tous.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

djes a écrit :Je sais bien de quoi tu parles car j'utilise tvpaint depuis vingt ans et il fait ça depuis toujours : être hyper réactif au dessin tablette, et bien lisser le tracé, y compris avec cercles, brosses, etc. Je t'ai donné les bons algos pour ça, les quelques trucs sur lesquels tu buttes sont faciles à régler si on s'y met tous.
Je veux bien de l'aide ;), ce serait vraiment super si on parvenait à obtenir à peu près ce que permet tvpaint ou photoshop (je parle surtout de l'aspect de la courbe obtenue, lissage et un peu de la réactivité), car je m'y casse les dents depuis quelques temps ^^.

Pour la réactivité, je passe par les sprites et le screen et c'est assez rapide, même avec beaucoup de calques et en 2000*2000. Mais je bloque vraiment sur l'aspect d'une jolie courbe (pour les brosses "dirty" ou aquarelle, ça va, mais pour un trait pour l'encrage c'est vraiment pas super pour le moment ^^).
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

J'ai réfléchi un peu à l'algo...
Je pense qu'il faudrait trois threads :
  • un pour mémoriser la position de la souris (j'ai parlé la dernière fois d'un tableau genre pile FIFO, mais une liste chaînée sera plus facile à gérer et évitera les problèmes de dépassement, etc),
  • un pour faire un dessin 'rapide' avec des sprites,
  • un pour faire le dessin final, plus lent.
Il faudrait une procédure pour le calcul précis du chemin, avec du bresenham, pour être sûr de travailler "au pixel", voire au sous-pixel. Cette procédure est appelée tous les n positions souris.

Pour le dessin en continu :
  • avec des brosses, il s'agit d'images bitmap, il faudrait peut-être réaliser un masque "OU", c'est à dire dessiner dans un image mémoire et appliquer ce masque à l'image finale seulement lorsque l'utilisateur relâche le bouton. Ce masque serait une sorte de couche alpha permettant de faire un bel anti-aliasing lors de "l'application".
  • avec des cercles ou effets vectoriels, voir s'il ne serait pas possible de travailler mathématiquement.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

Suite du post précédent ...
blendman a écrit :
djes a écrit :Voici un lien pour un très bon papier sur les types de courbes : http://members.chello.at/easyfilter/bresenham.pdf
Merci, j'avais déjà regarder du coté de bresenham (ici : http://members.chello.at/~easyfilter/bresenham.html), je pense qu'on retrouve des choses similaires ;).

Effectivement, j'aimerais bien utiliser une courbe avec l'algo de bresenham (thickline). j'avais essayer de traduire en purebasic le code, mais il y a des choses que je ne comprenais pas :

Code : Tout sélectionner

void plotLineWidth((int x0, int y0, int x1, int y1, float wd)
{ 
   int dx = Abs(x1-x0), sx = x0 < x1 ? 1 : -1; 
   int dy = Abs(y1-y0), sy = y0 < y1 ? 1 : -1; 
   int err = dx-dy, e2, x2, y2;                          /* error value e_xy */
   float ed = dx+dy == 0 ? 1 : sqrt((float)dx*dx+(float)dy*dy);
   
   For (wd = (wd+1)/2; ; ) {                                   /* pixel loop */
      setPixelColor(x0,y0,max(0,255*(Abs(err-dx+dy)/ed-wd+1));
      e2 = err; x2 = x0;
      If (2*e2 >= -dx) {                                           /* x Step */
         For (e2 += dy, y2 = y0; e2 < ed*wd && (y1 != y2 || dx > dy); e2 += dx)
            setPixelColor(x0, y2 += sy, max(0,255*(Abs(e2)/ed-wd+1));
         If (x0 == x1) Break;
         e2 = err; err -= dy; x0 += sx; 
      } 
      If (2*e2 <= dy) {                                            /* y Step */
         For (e2 = dx-e2; e2 < ed*wd && (x1 != x2 || dx < dy); e2 += dy)
            setPixelColor(x2 += sx, y0, max(0,255*(Abs(e2)/ed-wd+1));
         If (y0 == y1) Break;
         err += dx; y0 += sy; 
      }
   }
}
LSI avait sorti pas mal de routines avec AA, voir ici par exemple : http://www.purebasic.fr/french/viewtopi ... lit=LineAA
Sinon, j'en avais adapté une :

Code : Tout sélectionner

;
; ------------------------------------------------------------
;
;   PureBasic - Antialiased line Drawing example file
;
;    (c) 2005 - Background code by Fantaisie Software
;        2015 - LineAA by djes
;
; ------------------------------------------------------------
;

Procedure LineAA(x0.i, y0.i, x1.i, y1.i, color.i)
  ; /* draw an anti-aliased line on background */
  ; adapted by djes upon Alois Zingl's work - http://members.chello.at/~easyfilter/bresenham.html
  Define.i dx = Abs(x1 - x0), sx : If x0 < x1 : sx = 1 : Else : sx = -1 : EndIf
  Define.i dy = Abs(y1 - y0), sy : If y0 < y1 : sy = 1 : Else : sy = -1 : EndIf
  Define.i x2, e2, err = dx - dy; /* error value e_xy */
  Define.i ed : If dx + dy = 0 : ed = 0 : Else : ed = Sqr(dx*dx + dy*dy) : EndIf
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  Define.i blend
  While #True ; pixel loop
    blend = 255*Abs(err - dx+dy)/ed : c = Point(x0,y0)
    Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
    e2 = err : x2 = x0;
    If (2*e2 >= -dx)  ;{ /* x Step */
      If (x0 = x1) : Break : EndIf
      If (e2+dy < ed) 
        blend = 255*(e2+dy)/ed : c = Point(x0,y0+sy)
        Plot(x0, y0+sy, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
      EndIf
      err - dy : x0 + sx;
    EndIf
    If (2*e2 <= dy) ;{ /* y Step */
      If (y0 = y1) : Break : EndIf
      If (dx-e2 < ed)
        blend = 255*(dx-e2)/ed : c = Point(x2+sx,y0)
        Plot(x2+sx,y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
      EndIf
      err + dx : y0 + sy
    EndIf
  Wend
EndProcedure

If OpenWindow(0, 100, 200, 300, 200, "2D Drawing Test")
  
  ; Create an offscreen image, with a green circle in it.
  ; It will be displayed later
  ;
  If CreateImage(0, 300, 200, 32)
    If StartDrawing(ImageOutput(0))
      Circle(100,100,50, RGB(0,0,255))  ; a nice blue circle...
      
      Box(150,20,20,20, RGB(0,255,0))  ; and a green box
      
      FrontColor(RGB(255,0,0)) ; Finally, red lines..
      For k=0 To 20
        LineAA(10,10+k*8,150, 0, RGBA(255,255,0,0))
        LineXY(290,10+k*8,150, 0)
      Next
      
      DrawingMode(#PB_2DDrawing_Transparent)
      BackColor(RGB(0,155,155)) ; Change the text back and front colour
      FrontColor(RGB(255,255,255)) 
      DrawText(10,50,"Hello, this is a test")
      
      StopDrawing()
    EndIf
  EndIf
  
  ; Create a gadget to display our nice image
  ;  
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  ;
  ; This is the 'event loop'. All the user actions are processed here.
  ; It's very easy to understand: when an action occurs, the Event
  ; isn't 0 and we just have to see what have happened...
  ;
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow  ; If the user has pressed on the window close button
  
EndIf

End   ; All the opened windows are closed automatically by PureBasic
Je peux t'en refaire une si tu veux.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Trouver un point entre deux points

Message par blendman »

djes a écrit :J'ai réfléchi un peu à l'algo...
Je pense qu'il faudrait trois threads :
  • un pour mémoriser la position de la souris (j'ai parlé la dernière fois d'un tableau genre pile FIFO, mais une liste chaînée sera plus facile à gérer et évitera les problèmes de dépassement, etc),
  • un pour faire un dessin 'rapide' avec des sprites,
  • un pour faire le dessin final, plus lent.
C'est exactement ce que je pensais, avec cependant plus de paramètres à sauver pour le 1er thread ;).

D'ailleurs, pour le moment, j'effectue mon dessin en 3 temps :
1 ) je sauvegarde les points dans un tableau, avec pour chaque point sauvé:
- les valeurs RGB finales (en fonction du mélange par exemple)
- position(+dynamique genre Scatter)
- alpha (en fonction de la dynamique de l'alpha : pression, random..)
- size (+dynamique de la taille : pression, random, fade...)
- rotation (+dynamique de rotation (random, angle...))
- shape : image, ou autre (cercle, square...)

2) Affichage :
- Je dessine les points (pas encore ceux sauvegardés) sur un sprite, en fonction de leur alpha, size, rotation, scatter, color, etc...
- entre chaque points, je calcule la distance et je complète avec les points manquants.

L'idée est bonne, mais je dois utiliser le tableau (ou la slite) de points sauvegardées en 1). Il faut aussi recalculer la courbe formée par les points sauvegardés pour faire une belle courbe (d'où l'intérêt d'une courbe avec algo bresenham par exemple).

Puis, j'affiche tous sur le screen.
Chaque Layer est un sprite, et je dessine sur le sprite courant (layer choisi). C'est le plus rapide que j'ai trouvé et ça permet de bénéficier du zoom (avec zoomsprite()), du pan (bouger le canvas), des rotations hyper rapide (RotateSprite()), la gestion de l'opacité du calque (Sprite alpha), la position du layer (sprite x et y), transformation du sprite (encore zoomsprite()), etc...

Pour les blendmode, ce serait tellement pratique si on pouvait faire un rendertotexture sur un sprite et que ça gérait les shaders ^^.
Pour le moment, j'utilise SpriteBlendingMode(), mais je ne parviens pas à créer certains blendmode comme Overlay ou colorburn.

(Pour les blendmodes avec un canvas et des images, je les ai presque tous adapté d'informations que j'ai trouvé sur le net.)


3) Je dessine ensuite sur une image
Là, c'est clairement plus lent effectivement.

Du coup, je n'actualise mon layer (sprite) que si je change de blendmode.
Si je change de blendmode, alors, j'efface mon sprite (layer(LayerCourant)\Sprite), et je dessine dessus l'image qui y est attachée (layer(LayerCourant)\image) sur laquelle j'ai effectué les opérations précédentes.

il vaut mieux updater quand on ne fait pas une action de dessin (changer de calque ou de blendmode par exemple).

Il faudrait une procédure pour le calcul précis du chemin, avec du bresenham, pour être sûr de travailler "au pixel", voire au sous-pixel. Cette procédure est appelée tous les n positions souris.
ça, c'est ce que je recherche :).
J'ai une procédure mais c'est super basique, ça capture juste la position de la souris à l'instant où on dessine.
Pour le dessin en continu :
  • avec des brosses, il s'agit d'images bitmap, il faudrait peut-être réaliser un masque "OU", c'est à dire dessiner dans un image mémoire et appliquer ce masque à l'image finale seulement lorsque l'utilisateur relâche le bouton. Ce masque serait une sorte de couche alpha permettant de faire un bel anti-aliasing lors de "l'application".
  • avec des cercles ou effets vectoriels, voir s'il ne serait pas possible de travailler mathématiquement.
C'est aussi ce que je pensais ^^.

Pour le moment, j'ai deux types de brosses effectivement : image (bimtap) ou cercle.
Avec la brosse image, je me disais qu'on pouvait effectivement dessiner sur une sorte d'image temporaire (de la taille de la courbe qu'on a dessiné) et qu'on l'affiche quand l'utilisateur relâche le bouton.
J'ai fait un test sur un de mes fichiers et ça marche pas mal, ça permet même d'avoir un undo/redo.

Par contre, je ne comprends pas trop l'histoire du masque "OU" ;)


Sinon, j'avais déjà vu les exemples de LSI et le tiens. Mais, je n'ai rien trouvé concernant des brush avec images bitmap et algo bresenham (pour le moment).
Je peux t'en refaire une si tu veux.
Ah ben oui, ce serait super !
Un truc avec un brush-image + algo de bresenham par exemple ? :mrgreen:

En tout cas, encore merci.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

Je vois qu'on est sur la même longueur d'onde ! Je vais voir ce que je peux faire.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

J'ai commencé à convertir à la volée le code que j'avais. J'arrête pour l'instant. Ce n'est pas encore fonctionnel, ni vérifié !
MAJ : dessin à main levée sur un canevas, liste de points
MAJ : Bézier debugging (pas encore fonctionnel)
MAJ: plotCubicBezierSegAA debugging
MAJ: j'ai laissé tomber le bézier, et refait une petite fonction 'curve' qui crée une courbe entre deux mouvements de la souris en fonction de la direction prise par le 3ème point. J'ai laissé plein de code inutile pour l'instant, dont des exemples de Catmull-Rom qui utilisent deux points directeurs et qui pourraient aussi faire le même office (en se servant du point précédent ET du point suivant). A suivre : une fonction curve qui fait tout "à la" Bresenham, avec antialiasing, tant qu'à faire.
MAJ: J'ai refait la fonction curve, en fonction des tangeantes disponibles, et la fonction de suivi du mouvement de la souris correspondante.
MAJ: nettoyage du code, dernière version ici

Code : Tout sélectionner

;
; ------------------------------------------------------------
;
;   PureBasic - Drawing following mouse movement (curve approximation)
;   by djes@free.fr
;
;    (c) 2005 - Background code by Fantaisie Software
;        2015 - MouseMovementFollow by djes for blendman (aka super-smooth)
;
; ------------------------------------------------------------
;
CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Merci d'activer la gestion des threads" 
CompilerEndIf

#DebugLevel = 1
DebugLevel #DebugLevel

;---- Constants

#CurveDeviation = 1.0
#CurveMinimalDistance = 10

;---- Structures

Structure vertex
  x.f
  y.f
EndStructure

;---- Global variables

Global Semaphore = CreateSemaphore()
Global Mutex     = CreateMutex()

Global NewList Coords.vertex()
Global Dim SplineCoords.vertex(5)

Global CanvasWidth, CanvasHeight

;---- Procedures

Procedure.d min(a.d, b.d)
  If a<b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure.d max(a.d, b.d)
  If a>b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure.d VectorLength(vx.d, vy.d)
  ProcedureReturn Sqr(vx*vx + vy*vy)
EndProcedure

Procedure SetPixelAA( x0, y0, color, blend = 0)
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  If x0 >= 0 And y0 >= 0 And x0 < CanvasWidth-1 And y0 < CanvasHeight-1
    c = Point(x0, y0)
    Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
  EndIf  
EndProcedure

Procedure LineAA(x0.i, y0.i, x1.i, y1.i, color.i)
  ; /* draw an anti-aliased line on background */
  ; adapted by djes upon Alois Zingl's work - http://members.chello.at/~easyfilter/bresenham.html
  Define.i dx = Abs(x1 - x0), sx : If x0 < x1 : sx = 1 : Else : sx = -1 : EndIf
  Define.i dy = Abs(y1 - y0), sy : If y0 < y1 : sy = 1 : Else : sy = -1 : EndIf
  Define.i x2, e2, err = dx - dy; /* error value e_xy */
  Define.i ed : If dx + dy = 0 : ed = 0 : Else : ed = Sqr(dx*dx + dy*dy) : EndIf
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  Define.i blend
  While #True ; pixel loop
    If x0 >= 0 And y0 >= 0 And x0 < CanvasWidth-1 And y0 < CanvasHeight-1
      blend = 255*Abs(err - dx+dy)/ed : c = Point(x0,y0)    
      Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
    EndIf
    e2 = err : x2 = x0;
    If (2*e2 >= -dx)  ;{ /* x Step */
      If (x0 = x1) : Break : EndIf
      If (e2+dy < ed) 
        If x0 >= 0 And (y0+sy) >= 0 And x0 < CanvasWidth-1 And (y0+sy) < CanvasHeight-1
          blend = 255*(e2+dy)/ed : c = Point(x0,y0+sy)
          Plot(x0, y0+sy, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
        EndIf  
      EndIf
      err - dy : x0 + sx;
    EndIf
    If (2*e2 <= dy) ;{ /* y Step */
      If (y0 = y1) : Break : EndIf
      If (dx-e2 < ed)
        If (x2+sx) >= 0 And (y0) >= 0 And (x2+sx) < CanvasWidth-1 And y0 < CanvasHeight-1
          blend = 255*(dx-e2)/ed : c = Point(x2+sx,y0)
          Plot(x2+sx,y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
        EndIf  
      EndIf
      err + dx : y0 + sy
    EndIf
  Wend
EndProcedure

;-------------------------------------------
; Curves routines For smooth mouse following
; by djes@free.fr in 2015

; spline between p0-p1, tangent with p1-p2
Procedure CurveStart( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, color = #Black)
  
  ;Curve is between p1 and p0
  vx.d = x1 - x0
  vy.d = y1 - y0
  d.d = VectorLength(vx, vy)
  
  t2x.d = x2 - x1
  t2y.d = y2 - y1
  
  ;tangeant
  n2.d = VectorLength(t2x, t2y)
  If n2 = 0 : n2 = 0.00001 : EndIf
  f2.d = 1.0/n2 * #CurveDeviation
  
  ;minimal distance between p0 and p1
  If d >= #CurveMinimalDistance And n2 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1/d
    u.d = 0
    ox = x0 : oy = y0
    
    While u < 1
    ;For i = 1 To d
      
      x.d = x0 + u*vx - Sqr( Sin(u*#PI) * f2 ) * Tan(u) * t2x
      y.d = y0 + u*vy - Sqr( Sin(u*#PI) * f2 ) * Tan(u) * t2y
      
      ;SetPixelAA(x, y, color)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
    ;Next i
    Wend
      
    LineAA(x, y, x1, y1, color)
    
  Else
    
    LineAA(x0, y0, x1, y1, color)
    
  EndIf
  
EndProcedure  

;Spline between p1-p2 with two tangeants given by p0-p1 and p2-p3
Procedure CurveMiddle( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, x3.d, y3.d, color = #Black)
  
  CompilerIf #DebugLevel = 2
    LineXY(x1, y1, x2, y2, #Black)
    Line(x1-4, y1, 8, 1, #Blue)
    Line(x1, y1-4, 1, 8, #Blue)
    Line(x2-4, y2, 8, 1, #Green)
    Line(x2, y2-4, 1, 8, #Green)
  CompilerEndIf
  
  ;The curve is between p1 and p2
  vx.d = x2 - x1
  vy.d = y2 - y1
  d.d = VectorLength(vx, vy)
  
  ;1st tangeant
  t1x.d = x1 - x0
  t1y.d = y1 - y0
  n1.d = VectorLength(t1x, t1y)
  If n1 = 0 : n1 = 0.00001 : EndIf
  f1.d = 1.0/n1 * #CurveDeviation
  
  ;2st tangeant
  t2x.d = x3 - x2
  t2y.d = y3 - y2
  n2.d = VectorLength(t2x, t2y)
  If n2 = 0 : n2 = 0.00001 : EndIf
  f2.d = 1.0/n2 * #CurveDeviation 
   
  Debug d
  ;minimal distance between p1 and p2
  If d >= #CurveMinimalDistance And n1 > 1 And n2 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1.0/d
    u.d = 0
    ox = x1 : oy = y1
    
    While u < 1
    ;For i = 1 To cl
      
;      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) *f1) * Pow( Sin((1-u)*#PI/2), 2) * t1x - Sqr( Sin(u*#PI) *f2) * Pow( Sin(u*#PI/2), 2) * t2x ) /2
;      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) *f1) * Pow( Sin((1-u)*#PI/2), 2) * t1y - Sqr( Sin(u*#PI) *f2) * Pow( Sin(u*#PI/2), 2) * t2y ) /2
;      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) *f1) * Tan( Sin((1-u)*#PI/2)) * t1x - Sqr( Sin(u*#PI) *f2) * Tan( Sin(u*#PI/2)) * t2x ) /2
;      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) *f1) * Tan( Sin((1-u)*#PI/2)) * t1y - Sqr( Sin(u*#PI) *f2) * Tan( Sin(u*#PI/2)) * t2y ) /2
      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1x - Sqr( Sin(u*#PI) * f2) * Tan(u) * t2x ) / 2
      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1y - Sqr( Sin(u*#PI) * f2) * Tan(u) * t2y ) / 2
      
      ;SetPixelAA(x, y, #Black)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
    ;Next i
    Wend
      
    LineAA(x, y, x2, y2, color)
    
  Else
    
    LineAA(x1, y1, x2, y2, color)
    
  EndIf
  
EndProcedure  

;Spline between p1-p2 with tangeant given by p0-p1
Procedure CurveEnd( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, color = #Black)
  
  ;The curve is between p1 and p2
  vx.d = x2 - x1
  vy.d = y2 - y1
  d.d = VectorLength(vx, vy)
  
  ;tangeant
  t1x.d = x1 - x0
  t1y.d = y1 - y0
  n1.d = VectorLength(t1x, t1y)
  If n1 = 0 : n1 = 0.00001 : EndIf
  f1.d = 1.0/n1 * #CurveDeviation
  
  ;minimal distance between p1 and p2
  If d >= #CurveMinimalDistance And n1 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1/d 
    u.d = 0
    ox = x1 : oy = y1
    
    While u < 1
    ;For i = 1 To d
      
      x.d = x1 + u*vx + Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1x 
      y.d = y1 + u*vy + Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1y 
      
      ;SetPixelAA(x, y, color)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
    ;Next i
    Wend
      
    LineAA(x, y, x2, y2, color)
    
  Else
    
    LineAA(x1, y1, x2, y2, color)
    
  EndIf
  
EndProcedure  
;-------------------------------------------

; Wait mouse input movement sequence and draw
; corresponding plot/lines/curves
Procedure MouseMovementFollow(Null)
  
  While #True
    
    WaitSemaphore(Semaphore)
    
    If StartDrawing(CanvasOutput(0))
      LockMutex(Mutex)
      n = ListSize(Coords())
      While n > 0
        n = 0
        FirstElement(Coords())
        SplineCoords(0)\x = Coords()\x : SplineCoords(0)\y = Coords()\y
        If SplineCoords(0)\x = -2
          ;Sequence : -2 -> Nothing
          Debug "Sequence : -2"
          DeleteElement(Coords(), 1)
          n = ListSize(Coords())
        ElseIf SplineCoords(0)\x = -1
          If NextElement(Coords())
            SplineCoords(1)\x = Coords()\x : SplineCoords(1)\y = Coords()\y
            If SplineCoords(1)\x = -2
              ;Sequence : -1-2 -> Nothing
              Debug "Sequence : -1-2"
              ;Impossible... Anyway !
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              n = ListSize(Coords()) ;Continue processing
            Else
              If NextElement(Coords())
                SplineCoords(2)\x = Coords()\x : SplineCoords(2)\y = Coords()\y
                If SplineCoords(2)\x = -2
                  ;Sequence : -1P-2 -> Pixel
                  Debug "Sequence : -1P-2"
                  SetPixelAA(SplineCoords(1)\x, SplineCoords(1)\y, #Red)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  n = ListSize(Coords()) ;Continue processing
                Else
                  If NextElement(Coords())
                    SplineCoords(3)\x = Coords()\x : SplineCoords(3)\y = Coords()\y
                    If SplineCoords(3)\x = -2
                      ;Sequence : -1PP-2 -> Line
                      Debug "Sequence : -1PP-2"
                      LineAA(SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, #Red)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    Else
                      ;Sequence : -1PPP -> Start of curve (only one tangeant)
                      Debug "Sequence : -1PPP"
                      CurveStart(SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, SplineCoords(3)\x, SplineCoords(3)\y, #Red)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    EndIf
                  EndIf
                EndIf
              EndIf
            EndIf
          EndIf
        Else
          If NextElement(Coords())
            SplineCoords(1)\x = Coords()\x : SplineCoords(1)\y = Coords()\y
            If SplineCoords(1)\x = -2
              ;Sequence : P-2 -> Pixel
              Debug "Sequence : P-2"
              ;Impossible... Anyway !
              SetPixelAA(SplineCoords(0)\x, SplineCoords(0)\y, #Red)
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              n = ListSize(Coords()) ;Continue processing
            Else
              If NextElement(Coords())
                SplineCoords(2)\x = Coords()\x : SplineCoords(2)\y = Coords()\y
                If SplineCoords(2)\x = -2
                  ;Sequence : PP-2 -> Line
                  Debug "Sequence : PP-2"
                  LineAA(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, #Red)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  n = ListSize(Coords()) ;Continue processing
                Else
                  If NextElement(Coords())
                    SplineCoords(3)\x = Coords()\x : SplineCoords(3)\y = Coords()\y
                    If SplineCoords(3)\x = -2
                      ;Sequence : PPP-2 -> End of curve (one tangeant)
                      Debug "Sequence : PPP-2"
                      CurveEnd(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, #Red)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    Else
                      ;Sequence : PPPP -> Full curve (two tangeants)
                      Debug "Sequence : PPPP"
                      CurveMiddle(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, SplineCoords(3)\x, SplineCoords(3)\y, #Red)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    EndIf
                  EndIf
                EndIf
              EndIf  
            EndIf
          EndIf
        EndIf
      Wend
      UnlockMutex(Mutex)  
      StopDrawing()
    EndIf
    
  Wend
  
EndProcedure

;----  Main

CreateThread(@MouseMovementFollow(), 0)

; Ouverture de la fenêtre
OpenWindow(0, 0, 0, 800, 600, "Souris - Cliquer et utiliser la molette...",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CanvasWidth = 800 : CanvasHeight = 600
CanvasGadget(0, 0, 0, CanvasWidth, CanvasHeight)

lmb = #False : mmb = #False : rmb = #False
x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
If y < 100 : y = 100 : EndIf   

Repeat
  
  Repeat 
    Event  = WindowEvent() 
    Select Event 
      Case #PB_Event_Gadget 
        Select EventGadget() 
          Case 0
            Select EventType()
              Case #PB_EventType_LeftButtonDown 
                lmb = #True
                LockMutex(Mutex)
                AddElement(Coords())
                Coords()\x = -1
                ;Signal to the drawing routine that we start a new curve
                UnlockMutex(Mutex)
                SignalSemaphore(Semaphore)
              Case #PB_EventType_LeftButtonUp
                lmb = #False
                LockMutex(Mutex)
                AddElement(Coords())
                Coords()\x = -2
                ;Signal to the drawing routine that we end the curve
                UnlockMutex(Mutex)
                SignalSemaphore(Semaphore)
              Case #PB_EventType_MiddleButtonDown 
                mmb = #True
              Case #PB_EventType_MiddleButtonUp
                mmb = #False  
              Case #PB_EventType_RightButtonDown 
                rmb = #True
              Case #PB_EventType_RightButtonUp
                rmb = #False
                
              Case #PB_EventType_MouseWheel
                ; Molette de la souris = Rotation du curseur
                tiks = GetGadgetAttribute(0, #PB_Canvas_WheelDelta)
              Case #PB_EventType_MouseMove
                x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
                If y < 100 : y = 100 : EndIf            
            EndSelect 
        EndSelect
      Case #PB_Event_CloseWindow 
        End  
    EndSelect 
  Until Event = 0
  
  If lmb 
    If ox <> x Or oy <> y
      ;Mouse moved
      LockMutex(Mutex)
      AddElement(Coords())
      Coords()\x = x
      Coords()\y = y
      ox = x : oy = y
      UnlockMutex(Mutex)
      SignalSemaphore(Semaphore)
    EndIf
  EndIf
  
  ;- Main drawing
  StartDrawing(CanvasOutput(0))
  
  If rmb
    Box(0, 0, 800, 600, #White)
  EndIf
  
  ;-Spline test
  ;plotCubicBezierSegAA(x, y, 400, 200, 400, 300, 400, 400, $FF)
  ;x1 = 200 : y1 = 200 :   Plot(x1, y1, #Blue)
  ;x2 = 200 : y2 = 250 :   Plot(x2, y2, #Blue)
  ;x3 = 350 : y3 = 250 :   Plot(x3, y3, #Blue)
  ;x4 = 400 : y4 = 250 :   Plot(x4, y4, #Blue)
  ;CurveStart(x1, y1, x2, y2, x, y, #Red)
  ;CurveMiddle(x, y, x2, y2, x3, y3, x4, y4, #Red)
  ;CurveEnd(x, y, x2, y2, x3, y3, #Red)
  
  DrawText(0,5, "X=" + Str(x) + "   Y=" + Str(y) + "     " ) 
  If lmb
    DrawText(0,30, "Bouton Gauche", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(0,30, "Bouton Gauche", RGB(255,255,255))
  EndIf
  If mmb
    DrawText(150,30, "Bouton Central", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(150,30, "Bouton Central", RGB(255,255,255))
  EndIf
  If rmb
    DrawText(300,30, "Bouton Droit", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(300,30, "Bouton Droit", RGB(255,255,255))
  EndIf  
  If tiks <> 0
    DrawText(450,30, "Molette", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(450,30, "Molette", RGB(255,255,255))
  EndIf
  StopDrawing()

ForEver

End

End   ; All the opened windows are closed automatically by PureBasic
Dernière modification par djes le jeu. 23/juil./2015 9:32, modifié 6 fois.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Trouver un point entre deux points

Message par djes »

J'ai mis à jour le code, rien de bien extraordinaire pour l'instant.
Répondre