曲線の描画

直線を描くほかにも、Cairoを使えば簡単に曲線(技術的には3次ベジェスプライン)を描くことができます。Cairo::Context::curve_to()Cairo::Context::rel_curve_to()を使ってください。これらの関数は引数として終点の座標を取るほかに、2つの"制御"点を取ります。例を使って説明するのが一番いいでしょう、さあやってみましょう。

このシンプルなアプリケーションはCairoで曲線を描き、曲線の両端のところで制御点を示しています。

Figure 15.3. Drawing Area - Lines

Drawing Area - Lines

Source Code

File: myarea.h

#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_expose_event(GdkEventExpose* event);
};

#endif // GTKMM_EXAMPLE_MYAREA_H

File: myarea.cc

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

MyArea::MyArea()
{
}

MyArea::~MyArea()
{
}

bool MyArea::on_expose_event(GdkEventExpose* event)
{
  // This is where we draw on the window
  Glib::RefPtr<Gdk::Window> window = get_window();
  if(window)
  {
    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

    Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
    // 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(event->area.x, event->area.y,
            event->area.width, event->area.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

#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;
}

この例と直線の例の唯一の違いは、on_expose_event()関数にあります。しかし、こちらではいくつか新しい概念と関数が導入されています。簡潔に説明していきましょう。

ひとつ前の例と同様に、この例でも再描画される領域をクリップしていることに注目してください。ここではしかし、クリッピング後にCairo::Context:scale()を描画領域の幅と高さを引数に呼び出しています。こうすることでユーザー空間の座標系をスケールし、ウィジットの幅と高さを共に1.0単位にしています。このプログラムでは座標系をスケールする特別な理由はありませんが、そうすることはしばしば操作を行いやすくします。

Cairo::Context::curve_to()の呼び出しはほとんど自己説明的でしょう。第一引数の座標はカーブの始まりに対する操作点を定義します。第二の座標はカーブの終わりに対する操作点を定義し、そして最後の座標は終着点です。操作点の概念を視覚的にもうすこしわかりやすくするために、それぞれの操作点から関連付けられた曲線の端点へ直線が引かれています。操作点からの直線は両方とも透明であることに注目してください。これはset_source_rgb()の変種であるset_source_rgba()によって実現されています。この関数は第四の引数として色のアルファ値(有効範囲は0から1)を取ります。