Tracer des courbes de Bézier.

Les courbes de Bézier sont des courbes polynomiales très utiles et maléables.

Voir version :

Pas de dépendances

Télécharger :

#include <math.h>
#include <sdl/sdl.h>

#define XRES 800
#define YRES 600
#define MINX -2.0
#define MINY -3.0
#define MAXX 5.0
#define MAXY 4.0

#define NBCONTROL 4

#ifdef WIN32
#pragma comment(lib,"sdl.lib")
#pragma comment(lib,"sdlmain.lib")
#endif

typedef struct 
{
    double x,y;
} ControlPoint;


ControlPoint Clist[NBCONTROL];

void UpdateEvents(Sint32* mousex,Sint32* mousey,char boutons[8],char key[SDLK_LAST])
{
    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
        switch (event.type)
        {
        case SDL_KEYDOWN:
            key[event.key.keysym.sym]=1;
            break;
        case SDL_KEYUP:
            key[event.key.keysym.sym]=0;
            break;
        case SDL_MOUSEMOTION:
            *mousex=event.motion.x;
            *mousey=event.motion.y;
            break;
        case SDL_MOUSEBUTTONDOWN:
            boutons[event.button.button]=1;
            break;
        case SDL_MOUSEBUTTONUP:
            boutons[event.button.button]=0;
            break;
        }
    }
}

void SDL_PutPixel32(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    Uint8 *p = (Uint8*)surface->pixels + y * surface->pitch + x * 4;
    *(Uint32*)p = pixel;
}

Uint32 SDL_GetPixel32(SDL_Surface *surface, int x, int y)
{
    Uint8 *p = (Uint8*)surface->pixels + y * surface->pitch + x * 4;
    return *(Uint32*)p;
}

void Line(SDL_Surface* surf,int x1,int y1, int x2,int y2,Uint32 couleur)  // Bresenham
{
    int x,y;
    int Dx,Dy;
    int xincr,yincr;
    int erreur;
    int i;

    Dx = abs(x2-x1);
    Dy = abs(y2-y1);
    if(x1<x2)
        xincr = 1;
    else
        xincr = -1;
    if(y1<y2)
        yincr = 1;
    else
        yincr = -1;

    x = x1;
    y = y1;
    if(Dx>Dy)
    {
        erreur = Dx/2;
        for(i=0;i<Dx;i++)
        {
            x += xincr;
            erreur += Dy;
            if(erreur>Dx)
            {
                erreur -= Dx;
                y += yincr;
            }
            SDL_PutPixel32(surf,x, y,couleur);
        }
    }
    else
    {
        erreur = Dy/2;
        for(i=0;i<Dy;i++)
        {
            y += yincr;
            erreur += Dx;
            if(erreur>Dy)
            {
                erreur -= Dy;
                x += xincr;
            }
            SDL_PutPixel32(surf,x, y,couleur);
        }
    }
    SDL_PutPixel32(surf,x1,y1,couleur);
    SDL_PutPixel32(surf,x2,y2,couleur);
}

int Re_to_EcrX(double r)
{
    return (int)(XRES*(r-MINX)/(MAXX-MINX));
}

int Re_to_EcrY(double r)
{
    int y = (int)(YRES*(r-MINY)/(MAXY-MINY));
    y = YRES - y - 1;
    return y;
}

double Ecr_to_ReX(int i)
{
    return MINX + i*(MAXX-MINX)/XRES;
}

double Ecr_to_ReY(int i)
{
    return MAXY - i*(MAXY-MINY)/YRES;
}

void ShowAxis(SDL_Surface* screen)
{
    int centreX = Re_to_EcrX(0.0);
    int centreY = Re_to_EcrY(0.0);
    Line(screen,centreX,0,centreX,YRES-1,0xFFFFFF);  // axe vertical
    Line(screen,0,centreY,XRES-1,centreY,0xFFFFFF);  // axe horizontal
}

void ShowControlPoints(SDL_Surface* screen)
{
    int i;
    for(i=0;i<NBCONTROL;i++)
    {
        int x = Re_to_EcrX(Clist[i].x);
        int y = Re_to_EcrY(Clist[i].y);
        Line(screen,x-5,y-5,x+5,y+5,0xFF0000);
        Line(screen,x+5,y-5,x-5,y+5,0xFF0000);
    }
}

