menu
  Home  ==>  articles  ==>  graphique  ==>  courbes_de_bezier   

Courbes de Bézier - John COLIBRI.

  • résumé : construction interactive de courbes de Bézier
  • mots clé : Bézier - Interpolation - cubiques - Editeur graphique
  • logiciel utilisé : Windows XP, Delphi 6.0
  • matériel utilisé : Pentium 1.400Mhz, 256 M de mémoire
  • champ d'application : Delphi 1 à 2005 sur Windows
  • niveau : développeur Delphi
  • plan :


1 - Introduction

Pour réaliser des corrections de couleurs de bitmap, nous souhaitions pouvoir définir une courbe de correction. Outre les classiques translations, homotheties et diverses puissances, le plus souple est de laisser l'utilisateur dessiner sa courbe avec la souris, puis d'interpoler les valeurs de cette courbe pour corriger les couleurs.

Nous avons présenté dans un précédent article un éditeur de points qui permet de créer une liste de points à l'écran les déplacer, effacer etc.

Nous nous concentrerons donc ici uniquement sur la partie interpolation de Bézier: un série de points étant définie à l'écran, tracer la courbe de Bézier correspondante, et interpoler n'importe quelle valeur.


2 - Courbes de Bézier

Les courbes sont des des cubiques définies par 4 points de contrôle. Une droite est définie par 2 points, un cercle (une quadratique) par 3 points, et une cubique par 4 points. Etant donnée 4 points que nous appellerons before_point, start_point, end_point et after_point, les valeurs (l_x, l_y) des points entre start_point et end_point sont obtenues par:

for l_bezier_x:= 0.01 to 0.99 do
begin 
  l_x:= f_smooth_bezier(l_bezier_x, 0)* l_before_point.m_x
      + f_smooth_bezier(l_bezier_x, 1)* l_start_point.m_x
      + f_smooth_bezier(l_bezier_x, 2)* l_end_point.m_x
      + f_smooth_bezier(l_bezier_x, 3)* l_after_point.m_x;

  l_y:= f_smooth_bezier(l_bezier_x, 0)* l_before_point.m_y
      + f_smooth_bezier(l_bezier_x, 1)* l_start_point.m_y
      + f_smooth_bezier(l_bezier_x, 2)* l_end_point.m_y
      + f_smooth_bezier(l_bezier_x, 3)* l_after_point.m_y;
end;

où la fonction d'extrapolation f_smooth_bezier est:

Function f_smooth_bezier(p_parameterDoublep_point_indexByte): Double;
  Begin
    case p_point_index of
      0 : begin 
            p_parameter:= 1- p_parameter
            Result:= p_parameterp_parameterp_parameter/ 6           
          end;
      1 : Result:= p_parameterp_parameter* (p_parameter/ 2- 1)+ 4/6;
      2 : Result:= p_parameter* (1+ p_parameter* (1- p_parameter))/ 2+ 1/6;
      3 : Result:= p_parameterp_parameterp_parameter/ 6;
    End// case p_point
  end// f_smooth_bezier



Si nous avons une série de n points, il suffit donc pour tracer la courbe correspondante de répéter le calcul pour les points 2 à n-2.



Et pour trouver la valeur y correspondant à n'importe quelle valeur x, nous pouvons:

  • chercher quels sont les deux points située avant le point, et les deux points situés après le point
  • avec un pas défini par l'utilisateur, rechercher la valeur de y correspondant à la valeur de x la plus proche

3 - Le programme Delphi

3.1 - La liste de points

Notre liste de points est définie par un c_2d_point_list (cf editeur_de_points ).



3.2 - Calcul de la transformée

Pour cette liste de points, nous calculons la liste des points situés sur la courbe de Bézier correspondante. Entre deux points nous pouvons placer autant de points intermédiaires que nous le souhaitons. Pour l'écran, il n'est pas utile d'avoir plus de points que Round(longueur), mais si la courbe représente des données non graphique (une courbe de transfert pour une correction graphique), nous pourrions avoir besoin d'une interpolation plus fine.

Pour le dessin, nous fournissons la liste de points, et récupérons une liste des points interpolés. Cette seconde liste peut être utilisée pour visualiser la courbe de Bézier à l'écran.



3.3 - Interpolation

