GLSC の紹介 Version 6.4
桂田 祐史

2009 年 5 月 5 日, 2013 年 12 月, 2021 年 5 月 7 日
この文書の最新版はhttp://nalab.mind.meiji.ac.jp/~mk/labo/howto/intro-glsc/
で読めます。なお

http://nalab.mind.meiji.ac.jp/~mk/labo/howto/index.html#GLSCも適宜参照してください。
この文書を最初に書きだしたのは遥か大昔で、「明大数学科計算機室」なんてのがタイトルについていました。まだ、その時の事情を考慮した記述が残っていますが、「明大数学科計算機室」は削除しました。本来、全体を書き直すべきですが、整理する時間は取れ
そうにないです。

インストール法などを知りたい場合は、「GLSC についてまとめておく (2021 年
1版)」 をチェックして下さい。

目次
1

はじめに — GLSC とは

32

身の回りの環境での使い方

3

3

印刷の仕方 (g out の使い方)

61

http://nalab.mind.meiji.ac.jp/~mk/knowhow-2021/node16.html

1

4

GLSC のサンプル・プログラム
4.1 何をするプログラムか . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 ソースプログラム draw-graph.c . . . . . . . . . . . . . . . . . . .
4.3 読んでみよう . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.1 GLSC を利用するための宣言 . . . . . . . . . . . . . . . . .
4.3.2 どれが GLSC の命令か？ . . . . . . . . . . . . . . . . . . .
4.3.3 ウィンドウのサイズ . . . . . . . . . . . . . . . . . . . . . .
4.3.4 出力先 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.5 座標系の定義 . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.6 線種、文字種の定義 . . . . . . . . . . . . . . . . . . . . . .
4.3.7 定義しておいた座標系、線種、文字の呼び出し . . . . . . .
4.3.8 線分を描く、グラフを描く . . . . . . . . . . . . . . . . . . .
4.3.9 マウスの入力待ち . . . . . . . . . . . . . . . . . . . . . . . .
4.3.10 終了 (ウィンドウの削除) . . . . . . . . . . . . . . . . . . . .

8
8
9
11
11
11
11
12
12
13
13
14
14
15

5

GLSC+ について
5.1 その目的 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 インストールの仕方 . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3 新しく導入した関数 . . . . . . . . . . . . . . . . . . . . . . . . . .
5.4 サンプル・プログラム・ソース . . . . . . . . . . . . . . . . . . . .

15
15
15
16
16

A よく使う関数の説明

19

B PostScript への変換 (g out に関するノウハウ)

22

C 桂田研学生向け

23

D Cygwin+XFree86 環境での利用

26

E glscwin について
E.1 誰が作ったもの？入手するには？ . . . . . . . . . . . . . . . . . . .
E.2 特徴 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.3 C++ で glscwin を利用する . . . . . . . . . . . . . . . . . . . . . .
E.4 インストール・メモ . . . . . . . . . . . . . . . . . . . . . . . . . .
E.5 サンプル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.6 EMF について . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.6.1 wmf2eps のインストール . . . . . . . . . . . . . . . . . . . .

26
26
27
29
29
32
34
34

2

F 有向線分 (矢印) の描画

35

G GLSC で改善して欲しい点

37

はじめに — GLSC とは

1

GLSC (Graphic Library for Scientiﬁc Computing) とは、龍谷大学数理情報学科のグループ2 が作成した、科学技術計算の結果を可視化するためのライブラリィです3 。
ワークステーション環境 (具体的には UNIX + X) で、C や Fortran で図を描く手段には色々なものがありますが、GLSC は実際に数値解析の分野で仕事をしてきた人達が作ったものだけに、数値シミュレーション結果の可視化には本当に便利なものだと筆者は思っています。具体的には、2 変数関数の可視化 (等高線、ちょうかんず鳥瞰図の描画) のためのサブルーチン、関数が揃っています。
マニュアル (PostScript フォーマット) も公開されていて、それを PDF に変換したものを

http://nalab.mind.meiji.ac.jp/~mk/labo/howto/GLSC.pdf
においてあります (機械的に PDF に変換しただけで、何も手を入れていませんが、ないよりはましでしょう)。

glscwin — Windows 版 GLSC
オリジナルの開発者の一人である高橋大輔氏の研究室によって、Win32 環境4 に移植された glscwin については、付録の E を見て下さい。

身の回りの環境での使い方

2

数学科計算機室 (6701 号室) にある Solaris 2.6 で動いているワークステーション
や、Linux マシン、さらには桂田研のノートパソコン (Cygwin であったり、Knoppixであったり) には、GLSC がインストールされています。
2

小林亮、高橋大輔、中野浩、松木平淳太。
ftp://ftp.st.ryukoku.ac.jp/pub/ryukoku/software/math/ から ftp で入手できます。
4
具体的な OS の名前で言うと、Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000 のことを指します。
33

(ソース・ファイルからのインストールの仕方を付録にでも書いておきたい…)
1. インクルード・ファイル/usr/local/include/glsc.h
2. インクルード・ファイル/usr/local/include/glsc ftn.h
具体的には 3. ライブラリィ・アーカイブ /usr/local/lib/libglscd.a
4. ライブラリィ・アーカイブ /usr/local/lib/libglscs.a
5. 画像変換ユーティリティ/usr/local/bin/g outという 5 つのファイルです。
また、PostScript 形式のマニュアルが用意されています。これは ftp://ftp.st.
ryukoku.ac.jp/pub/ryukoku/software/math/ から入手できます。桂田研の学生には印刷したものを配布することにしています。
プログラムの書き方 (1) 詳しくは GLSC のマニュアルを読むべきですが5 、インクルード・ファイルの読み込みと、C や C++ の場合の浮動小数点数の宣言の問題を解決するおまじないについて説明しておきます。

(i) C の場合は、“#define G DOUBLE”6 、それに続けて “#include <glsc.h>”とする。
(ii) C++ の場合も “#define G DOUBLE”、それに続けて

extern "C" {#include <glsc.h>
};





とする (まあ、C++ で C のファイルをインクルードするときの定跡ですが)。

