titech-is-cs115 / techdraw

techdraw
0 stars 0 forks source link

ミッション3:折れ線,多角形,曲線の変形 #3

Open wakita opened 8 years ago

wakita commented 8 years ago

ClosePath, CubicCurve, Polyline,Polygon, QuadCurveあたりの制御点を操作して図形を描画し,変形する

kensakamoto commented 8 years ago

A 奥村、坂本、神田、池上、七島、佐藤、土屋

KSato0428 commented 8 years ago

A班

外見 |============| |ツールボックす | | | | キャンバス | | | ツールボックスとキャンバスがあります

デフォルト状態を選択モード

ツールボックスの図形ボタンを押しすと 描画モードへ 左クリックで頂点を追加していく ダブルクリックで描画完了 選択モードへ移行

図形を選択する(scalafxのcontainsや四角形との交差で判断する) 変形モードへ 制御点を表示する。 (アクション) 左クリックのとき |クリックされた位置から半径r以内に点があるとき | その点を選択し、 | ドラッグされた終点へ選択された点を移動する。 |半径内に点がないとき |  変形モードへ戻る
右クリックのとき |クリックされた位置から半径rに点があるとき |  メニュー画面を開く      |そうでないとき、選択モードへ戻る

メニュー画面の説明 ___| |delete | |__| |add | |__| | ..etc |

点が一つのときは消さない ボタン選択以外のイベントが起きたら変形モードへ

点の追加方法 選択された点A、そのすぐ後の点Bを覚えておく。 マウスの位置Cに新たな点を記憶してき、 A->C->Bの順番でつなぐ

発表後のアドバイス 線を選択したらその線を曲げたりすることができる方が便利!

tomoya6092 commented 8 years ago

B:伊藤、高橋

他の方の名前がわからないので各自コメントで追加をお願いします

yudaitnb commented 8 years ago

B: 田辺

1. 話したこと

ライブラリが充実してるのであまり弄らなくても実装自体はできそう。

多角形をどう作るか

多角形を頂点と頂点組みを結ぶ線分の集合とみなす。(ようするに2-正則グラフに座標がついたもの。開始方向から辿っていって途中で二股に分かれてしまう場合は考えない。)頂点座標のリストでこれを表現したい。 描画するときはそのリストを受け取り、先頭から二頂点ずつ、二つの頂点の始点が前の二つの頂点の終点になるように線分でつないでいけばよい。最後に(リスト全体の)終点と始点を結ぶ。 この方法はcomplex quadrilateralをはじめとしたねじれた図形も表現可能なので一般性がある。 (ただし、色をつけるのは難しい。内部がどこかというtopologicalな判定が必要なため。)

使用する際は、「多角形描画開始ボタン」を押し、一回ずつ適当な場所をクリックして頂点座標のリストを作る。最後に「~終了ボタン」を押し、クリックした点に基づく多角形を描写する。 「~終了ボタン」は右クリック等他の操作の方が良いのではないかという意見もでた。 また、頂点をクリックして追加している最中に、一つずつ線分を描画した方がわかりやすいという意見も出た。

曲線と折れ線をどう作るか

※最初に曲線は折れ線から派生させて作ればいいのではないかという意見が出た。 曲線は二次のBézier曲線を使う。これは以下のメソッドで実現できる。 (quadCurve) http://docs.scalafx.googlecode.com/hg/scalafx-1.0/scaladoc/index.html#scalafx.scene.shape.QuadCurve quadCurveは始点、制御点、終点の座標を受け取り、それに基づいたBézier曲線を描画する。 多角形と同様に頂点座標をリストとして持っておき、それを元にリスト内で隣り合った頂点同士を線分や曲線で結んでいく。 曲線を引くか線分で結ぶかの判断をするために、各頂点に識別子を持たせておく。 以下では簡単の為、折れ線と曲線の頂点を

p(i)
・・・頂点のうち、少なくとも一方の接続辺が折れ線のもののi番目。折れ線、曲線の始点と終点に対応。
q(j)
・・・頂点のうち、接続辺が共に曲線のもののj番目。曲線の制御点に対応。

とする。例えば、p(i)は((X座標,Y座標),[折れ線端点の識別子])の意味である。 (ただし各indexはリストの先頭から順番に振る。また、グラフが一本道の場合のみを考える。)

描画する際はリストの前から読み、