Pour l'interpolation, nous fournissons la liste de points, une valeur x et le nombre de points à utiliser entre les deux points. Nous récupérons la valeur y en deux étapes:
  • nous recherchons quels sont les deux points situés juste avant et juste après le point cherché
  • ayant trouvé ces deux points, nous recherchons pour quelle valeur du paramètre de Bézier nous obtenons la valeur la plus proche de x. Pour ce paramètre, nous calculons la valeur y.
 function f_interpolate_value(p_c_2d_point_listc_2d_point_list;
    p_xDouble): Double;
    // -- assumes a FUNCTION (a single y value for each x)

  function f_interpolate(p_point_indexInteger): Double;
      // -- interpolate
    var l_c_start_pointl_c_end_pointc_2d_point;
        l_c_before_pointl_c_after_pointc_2d_point;
        l_bezier_parameterl_bezier_parameter_stepDouble;
        l_distancel_xDouble;
    begin
      with p_c_2d_point_list do
      begin
        l_c_before_point:= f_c_2d_point(p_point_index- 1);
        l_c_start_point:= f_c_2d_point(p_point_index);
        l_c_end_point:= f_c_2d_point(p_point_index+ 1);
        l_c_after_point:= f_c_2d_point(p_point_index+ 2);

        l_distance:= Sqrt(Sqr(l_c_end_point.m_xl_c_start_point.m_x)
            + Sqr(l_c_end_point.m_yl_c_start_point.m_y));
        if l_distance= 0
          then l_distance:= 1;
        // -- at least a value for each integer x
        // --   (for horizontal should be 1 / distance)
        l_bezier_parameter_step:= 1/ l_distance/ 2;

        l_bezier_parameter:= - l_bezier_parameter_step;
        repeat
          l_bezier_parameter:= l_bezier_parameterl_bezier_parameter_step;

          l_x:= f_smooth_bezier(l_bezier_parameter, 0)* l_c_before_point.m_x
              + f_smooth_bezier(l_bezier_parameter, 1)* l_c_start_point.m_x
              + f_smooth_bezier(l_bezier_parameter, 2)* l_c_end_point.m_x
              + f_smooth_bezier(l_bezier_parameter, 3)* l_c_after_point.m_x;
        until (l_bezier_parameter_step> 1) or (l_xp_x);

        Result:= f_smooth_bezier(l_bezier_parameter, 0)* l_c_before_point.m_y
            + f_smooth_bezier(l_bezier_parameter, 1)* l_c_start_point.m_y
            + f_smooth_bezier(l_bezier_parameter, 2)* l_c_end_point.m_y
            + f_smooth_bezier(l_bezier_parameter, 3)* l_c_after_point.m_y;
      end// with p_c_2d_point_list
    end// f_interpolate

  var l_point_indexInteger;

  begin // f_bezier_value
    // -- find the interval
    with p_c_2d_point_list do
    begin
      if f_2d_point_count= 0
        then begin
            Result:= 0;
            Exit;
          end;

      l_point_index:= 0;
      while l_point_index<= f_2d_point_count- 1 do
        if f_c_2d_point(l_point_index).m_xp_x
          then Break
          else Inc(l_point_index);

      if l_point_index<= 1
        then Result:= f_c_2d_point(0).m_y
        else
          if l_point_indexf_2d_point_count- 2
            then begin
                l_point_index:= f_2d_point_count- 1;
                Result:= f_c_2d_point(l_point_index).m_y;
              end
            else Result:= f_interpolate(l_point_index- 1);
    end// with p_c_2d_point_list
  end// f_interpolate_value



3.4 - La classe de transformation

Comme nous fournissons toutes les données pour calculer la transformée ou interpoler un point, il n'y a aucune raison de créer une classe: un appel de procédure ou de fonctions suffit.

Toutefois, pour la correction de contraste de photo, nous souhaitions basculer d'une interpolation linéaire à une interpolation de Bézier. Le plus simple est alors de créer une classe abstraite ayant les deux fonctions que nous souhaitons, puis dériver deux classes, l'une pour une poly-line et une autre pour Bézier.

La classe abstraite est définie par:

 c_transformerclass(c_basic_object)
                  function f_c_transform(p_c_2d_point_listc_2d_point_list;
                      p_interpolation_countInteger):
                      c_2d_point_listVirtualAbstract;
                  function f_interpolate_value(p_c_2d_point_listc_2d_point_list;
                      p_xDouble): DoubleVirtualAbstract;
                 end// c_transformer



Et pour Bézier:

c_bezier_transformerclass(c_transformer)
                         constructor create_bezier_transformer(p_nameString);

                         function f_c_transform(p_c_2d_point_listc_2d_point_list;
                             p_interpolation_countInteger): c_2d_point_listOverride;
                         function f_interpolate_value(p_c_2d_point_listc_2d_point_list;
                             p_xDouble): DoubleOverride;
                       end// create_bezier_transformer



Vu du côté utilisateur:

  • nous déclarons une variable (ou un champ) de type c_transformer
  • nous créons soit un transformateur linéaire ou un transformateur de Bézier
  • pour dessiner la courbe, nous appelons la fonction f_c_transform et dessinons la courbe correspondante
  • pour connaître la valeur d'un point, nous appelons f_interpolate_value


Pour des exemples, voyez editeur_de_points ou correction_couleur




4 - Télécharger les sources

Vous pouvez télécharger:
  • points_editor.zip : l'éditeur de points avec transformation de Bézier et le projet example (22 K)
Ce .ZIP qui comprend:
  • le .DPR, la forme principale, les formes annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonaume)
Ces .ZIP contiennent des chemins RELATIFS. Par conséquent:
  • créez un répertoire n'importe où sur votre machine
  • placez le .ZIP dans ce répertoire
  • dézippez et les sous-répertoires nécessaires seront créés
  • compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.



Comme d'habitude:

  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.

5 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Created: jan-04. Last updated: mar-2020 - 250 articles, 620 .ZIP sources, 3303 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2020
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
    + web_internet_sockets
    + services_web_
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
      – rectangle_de_selection
      – editeur_de_points
      – courbes_de_bezier
      – correction_couleur
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
    + admin
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Architecte Delphi Architecture, Refactoring, choix de technologies, revue de code, mise en place de test, optimisation - Tél 01.42.83.69.36