うしブログ

うしブログ

趣味で運営する、GeoGebraの専門ブログ。

(作業メモ)StartPoint要検証(2行の場合;テキスト変更時未定義問題)

(要修復)ToggleButton・RollPolygonWithoutSlipping・貯金時計・直感力トレーニング

ドロネー図の三角形をリストとして取得する

前提オブジェクト

点のリスト originalPointList

ドロネー図 graph1 = DelaunayTriangulation[originalPointList]

f:id:usiblog:20190505050403p:plain

課題

ドロネー図の三角形を、リストオブジェクトとして取得したい。

上図の例では、下図のように、5つの三角形からなるリストを取得したいということである。

f:id:usiblog:20190505050800g:plain

取得手順

パスパラメータの割り当てを分析する

f:id:usiblog:20190505051638g:plain

上図のように、ドロネー図のパスパラメータの割り当ては、良く分からない。

しかし、一定の法則性を見出すことができる。

法則①:パスパラメータを0から等速で増やしていくと、点が線分上を通過していく挙動、線分以外の良く分からない場所を動いていく挙動、ある点上で停止する挙動が次々と観察される。

これら観察されるそれぞれの挙動を、「フェーズ」と総称することにする。点が線分上を通過していく挙動を「通過フェーズ」、線分以外の良く分からない場所を通過していく挙動を「ジャンプフェーズ」、ある点上で停止する挙動を「停止フェーズ」と呼ぶことにする。

法則②:フェーズの切り替わりは、等間隔に訪れる。すなわち、フェーズの始まりにおけるパスパラメータと、フェーズの終わりにおけるパスパラメータとの差は、常に(どのフェーズでも)一定である。

法則③:どの通過フェーズおよびジャンプフェーズにおいても、パスパラメータを等速で増加させると、点は等速で動く。

法則④:パスパラメータを0から増やしていくと、最初に訪れるフェーズは通過フェーズである。そのフェーズでは、パスパラメータ0の点が始点、パスパラメータ1の点が終点である。

以下では、これらの法則を利用していく。

「パスパラメータ0の点と1の点との中点」のパスパラメータを2倍すると、1フェーズに割り当てられているパスパラメータの量を計算できる(unitParameter)。

unitParameter = 2PathParameter[ClosestPoint[graph1, Midpoint[Point[graph1, 0], Point[graph1, 1]]]]

unitParameterの逆数をとれば、フェーズの数を計算できる。

frequency = 1 / unitParameter

各フェーズの中間における点のリストを取得する

half = unitParameter / 2

halfParamList = Sequence[Point[graph1, half + k unitParameter], k, 0, frequency - 1]

 halfParamListは、各フェーズの中間における点のリストである(下図の赤い点)。

f:id:usiblog:20190505055144p:plain

各フェーズの1/4段階における点のリストを取得する

quarter = unitParameter / 4

quarterParamList = Sequence[Point[graph1, quarter + k unitParameter], k, 0, frequency - 1]

 quarterParamListは、各フェーズの1/4段階における点のリストである(下図の緑色の点)。

f:id:usiblog:20190505055436p:plain

各フェーズの1/4段階〜中間を線分で結ぶ

quarterToHalfSegmentListFull = Unique[Zip[Segment[s, t], s, quarterParamList, t, halfParamList]]

quarterToHalfSegmentListFullは、各フェーズの1/4段階〜中間を線分で結んだものである(下図の赤い線分)。

f:id:usiblog:20190505055836p:plain

quarterToHalfSegmentListRemoved = Unique[RemoveUndefined[Zip[If[Point[s, 1] ≟ ClosestPoint[graph1, Point[s, 1]], s, ?], s, quarterToHalfSegmentListFull]]]

quarterToHalfSegmentListFullのうち、ドロネー図上にないもの(ジャンプフェーズにおけるもの)を削除する(quarterToHalfSegmentListRemoved、下図)

f:id:usiblog:20190505060105p:plain

