Cairoを使う：（その2）図形を描く

### 描画の基本

Cairoでは、描画対象（ページ）の左上隅が原点となります。
図形を描画するには、

- パス
- ソース
- マスク
- ストローク/フィルの別

の四つを与えます。パスは図形の輪郭、ソースは図形の塗りの元、マスクは塗り効果をそれぞれ決めるものです。ソースとマスクについては別記事で説明します。全ての図形についてこれらを与えることで、描画がなされます。

例えば[前回](https://qiita.com/zhidao/items/32dd8ac81dd212276623)の例では描画部分は次のようになっていました。

```C
void draw(cairo_t *c, int width, int height)
{
  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );
  /* red rectangle */
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_fill( c );
}
```

これで、ページと同じサイズの白い長方形と、ページの1/4サイズの赤い長方形が描画されました。どちらの例もcairo_set_source_rgb()で単色のソースを、cairo_rectangle()で長方形型のパスをそれぞれ与え、cairo_fill()でフィル（パスの内部を塗りつぶすこと）を選んでいます。

後者を

```C
  /* red rectangle */
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_stroke( c );
```

と変えてフィルではなくストローク（パス自体を描くこと）を選べば、次のような絵が出力されるはずです。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/0b7e13a0-6904-2e3c-d4ef-4bc51a2d9235.png)
フィルした後にストロークも描く場合には、次のようにすればOKです。

```C
  /* red rectangle */
  cairo_set_source_rgb( c, 1, 0.6, 0.8 );
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_fill( c );
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_stroke( c );
```

次のような絵が出力されたでしょうか。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/f1513e5b-a5f8-4f61-5673-d81de2a4a9eb.png)
あるいは次のように書いても同じ結果になります。

```C
  /* red rectangle */
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_set_source_rgb( c, 1, 0.6, 0.8 );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_stroke( c );
```

線の太さを変えたければ、後半を

```C
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_set_line_width( c, 10 );
  cairo_stroke( c );
```

のようにすればOKです。出力は次のようになります。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/37f1d592-22e1-6688-d520-7f183d608498.png)


### 多角形の書き方

長方形ならば上の例のようにcairo_rectangle()が使えます。
例えばdraw()を次のように変えてみましょう。

```C
void draw(cairo_t *c, int width, int height)
{
  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );
  /* blue triangle */
  cairo_set_source_rgb( c, 0, 0, 1 );
  cairo_move_to( c,   width/4, 3*height/4 );
  cairo_line_to( c, 3*width/4, 3*height/4 );
  cairo_line_to( c, 3*width/4,   height/4 );
  cairo_line_to( c,   width/4, 3*height/4 );
  cairo_stroke( c );
}
```

次のような絵が出力されたはずです。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/c5d5782b-aabd-17ef-7217-da4269a135cc.png)

後者を次のようにしても同じ出力が得られます。

```C
  /* blue triangle */
  cairo_set_source_rgb( c, 0, 0, 1 );
  cairo_move_to( c,   width/4, 3*height/4 );
  cairo_rel_line_to( c, width/2, 0 );
  cairo_rel_line_to( c, 0, -height/2 );
  cairo_close_path( c );
  cairo_stroke( c );
```

上の例は三角形ですが、一般的な多角形も同様にして描けます。

cairo_set_dash()を用いて線を破線にすることも可能です。線と空白の長さを交互に納めた配列でパターンを与えます。例えば次を試してみましょう。

```C
  cairo_set_source_rgb( c, 0, 0.2, 0.5 );
  double dash1[] = { 10.0, 2.0 };
  int i;
  for( i=0; i<=10; i++ ){
    cairo_set_dash( c, dash1, sizeof(dash1)/sizeof(double), i );
    cairo_move_to( c, width/4, height/4+5*i );
    cairo_rel_line_to( c, width/2, 0 );
    cairo_stroke( c );
  }
  double dash2[] = { 10.0, 3.0, 1.0, 3.0 };
  cairo_set_dash( c, dash2, sizeof(dash2)/sizeof(double), 0 );
  cairo_move_to( c, width/4, height/2 );
  cairo_rel_line_to( c, width/2, 0 );
  cairo_stroke( c );
```

出力は次のようになります。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/9f25529d-a630-7347-2c30-6de046f40203.png)

前半のループの中では、破線パターンは同じものですが、cairo_set_dash()の4番目引数でパターンの開始オフセット値を与えていることが分かるでしょうか。

### 円弧の描き方

draw()を次のように変えてみましょう。

```C
#include <cairo/cairo.h>
#include <math.h>

void draw(cairo_t *c, int width, int height)
{
  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );

  /* green circle */
  cairo_arc( c, width/4, height/4, height/8, 0, 2*M_PI );
  cairo_set_source_rgb( c, 0, 1, 0 );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 0, 0.5, 0 );
  cairo_stroke( c );

  cairo_arc( c, width/2, height/4, height/8, 0, 3*M_PI/4 );
  cairo_set_source_rgb( c, 0, 1, 0 );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 0, 0.5, 0 );
  cairo_stroke( c );

  cairo_arc( c, 3*width/4, height/4, height/8, 0, 3*M_PI/2 );
  cairo_set_source_rgb( c, 0, 1, 0 );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 0, 0.5, 0 );
  cairo_stroke( c );

  cairo_move_to( c, width/2, 3*height/4 );
  cairo_rel_line_to( c, height/8, 0 );
  cairo_arc( c, width/2, 3*height/4, height/8, 0, 3*M_PI/4 );
  cairo_close_path( c );
  cairo_set_source_rgb( c, 0, 1, 0 );
  cairo_fill( c );
  cairo_arc( c, width/2, 3*height/4, height/8, 0, 3*M_PI/4 );
  cairo_set_source_rgb( c, 0, 0.5, 0 );
  cairo_stroke( c );

  cairo_move_to( c, 3*width/4, 3*height/4 );
  cairo_rel_line_to( c, height/8, 0 );
  cairo_arc( c, 3*width/4, 3*height/4, height/8, 0, 3*M_PI/2 );
  cairo_close_path( c );
  cairo_set_source_rgb( c, 0, 1, 0 );
  cairo_fill( c );
  cairo_arc( c, 3*width/4, 3*height/4, height/8, 0, 3*M_PI/2 );
  cairo_set_source_rgb( c, 0, 0.5, 0 );
  cairo_stroke( c );
}
```

出力は次のようになります。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/ac80d95c-b184-66db-a7e1-30ba9f1632de.png)
このように、cairo_arc( c, 中心x, 中心y, 半径, 開始角度, 終了角度 )は弓型になるのですが、cairo_move_to()、cairo_line_to()、cairo_close_path()と組み合われば扇形を描くことができます。

円弧でない曲線として、[楕円弧の描き方](https://qiita.com/zhidao/items/2d2e63dbde03f7588996)、[3次ベジエ曲線の描き方](https://qiita.com/zhidao/items/1050cec295e196175cd0)をそれぞれ別記事で説明します。