画曲线

除了绘制直线以外,开罗还允许你用Cairo::Context::curve_to()Cairo::Context::rel_curve_to()函数轻松的绘制曲线(从技术上而言是三次贝塞尔曲线)。这些函数需要一个目标点的坐标和两个'控制'点的坐标。这最好用一个示例来解释,所以让我们开始吧。

16.3.1. 示例

这个简单的示例程序使用开罗绘制了一条曲线并显示了曲线两端的控制点。

Figure 16-4绘图区域 - 线

源代码

File: myarea.h (For use with gtkmm 4)

#ifndef GTKMM_EXAMPLE_MYAREA_H
#define GTKMM_EXAMPLE_MYAREA_H

#include <gtkmm/drawingarea.h>

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

protected:
  void on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height);
};

#endif // GTKMM_EXAMPLE_MYAREA_H

File: main.cc (For use with gtkmm 4)

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

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();

protected:
  MyArea m_area;
};

ExampleWindow::ExampleWindow()
{
  set_title("DrawingArea");
  set_child(m_area);
}

int main(int argc, char** argv)
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: myarea.cc (For use with gtkmm 4)

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

MyArea::MyArea()
{
  set_draw_func(sigc::mem_fun(*this, &MyArea::on_draw));
}

MyArea::~MyArea()
{
}

void MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int 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

  // scale to unit square (0 to 1 width 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();
}

这个示例与绘制直线示例的唯一区别在它们的on_draw()函数,不过这里引入了一些新的概念和函数,所以让我们简要的介绍一下它们。

我们调用Cairo::Context::scale()并传入绘图区域的宽和高,这将使用户空间坐标系被缩放为"1个单位"(宽高的范围变成[0.0,1.0])。在这其实并没有什么特别的要对坐标系进行缩放的理由,只是为了使绘图操作有时候更易用。

Cairo::Context::curve_to()的调用应该是不言自明的。第一组坐标定义了曲线起点的控制点。第二组坐标定义了曲线终点的控制点,而最后一组坐标定义了目标点。为了使控制点的概念更容易被看清,从每个控制点到与之关联的曲线上的端点上都画了一条线。请注意,这些控制点线都是半透明的。这是通过调用set_source_rgb()的变体函数set_source_rgba()实现的。这个函数使用第四个参数来接受指定颜色的alpha值(值的有效区间为0到1)。