ぐる式 (貳) より引っ越し作業中.未完.

2010年4月17日土曜日

ぐる式最後 (から二番目) の闘い: Squeak で Grapher る II

ずいぶんと *古い* ネタである.

あの 後,けっきょく 2 回作り直した.

  1. 素直に Morph バージョン
  2. Form バージョン
  3. FormCanvas バージョン

1) やっぱ要素数が増えると重くて動かん例題があるというのがネック.じゃぁってんで代替えでひねり出したのが, 2) いつもの Form を使うヤツ.一度 aForm に書き出して anImageMorph に変換して持つというもの.ボルヘス流に言えば縮尺 1:1 の投影地図である.これだと,モデルが元々持ってる displayOn: がそのまま使えるというメリットがある.が,表示用のウィンドウを作る際に一度作るだけなんだが,途中でグラフの大きさが変わると,その都度作り直すことになる.動きは随分と軽くなるが,それでも横 2000,縦 75000 みたいなデカい aForm は Display depth ではメモリ不足で作れん.メモリが足りんときは表示深度を落とし,書き出せんときは分割して,みたいなことをやらざるを得ん.あと,状態更新にも弱い.

で,次いでひねくり出したのが 3) FormCanvas を使うバージョン.これは Morph の表示用メカニズム drawOn:[こんとき,個々の aMorph で呼び出される drawOn: のパラメータである aCanvas は WorlsState が作って渡す FormCanvas のインスタンス.ディスプレイ] を使うもの.これは中身の実体を持っていない. aFormCanvas は内部的に form を抱え込んでいる.表示用にからっぽの Morph を作り drawOn: を再定義して,そんままモデルに渡すもの.渡すときに drawOn: の引数である aCanvas から form を取得して渡せば,モデルの displayOn: がそんまま使えるが,今回は新規に drawOn:at: を定義している.もし自前で aFormCanvas を作った場合は,描き終えた後で showAt: しなければならない.元ネタは古い Goodies for Squeak (Smalltalk-80)DisplayView

以下は樹状整列とスクローリングをアニメーションで表示する例題の実行時間を計測したもの.現在のトップウィンドウの領域に上書き描画するプログラムなので 2) と 3) ではほとんど同じ速度で動く.描画領域は全部 768 @ 571 で統一してある.

Timing of constructing and scrolling graph.
examples Squeak3.10.2-7179web09.07.1 VWNC7.7 + Jun786
Morph pattern Form pattern FormCanvas pattern
example30
(exampleTree)
29 48
25.81
(0.54 sec/node)
10.56
(0.36 sec/node)
10.31
(0.36 sec/node)
25.29
(0.53 sec/node)
example31
(exampleForest)
173 244
52.81
(0.31 sec/node)
37.49
(0.22 sec/node)
38.10
(0.22 sec/node)
83.69
(0.34 sec/node)
example32
(exampleSmalltalk)
4449 3071
1080.90
(18min 0.9sec)
(0.24 sec/node)
227.45
(3min 47.5sec)
(0.05 sec/node)
229.09
(3min 49.1sec)
(0.05 sec/node)
188.22
(3min 8.2sec)
(0.06 sec/node)
  • GrapherExampleTokyo

同心円状整列 (arrangeFormat: #concentric) の例.あ,そうそう,前回の重み付きのグラフ:京都 or 東京では連結されてないノードを表示してなかったので,直した.

  • GrapherExampleTokyo

同心円状整列グラフの鳥瞰画像の例.

  • birdView

4449 個のノードを持つグラフの俯瞰.赤い線のように見えるのは,鳥瞰描画に入る前に,このウィンドウに描画していた領域↓.

  • CustomQuestionDialogWindow

鳥瞰図から,この系統がいちばん深い継承を持っていることが判る.この末端は "Polymorph-Widgets-Windows" パッケージに含まれる CustomQuestionDialogWindow クラスで,スーパークラスは 12 個ある.

ProtoObject    Object        Morph            BorderedMorph                MorphicModel                    SystemWindow                        StandardWindow (ここから下は "Polymorph-*" パッケージ)                            DialogWindow                                MessageDialogWindow                                    ProceedDialogWindow                                        QuestionDialogWindow                                            QuestionWithoutCancelDialogWindow                                                CustomQuestionDialogWindow

ノード数が多いグラフで鳥瞰モードに入ると,やはり重い.何か工夫せんと使い難くてかなわん.とりあえず思い付くのは,ダメージ領域だけを再描画する,か.鳥瞰図を保存するには,例えば以下のような感じでモルフ化してエクスポートする.

    | aGrapher window aNode view scaleFactor aCanvas previousBox aBox |    aGrapher := NshGrapherJunGrapher exampleSmalltalk.    window := aGrapher open.    window extent: 600 @ 400.    aNode := aGrapher graph labelStringAt: 'CustomQuestionDialogWindow'.    aNode ifNotNil: [aGrapher scrollFor: aNode].    view := aGrapher getView.    view scrollAmount: view scrollAmount + (200 @ 0).    aGrapher changed.    scaleFactor := (view bounds extent - (2 @ 2)) / aGrapher boundingBox extent.    aCanvas := Display defaultCanvasClass extent: view bounds extent.    previousBox := ((view bounds                translateBy: view bounds origin negated - aGrapher boundingBox origin                        - view scrollAmount)                    scaleBy: scaleFactor) rounded.    aCanvas fillColor: aGrapher graph class defaultWorldColor.    aGrapher        drawOn: aCanvas        at: 0 @ 0 - view model boundingBox origin        scaledBy: scaleFactor.    aCanvas        frameRectangle: previousBox        width: 2        color: Color blue darker darker.    aBox := ((view bounds                translateBy: view bounds origin negated - aGrapher boundingBox origin                        - view scrollAmount)                    scaleBy: scaleFactor) rounded.    aGrapher selectionBorderWidth timesRepeat:             [aCanvas                frameAndFillRectangle: aBox                fillColor: Color transparent                borderWidth: 1                borderColor: aGrapher selectionBorderColor.            aBox := aBox insetBy: (1 @ 1 corner: 1 @ 1)].    "aCanvas showAt: 0 @ 0."    aCanvas form asMorph openInWindow

表示のタイミングで書き出した画像を束ねてアニメーションにしたので,実際の動きとは異なる.