(iii) UNIX 伝統の FORTRAN (f77) の場合は、


include ’/usr/local/include/glsc_ftn.h’




とする。
プログラムの書き方 (2) 以下述べることはどの言語にも共通しています。

5

GLSC のマニュアルにはサンプル・プログラムのソース・ファイルと実行結果も載っています。
また、これらサンプル・プログラムのファイルが http://nalab.mind.meiji.ac.jp/~mk/labo/
glsc-sample/ に置いてあります。
6
この意味は、GLSC に属する関数で、浮動小数点数の型は float でなく double を使う、ということである。

4

(i) 最初に “g init("metaﬁlename", ウィンドウの横幅, ウィンドウの高さ)” を呼び出します (サイズの単位は mm で、引数の型は浮動小数点型です)。メタファイルというのは、描画した図形を記録するためのファイルのことです。
(ii) 出力デバイスを “g device(出力先)” 呼び出しで指定します。G BOTHとすると、画面とメタファイルの両方に出力するようになります。
(iii) “g def scale()” で座標系を定義します。座標系は複数個定義できて、以下は番号を使って g sel scale(番号); として指定できます。
→ GLSC の中で、マルチ・ウィンドウもどきが簡単に実現できます。
(iv) “g def line()” を呼び出して、使用する線 (色、太さ、線種) を定義します。複数の線が定義できて、後から番号で呼び出せます。
(v) “g cls()” で画面のクリアをします。
(vi) 既に “g def ほげほげ” で定義したものを “g sel ほげほげ” で指定します。
(vii) 色々な描画命令を並べます。
(viii) “g sleep()” で停止します。
(ix) “g term()” で GLSC を終了します。
コンパイルの仕方 最もフツーのコンパイルの仕方。
倍精度の場合 “-I/usr/local/include” と “-L/usr/local/lib -L/usr/X11R6/lib-lglscd -lX11 -lm” を指定するのが基本です7 (Solaris 2.6 の場合は-lsocket というのも必要になります)。

(i) gcc の場合は
gcc -o myprog -I/usr/local/include myprog.c -L/usr/local/lib -L/usr/X11R6/lib-lglscd -lX11 -lm (2 行に分けてますが、1 行コマンドです。)(ii) g++ の場合は
g++ -o myprog -I/usr/local/include myprog.C -L/usr/local/lib -L/usr/X11R6/lib-lglscd -lX11 -lm (2 行に分けてますが、1 行コマンドです。)(iii) FORTRAN の場合はf77 -o myprog myprog.f -L/usr/local/lib -L/usr/X11R6/lib -lglscd -lX117

コンパイル・オプション “-l ほげほげ” で lib ほげほげ.a をリンクすることになります。こ
こでは libglscd.a, libX11.a, libsocket.a, libm.a をリンクするわけです。

5いずれも少々面倒なので、エイリアスを定義したり、Makeﬁle を作った
りして、手間を軽減すべきでしょう。筆者は次のような行を .cshrc に書き加えています。


alias ccmg ’gcc -O -o \!^:r -I/usr/local/include \!* -L/usr/local/lib-L/usr/X11R6/lib -lmatrix -lglscd -lX11 -lm’

単精度の場合 “-lglscd” の代わりに “-lglscs” を指定するのが基本です。

印刷の仕方 (g out の使い方)

3(昔から悩みの種だったけれど、最近はとりあえず困っていません。)
例えば、C のプログラムで、

g_init("Meta", ...);
g_devie(G_BOTH);のようにした場合 (G BOTH は画面表示とメタファイル出力の両方を行なう、という意味ですが、G META として画面表示は行なわず、メタファイルの出力のみを行なうことも出来ます)、プログラム終了後に、Meta という名前のファイルが出来ているはずです。
oyabun% g out -v Meta

として Meta.ps という PostScript 形式のデータが出来ます。後は再表示 PostScript 形式のデータは、Ghostscript などのビューアーで表示できます。


gs Meta.ps あるいは ghostview Meta.ps & あるいは
gv Meta.ps & あるいは ggv Meta.ps &(ここら辺は環境による、ですね。)


MacOS の場合は、GhostScript がなくても、

open Meta.ps


で表示できます。

6

印刷 UNIX 風の環境で (最近の Mac もこれに属します)、PostScript プ
リンターが用意されていれば, lp Meta.ps あるいはlpr Meta.ps
で印刷できるはずです。

• カラーのまま印刷したい場合は、-i というオプションをつけて Illustrator
形式に変換します。その場合、Meta.i00 のようなファイル名になります。
• -v はポートレート形式にするという意味ですが、BoundingBox がかなりおかしな値になるので、-v をつけずに変換して、後から必要に応じて回転する方が良いかもしれません。例えば LATEX に取り組む場合は、\usepackage[dvips]{graphicx}...
\includegraphics[angle=90,width=10cm]{Meta.i00}のように angle=90 とします (angle= と width= の順番には意味があります)。

• g out の作る PostScript には、一応 BoundingBox コメントはついていますが、(余白が大きかったりして) 値は使い物になりません。そうして作られた
PostScript ファイルも、ps2epsi (あるいは ps2eps — 紛らわしい名前！) というプログラムで (まあまあまともな) BoundingBox のついた EPS 形式に変換できます。

こんな感じ

knoppix% g_out -i Meta
knoppix% ps2epsi Meta.i00
knoppix% ggv Meta.i00.epsi(表示してチェック)

LATEX への取り込みは\includegraphics[angle=90,width=10cm]{Meta.i00.epsi}• BoundingBox に負の座標が含まれている場合、クリップされて図が欠けたり (特に PDF にした場合)、色々と不都合が起こる場合があります。そういう場合は ps2eps -t=x,y で図を平行移動して (x, y の単位はポイント (1/72インチ) である)、負の値をなくすと良いでしょう。


chronos% ps2eps -t=100,200 Meta.i00


7

Meta.i00.eps というファイルが生成されます。なお、もとのファイルの名
前が Meta.ps だった場合は Meta.eps という名前のファイルの生成されます(元々 .i00 が風変わりな名前ということなのでしょう)。
• (2012 年 12 月現在の私のお勧め)

