PPPUC++#14

12. A Display Model

"The world was black and white then. [It] didn't turn color until sometime in the 1930s."
漫画カルビン&ホッブスでの父との会話ですね。「なんで昔の写真は白黒なの?」というカルビンの質問に対するもの。
「で、じゃあなんで(1930年になってから)写真も色つきにならなかったの?」「そりゃあ簡単さ、それは白黒の世界を撮ったカラー写真だからさ」
こんなとーちゃんでいたいです(迷惑)

12.1 Why Graphics?

  • グラフィックスの本でも無いのになぜ4章分もGUI?
    • プログラミングの重要な部分を浮き彫りにするテーマなのです
      • ほんまデスか?
    1. 有用: 多くの領域で図的な表現が本質だったり重要だったり。たとえば科学技術演算の結果を数値だけで理解するのは退屈だし困難
    2. たのしい!: いやまちがいなく。全然使い物にならなくても結果が目に見えるのは楽しいです。そして楽しいと理解が進みます
    3. 読むのに良い: 結果と一対一対応するので、同レベルの複雑度の他のコードに比べてグラフィックスのコードは読みやすい
    4. 設計の例: 関数の設計、抽象レイヤ、ライブラリの構成、など設計の例としても好例
    5. オブジェクト指向: 画面に表示される「モノ」と一対一対応するため、非常に判りやすい例になる
    6. 複雑な概念もある: 教材として申し分ない

12.2 A display model

  • iostreamで扱うデータは、一次元の文字ストリームを間接的に2次元にマッピングする表現でした
    • 改行とタブくらいでしか位置をコントロールできないけど。。。
      • エスケープシーケンスを使えばグラフィカルなことも出来るけど。。。
    • XMLやHTMLなんかのマークアップも同様ですね
  • この章で使う表現では、2次元の画面上の領域に対して、直接「ここ」という表現になります
    • メモリ上のオブジェクト(座標とか、線、矩形、円など)と画面上の何か、が一対一対応している
  • 描画したい物体(線とか)をウィンドウ(画面)に貼り付ける(attach)というイメージ
  • ディスプレイ、というオブジェクトは グラフィックスエンジン、グラフィックスライブラリ、GUIライブラリ、などと見なせます
  • 小人さんはattachされているオブジェクトを持ってきて、それを直接画面に描画する任を担っています。
    • 実はその小人さんたちも更にOSという別の小人さんに仕事をほとんど丸投げしているだけなのですがw

12.3 A first example

  • ちょっとした連結線の例
    • キモは単なるクラスの定義なのです
#include "Simple_window.h"   // window lib
#include "Graph.h"           // graphics library

int main()
{
  using namespace Graph_lib;

  Point tl(100,100);          // 左上座標.
                              // tlはウィンドウの位置らしい。なんか変態的
  Simple_window win(tl, 600, 400, "Canvas");

  Polygon poly;               // make a shape (a polygon)
  poly.add(Point(300,200));
  poly.add(Point(350,100));
  poly.add(Point(400,200));
  poly.set_color(Color::red);

  win.attach(poly);
  win.wait_for_button();      // push next button!
}

  • まあ説明の必要も無いほどにシンプル。まさに三輪車、補助輪付自転車。
    • tlがフレームの位置か描画の位置か、っておそらくフレームの位置でしょうね
  • 右上にNEXTというボタンが出るらしく, wait_for_button()でこれを待ってくれるらしい。
    • これを使って紙芝居が作れるみたいです
  • 16章でこの補助輪を外すそうです。楽しみですな
  • クローズボタンとかはウィンドウシステムが無料でくれたものですがなかなか使いでがありますよー、とか

12.4 Using a GUI library

  • OS直のグラフィックとかGUI機構は使いません
    • 一つはやはり互換性。プラットフォーム依存しないため
    • もう一つは楽をするため。直駆動はかなり大変。
      • 本質的に複雑なことを、単純な言葉で言い表すのは大変なのです
  • ところが、残念なことにC++標準GUIライブラリというのは無いんですね
      • この辺りがJavaとかが一気に市民権を取った理由かな. .NETも二番手でなければ・・・
  • 数あるGUIライブラリの中から FLTKを選びました http://www.fltk.org/
    • 更にそれに" Our interface library "で皮を被せてもうすこし可搬性と可読性を上げます
      • そういえば以前に少しだけいじってみたことがありました http://d.hatena.ne.jp/tkuro/20090528/1243489842
      • まあFLTK自体がほとんどのプラットフォームで動くので可搬性はどうでもよさそうですが、Mr.S的にはこのラッパライブラリのアイディアが伝えたいっぽい
  • このラッパライブラリは非常に小さく600行くらい
  • 全体としてはこんなイメージになります

  • 16章ではコールバック関数についてもやります

