C 言語でPostScript ベースの図形描写ライブラリの使い方についてのまとめ

この記事は、この[「手続き型プログラミング言語C」](https://www.amazon.co.jp/%E6%89%8B%E7%B6%9A%E3%81%8D%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9EC-%E6%B0%B4%E5%B3%B6-%E4%BA%8C%E9%83%8E/dp/4780601347)をプログラミングの教科書として使用している図形描写ライブラリの使い方についてまとめました。

生成された PostScript ファイルを確認するには、[PostScript Viewer and Compiler](https://ehubsoft.herokuapp.com/psviewer/) を利用するか、

次の２つのライブラリをインストールしてください。

- [GhostScript](https://www.ghostscript.com/)
- [GSView](http://www.ghostgum.com.au/software/gsview.htm)


C 言語 の コンパイラにつきましては、[Visual C++](https://visualstudio.microsoft.com/ja/downloads/), あるいは [gcc](https://gcc.gnu.org/) のいずれかをインストールして実行します。

今回は、これらのツールのインストールの仕方については省略します。

## 実際に描写してみる

### 基本設定

このライブラリを使って、まずはデカルト図表を描写します。
まず、このライブラリを次のように設定します。このコードを `sample.c` に実装します。

同じディレクトリには、`ps.h`、`psbasic.c` ファイルを用意します。このファイルは次のURL にて取得できます。

https://www1.doshisha.ac.jp/~jmizushi

（注意）：現在、上記のURLではファイルの配布が終了し、取得できなくなっています。

```sample.c 
#include<stdio.h>
#include<string.h>
#include<math.h>

#indlude"ps.h"

// デカルト座標をここに設定する
void frame(){
    int n,i;
	double x,y,dx,dy;
	arrow(-1.1,0.0,1.1,0.0,0.02,0.0,1.0);	
	arrow(0.0,-1.1,0.0,1.1,0.02,0.0,1.0);
	
   // text(x, y, word): 座標(x,y) に 文字word を入力する
	text(1.1,-0.1,1,"x");
	text(-1.1,-0.12,2,"-1");
	text(0.98,-0.12,1,"1");
	text(-0.1,1.1,1,"y");
	text(-0.12,-1.02,2,"-1");
	text(-0.12,0.98,1,"1");
	text(-0.12,-0.1,1,"0");

  // ここでグラフに目盛りを入力する
	n=10;
	for(i=1;i<=n;i++){
		x=0.1*i;
		dy=i/5*5==i?0.02:0.01;
		line(-x,-dy,-x,dy,0.0,1.0,1);
		line(x,-dy,x,dy,0.0,1.0,1);
	}
	for(i=1;i<=n;i++){
		y=0.1*i;
		dx=i/5*5==i?0.02:0.01;
		line(-dx,-y,dx,-y,0.0,1.0,1);
		line(-dx,y,dx, y,0.0,1.0,1);
	}
	
	stroke();
	return;
  return;
}

// 描写したいグラフをここに設定する
void drawline(){
  return; 
}

int main(){

  init();
  viewport(0.2, 0.2, 0.8, 0.8);
　xyworld(-1.2, -1.2, 1.2, 1.2);
  frame();
  drawline();  // 今回はこの関数は実装しない
  stroke();
  fin();

  return 0;
}

```

続いて、この `sample.c` をコンパイルします。

- Visual C++ を使用する場合

```bash
cl sample.c psbasic.c
```
- gcc を使用する場合

```bash
gcc sample.c psbasic.c
```
をコマンドプロントで実行します。

実行すると `sample.exe (gcc ならa.exe)` が生成されると思います。コマンドプロント上で、

```bash 
# Visual C++ でコンパイルしたとき
sample.exe

# gcc でコンパイルしたとき
./a.exe 
```
を実行します。実行すると `temp1.ps` が生成されます。これを Viewer 確認すると、次のようなグラフが生成されます。

![2020-10-03 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271708/b8aa729c-f437-ea13-4787-963d2c8e1478.png)


以上が、基本的な使い方についてのまとめです。

### 基本的な図形を描写

続いて、グラフを生成します。$-\pi\leq x\leq \pi$ において、２関数 $ y= \cos x, y=x$ を描写します。
先ほどの `sample.c` の 関数 drawline() を次のように書き換えます。 


```sample.c
// (省略)

// この関数に実装したいものを実装する
void drawline(){
  int i, nx = 100;
  double x, y, pi;
  x = -1.0; y = - 1.0;
  pi = 4.0 * atan(1.0);
  linewidth (1.5);
  plot ( x, y, 3);
  for ( i= -nx+1 ; i <= nx; i++ ){
		x = (double) i / (double) nx;
		y = cos(x* pi );
		plot ( x, y, 2 );
  } 
  linety(1);
  plot(-1.2,-1.2,3);
  plot(1.2,1.2,2);
  stroke();
  return;
}

```

先ほどと同様にコンパイル、実行すると、次のファイルが生成されます。
![2020-10-03 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271708/9fc3ce33-dbe3-545f-a200-46e15538ff06.png)


## 基本的な関数の一覧

図形を描写する関数には、以下が予約されています。図形を描写する関数の中で `○○1()` という名前があるが、これは線の色や太さ、点線への設定にするかどうかといった設定を省略するために用意された関数です。

### init()

ポストスクリプトの図を描くための初期設定を行います、コンパイルされたファイルを実行すると、ポストスクリプトファイル（temp1.ps）が生成されます。

### viewport(𝑥1, 𝑦1, 𝑥2, 𝑦2) 

図形を描く用紙上の範囲を設定する関数です。(𝑥1, 𝑦1) は用紙での左下の座標．(𝑥2, 𝑦2) は右上の座標の範囲内で描写されます。

### xyworld(𝑥1, 𝑦1, 𝑥2, 𝑦2) 
世界座標を設定する関数です。(𝑥1, 𝑦1)は世界座標での左下、(𝑥2, 𝑦2)は右上の座標の範囲で設定されます。


### text(𝑥, 𝑦, 𝑛, "string") 
文字を入力する関数です。(𝑥, 𝑦)は最初の 1 文字の左下の座標，𝑛（整数）は文字数、string（13 文字以内の文字）は出力する文字列が設定されます。


### plot(𝑥, 𝑦, 𝑖𝑝𝑒𝑛)

現在の点から(𝑥, 𝑦)までポインタを移動するための関数です．(𝑥, 𝑦)は終点の座標．𝑖𝑝𝑒𝑛は整数でペンの状態を表し，𝑖𝑝𝑒𝑛 = 2はペンを下して移動．𝑖𝑝𝑒𝑛 = 3はペンを上げて移動します。この関数を利用して、関数の描写を開始する座標を変更します。

### stroke() 
カレントパスに図形を描画する関数です。

### fin() 
ポストスクリプトの記述を終了する関数です。

### arrow(𝑥, 𝑦, 𝑥1, 𝑦1 𝑔, 𝑤, 𝑖𝑡) / arrow1(𝑥, 𝑦, 𝑥1, 𝑦1)

**(𝑥, 𝑦) から (𝑥1, 𝑦1) へ向けて矢印を描写する関数です。**

．𝑔（実数）は線の明るさで𝑔 = 1.0 は白，𝑔 = 0.0は黒．𝑤 （実数）は線の太さで𝑤 = 0.0は細く，𝑤 = 2.0は標準，𝑤 = 5.0は太い．𝑖𝑡（整数）は線のタイプで，𝑖𝑡 = 1は実線，𝑖𝑡 = 2は点線，𝑖𝑡 = 3は波線，𝑖𝑡 = 4は一点鎖線．

### line(𝑥, 𝑦, 𝑥1, 𝑦1 𝑔, 𝑤, 𝑖𝑡) / line1(𝑥, 𝑦, 𝑥1, 𝑦1)
**(𝑥, 𝑦) と(𝑥1, 𝑦1)を直線で描写する関数です。**

𝑔（実数）は線の明るさで𝑔 = 1.0 は白，𝑔 = 0.0は黒．𝑤 （実数）は線の太さで𝑤 = 0.0は細く，𝑤 = 2.0は標準，𝑤 = 5.0は太い．𝑖𝑡（整数）は線のタイプで，𝑖𝑡 = 1は実線，𝑖𝑡 = 2は点線，𝑖𝑡 = 3は波線，𝑖𝑡 = 4は一点鎖線．

### rect(x0, y0, 𝑥1, 𝑦1, 𝑔, 𝑤, 𝑖𝑡) / rect1(𝑥, 𝑦, 𝑥1, 𝑦1)

**(𝑥0, 𝑦0) を左下頂点，(𝑥1, 𝑦1)を右上頂点とする長方形を描く関数です。**

𝑔（実数）は線の明るさで𝑔 = 1.0は白，𝑔 = 0.0は黒．𝑤（実数）は線の太さで𝑤 = 0.0は細く，𝑤 = 2.0は標準，𝑤 = 5.0は太い．𝑖𝑡（整数）は線のタイプで，𝑖𝑡 = 1は実線，𝑖𝑡 = 2は点線，𝑖𝑡 = 3は波線，𝑖𝑡 = 4は一点鎖線．

### circ(𝑥, 𝑦, 𝑥1, 𝑦1 𝑔, 𝑤,𝑖𝑡 ) / circ1(𝑥, 𝑦, 𝑟) 
**(𝑥, 𝑦) を中心とし半径𝑟の円を描く関数です。**

𝑔（実数）は線の明るさで𝑔 = 1.0は白，𝑔 = 0.0は黒．𝑤（実数）は線の太さで𝑤 = 0.0は細く，𝑤 = 2.0は標準，𝑤 = 5.0は太い．𝑖𝑡（整数）は線のタイプで，𝑖𝑡 = 1は実線，𝑖𝑡 = 2は点線，𝑖𝑡 = 3は波線，𝑖𝑡 = 4は一点鎖線．

### arc(𝑥, 𝑦, 𝑥1, 𝑦1 𝑔, 𝑤, 𝑖𝑡) / arc1(𝑥, 𝑦, 𝑟) 
**(𝑥, 𝑦)を円の中心とし，半径𝑟の円弧を始点角𝑡ଵから終点角𝑡ଶまで横軸から反時計回りに描く関数です。**

𝑔（実数）は線の明るさで𝑔 = 1.0は白，𝑔 = 0.0は黒．𝑤（実数）は線の太さで𝑤 = 0.0は細く，𝑤 = 2.0は標準，𝑤 = 5.0は太い．𝑖𝑡（整数）は線のタイプで，𝑖𝑡 = 1は実線，𝑖𝑡 = 2は点線，𝑖𝑡 = 3は波線，𝑖𝑡 = 4は一点鎖線．

 
## 使用した感想

使用していていちいち上記のコマンドを実行するのはとても大変です。正直、これらのコマンドを Makefile や bash ファイルにまとめて実行したり、図形描写を matplotlib で代用したほうがいいと思います。