g_out -i Meta
ps2eps Meta.i00






\includegrahics[angle=90,width=10cm]{Meta.i00}

人にもらった or ずっと昔に作った (メタファイルが残っていない) PostScript
ファイルに負の座標の BoundingBox が含まれていたら、ps2eps -t=100,200
Meta.i00 とします。\includegraphics 時に angle= を指定するかどうかは、もちろんデータに依ります。

• (2015 年 4 月現在の私のお勧め — 今さら)

g_out -i Meta
ps2eps -f -R=- Meta.i00






\includegrahics[angle=90,width=10cm]{Meta.i00.eps}

画像の回転は g out の -v オプションではなく、\includegraphics[] のangle= オプションでもなく (LaTeX2HTML と相性が悪い)、ps2eps の -R=
オプションを使うのが一番スッキリする。いくつか試した限りでは、座標の平行移動の必要もないみたい。

4

GLSC のサンプル・プログラム

4.1

何をするプログラムかありきたりですが、1 変数関数のグラフを描くプログラム例を示します8 。0 次
Bessel 関数 j0() の −10π ≤ x ≤ 10π の範囲のグラフを描きます。
8

グラフを描く目的でしたら、gnuplot などを使う方が便利です。あくまでも GLSC の解説用のプログラムです。

8

Bessel function J0(x) (-31.4159<=x<=31.4159)

4.2

ソースプログラム draw-graph.c

以下のプログラムは http://nalab.mind.meiji.ac.jp/~mk/labo/howto/glsc-progs/に置いてあります (curl -O http://nalab.mind.meiji.ac.jp/ mk/labo/howto/glsc-progs/dra
で入手可能)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/*
* draw-graph.c -- 1 変数関数のグラフを描く*
コンパイル: ccmg draw-graph.c*/#include <stdio.h>#include <math.h>#define G_DOUBLE#include <glsc.h>double pi;
int main()

9

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

{
int i, n;double a, b, c, d;double h, x;
double f(double);char title[100];
double win_width, win_height, w_margin, h_margin;
pi = 4 * atan(1.0);/* 表示する範囲 [a,b] × [c,d] を決定 */a = - 10 * pi; b = 10 * pi; c = - 2.0; d = 2.0;/* 区間の分割数 n */n = 200;/* GLSC の開始
メタファイル名、ウィンドウ・サイズの決定 */win_width = 200.0; win_height = 200.0; w_margin = 10.0; h_margin = 10.0;
g_init("GRAPH", win_width + 2 * w_margin, win_height + 2 * h_margin);/* 出力デバイスの決定 */g_device(G_BOTH);/* 座標系の定義: [a,b] × [c,d] という閉領域を表示する */g_def_scale(0,a, b, c, d,
w_margin, h_margin, win_width, win_height);/* 線を二種類用意する */g_def_line(0, G_BLACK, 2, G_LINE_SOLID);
g_def_line(1, G_RED,
0, G_LINE_SOLID);/* 表示するための文字列の属性を定義する */g_def_text(0, G_BLACK, 3);/* 定義したものを選択する */g_sel_scale(0); g_sel_line(0); g_sel_text(0);/* 座標軸を描く */g_move(a, 0.0); g_plot(b, 0.0);
g_move(0.0, c); g_plot(0.0, d);/* タイトルを表示する */sprintf(title, "Bessel function J0(x)g_text(20.0, 10.0, title);/* 刻み幅 */h = (b - a) / n;10(%g<=x<=%g)", a, b);

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

/* グラフを描くための線種の選択 */g_sel_line(1);/* 折れ線でグラフを描く */g_move(a, f(a));
for (i = 1; i <= n; i++) {x = a + i * h;g_plot(x, f(x));}/* ユーザーのマウス入力を待つ */printf("終りました。X の場合はウィンドウをクリックして下さい。\n");g_sleep(-1.0);/* ウィンドウを閉じる */g_term();return 0;}
double f(double x){/* 0 次 Bessel 関数 */return j0(x);}4.3

読んでみよう4.3.1

GLSC を利用するための宣言#define G_DOUBLE#include <glsc.h>


4.3.2



どれが GLSC の命令か？

GLSC の関数はすべて、名前の先頭が g となっています。g init(), g device(),g def scale(), g def line(), g def text(), g sel scale(), g sel line(), g sel text(),
g text(), g move(), g plot(), g sleep(), g term() という関数を使っています。

4.3.3

ウィンドウのサイズ

ウィンドウのサイズは直接数値を書き込むと分かりづらくなるので、win width+ 2 * w margin, win height + 2 * h margin のような式で表わしました。ここ11

で win width, win height はそれぞれ表示領域の幅と高さで、w margin, h height
はウィンドウの縁に用意する余白 (マージン) の大きさです。具体的な値は


win_width = 200.0; win_height = 200.0; w_margin = 10.0; h_margin = 10.0;として与えています。こうして定めたウィンドウのサイズを

g_init("GRAPH", win_width+ 2 * w_margin, win_height + 2 * h_margin);として GLSC に指示しています。ここで "GRAPH" は「メタファイル」の名前です。これは描画した図形の情報をファイルに記録する場合にはファイル名として採用されるものです。

4.3.4

出力先

g device() によって、どこに出力するか指定します。選択肢は G NONE (出力しない), G DISP (ディスプレイ), G META (メタファイル), G BOTH (ディスプレイとメ
タファイルの両方) の 4 つです。サンプル・プログラムでは

g_device(G_BOTH);として、画面にも表示するし、ファイルにも記録するように指定しています。

4.3.5

座標系の定義「表示したい対象物の世界」における座標と出力デバイス (画面等) の座標との関係を定義する必要がありますが、これは、辺が座標軸に平行な長方形 (表示領域) を、二つの世界それぞれにおいて指定することで実現されます。
出力デバイスにおける長方形は、ウィンドウの左上隅の頂点からの余白 (水平方向, 垂直方向) と、長方形の辺の長さ (横、縦) の 4 つの数値を使って、指定されます。サンプル・プログラムでは、これらの値は w margin, h margin, win width,
win height という変数に記憶されています。
「表示したい対象物の世界」における長方形は、プログラムの中の変数 a, b, c,d を用いて定義できる [a, b] × [c, d] です。
これらの情報を関数 g def scale() に渡すことになります。