12.5 Coordinates

  • コンピュータの画面はピクセルで構成された矩形領域です
  • ピクセルは画面上の小さな点
  • 場所は(x,y)の対で表されます
  • が原点で、y座標は普通の数学とは逆。数字が大きいほど下になってます
    • コンピュータグラフィックスではよくあること
    • 実際反対でも特に問題は無いはずなのですが・・・
      • 実際GLやQuartzの座標系はそうなってますね
    • コンピュータ屋はついつい無意識に画面座標にターミナルでの表示方向やメモリアドレスをマップしてしまうのでこうなってしまうのでしょうね。
    • テキストを書く場合は確かにチト問題あるかも
  • Mr.Sもコンピュータ屋なので、頭が凝り固まってコンピュータでよく使われるプログラムの都合にあわせて、「スクリーンとかウィンドウっていろんなサイズあるからさ、左上の点ってほら共通じゃん」とか頭悪い素晴らしい説明をしています。
      • いろんなサイズあるから何? 左下が共通でも同じだろアホか。いやあ Mr.Sっておもしろいです
  • ウィンドウってのはスクリーンを切り取った仮想スクリーンだよ、とか
  • ちなみにコード中で指定したサイズはウィンドウ周りのタイトルバーとかボタンとかの領域は含んでないよ、とかでした

12.6 Shapes

  • クラス階層はこんな感じ

  • なんか継承という言葉をまだ使いたくないらしく、"矢印の先のクラスが必要な時に、根元側のクラスが使えるんだよー"とか微妙にイミフな事を仰ってる
    • Polygonは Shapeの一種なんだよーとか、こっちの方がわかりやすいよね
      • 素直に分類学のメタファで説明しちゃだめなんだろか。類とか目とか、こんな系統図だよね
  • さて、こっからはギャラリーです
    • 本章では静的なパーツだけ扱います。GUIパーツは後のお楽しみ
      • あと自分で スプラインとかグリッドとかパイチャートとか付けやがれ、だそうです

12.7 Using Shape primitives

  • Mr.S自慢のライブラリで何ができるか見ていきましょう
  • 例の紙芝居方式で足していく事ができてラクチン!
12.7.1 Graphics headers and main
  • まずはヘッダのinclude。
#include "Window.h"  // a plain window.  if you want NEXT button, include "Simple_window.h" instead
#include "Graph.h"
  • Graph_lib namespaceの中に詰め込んでますので、using namespaceなりご自由に(ただし既にバッティングします)
12.7.2 An almost blank window
  • この先は、紙芝居のためか、とりあえずSimple_Windowしか考えないみたい
  • 単に Simple_windowを作って Simple_window::wait_for_button()するとウィンドウがdraw()されて、NEXTボタン押しを待つようになってます
  • Mr.Sのラップトップのデスクトップ画面が出てます
    • Mr.Sは自分のデスクトップの奇麗さを自慢したいらしいのですが、そんなことはどうでもよろしい
    • どうもフランス旅行に行ったのを自慢したいらしいのですが、やっぱりどうでもよろしい
      • まったく面白いオッサンだ
  • さあ気を取り直して・・・
