Tracé de courbes

Outre la possibilité de tracer des droites, Cairo vous permet de tracer facilement des lignes courbes (techniquement une courbe de Bézier d'ordre 3) avec les fonctions Cairo::Context::curve_to() et Cairo::Context::rel_curve_to(). Ces fonctions prennent en paramètres les coordonnées des extrémités ainsi que celles de deux points de « contrôle ». Ce sera plus facile à expliquer sur un exemple, alors lançons-nous.

XVII.III.I. Exemple

Cette simple application trace une courbe avec Cairo et affiche les points de contrôle pour chaque extrémité de la courbe.

Figure XVII.3 Zone de dessin ‑ Lignes

Code source

File: myarea.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLE_MYAREA_H
#define GTKMM_EXAMPLE_MYAREA_H

#include <gtkmm/drawingarea.h>

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();

protected:
  //Override default signal handler:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
};

#endif // GTKMM_EXAMPLE_MYAREA_H

File: myarea.cc (For use with gtkmm 3, not gtkmm 2)

#include "myarea.h"
#include <cairomm/context.h>

MyArea::MyArea()
{
}

MyArea::~MyArea()
{
}

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
  Gtk::Allocation allocation = get_allocation();
  const int width = allocation.get_width();
  const int height = allocation.get_height();

  double x0=0.1, y0=0.5, // start point
         x1=0.4, y1=0.9,  // control point #1
         x2=0.6, y2=0.1,  // control point #2
         x3=0.9, y3=0.5;  // end point

  // clip to the area indicated by the expose event so that we only redraw
  // the portion of the window that needs to be redrawn
  cr->rectangle(0, 0, width, height);
  cr->clip();

  // scale to unit square (0 to 1 with and height)
  cr->scale(width, height);

  cr->set_line_width(0.05);
  // draw curve
  cr->move_to(x0, y0);
  cr->curve_to(x1, y1, x2, y2, x3, y3);
  cr->stroke();
  // show control points
  cr->set_source_rgba(1, 0.2, 0.2, 0.6);
  cr->move_to(x0, y0);
  cr->line_to (x1, y1);
  cr->move_to(x2, y2);
  cr->line_to (x3, y3);
  cr->stroke();

  return true;
}

File: main.cc (For use with gtkmm 3, not gtkmm 2)

#include "myarea.h"
#include <gtkmm/main.h>
#include <gtkmm/window.h>

int main(int argc, char** argv)
{
   Gtk::Main kit(argc, argv);

   Gtk::Window win;
   win.set_title("DrawingArea");

   MyArea area;
   win.add(area);
   area.show();

   Gtk::Main::run(win);

   return 0;
}

La seule différence entre cet exemple et l'exemple des droites réside dans la fonction on_expose_event(), mais quelques nouveaux concepts et fonctions sont introduits ici ; examinons-les brièvement.

Notez que nous découpons la surface nécessitant d'être redessinée exactement comme nous l'avions fait dans l'exemple précédent. Après découpe, toutefois, nous faisons appel à Cairo::Context::scale() en passant à cette fonction la largeur et la hauteur de cette surface de tracé. Le système de coordonnées de l'espace utilisateur est ainsi gradué de telle sorte que la hauteur et la largeur du élément graphique ont tous deux une mesure de 1,0 « unité ». Il n'y avait pas de raison particulière de modifier la graduation du système de coordonnées dans notre cas, mais cela peut quelquefois faciliter les opérations de tracé.

L'appel à Cairo::Context::curve_to() est vraiment explicite en soi. Le premier couple de coordonnées définit le point de contrôle au début de la courbe, le deuxième celui à la fin de la courbe. Le dernier groupe de coordonnées indique les extrémités de la courbe. Pour faire en sorte que le concept des points de contrôle soit plus facile à visualiser, nous avons tracé une droite entre extrémité de la courbe et point de contrôle associé. Notez que ces droites (tangentes aux extrémités de la courbe) sont translucides. Ceci est réalisé à l'aide d'une variante de set_source_rgb() intitulée set_source_rgba(). Cette fonction prend un quatrième argument indiquant le coefficient alpha de la couleur (les valeurs correctes s'échelonnent entre 0 et 1).