12





/* 座標系の定義: [a,b] × [c,d] という閉領域を表示する */g_def_scale(0,a, b, c, d,
w_margin, h_margin, win_width, win_height);

第 1 の引数である 0 は、座標系の番号を表わします。実は GLSC では、一度に複数の座標系を定義しておいて、必要に応じて番号を使って呼び出すことができるようになっています。

4.3.6

線種、文字種の定義

描画に用いる線には、色、太さ、パターン (実線なのか点線なのか破線なのか)などの属性を持っています。GLSC では、これらの属性を備えた線種を定義する
ことができます。
/* 線を二種類用意する */g_def_line(0, G_BLACK, 2, G_LINE_SOLID);
g_def_line(1, G_RED,
0, G_LINE_SOLID);

同様に文字列を表示する場合の文字も、色と大きさの属性を持ち得ます。

/* 表示するための文字列の属性を定義する */g_def_text(0, G_BLACK, 3);




4.3.7

定義しておいた座標系、線種、文字の呼び出し

これは簡単で g sel 某 () という関数に番号を与えて呼び出すだけです。

/* 定義したものを選択する */g_sel_scale(0); g_sel_line(0); g_sel_text(0);




13

4.3.8線分を描く、グラフを描く

GLSC では、XY プロッター9 風の、「現在点から指定した点までの線分を引く」という機能を持った関数 g plot(double x, double y) が用意されています。線
を描かずに現在点のみを移動する機能の関数 g move(double x, double y) と一緒に使うことで、自由に線分が描けます。
例えば x 軸を表示する目的で、サンプル・プログラムでは二点 (a, 0), (b, 0) を端点とする線分を

g_move(a, 0.0);

g_plot(b, 0.0);として描いています。
g move(), g plot() のような関数があるときに、1 変数のグラフを描く手順は、次のようになります (定跡的であると言って良いでしょう)。
/* 折れ線でグラフを描く */g_move(a, f(a));
for (i = 1; i <= n; i++) {x = a + i * h;g_plot(x, f(x));
}

4.3.9



マウスの入力待ち

何かを見せる目的のプログラムでは、ユーザーが好きな間だけ見ていられるよ
うに、他に何もしないで「待つ」ことが必要になります。GLSC ではそのために
g sleep(double t) という関数が用意されています (t として待ち時間を秒を単位として与えます)。
g_sleep(-1.0);のように t として負の数を与えると、「ユーザーが GLSC のウィンドウをマウスでクリックされるまで待つ」ことになります。

9

今では XY プロッターと言っても目にする機会がなくなってしまったが、紙の上にペンをアームで動かすことにより、2 次元の線画を描く機械であった。現在ペンのある位置 (2 次元的な) が「現在点」のわけである。

14

4.3.10

終了 (ウィンドウの削除)

描画用のウィンドウを削除するには単に

g_term();とするだけです。

5

GLSC+ について

5.1

その目的

当数学科での GLSC 利用の「歴史」も結構長くなって来ました。最初のうちは
GLSC をオリジナルのままに使っていたのですが、しばしば等高線や鳥瞰図を描
く関数が使いづらいと感じていました。その理由は、GLSC が C 言語で書かれているため、Fortran のような整合配列が利用できないためと言えるでしょう。格子
点上の数値データや行列のような二重添字を持つ数列を二次元配列ではなく、長い 1 次元配列に (ユーザーが自分の責任で) 詰め込んで扱うのは、本質的でない複雑さが生じます。
そこで、長い 1 次元配列の代わりに

typedef G_REAL **matrix;として定義した、G REAL へのポインターのポインター (matrix 型) を使ったインターフェイス (C 言語用) を用意しました。

5.2

インストールの仕方

http://nalab.mind.meiji.ac.jp/~mk/program/graphics/glsc+2.tar.gz を
入手する。






tar xzf glsc-3.5.tar.Z
tar xzf glsc+2.tar.gz -C glsc-3.5
cd glsc-3.5
cat README_GLSC+

後は README GLSC+ の指示に従って下さい (最後の vi Makeﬁle は emacs Makeﬁle
かも)。

15



5.3

新しく導入した関数

とにかく 2 変数関数のグラフの鳥瞰図と等高線が描ければよい、と考えたので、次の 3 つだけです。

1. g hidden2()
2. g fake hidden2()
3. g contln2()
使い方は名前の末尾に 2 がついていない関数とほとんど同じです。ただ一点 G_REAL
へのポインターでなく、G_REAL へのポインターのポインターを引数として受け取るところが異なります。

5.4

サンプル・プログラム・ソース/** test-contln2.c*
cc test-contln2.c -lmatrix -lglscd -lX11 -lm*/#define G_DOUBLE#include <stdio.h>#include <math.h>#include "glsc.h"#include <matrix.h>#define W0 80.0
#define H0 80.0
#define W1 80.0
#define H1 80.0
#define W_MARGIN 10.0
#define H_MARGIN 10.0
double pi;
void compute(double (*)(), matrix,
double, double, double, double,
int, int);
double f(double, double);double max(double x, double y) { return (x > y) ? x : y; }int main(){
int m, n, k;

16

double xmin, xmax, ymin, ymax, f();matrix u;
pi = 4 * atan(1.0);/* 分割数 */m = 100; n = 100;/* 定義域は [-π, π] × [-π, π] */xmin = - pi; xmax = pi; ymin = - pi; ymax = pi;/* 格子点における数値を納める変数 */if ((u = new_matrix(m+1,n+1)) == NULL) {fprintf(stderr, " 行列のためのメモリーが確保できませんでした。\n");return 1;}/* GLSC */g_init("Meta", W0 + W1 + 3 * W_MARGIN, max(H0, H1) + 2 * H_MARGIN);
g_device(G_BOTH);/* ウィンドウ 0 */g_def_scale(0,xmin, xmax, ymin, ymax,
W_MARGIN, H_MARGIN, W0, H0);
g_def_scale(1,xmin, xmax, ymin, ymax,
W_MARGIN + W0 + W_MARGIN, H_MARGIN, W1, H1);/* */g_def_line(0, G_BLACK, 0, G_LINE_SOLID);
g_def_text(0, G_BLACK, 2);/* 定義したものを呼び出す */g_sel_scale(0);g_sel_line(0);g_sel_text(0);/* title */g_text(W_MARGIN + W0 * 0.6, H_MARGIN / 2, "contour and bird view");/* 格子点上での関数値を計算する */compute(f, u, xmin, xmax, ymin, ymax, m, n);/* 等高線 */for (k = -10; k <= 10; k++)g_contln2(xmin, xmax, ymin, ymax, u, m+1, n+1, 0.1 * k);/* 鳥瞰図 */g_hidden2(1.0, 1.0, 0.4,
-1.0, 1.0,/* 視点 (距離, 方角を表わす (θ, φ) ) */5.0, 30.0, 30.0,
W_MARGIN + W0 + W_MARGIN, H_MARGIN,
W1, H1,u, m + 1, n + 1, 1,
G_SIDE_NONE, 2, 1);17printf("終了したらウィンドウをクリックして終了してください。\n");g_sleep(-1.0);
g_term();return 0;}/** [xmin,xmax] × [ymin,ymax] を x 軸方向に m 等分、y 軸方向に n 等分して* 各格子点上の f の値を u に格納する。
*/
void compute(double (*f)(), matrix u,
double xmin, double xmax, double ymin, double ymax,
int m, int n){
int i, j;double dx, dy, x, y;
dx = (xmax - xmin) / m;dy = (ymax - ymin) / n;for (i = 0; i <= m; i++) {x = xmin + i * dx;for (j = 0; j <= n; j++) {y = ymin + j * dy;u[i][j] = f(x, y);}}}double f(double x, double y){return sin(x) * sin(y);}contour and bird view18

よく使う関数の説明

Ag init

書式 g init(char *filename, G REAL window width, G REAL
window height)
機能 GLSC の初期化を行なう。
ﬁlename はメタファイルの名前。window width, window height はウィン
ドウのサイズ (単位は mm)。
例g_init("Meta", 340.0, 220.0);








g device

書式 g device(int device)
機能 出力先デバイスを指定する。
device は出力先を指定する数値。以下の定数がインクルード・ファイルに定義されている。
G NONE 出力しない
G META メタファイル
G DISP 画面
G BOTH 画面とメタファイル


例




g_device(G_BOTH);





19


g def scale

書式 g def scale(int scale id,
G REAL x left, G REAL x right, G REAL y bottom,
G REAL y top,
G REAL left margin, G REAL top margin, G REAL
width, G REAL height)
機能 座標変換を定義する。
scale id は座標変換につける番号 (複数定義して、番号で区別することができる)。ユーザー座標系の [xleft , xright ] × [ybottom , ytop ] という長方形閉領
域を [left margin, left margin+width]×[top margin, top margin+height]という長方形閉領域に写像する。


例




g_def_scale(0, -1.6, 1.6, -1.0, 1.0,
10.0, 10.0, 320.0, 200.0);



20





g def line

書式 g def line(int line id, int color id, int line width, int
line type)
機能 線 (というよりはペン) を定義する。
line id は線につける番号 (複数定義して、番号で区別することができる)。
色が color id、太さが line width, 種類が line type の線に line idという番号をつける。

• 色としてはG BLACKG RED
G GREEN
G BLUEG MAGENTA
G YELLOWG CYANG WHITE
が使える。

黒
赤
緑
青
マゼンタ (赤紫)黄シアン (澄んだ青緑色、赤の補色)
白

0
1
2
3
4
5
6
7

• 線の太さは 0 から 3 まで。0 と 1 は太さ同じだが 0 の方が速い。
• 線種としてはG LINE SOLID
G LINE DOTS
G LINE DASHEDG LINE LONG DASHEDG LINE THIN DOTS
G LINE DOT DASHEDG LINE D DOT DASHED

実線



例




g_def_line(0, G_BLACK, 0, G_LINE_SOLID);





21


g cls



書式 g cls()
機能 画面の消去を行なう (これまでに描かれたものを削除する)。
例



g_cls();


g sleep

書式 g sleep(G REAL time)
機能 time が正の場合、time 秒停止する。time が負の場合、マウスをクリックするまで停止する。
例

g_sleep(-1.0); /* マウスをクリックするまで待つ */








g term

書式 g term()
機能 GLSC を終了する。


例


B



g_term();

PostScript への変換 (g out に関するノウハウ)(3 「印刷の仕方 (g out の使い方)」を読むことをお勧めします。)
関数 g init() の第一引数で指定した「メタファイル」には、描画した図形データの内容が記録されていて、コマンド g out により、PostScript 形式に変換できる。
-v を指定するとポートレイト形式になる。ただし PostScript に変換後の座標が負になったりするので、使わないほうが無難かもしれない (ps2epsi に失敗するよ
うになる原因となる？PDF にすると図が欠ける？)。TEX で \includegraphics
を用いて取り込む場合には、

22





\includegraphics[width=10cm,angle=90]{mygraph.i00}のように angle=角度 オプションで回転できるので、あえて中途半端な -v オプ
ションに頼る必要はないかもしれない (私は最近は使わなくなりました)。
出来上がった PostScript ファイルの BoundingBox コメントは、“A4 紙 1 枚全部” というものらしく、LATEX に取り込むには余白が生じるのが普通で不適当なので、ps2epsi コマンドで直すか、ghostview などで表示させて測った値をテキスト・
エディターで書き込むのがよい。
特に -i オプションを指定すると、Adobe のイラストレーター形式でセーブされるという。これも一種の PostScript であることに違いはないが、カラーで描いた図がモノクロのデータに変換されることがないので、色つきの画像データを作るときに使える。また、複数ページからなるメタファイルが、1 ページ毎のばらばらのファイルに変換されることも、場合によっては便利である。
線の太さや文字の大きさなどの情報は、PostScript に変換すると消えてしまうが、例えば使用している文字をすべて大きくして構わないのならば、直接 PostScript
ファイルを編集して直すことが比較的容易である。
熱方程式や波動方程式のような発展系の数値計算結果を可視化した場合、一つのメタファイルに複数の図が記録される。このとき、一枚の紙に複数の図を連ねて表示する「紙芝居」を作るには、-f 行の数, 列の数 と-m 倍率 というオプショ
ンを使うとよい。例えば


