Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tracer une courbe passant par X points

SDL

Sujet résolu
    2 juillet 2010 à 9:41:33

    Bonjour tout le monde!

    Ça fait un petit moment que je ne suis pas venu ici... Mais maintenant que les vacances sont là, je vais pouvoir continuer mon petit bout de programme qui est au point mort depuis 6 mois :euh:

    En fait je coince sur une chose: "Tracer une courbe passant par X points".
    A l'époque Fvirtman m'avait recommandé ceci: ancien post

    J'ai fait une recherche sur google, et je me retrouve face à plein de méthodes et algorithmes différents...
    Celui-ci me parait correct et documenté mais je ne comprends pas tout: lien

    Si Fvirtman ou quelqu'un d'autre pouvait me guider vers le bon chemin, ca serait vraiment sympa :D

    Après ce petit problème il ne me restera plus qu'à faire la GUI mais laquelle s'interface le mieux avec SDL... Qt ou wxWidgets? :-°

    Merci d'avance pour tout!
    • Partager sur Facebook
    • Partager sur Twitter
      2 juillet 2010 à 9:52:35

      Il y a en effet plusieurs solutions.

      Déja tu veux une équation cartésienne (y = f(x) )ou paramétrique (x = fx(t) ; y = fy(t)) ?

      Sais tu dériver une fonction ? Si je te dis "dérivée de polynome, ça te parle ?"

      Si ça te parle, je te parlerai de calcul de tangente avec l'algo de Catmull Rom.
      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        2 juillet 2010 à 9:56:32

        Ah bonjour Fvirtman, ca fait un petit moment depuis la dernière fois!
        A chaque fois vous avez les bonnes réponses ^^

        Pour l'équation, peu importe... mais l'équation paramétrique est plus souple à l'usage je trouve.
        Sinon même si c'est un peu loin, pas de problème pour dériver une fonction ;D

        Merci de votre aide!
        • Partager sur Facebook
        • Partager sur Twitter
          2 juillet 2010 à 10:08:52

          Bon, alors tu as plein de points P0(x,y),P1(x,y), ..., Pn(x,y)
          D'abord, tu vas calculer un paramètre a chaque point :

          Pour ça, tu dis que t0 (parametre de P0) est 0.0
          puis t1, parametre de P1, sera la distance de P0 a P1, puis t2 la distance de P1 a P2 + t1 ...

          Ainsi, tu as des paramètres croissants.
          On parle de distance chordale

          L'algo de Catmull Rom te permettra de calculer la tangente a un point Pi.
          On posera Ti = m*(P(i+1) - P(i-1). avec m = 0.5

          Cela marche pour les tangentes de tous les points sauf les extrémités.

          Pour les extrémités, on posera juste que la dérivée seconde est nulle.

          Maintenant, entre chaque segment, on définir un polynome cubique : F = ax^3 + bx² + cx + d
          4 inconnues, 4 équations :

          Entre le segment i,i+1, on a :

          Fi(ti) = Pi;
          F(i+1)(t(i+1)) = P(i+1);
          Fi'(ti) = Ti;
          F(i+1)'(t(i+1)) = T(i+1);

          Et pour les extrémités, on remplacera l'une des 2 derniere équations par Fi''(ti) = T'i

          il est d'usage de faire une translation, donc de ne pas faire entre ti, et t(i+1), mais entre 0 et (t(i+1) - ti)
          • Partager sur Facebook
          • Partager sur Twitter

          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

            2 juillet 2010 à 10:21:11

            OK merci, c'est le même algo que dans mon lien je pense, sauf qu'il utilisent 4 points.

            Apparemment pour résoudre les équations ils font avec une matrice... Ca a l'air plus propre mais j'ai pas compris.

            Merci pour l'aide je vais essayer de m'en sortir avec tout ca, je pense avoir compris :D

            Sinon pour l'interface SDL/GUI... Qt ou wxWidgets?
            • Partager sur Facebook
            • Partager sur Twitter
              2 juillet 2010 à 10:38:11

              Tiens marrant la résolution d'un système de x équations via une matrice M(x,x) je l'ai fait ya pas longtemps en cours :p

              C'est juste une reproduction plus ergonomique de la version combinaison + substitution que t'apprends au collège :) Si j'dis pas de bêtise, il faut se renseigner du côté de la méthode du "Pivot de Gauss".
              Bon courage pour l'algorithme x)
              • Partager sur Facebook
              • Partager sur Twitter
                2 juillet 2010 à 10:41:03

                Merci je vais regarder de ce coté aussi alors :)
                • Partager sur Facebook
                • Partager sur Twitter
                  2 juillet 2010 à 10:54:33

                  Pivot de Gauss

                  Voilà ici c'est bien expliqué :)
                  Encore une fois bon courage pour l'algo ça va pas être simple ^^'
                  • Partager sur Facebook
                  • Partager sur Twitter
                    2 juillet 2010 à 11:22:18

                    Citation : quentin-fait-du-c

                    Encore une fois bon courage pour l'algo ça va pas être simple ^^'



                    Oui je sens que je vais bien m'amuser cet après midi...

                    De toute façon si ça ne marche pas je reviens ce soir sur le forum en courant ^^
                    • Partager sur Facebook
                    • Partager sur Twitter
                      2 juillet 2010 à 17:01:45

                      Fvirtman>> ce que tu propose est un spline cubique, non ?

                      Hedi
                      • Partager sur Facebook
                      • Partager sur Twitter
                        2 juillet 2010 à 17:05:47

                        Citation : hedi07

                        Fvirtman>> ce que tu propose est un spline cubique, non ?
                        Hedi



                        Oui.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                          2 juillet 2010 à 19:11:24

                          Hum ça marche parfaitement ;D
                          Merci tout le monde!

                          Juste ma dernière question "trollesque": pour une interface SDL/GUI, faut-il préférer Qt ou wxWidgets?
                          • Partager sur Facebook
                          • Partager sur Twitter
                            5 juillet 2010 à 18:59:32

                            Citation : LaTo59

                            Hum ça marche parfaitement ;D
                            Merci tout le monde!

                            Juste ma dernière question "trollesque": pour une interface SDL/GUI, faut-il préférer Qt ou wxWidgets?



                            Ou ne faudrait-il pas plutôt switcher complètement vers Qt ou wxWidgets (à la place de la SDL) avec une fenêtre openGl?

                            Merci.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              23 août 2010 à 16:34:58

                              Bonjour tout le monde,
                              Désolé pour le petit déterrage mais j'ai de nouveau un petit soucis :D

                              Bon, l'algo de Catmull-Rom marche parfaitement mais lors du tracé, la courbe est aliasée... Ce qui est très moche :euh:

                              J'ai fait une recherche sur google, mais je suis tombé que sur les algos pour anti-aliaser les lignes/cercles.

                              La seule référence que j'ai trouvé est celle-ci: lien 1
                              (ou celle-ci mais je n'ai pas de compte: lien 2)

                              Est-ce que quelqu'un aurait une idée?
                              Merci d'avance!

                              Si jamais Fvirtman est dans le coin... ^^
                              • Partager sur Facebook
                              • Partager sur Twitter
                                24 août 2010 à 17:25:39

                                Personne?

                                En fait il me faudrait comme ce nouveau tuto (lien) mais pour les courbes...


                                :euh:
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  24 août 2010 à 17:35:23

                                  T'as regardé du côté des polynômes interpolateurs de Lagrange ?
                                  C'est la méthode la plus simple je pense.
                                  La courbe la plus simple qui passe par 2 points est une droite, la courbe la plus simple qui passe par 3 points et une parabole, etc...
                                  La courbe la plus simple qui passe par n points est un polynôme de degré n-1 et une méthode pour trouver ce polynôme est d'utiliser les polynômes interpolateur de Lagrange !
                                  J'aurais regardé de ce côté là en tout cas...
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    24 août 2010 à 17:37:45

                                    Avec quoi dessines tu tes courbes ? des gllines ?
                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                      24 août 2010 à 17:39:26

                                      Merci pour les réponses!


                                      MisterM> L'interpolation est réglée, il ne me reste plus que le problème d'aliasing.

                                      Fvirtman> Non, juste avec la SDL: pixel par pixel avec une interpolation de Catmull-Rom.


                                      Pas facile de trouver de la documentation sur le sujet :?
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        24 août 2010 à 17:45:56

                                        pixel par pixel, que fais tu ? un pas sur le parametre t puis des pixels ?
                                        Tu dois avoir des "trous" plus que de l'aliasing non ?

                                        Pour tracer une courbe, il faut tracer des petits segments entre points prets les uns des autres (avec un pas du paramètre t petit).
                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                          24 août 2010 à 17:54:20

                                          Pour faire très simple, j'ai une équation de type y = f(x) qui correspond à la courbe.

                                          Pour chaque x s'obtient mon y qui me permet de colorier directement la bonne position.

                                          Je fais ça de x1 à x2 avec un pas de 1, et la courbe est tracée.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            24 août 2010 à 18:16:47

                                            Tu dessines donc des segments ou des points ?
                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                              24 août 2010 à 18:23:12

                                              Des points.

                                              Edit: avec des lignes ça marche mieux, plus de trous effectivement.

                                              Mais le problème d'aliasing est toujours là :( , une image qui illustre mes propos (prise depuis ce lien) :

                                              Image utilisateur

                                              Moi j'ai le même résultat qu'à gauche, et je voudrais celui de droite :D
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                24 août 2010 à 18:41:22

                                                Alors déjà, trace des segments. pour t(i), t(i+1) tu traces les segment t(i);f(t(i)) -> t(i+1);f(t(i+1))

                                                Ensuite, prend le tuto dont tu as mis le lien, et c'est ta fonction qui trace le segment qu'il faut adapter :)
                                                • Partager sur Facebook
                                                • Partager sur Twitter

                                                Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                  24 août 2010 à 18:43:49

                                                  Citation : Fvirtman

                                                  Alors déjà, trace des segments. pour t(i), t(i+1) tu traces les segment t(i);f(t(i)) -> t(i+1);f(t(i+1))

                                                  Ensuite, prend le tuto dont tu as mis le lien, et c'est ta fonction qui trace le segment qu'il faut adapter :)


                                                  J'ai déjà essayer de cette manière, mais le résultat était peu concluant... L'antialising n'était pas "naturel", je sais pas comment expliquer.

                                                  Je vais réessayer, merci pour l'aide.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    24 août 2010 à 22:32:06

                                                    Marrant, j'ai fait un screenshot de ton image, pour le zoomer sous paint : on a déja de l'antialiasing sur l'image de gauche :) sisi !
                                                    Mais moins

                                                    Sinon, l'image de droite, on dirait qu'elle a subit un filtre "Blur" en post-traitement.
                                                    http://www.student.kuleuven.be/~m02169 [...] iltering.html

                                                    Bonne lecture.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter

                                                    Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                      25 août 2010 à 0:05:37

                                                      Et tu as essayé d'augmenter la précision tout simplement sinon ?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        25 août 2010 à 9:34:54

                                                        Je poste suite à ton "interpellation" via MP, donc voila ma proposition, à partir de du tuto pour faire des formes antialiasés.

                                                        Alors pour moi, la solution à explorer c'est à partir de la dérivée, car comme expliqué dans le tuto, tout est une question de dérivée! ^^

                                                        Le principe est le même que pour tracer la droite, sauf que la droite, la dérivée est constante, or ici elle varie... donc c'est la partie "+= grad" qu'il va falloir changer...

                                                        Pour moi, cela devrait marcher en faisant ce code (je ne peux pas tester la ou je suis...). Il te faut la dérivée (en fonction de x) et la dérivée de la réciproque qui dans le cas d'un polynôme est également la réciproque de la dérivée (il me semble).

                                                        Donc comme c'est une cubique, tu as un polynôme du 3e ordre, donc en argument j'ajoute les 4 facteurs a0..a3 (y = a3.x^3 + a2.x^2 + a1.x^1 + a0.x^0), ma dérivée est donc (grad = ) y' = 3*a3.x^2 + 2*a2.x^1 + a1.x^0.

                                                        La dérivée/réciproque est ... et c'est là que cela devient un peu plus compliqué, car pour avoir la réciproque, il faut que la courbe soit de dévirée constante sur cet intervalle... laissons de coté cette partie, on va déjà voir si cela fonctionne pour une courbe dont la dérivée est comprise entre -1 et 1 (donc attention quand tu traces tes points! Fait des points "plutôt" alignés horizontalement... i.e. avance plus horizontalement que ce que tu montes ou descends!)

                                                        NB: x1, y1 et x2, y2, pt de départ et d'arrivée...

                                                        void cubic_trace(int x1, int y1, int x2, int y2, int a3, int  a2, int a1, int a0, Uint32 color, SDL_Surface *map, int dotted)
                                                        {
                                                          int x, y, to_dot = 0;
                                                          float xf,yf;
                                                          Uint8 r1,g1,b1,a1,r2,g2,b2,a2,r,g,b,a;
                                                          Uint32 colorAA1,colorAA2;
                                                        
                                                          // Getting the r,g,b,a values of the specified color
                                                          SDL_GetRGBA(color,map->format,&r1,&g1,&b1,&a1);
                                                        
                                                          if (1) // A CHANGER PLUS TARD
                                                          {
                                                            if (x1 > x2) // Because of the FOR, going from the smallest to the greatest value
                                                            {
                                                              int_switch(&x1, &x2);
                                                              int_switch(&y1, &y2);
                                                            }
                                                        
                                                            yf = (float)y1;
                                                        
                                                            // Start and arrival points
                                                            setPixel(x1, y1, color, map);
                                                            setPixel(x2, y2, color, map);
                                                        
                                                            for (x = x1+1; x <= x2; x++)
                                                            {
                                                             if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && yf>0 && yf<map->h) // If not outside of the map surface
                                                             {
                                                                 // Getting the color of current (background) pixel
                                                                 getPixelColor(x, (int)yf, map, &r2,&g2,&b2,&a2);
                                                        
                                                                 // For the antialising 2 pixels are drawn, one one top (x,y+1), the other below (x,y)
                                                                 // The color is a mix of:
                                                                 // - the color of background
                                                                 // - the color of the line
                                                                 // The amount of each color (bg & line color), on the 2 pixels is 100% (e.g. 10% on one, 90% on the other)
                                                        
                                                                 r=(Uint8)(frac(yf)*r1+invfrac(yf)*r2);
                                                                 g=(Uint8)(frac(yf)*g1+invfrac(yf)*g2);
                                                                 b=(Uint8)(frac(yf)*b1+invfrac(yf)*b2);
                                                                 a=(Uint8)(frac(yf)*a1+invfrac(yf)*a2);
                                                                 colorAA1=SDL_MapRGBA(map->format,r,g,b,a); // Color for pixel one (x,y+1)
                                                        
                                                                 r=(Uint8)(frac(yf)*r2+invfrac(yf)*r1);
                                                                 g=(Uint8)(frac(yf)*g2+invfrac(yf)*g1);
                                                                 b=(Uint8)(frac(yf)*b2+invfrac(yf)*b1);
                                                                 a=(Uint8)(frac(yf)*a2+invfrac(yf)*a1);
                                                                 colorAA2=SDL_MapRGBA(map->format,r,g,b,a); // Color for the 2nd pixel (x,y)
                                                        
                                                                 // Blitting
                                                                 setPixel(x, (int)yf, colorAA2, map);
                                                                 setPixel(x, (int)yf+1, colorAA1, map);
                                                             }
                                                             to_dot++;
                                                        
                                                             yf += 3*a3*pow(x, 2) + 2*a2*x + a1; // <= PRISE EN COMPTE DE LA DERIVEE
                                                            }
                                                          }
                                                        
                                                         else //A FAIRE PLUS TARD
                                                          {
                                                             // OSEF pour l'instant
                                                          }
                                                        }
                                                        
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          25 août 2010 à 13:46:38

                                                          Alors voici la technique de Fvirtman en utilisant des lignes anti-aliasées pour tracer la courbe:

                                                          Image utilisateur


                                                          Et le code associé:
                                                          int main ( int argc, char** argv )
                                                          {
                                                              // Init
                                                              SDL_Init( SDL_INIT_VIDEO );
                                                              SDL_Surface* screen = SDL_SetVideoMode(256, 256, 32, SDL_SWSURFACE);
                                                          
                                                              // Draw
                                                              SDL_FillRect(screen, 0, 0x00000000);
                                                          
                                                              int curve[256];
                                                              GetSpline("0-0;16-128;96-128;128-96;180-128;192-64;224-128;255-128", curve);
                                                          
                                                              for( int k = 0 ; k < 256-1 ; k++ )
                                                                  SetLine(k, curve[k], k+1, curve[k+1], 0xFFFFFFFF, screen, 0);
                                                          
                                                              SDL_Flip(screen);
                                                          
                                                              // Pause
                                                              bool done = false;
                                                              SDL_Event event;
                                                          
                                                              while (!done)
                                                              {
                                                                  SDL_WaitEvent(&event);
                                                          
                                                                  switch (event.type)
                                                                  {
                                                                  case SDL_QUIT:
                                                                      done = true;
                                                                      break;
                                                                  }
                                                              }
                                                          
                                                              return EXIT_SUCCESS;
                                                          }
                                                          


                                                          SetLine est un dérivé de la fonction "line_trace" de ce tuto.

                                                          J'ai juste commenté ces 2 lignes à 2 reprises (sinon c'était encore pire au niveau du résultat):
                                                          setPixel(x1, y1, color, map);
                                                          setPixel(x2, y2, color, map);

                                                          Je n'ai pas encore essayé ta technique AstroB, sinon vous avez une idée? A certain endroit c'est parfait, à d'autres c'est nul :D
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            25 août 2010 à 14:17:21

                                                            Il y a des problemes de raccord dans ton screenshot, voir même des trous (si je zoome). Bizarre ! ça fait la même chose si tu traces la courbe avec des segments classiques ?
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                              25 août 2010 à 14:36:50

                                                              Voila la même chose mais en ne traçant que des points:

                                                              Image utilisateur

                                                              /* for( int k = 0 ; k < 256-1 ; k++ )
                                                                      SetLine(k, curve[k], k+1, curve[k+1], 0xFFFFFFFF, screen, 0); */
                                                              
                                                                  for( int k = 0 ; k < 256 ; k++ )
                                                                      SetPixel(k, curve[k], screen, 0xFFFFFFFF);
                                                              
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              Tracer une courbe passant par X points

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown