13. Graphics Classes
"A language that doesn't change the way you think isn't worth learning."
逆に言うと僕たちは自分が考えていると思っているけど、本当は言語こそが主であり、僕たちは寄生された哀れな生き物なのかも。。。。こわー、、、、、、いけどそれでいいや。
この章は各クラスについて設計や実装をみていきます。
13.1 Oerview of graphics classes
- グラフィックスやGUIライブラリというのは巨大になりがち
- 数百ものクラスや何十個もの関数とか
- マニュアルが古臭い植物学の教科書みたいに曖昧な分類項目で埋め尽くされてて、、、
- しかしエキサイティングでもあります。機能を見ていくと結構きゃーきゃーできるくらいに
- ただ、どっから始めたら良いものなのか、なのですよね
- 本書で使ってるラッパライブラリはそんなあなたのための緩衝材
- グラフィックスやGUIに必要な主要な概念を抽出しているので、学習にピッタリ。効率的に概念を吸収できます
- 14章を終える頃にはコンセプトも理解できる予定
- 中心となるI/Fクラスは以下のものです
I/Fクラス |
説明 |
Color |
線、テキスト、塗りつぶし色 |
Line_style |
線の描画に使用 |
Point |
スクリーンやウィンドウ上の場所を表す |
Line |
線分。2つのPointからなる |
Open_polyline |
連結されたPointのつらなり |
Closed_polyline |
Open_polylineと同様で更に最後のPointが最初のPointと連結したもの |
Polygon |
交差の無い Open_polyline |
Text |
文字列 |
Lines |
複数の線分の集まり |
Rectangle |
矩形 |
Circle |
円 |
Ellipse |
楕円 |
Function |
任意の1変数関数 |
Axis |
ラベル付の座標軸 |
Mark |
文字でマークされた点 |
Marks |
Markの集まり |
Marked_polyline |
各点がMarkであるようなOpen_polyline |
Image |
ファイル中のビットマップ画像 |
- 15章では更にGUI部品となるようなものを扱います
I/Fクラス |
説明 |
Window |
ウィンドウ |
Simple_window |
Nextボタンによる紙芝居に対応したWindow |
Button |
ボタン |
In_box |
ユーザからの入力用の領域(テキストボックス) |
Out_box |
プログラムからの出力用の領域 |
Menu |
Buttonのvectorアレイ |
- モジュール設計とかは略
- ShapeやWidgetを取って置くための便利クラスも用意しています
- この章はあまり急いで進むべからず。
- コードと生成される絵の対応
- コードリーディングに慣れ、コードがどう動くかを考えるのに慣れてもらう
- コード設計を考えてもらう。特にアイディアをクラスに落とし込む方法. どうしてこうすると上手く行くのか、とかどんな選択がでてくるのか、とか。
- てなわけでゆっくり着実に。
13.2 Point and Line
- 点、それは基本
- 点を定義するというのは、幾何空間をどう考えるか、というのを決めてしまうこと
- ここで使っているのは良くある(x,y)の対で表す方法(12.5にて説明済み)
- Pointは単に int の対を保持するのみ。あとはコンストラクタだけ
struct Point {
int x,y;
Point(int x, int y) : x(x), y(y) { }
Point() : x(0), y(0) { }
};
- あと等価性の演算子 == , != 。これは単に 二つのベクトルの各対が a.x == b.x && a.y == b.y なら trueというやつ
-
- != は !(==) で表しててぐっとー DRYDRY
- Line等の具体的な図形は抽象クラス Shapeを継承する、という良くあるパターンになっている
struct Line : Shape {
Line(Point p1, Point p2);
} ;
- こう書くことで「LineはShapeの一種です」という表明に
- Shapeはベースクラスとか、単にベースとか(親クラスとも)
- 詳細は後の章で。とりあえず Shapeは Lineを定義するのに便利な要素が入っているというイメージです
- LineはPointを2つ用意して作ります
13.3 Lines
- つ、つまらん技だと(ry (もういいって...)
- まあ一本だけってのもあんまり無いかと
Lines x;
x.add(Point(xx1,yy1), Point(xxx1,yyy1))
x.add(Point(xx2,yy2), Point(xxx2,yyy2))
- のような感じに連ねていく
- Line をたくさん使えばいいじゃん ー>
- <ー 複数の線をいっぺんに一塊で扱います、という表明になります
- 例えば、全部の色を変えるとかの時に便利
- 正直それなら Containerクラスを作る方が好み。線だけじゃなくいろんなオブジェクトにそうできるし。
- あ、そうか、「オブジェクトは画面に表示されるものと一対一対応している」っていう表明と矛盾してしまうのか
- gridを表示する例として出ている.
-
- 一本一本の線に名前付きオブジェクトってバカバカしす。なるほどなあ
- Lines::add()はベースクラスのadd()を使って2点を登録するだけ
- この際、ベースクラスの add()は Shape::add()と修飾する必要あり
- draw_lines()が描画コールバック(次の章でやります)
- 実装としては2点ずつ拾っていって(FLTKの場合)fl_line()で線を引いていってるだけ
void Lines::draw_lines() const
{
if (color().bisibility())
for (int i = 1; i< number_of_points(); i+=2)
fl_line(point(i-1).x, point(i-1).y, point(i).x, point(i).y);
}
{
const Point &from = point(i-1), &to =point(i);
fl_line(from.x, from.y, to.x, to.y);
}
-
-
- しませんのこと? (冗長かな?) 個人的にはforチェックに-1が入っても良いからfrom=cur-1ではなくてto=cur+1な概念で書きたい気もします
- color().visibility()で現在設定されているカラーのアルファがとれるのでこれで描画の要不要判定
- 登録されている点が偶数であることのチェックは明確だからいらん、とゆうてるけど・・・
- ここはassert()いれといた方が良いんじゃ? 明確な invariantだと思う。コンパイル時外せば良いんだし, というのが tkuro的意見
- コンストラクタは定義しない。空っぽで初期化、後からadd()のほうが柔軟でいいじゃん、しかも、それ以外の使いかたってまず現実にはないヨ、というご意見。
-
- これ自身はまあどっちとも言えないんだけど、次の台詞はシビれた
- あやしい、と感じたらその新機能を追加してはイケナイ
- 機能の追加は必要になったらいつでもできるが、既に使っている機能の削除は大変困難
13.4 Color
- Colorはこの場合単純に FLTK1.0の FL_Colorをラップしたもの
- enumにてsymbolic nameを規定している。これによってColorクラスの名前空間に色名を閉じ込めています
- この他にさっきもちらっと出てきた透明度(アルファ)をパックしています
- 色を選ぶためにはいくつかの方法があります
- enumによる名前付きカラー、Color::dark_blueみたいな感じ
- パレットカラー(0〜255) 。これはFLTK1.0で規定されている下のようなパレット
- RGBはここではせつめいしませぬ。Exerciseであるらしいけど
- コンストラクタはColor_typeか intかどちらかを引数にとります。内部カラーは メンバの c に入れます。
- 名前が短い、衝突するぞって? いいんです。ここでしか使わないし、外には見えない privateなので。これがprivateの力!
- cは実装である所の Fl_Colorをユーザから隠蔽しています
-
- そしてFl_ColorはウィンドウシステムやOSの色空間を隠蔽してる、と( X11とか Quartzとか W32とか)。タマネギの皮みたい
- 透明度はメンバ vとして定義しています。これも 0〜255
- あと定数メンバとして Color::visible( = 255), Color::invisible( = 0)を用意
- invisibleカラーってなんにつかうのー? と思うかもしれないけど便利なんだなー、とかいう達観者視点
13.5 Line_style
- 色だけじゃないよ線種もだよ、という話
- まあ基本的には Colorと同じようなクラス。特記事項あんまなし
- 実は FLTK1.0では線種をintで表してて
ださいのでこれをラップしているなんて先進的
- むろん新しいバージョンの FLTKではそんな事はありませぬ(カラーも古いFLTKは pseudo color時代のだったので大変古くさいですニ)
- 大抵は線種なんて気にする必要も無い
- なんも指定しないでも、結構イケテル線が引けてるのは デフォルトコンストラクタのお陰だぜ、とか
- Line_styleは 線種と太さの指定ができます
-
- そうか、まだデフォルト引数自体は出てきてないのか・・・
- デフォルトの太さは1です!!!!!
Line_style(Line_style_type ss) :s(ss), w(0) { }
-
- のあーー
- まあ、0のときシステムのデフォルト(大抵は =1 + antialias)なので間違っちゃあいないのですが・・・探究心の強い人がソース見たらビックリする罠が
- あとここで言うの微妙だけど、さっきのLinesだとグルーピングしちゃうのでここの部品の色分けとかできないよーとかいう話してます。なんのこっちゃ
13.6 Open_polyline
- 連結線成分です
- 余談ですが poly とはギリシア語で manyという意味だそうです
- 下記のようにしててですね、
struct Open_polyline : Shape {
void add(Point p){ Shape::add(p); }
};
-
- なんよ? なぜな? なぜ まったく一緒な事するのにオーバーライドしてんのよ、とか言うと
class Shape {
:
protected:
void add(Point p) ;
};
-
- この後に"We don't even need to define a draw_lines() because Shape by default interprets the Points add()ed as a sequence of connected lines."(まあようは「draw_lines()はいらないよー。Shapeのデフォルト実装と一緒だからー」)とか
ほざいてる書いてるのですが、、、
struct Open_polyline : Shape {
void add(Point p) { Shape::add(p); }
void draw_lines() const;
};
-
-
- ........orz
- まあそりゃそうなんだよね、だってpolylineはClosedで無くても内部をfillできるのでそのコードが必要なのですよね
- 実際、外側のLine描画には Shape::draw_lines()しているだけなので、全く嘘でも無いのですが。。ねえ
- きっと教育的配慮なんだようんまちがいないよそうだようん
- おそらくは最初はOpen_polylineにはfillが無かったんじゃないかと妄想。それなりに
いいかげん細部にこだわらず大局を見るMr.Sのことなので、そのときの記憶のまま説明書いたか、または本文書いた後で思いついてコードを直してしまい個体ロケットブースター切り離し仕様になったとかそういう・・・
|
13.7 Closed_polyline
- さっきのヤツに最後の終点と視点をつなぐコードを継承で足しただけ
- というわけで実際その通りのコードになっています
- FLTKの素の部分を隠蔽してるので入れ替えし放題! ということを言いたいそうな
-
- visibility() == false の場合も Open_polyline::draw_lines()呼んでるのがダブルチェックでなかなかに赴き深いんだけど、ひょっとしたらあるのかもしれない。visibility()が無くても表示させなきゃな図形が!(ねーよ)。うーんどっちがいーのか僕にもわかりません
void Closed_polyline::draw_lines() const
{
Open_polyline::darw_lines();
if (color().visibility())
fl_line( ... ...);
}
13.8 Polygon
- Closed_polylineと何が違うっ!?
- どうかく?
- 要するにintersect_line_segmentするかどうか、というだけの話な感じ
- いらんおせっかい?
- 特に説明無いけど、equality checkと代入間違えちゃった!( == or = )の回避策がひっそりとさりげなく入ってたり。Mr.Sの性格的にここは
自慢説明するかと思ってました
- intersect_line_segment()自体は、良くある媒介変数を使った線分の交差判定式そのままです
- いらんおせっかいは、なかなかのパワー食いで、O(N2)だよとか
- しかもそれだけでは「ポリゴンです」と言い切るのは不十分で、例えば2点以下のポリゴンとかありえへん、という話
- ポリゴンの普遍条件が、困った事にポリゴンのすべての点がわかるまでわからない、というのが原因
- 実はこれに関する問題がまだあって、(1)「全部一直線上に並んでしまった」と(2)「前の点と同じ場所」というケース
- これ実地では微妙な気が。。。
- (1)コード中では全ポイントを調べるのは重過ぎ、という判断からか直前の2点との関係だけ調べてるので、例えばマウスクリックで順に点を作る場合に一回でも直前の辺とparallelなだけではねられてしまう
- (2)にも同様な問題が。
13.9 Rectangle
- 最も基本的な図形らしい
- 大抵のGUIシステムでは、良く使う、ということと、実装の容易性から、多角形描画とは別に矩形描画機能を持たせる場合が多い
- コンストラクタは二点指定(対角線)か、視点+(縦、横)かのどちらか
- sanity checkもしてますよ、とか
- fill_color指定なしだと透明になりますよ、とか
- move()もできます
- ついでにここでreorderingについて書いてる
- 基本的にはテーブルに紙を置いていくように後から書いたものが上、という説明方法。いわゆるペインターズアルゴリズムですね
- Window::put_on_top(Shape&)で一番上に持っていく事もできるみたい。これはおそらくリニアサーチして見つかったヤツをvectorの一番後ろにもっていくのですね。。。ってその通りだった (>>Window.cpp)
- あとは外枠を書かなくするには Color::invisibleを指定して、とか言う話
- FLTK内部では fl_rectf()(塗りつぶし)、fl_rect()(枠だけ)と言う風にAPIが分かれてるらしいですが、まあ些末な事ですね。Mr.S的にはこれがmessyらっしー