g_out -vfm 4,3 0.4 Metaとすると、1 ページあたり 4 段 (行？) 3 列、全部で 12 の図が入った PostScript
ファイルが出来る。

C

桂田研学生向け

桂田研の学生にはおなじみの heat1d-e.c の GLSC 版です。
/*
* heat1d-e-glsc.c -- 1 次元熱伝導方程式の初期値境界値問題を陽解法で解く。
*
コンパイル: ccmg heat1d-e-glsc.c** オリジナルは fplot ライブラリィを利用した* http://www.math.meiji.ac.jp/%7Emk/program/fdm/heat1d-e.c*/

23

#include <stdio.h>#include <stdlib.h>#include <math.h>#define G_DOUBLE#include <glsc.h>
int main(){
int i, n, nMax, N;
double tau, h, lambda, Tmax;
double *u, *newu;
double f(double);double win_width, win_height, w_margin, h_margin;
char message[100];/* N, λ を入力する */printf("区間の分割数 N = "); scanf("%d", &N);
printf("λ (=τ/h^2) = "); scanf("%lf", &lambda);/* h, τ を計算する */h = 1.0 / N;
tau = lambda * h * h;printf("τ=%g\n", tau);/* 最終時刻を入力する */printf("最終時刻 Tmax = "); scanf("%lf", &Tmax);/* ベクトル u, newu を用意する */u = malloc(sizeof(double) * (N+1));
newu = malloc(sizeof(double) * (N+1));/* 初期値の代入 */for (i = 0; i <= N; i++)u[i] = f(i * h);/* ***************** グラフィックスの準備 ***************** *//* メタファイル名は "HEAT",* ウィンドウのサイズは、
横 win_width + 2 * w_margin, 縦 win_height + 2 * h_margin */win_width = 200.0; win_height = 200.0; w_margin = 10.0; h_margin = 10.0;
g_init("HEAT", win_width + 2 * w_margin, win_height + 2 * h_margin);/* 画面とメタファイルの両方に記録する */g_device(G_BOTH);/* 座標系の定義: [-0.1,1.1] × [-0.1,1.1] という閉領域を表示する */g_def_scale(0,-0.1, 1.1, -0.1, 1.1,
w_margin, h_margin, win_width, win_height);/* 線を二種類用意する */24

g_def_line(0, G_BLACK, 0, G_LINE_SOLID);
g_def_line(1, G_BLACK, 0, G_LINE_DOTS);/* 表示するための文字列の属性を定義する */g_def_text(0, G_BLACK, 3);/* 定義したものを選択する */g_sel_scale(0); g_sel_line(0); g_sel_text(0);/* タイトルと入力パラメーターを表示する */g_text(30.0, 30.0,"heat equation, homogeneous Dirichlet boundary condition");sprintf(message, "N=%d, lambda=%g, Tmax=%g", N, lambda, Tmax);
g_text(30.0, 60.0, message);/* 座標軸を表示する */g_sel_line(1);g_move(-0.1, 0.0); g_plot(1.1, 0.0);
g_move(0.0, -0.1); g_plot(0.0, 1.1);
g_sel_line(0);/* t=0 の状態を表示する */g_move(0.0, u[0]);for (i = 1; i <= N; i++)g_plot(i * h, u[i]);/* ループを何回まわるか計算する (四捨五入) */nMax = rint(Tmax / tau);/* 時間に関するステップを進めるループ */for (n = 0; n < nMax; n++) {/* 差分方程式 (n -> n+1) */for (i = 1; i < N; i++)newu[i] = (1.0 - 2 * lambda) * u[i] + lambda * (u[i+1] + u[i-1]);/* 計算値を更新 */for (i = 1; i < N; i++)u[i] = newu[i];/* Dirichlet 境界条件 */u[0] = u[N] = 0.0;/* この時刻 (t=(n+1) τ) の状態を表示する */g_move(0.0, u[0]);for (i = 1; i <= N; i++)g_plot(i * h, u[i]);}printf("終りました。X の場合はウィンドウをクリックして下さい。\n");g_sleep(-1.0);/* ウィンドウを閉じる */g_term();return 0;}25

double f(double x){
if (x <= 0.5)
return x;
else
return 1.0 - x;}

Cygwin+XFree86 環境での利用

D

個人的に GLSC がすごいと思うのは、X の基本的な機能しか使っていないので(その点非常に禁欲的です)、様々なシステム (GLSC の開発後に登場してきたもの
でも) に対して、無修整あるいは非常に微弱な修正で利用できるようになることです。
最近、普及してきた Cygwin+XFree86 という環境でもごく簡単に利用できます。
自力で make するのも簡単ですが、バイナリーを用意しました。http://nalab.
mind.meiji.ac.jp/~mk/labo/cygwin/cygwin-glsc+.tar.gz から cygwin-glsc+.tar.gzを入手して、

tar xzf cygwin-glsc+.tar.gz -C /usr/local

のように展開すれば使えるようになります (ヘッダー・ファイルを /usr/local/include,
ライブラリィ・ファイルを /usr/local/lib に格納します。コンパイルは /usr/local/bin/ccmgというスクリプトで可能です。スクリプトを見ればコンパイル&リンクの仕方が分かるでしょう)。
(2006/6/12 追記) Cygwin 環境だと、glscwin の方が便利かも知れません。次の節で解説します。

E

glscwin について

E.1

誰が作ったもの？入手するには？

オリジナル GLSC の開発者の一人である高橋大輔氏の研究室によって、GLSC
が Win32 環境10 に移植されたものが glscwin です。
10

具体的な OS の名前で言うと、Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000 のことを指します。

26