12.7.3 Axis
  • やっぱ何か表示したい。
  • 遊んでる訳じゃあないんだから、やっぱりまじめな事をするのダ
    • となるとやっぱり座標よね。マジメっぽい
  • ということで、便利そうで、実際にはあんまり使いどころの無いな座標表示
  • ナイスなグラフ表示なら内容無くても(ry!!
    • 飛ばしてるなMr.S
  {
    Axis xs(Axis::x, Point(50, 350), 530, 90, "x axis"); // x or y, 座標原点, 長さ, ノッチの数, ラベル
    Axis ys(Axis::y, Point(50, 350), 290, 20, "縦だだだ");

    xs.set_color(Color::blue);
    ys.set_color(Color::black);

    xs.label.set_color(Color::dark_green);

    win.attach(xs);
    win.attach(ys);

    win.wait_for_button();
  }

  • とくに説明無いけれども一応destructされると画面から消えるのでこのようにブロックに囲っとくと紙芝居しやすい
    • 日本語でター!
    • ついでに 90とかしてやったら結構誤差誤差のバグっぽいですね
  • ラベルの色だけとかも変えられる。結構スゴい
    • 適当に遊んでたら、次のページに "We don't actually think that it is a good idea to use differnet colors for x and y axes.".... スミマセン
    • "In particular, novices tend to use color with more enthusiasm than taste" ........ oI~~~~z
12.7.4 Graphing a function
  • 関数系も書けるのですね
    Function fsine(sin, 0, 100, Point(50, 150), 1000 ,50, 50);
               // func, range,  start,    point, scalex, scaley;
    Function fsinc(sinc, 0.01, 100, Point(50, 250), 1000 ,20, 90);

    fsinc.set_color(Color::dark_red);
    fsine.set_color(Color::dark_cyan);

    win.attach(fsine);
    win.attach(fsinc);

    win.wait_for_button();

    • おもしろーい
  • 詳細は15章にて
  • 画面外への描画はGUIシステムによって無視されるようになっている
12.7.5 Polygons
  • これは既にやった。
  • データ表現ではないもの、普通に多角形。ポリゴン
12.7.6 Rectangles
  • 矩形です。
  • 現実世界に沢山あります。角が丸まったヤツも(Steve Jobsによると)沢山あります
    Rectangle rect(Point(200, 200), 100, 50);

    win.attach(rect);
    win.set_label("rectangle");

    win.wait_for_button();
  • 閉じたポリラインでも書けるよ、という話
12.7.7 Fill
  • 塗りつぶしや線種など
    rect.set_fill_color(Color::yellow);
    poly.set_style(Line_style(Line_style::dash, 4));
    poly_rect.set_style(Line_style(Line_style::dash, 2));
    poly_rect.set_fill_color(Color::green);

    win.wait_for_button();

  • いや実際おもそろい
12.7.8 Text
  • テキストの描画が無いと完全じゃない
  • 線で書くのはダメ。敷居が高くなりすぎる
    Text t(Point(180, 150), "Hello, graphical world!");
    t.set_font_size(30);
    win.attach(t);

    win.wait_for_button();

  • 実は Axisのラベルもテキストオブジェクトだったり
  • もちろんフォントや装飾だって変えられます
12.7.9 Images
  • まあ絵ですね
  Image ii(Point(100,50), "hoge.jpg");
  win.attach(ii);
    :
  • あとから .move()で動かす事もできます
12.7.10 And much more
  • 他にもいろいろ
    • この短さで驚異的だなあ
      • というかそんだけ FLTKが簡便に書ける、という事なのですが。まさに複殺
  • Circle, Ellipse, Mark, imageのmaskなど
  • ここまで見てきたように コードと画面に表示されるものは一対一対応しています

12.8 Getting this to run

  • ウィンドウの作り方、その中での図形の描画についてざっと見てきました
  • でも実際に動かすためにはここにあるコード以上にいろいろ必要です
  • インターフェイスライブラリ、FLTKライブラリ、
    • 愛、希望、かけら、、、、(寝ぼけてます)
  • いろんなファイルが関わってるんだなーという雰囲気
  • 付録Dに統合方法が書いてあるっぽい。読んでないけど。。。
12.8.1 Source files
  • 5つのヘッダと、3つの実装ファイル
      • そしてあまたのアホなバグ
      • 予想通り以前に文句言ってた #define vector Vector が悪さをしてわかりにきー変なエラー出たり、templateのtype指定が抜けてたりとか、コンストラクタがheaderと実装ファイルで二重定義とか、unsigned と signedが混在してwarningだらけとか、Fl_Windowに入った直後 make_currentしてないからリサイズとかしないとShapeが表示されないとか、初期化順が不規則とか、Windowが安易にusing namespaceしてるせいでバッティングしてるとか、もうアホかと
      • どーどー。教育的配慮なんだよ。教育的配慮。全く触った事ない人が全部をなんとかできるとは到底思えないが・・・
    • 要望あればgithubにでも上げておきます.
  • 手品の種明かしは16章までおあずけ、だそうです。