Dilateで拡大して、ドロネー図の線分と揃える

dilateSegmentListFull = Unique[Zip[Dilate[s, 4, Point[s, 1 / 3]], s, quarterToHalfSegmentListRemoved]]

quarterToHalfSegmentListRemovedをDilateで適切に拡大して、ドロネー図の線分と長さ・位置を揃える(dilateSegmentListFull、下図のオレンジの線分)。

f:id:usiblog:20190505060307p:plain

delauneySegmentList = RemoveUndefined[Zip[If[Length[s] ≠ 0, s, ?], s, dilateSegmentListFull]]

dilateSegmentListFullのうち、長さ0のもの(停止フェーズがあると生じる)を削除する(delauneySegmentList、下図の水色の線分)。

f:id:usiblog:20190505060623p:plain

delauneySegmentListは、本稿の課題の最終目標ではないが、これ自体も、ドロネー図の各線分をリストで返すものとして、意義があるだろう。

点のリスト originalPointListによって作成しうる全ての三角形をリストで返す

polygonListFull = Unique[Flatten[Sequence[Sequence[Sequence[Polygon[Element[originalPointList, s], Element[originalPointList, t], Element[originalPointList, u]], s, 1, Length[originalPointList]], t, 1, Length[originalPointList]], u, 1, Length[originalPointList]]]]

polygonListRemoved = RemoveUndefined[Zip[If[Area[s] ≠ 0, s, ?], s, polygonListFull]]

f:id:usiblog:20190505061017p:plain

必要な三角形のみを抽出する

delauneyPolygonList = RemoveUndefined[Zip[If[Sides[s] ⊂ delauneySegmentList, s, ?], s, polygonListRemoved]]

polygonListRemovedの要素である各三角形のうち、3辺がすべてdelauneySegmentList(ドロネー図の線分のリスト)の要素であるような三角形だけを抽出する(delauneyPolygonList、下図の青い三角形)。これが、目的のリストである。

なお、Sides[<多角形>]は、オリジナルツールである。詳細は、下記記事参照。

多角形オブジェクトを用いて、頂点または辺のリストを返す - うしブログ

f:id:usiblog:20190505061341p:plain

参考情報

以下の数式は、点のリストoriginalPointListから、ドロネー図の三角形のリストを返す。

処理落ち回避のため、CopyFreeObjectを入れてある。

Zip[Polygon[τ],τ,CopyFreeObject[Zip[{Vertex[σ]}, σ, RemoveUndefined[Zip[If[Sides[ρ] ⊂ RemoveUndefined[Zip[If[Length[η] ≠ 0, η, ?], η, Unique[Zip[Dilate[ζ, 4, Point[ζ, 1 / 3]], ζ, Unique[RemoveUndefined[Zip[If[Point[ε, 1] ≟ ClosestPoint[DelaunayTriangulation[originalPointList], Point[ε, 1]], ε, ?], ε, Unique[Zip[Segment[γ, δ], γ, Sequence[Point[DelaunayTriangulation[originalPointList], (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]]) / 4 + β (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]])], β, 0, 1 / (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]]) - 1], δ, Sequence[Point[DelaunayTriangulation[originalPointList], (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]]) / 2 + α (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]])], α, 0, 1 / (2PathParameter[ClosestPoint[DelaunayTriangulation[originalPointList], Midpoint[Point[DelaunayTriangulation[originalPointList], 0], Point[DelaunayTriangulation[originalPointList], 1]]]]) - 1]]]]]]]]]], ρ, ?], ρ, RemoveUndefined[Zip[If[Area[ξ] ≠ 0, ξ, ?], ξ, Unique[Flatten[Sequence[Sequence[Sequence[Polygon[Element[originalPointList, κ], Element[originalPointList, λ], Element[originalPointList, μ]], κ, 1, Length[originalPointList]], λ, 1, Length[originalPointList]], μ, 1, Length[originalPointList]]]]]]]]]]]