しばらく公開をやめたように思っていたのですが高橋大輔研究室11 の講義のページにあるのを見つけました。「数値計算法 A12 内に glscwin-20070914.zip13 が置かれています。またマニュアル glscm.zip14 もあります。
龍谷大学にあるページ

http://sparrow.math.ryukoku.ac.jp/~junta/edu/nc2000/glscman/glscm.html
は説明を読むのに重宝しています。

E.2

特徴

glscwin にはオリジナルの GLSC にはない利点が色々あります。
(1) 画像を EMF (Enhanced Meta File) 形式で出力可能。
(Windows で表示が出来、動画を連番ファイルで出力しておくと、紙芝居というか簡易アニメーションが出来る — 何を言っているのか分からないかも。百聞は一見に如かずなのだが…)(2) マウスのイベントを扱える。
(3) 使える色が多い (いわゆるフルカラー)
例えば g density plot color() という、2 変数関数のレベルを色で塗り分ける関数があって便利です。
明治大学数学科の 6701 号室の Windows パソコンには、glsc ver0.82.lzh をインストールしてあります。コンパイルには、/usr/local/?/cglscs, /usr/local/?/cglscdというスクリプトを使うと良いでしょう。

11

http://hakotama.jp/
http://hakotama.jp/report/SuuchiKeisanHouA/
13
http://hakotama.jp/report/glscwin/glscwin-20070914.zip
14
http://hakotama.jp/report/glscwin/glscm.zip
1227図 1: sin πx sin πy を g density plot color() で見る

28


glscd



#!/bin/sh
GLSCDIR=/usr/local/glscwin-ver0.82
KANJI="-finput-charset=cp932 -fexec-charset=cp932"#CFLAGS="-W -Wall -O -DG_DOUBLE -I$GLSCDIR/include"
CFLAGS="-O -DG_DOUBLE -I$GLSCDIR/include"
LDFLAGS="-L$GLSCDIR/lib -lglscd -luser32 -lgdi32 -lwinmm -lcomdlg32 -lcomctl32 -lm"
prog=‘basename $1 .c‘
gcc $KANJI $CFLAGS -o $prog "$@" $LDFLAGS


E.3



C++ で glscwin を利用する

ずっと以前に書いたメモ 『glscwin を C++ プログラムから使う』15 を読んで下さい (無保証です)。

E.4

インストール・メモ

手元に glscwin 0.82.lzh というファイルがある。

まずはばらす

mkdir glscwin_0.82
cd glscwin_0.82
lha x ../glscwin_0.82.lzh


15



http://nalab.mind.meiji.ac.jp/~mk/labo/howto/GLSCWIN_C++.txt

29


glsc ext.c の修正