スタート
    (1)p(i),p(i+1)と連続した場合
        両点を線分で結び、p(i+1)を始点としてスタートに戻る
    (2)p(i),q(j)と連続した場合
        (2-1)q(j)の次がp(i+1)の場合
            始点p(i),制御点q(j),終点p(i+1)でBézier曲線を描画
            p(i+1)を始点としてスタートに戻る
        (2-2)q(j)の次がq(j+1)の場合
            pがくるまで次を読み、pで挟まれたすべてのqを制御点としてBézier曲線を描画する
            p(i+1)を始点としてスタートに戻る
    (3)リストのサイズが0,1の場合
        描画終了(1の場合は1点かいてもいい)

ようするにpが連続したら折れ線、pqpは曲線。

使用する際は「曲線と折れ線描画開始ボタン」を押し、一回ずつ適当な場所をクリックして頂点のリストを作る。最後に「~終了ボタン」を押し、クリックした点に基づいて折れ線を描写する。 多角形同様「~終了ボタン」は右クリック等他の操作でもいいのではないかという意見もでた。 また、頂点をクリックして追加している最中に、一つずつ線分もしくは折れ線を描画した方がわかりやすいという意見も出た。

折れ線と曲線に対して頂点、制御点の追加

※最初に線分をドラッグすることで、その間に点を追加しようという意見が出た。 どのような頂点の追加方法にしても、ひとまず点を追加したい部分の線分を選択したいが、これが難しい。 図形の近くの点をクリックしたとして、それと最も近い図形をどう判断すればいいのか? (そもそも線を目測でキッチリクリックするのは不可能。) ⇒脇田先生がintersectで判定すればよいとA班にコメント。これで解決。

折れ線に頂点を追加する際には、線分を選択して頂点pを追加する。List(~,p(i),p(i+1),~)となっているところをList(~,p(i),p(i+1),p(i+2),~)とすればよい。

折れ線に制御点を追加する(線分を曲線にする)際には、線分を選択して制御点qを追加する。List(~,p(i),p(i+1),~)となっているところをList(~,p(i),q(j),p(i+1),~)とすればよい。

曲線の制御点を追加する際に、森先生が指摘してくださった事に関連する問題(後述)について考察した。 例えばList(p(1),q(1),p(2))で制御点を追加し、List(p(1),q(1),q(2),p(2))としたい。しかしこれは上記の描画方法ではエラー扱いとなる。 このとき二次より高次のBézier曲線を描画する方法を知らなかった為、無理と結論した。

※多角形の頂点の追加については時間が無かったので考察しなかった。

折れ線と曲線に対して頂点、制御点の削除

追加の反対の操作をすればよい。これはそこまで難しくないので実装できそうだという意見が出た。

※多角形の頂点の削除についても時間が無かったので考察しなかった。

2. 森先生のコメント

※意訳していますが、取り違えているところがありましたらご指摘よろしくお願い致します。

森先生: (例えばy=x^3-1のような)凹凸の変わるぐにゃぐにゃした図形を滑らかに描画するのは可能なのか?
返答: 例えばList(p(1),q(1),p(2),q(2),p(3))で上手く座標を取って再現しようとした場合、p(2)の部分で曲線がなめらかでなくなってしまう。私たちが考えた実装ではこれをなめらかにすることはできない。

⇒後で脇田先生に相談したところ、List(p(1),q(1),q(2),p(2))のように制御点が2つ以上の場合でも、対応するn次のBézier曲線を書くメソッドがある(はずである)とのこと。解決。 例えばList(p(1),q(1),q(2),p(2))で二つの制御点qの座標をうまくとれば、凹凸の変わる曲線が書けるはずである。

※参考 2次と3次のBézier曲線のFlash。赤い点が制御点(q)、白い点が始点と終点(p)に対応する。 2次 http://hakuhin.jp/as/curve.html#CURVE_01 3次 http://hakuhin.jp/as/curve.html#CURVE_02

wakita commented 8 years ago

最後の点ですが,折れ線を描画するサンプルコードを作成しました.

https://gist.github.com/wakita/e1040d01cdb575a8aa18

wakita commented 8 years ago

プレゼン中にコメントしましたが,折れ線がクリックされたか否かを判定するには,Polylineクラスのintersetcsメソッドを利用するのが簡単だと思います.二種類ありますが,後者の方がすこし便利かもしれません.