void InitCpoints()  // je place les points de controle arbitrairement autour d'un cercle fictif
{
    int i;
    for(i=0;i<NBCONTROL;i++)
    {
        double t = 0.15 + (i*3.0/NBCONTROL);
        Clist[i].x = cos(t);
        Clist[i].y = sin(t);
    }
}

void Casteljau(double t,ControlPoint* tab,int nbpoints,double* rx,double* ry)
{
    ControlPoint subtab[NBCONTROL];
    int i;
    if (nbpoints == 1)
    {
        *rx = tab[0].x;
        *ry = tab[0].y;
        return;
    }
    for(i=0;i<nbpoints-1;i++)
    {
        subtab[i].x = t*tab[i].x + (1-t)*tab[i+1].x;
        subtab[i].y = t*tab[i].y + (1-t)*tab[i+1].y;
    }
    Casteljau(t,subtab,nbpoints-1,rx,ry);
}

void ShowBezier(SDL_Surface* screen,double tstep,unsigned long couleur)
{
    double t = 0.0;
    int lastx = 0;
    int lasty = 0;
    int x,y;
    double rx = 0.0;
    double ry = 0.0;
    int i = 0;
    while(t<=1.0)
    {
        Casteljau(t,Clist,NBCONTROL,&rx,&ry);
        x = Re_to_EcrX(rx);
        y = Re_to_EcrY(ry);
        if (i!=0)
            Line(screen,x,y,lastx,lasty,couleur);
        lastx = x;
        lasty = y;
        t+=tstep;
        i++;
    }
}

void CheckMouseDeplace(Sint32 mousex,Sint32 mousey,char boutons[8])
{
    int i;
    if (boutons[SDL_BUTTON_LEFT]==0)
        return;
    for(i=0;i<NBCONTROL;i++)
    {
        int x = Re_to_EcrX(Clist[i].x);
        int y = Re_to_EcrY(Clist[i].y);
        if (abs(mousex-x)<=10 && abs(mousey-y)<=10)
        {
            Clist[i].x = Ecr_to_ReX(mousex);
            Clist[i].y = Ecr_to_ReY(mousey);
            return;
        }
    }
}

int main(int argc,char** argv)
{
    Sint32 mousex = 0;
    Sint32 mousey = 0;
    char boutons[8] = {0};
    char key[SDLK_LAST] = {0};
    SDL_Surface* screen;
    SDL_Init(SDL_INIT_VIDEO);
    screen=SDL_SetVideoMode(XRES,YRES,32,SDL_SWSURFACE|SDL_DOUBLEBUF);  
    SDL_ShowCursor(1);
    InitCpoints();
    while(!key[SDLK_ESCAPE])
    {
        SDL_FillRect(screen,NULL,0);
        UpdateEvents(&mousex,&mousey,boutons,key);
        if (SDL_MUSTLOCK(screen))
            SDL_LockSurface(screen);

        CheckMouseDeplace(mousex,mousey,boutons);
        
        ShowAxis(screen);
        ShowControlPoints(screen);
        ShowBezier(screen,0.002,0x00FF00);
        
        if (SDL_MUSTLOCK(screen))
            SDL_UnlockSurface(screen);        
        SDL_Flip(screen);
    }
    return 0;
}




Commentaires


  Voici un tuto sur les courbes de Bézier :  concept tres utilisé pour faire des courbes tres lisses.

  Lancez le programme tout de suite pour voir :

  Un graphique s'affiche, avec des points rouges (des points mathématiques, donc des croix), et une belle courbe verte, bien lisse.
  Avec la souris, cliquez sur un point rouge, et bougez le : la courbe vous suit.

  Vous constatez qu'il y a 4 points : regardez en haut du programme le #define NBCONTROL : il est a 4. Essayez de rajouter des points
  (n'en mettez pas 50 quand meme...)
  

  Une courbe de Bézier (courbe verte) est définie uniquement par ses points de controls (points rouges)
  Si vous en déplacez un, ça modifie la courbe.
  C'est une courbe paramétrique polynomiale.
  http://fr.wikipedia.org/wiki/Courbe_de_B%C3%A9zier


  Pour afficher une courbe de Bézier, une bonne méthode est l'algorithme de Casteljau :
  http://fr.wikipedia.org/wiki/Algorithme_de_De_Casteljau

  Le code est juste une illustration de ces algos.


  Il existe d'autres courbes, plus complexes que les Bézier : les B-Splines, et les NURBS. Ces courbes sont plus complexes, mais
  sont une généralisation de Bézier, avec d'autres parametres (vecteur nodal, poids des points...)