mathpc% diff -c glsc_ext.c.org glsc_ext.c*** glsc_ext.c.org
Mon Jun 28 03:30:28 1999--- glsc_ext.c Tue May 20 23:32:29 2008****************** 797,803 ****
g_area_rgb(c.r, c.g, c.b);}/***************************************/! double g_color_gen_func(x)/***************************************/
G_FLOAT x;{--- 797,803 ---g_area_rgb(c.r, c.g, c.b);}/***************************************/! G_FLOAT g_color_gen_func(x)/***************************************/
G_FLOAT x;{
mathpc%




30


コンパイルしてライブラリィ・アーカイブ・ファイルを作る

mathpc% cat make.sh#!/bin/sh#CFLAGS=-W -Wall
gcc $CFLAGS -c -O glsc.c
gcc $CFLAGS -c -O glsc_ext.c#gcc $CFLAGS -c -O glsc_win.c
gcc $CFLAGS -c glsc_win.c
gcc $CFLAGS -c -O ezfont.c
ar cru libglscs.a glsc.o glsc_ext.o glsc_win.o ezfont.oranlib libglscs.a
gcc $CFLAGS -c -O -DG_DOUBLE glsc.c
gcc $CFLAGS -c -O -DG_DOUBLE glsc_ext.c#gcc $CFLAGS -c -O -DG_DOUBLE glsc_win.c
gcc $CFLAGS -c -DG_DOUBLE glsc_win.c
gcc $CFLAGS -c -O ezfont.c
ar cru libglscd.a glsc.o glsc_ext.o glsc_win.o ezfont.oranlib libglscd.amathpc%glsc win.c だけコンパイルに -O をつけていないが、

while (TRUE) {if (w_lbutton_down == G_YES) {break ;}}というくだりがあるからである。volatile する方が正しいか？

31






倍精度ライブラリィとコンパイル＆リンクするためのスクリプト例— cglscd #!/bin/sh
GLSCDIR=/usr/local/glscwin-ver0.82
KANJI="-finput-charset=cp932 -fexec-charset=cp932"#CFLAGS="-W -Wall -O -DG_DOUBLE -I$GLSCDIR/include"
CFLAGS="-O -DG_DOUBLE -I$GLSCDIR/include"
LDFLAGS="-L$GLSCDIR/lib -lglscd -luser32 -lgdi32 -lwinmm -lcomdlg32 -lcomctl32 -lm"
prog=‘basename $1 .c‘
gcc $KANJI $CFLAGS -o $prog "$@" $LDFLAGS


E.5



サンプル

以下のプログラムは http://nalab.mind.meiji.ac.jp/~mk/labo/howto/glsc-progs/に置いてあります。

/** testdensity.c --- g_density_plot_color() のテスト*
GLSCWIN が必要です。
*
桂田研パソコンならば glscd testdensity.c でコンパイル可能*/#include <stdio.h>#define G_DOUBLE#include <glsc.h>#define N (100)double pi;
double f(double x, double y){return sin(pi * x) * sin(pi * y);}
int main()32

{double xmin, xmax, ymin, ymax, w_margin, h_margin, w_width, w_height;
G_REAL u[N+1][N+1];
int i, j, n, nx, ny;
double x, y, dx, dy;nx = ny = N;
pi = 4 * atan(1.0);/* 矩形領域を定める */xmin = -1.0; xmax = 1.0; ymin = -1.0; ymax = 1.0;/* ウィンドウのサイズ */w_margin = 1.0; h_margin = 1.0; w_width = 100.0; w_height = 100.0;/* GLSC の開始 */g_init("DENSITY", w_width + 2 * w_margin, w_height + 2 * h_margin);g_device(G_BOTH);/* 座標系を決める */g_def_scale(0,xmin, xmax, ymin, ymax,
w_margin, h_margin, w_width, w_height);
g_sel_scale(0);/* 格子点上での関数値の計算 */dx = (xmax - xmin) / nx;
dy = (ymax - ymin) / ny;for (i = 0; i <= nx; i++) {x = xmin + i * dx;for (j = 0; j <= ny; j++) {y = ymin + j * dy;u[i][j] = f(x,y);
}
}
/* */
g_density_plot_color((G_REAL *)u, nx + 1, ny + 1, 0, nx, 1, 0, ny, 1,
G_NO, G_NO,
xmin, xmax, ymin, ymax,-1.0, 1.0);33

g_sleep(-1.0);
g_term();return 0; // もしマウス・クリックだけで終了したいのならば exit(0); とする。
}

EMF について

E.6

glscwin で作ったファイルは、拡張子が .emf のいわゆる Windows メタファイ
ルである。
• Windows 標準のコマンド、例えばペイントでも扱える。
• 他のイメージ・フォーマットに変換するには、Windows 版 ImageMagick のconvert を使えば良い (Windows 版でないとダメのようである)。


set path=(/cygdrive/c/Program\ Files/ImageMagick-6.2.8-Q16 $path)convert -geometry "25%" mygraph.emf mygraph.jpg
• PostScript に変換するには、convert でも可能であるが、シェアウェアのWMF2EPS16 を使うこともできる。

E.6.1

wmf2eps のインストール

1. http://www.wmf2eps.de.vu/ から入手する。2008 年 10 月 12 日現在、WMF2EPS1.32.ZIP
が最新版である。
2. wmf2eps.exe を適当な場所にコピーして、実行できるようにする。

3. プリンタ “WMF2EPS Color PS L2” をインストールをする。
[プリンタと FAX] → [プリンタのインストール] → [プリンタの種類を指定してください] に対して「このコンピュータに接続されているローカルプリンタ」、[次のポートを使用] に対して「FILE:」を選択、[プリンタ ソフトウェアのインストール] で [ディスクの使用] を選び、WMF2EPS1.32YPSprintYWin2000YStandardYW2kPrint.I
を選択する。
16

http://www.wmf2eps.de.vu/

34

4. プリンタのプロパティの設定
WMF2EPS Color PS L2 のプロパティから、全般→印刷設定→詳細設定を開く。
(a) PostScript オプション→ PostScript 出力オプションを “EPS(Encapsulated
PostScript)” にする。
(b) グラフィックスの印刷品質は “1200dpi”(c) TruType フォントは “ソフトフォントとしてダウンロード”(d) TruType フォントダウンロードオプションは “自動”
以上は、17 を参考にした。
なお、古いフリーのバージョンがあり、Windows 2000, Windows XP でも使えるらしい。「wmf2eps の旧バージョンを Win2k で使う方法」18 を見よ。

F

有向線分 (矢印) の描画/** arrow.c --- 有向線分の描画*/#include <stdio.h>#include <math.h>#define G_DOUBLE#include <glsc.h>/* ------------------------------------------------------------- *//* π, 度とラジアンの換算用の比 */double arrow_pi, arrow_degree;
int arrow_initialized = 0;
void init_arrow(){arrow_initialized = 1;arrow_pi = 4 * atan(1.0); arrow_degree = arrow_pi / 180.0;}/* 有向線分 (矢印のある線分) を描く */void arrow(double p1, double p2,
double q1, double q2,
double lambda)
1718

http://www.bunmeisha.co.jp/LaTeX2e/latex2e_eps.html
http://rakasaka.fc2web.com/tex/tex.html

35

{
double e1, e2, norm;
double fl1, fl2, fu1, fu2, theta, cost, sint;double qu1, qu2, ql1, ql2, r1, r2, t;
double phi;double vx[5], vy[5];int fill;if (!arrow_initialized)
init_arrow();/* */theta = 15.0 * arrow_degree; phi = 30.0 * arrow_degree;/* e=(p-q)/||p-q|| */e1 = p1 - q1; e2 = p2 - q2; norm = hypot(e1, e2);
e1 /= norm; e2 /= norm;/* fl = λ R(θ) e */cost = cos(theta); sint = sin(theta);
fl1 = lambda * (cost * e1 - sint * e2);fl2 = lambda * (sint * e1 + cost * e2);/* fu = λ R(-θ) e */fu1 = lambda * ( cost * e1 + sint * e2);
fu2 = lambda * (- sint * e1 + cost * e2);/* ql = q + fl */ql1 = q1 + fl1; ql2 = q2 + fl2;/* qu = q + fu */qu1 = q1 + fu1; qu2 = q2 + fu2;/* r = q + λ cos θ (1-tan θ/tan φ)e */t = lambda * cost * (1 - tan(theta) / tan(phi));r1 = q1 + t * e1; r2 = q2 + t * e2;/* */vx[0] = q1; vy[0] = q2;
vx[1] = qu1; vy[1] = qu2;vx[2] = r1; vy[2] = r2;
vx[3] = ql1; vy[3] = ql2;
vx[4] = q1; vy[4] = q2;
g_sel_area(0);fill = G_YES;/* */g_move(p1, p2); g_plot(r1, r2);g_polygon(vx, vy, 5, G_NO, fill);}/* ------------------------------------------------------------- */int main(){g_init("META", 220.0, 220.0);
g_device(G_BOTH);
g_def_scale(0,36-1.0, 5.0, -1.0, 5.0,
10.0, 10.0, 200.0, 200.0);
g_sel_scale(0);/* arrow のために必要 */g_def_area(0, G_BLACK);g_def_line(0, G_BLACK, 3, G_LINE_SOLID);
g_sel_line(0);arrow(1.0, 1.0, 4.0, 1.0, 0.8);
g_sleep(-1.0);
g_term();return 0;}

G

GLSC で改善して欲しい点• ウィンドウの再描画をすること。

言い出しっぺの法則？？？

37