カーブしたポイントツーポイントの「ルートマップ」


39

私は最近、特定の都市からサービスを提供する他のすべての都市へのルートを表示する航空会社のWebページを見ています。ポイント間に同様の曲線ルートを作成できるようにしたいと思います。この例に表示されているような曲線の弧を生成するスクリプトまたは関数を作成した人はいますか?

飛行経路

PostGISでは、2点を接続するときに使用する曲線の量を指定できるST_MakeLineの実装がありますか?

現在、PostGISとQGISを使用していますが、同じ外観を作成できる可能性のある他のソフトウェアオプションについて聞いていただければ幸いです。


誰もこれの素晴らしい実装を知っていますか?例か何ですか?
マークボールダー

回答:


26

大円を作成すると、希望する効果が得られます。

たぶんhttp://lists.osgeo.org/pipermail/postgis-users/2008-February/018620.htmlで議論されているようなもの

更新:

「グローバル接続の視覚化」でこのアイデアをフォローアップしました。これは、再投影を使用してアークを作成する純粋なPostGISベースのソリューションです。

SELECT ST_Transform(
  ST_Segmentize(
    ST_MakeLine(
      ST_Transform(a.the_geom, 953027),
      ST_Transform(b.the_geom, 953027)
    ), 
  100000), 
4326)

(953027のCRS定義は、http://spatialreference.org/ref/esri/53027/にあります)

ここに画像の説明を入力してください


4
私はこのアイデアが好きですが、大きな円では、あなたが出くわす問題は、より短い距離では、まだほぼ直線になるということです。ラインに入れるアークの量を制御できるようにしたい(つまり、アーク長=距離* 2)。
ライアンダルトン

1
これは、単に大円を使用する場合の問題の良い例です。gc.kls2.com
bin

1
いくつかの追加調査の後、この方法を支援するのに役立つこの投稿を見つけました。 mail-archive.com/postgis-users@postgis.refractions.net/…– RyanDalton 11
1

将来の読者の使用のために、私は先に進んで、このトピックをカバーする@underdarkの最近のブログ投稿にリンクすると思いました。 underdark.wordpress.com/2011/08/20/...
RyanDalton

それは素晴らしいことです!!私のプロジェクトで、ユーザーのチェックインと会場の場所の間に線を引くために使用しました。Forsquare
Lorenzo Barbagli

24

問題は、視覚的な解像度を向上させるために円弧をどれだけ曲げるかを把握することです。

これが1つの解決策です(可能な限り多くあります)。共通の起源から発生するすべてのアークを考えてみましょう。ここでアークが最も混雑します。それらを最適に分離するには、等間隔の角度で広がるように配置しましょう。通常、出発地から目的地まで直線セグメントを描画すると、さまざまな方向に目的地のクラスターが存在するため、問題です。出発角度を可能な限り均等に配置するために、自由にアークを曲げてみましょう。

簡単にするために、地図上で円弧を使用します。点yから点xへの弧の「曲がり」の自然な尺度は、yでの方位とyからxへの直接の方位との差です。このような弧は、yxの両方が存在する円の扇形です。基本ジオメトリは、曲げ角度がアークのincluded角の半分に等しいことを示しています。

アルゴリズムを説明するには、もう少し表記が必要です。ましょうyは原点である(地図上に投影されるように)およびlet X_1をX_2、...、x_nに関する先のポイントです。a_iをyからx_iへの方位、i = 1、2、...、nになるように定義します。

準備段階として、ベアリング(すべて0〜360度)が昇順であると仮定します。これには、ベアリングを計算してから並べ替える必要があります。どちらも簡単なタスクです。

理想的には、アークのベアリングを、ある開始ベアリングに対して360 / n、2 * 360 / nなどに等しくすることが望まれます。したがって、目的のベアリングと実際のベアリングの差は、i * 360 / n -a_iに開始ベアリングa0を加えたものに等しくなります。最大の差はこれらのn個の差の最大値であり、最小の差は最小値です。a0を最大値と最小値の中間に設定してみましょう。これは、発生する最大曲げ量を最小化するため、開始ベアリングの適切な候補です。したがって、定義する

b_i = i * 360 / n - a0 -a_i:

これは使用する曲げです。

2 b_iの角度を定めるyからxまでの円弧を描くことは基本的なジオメトリの問題であるため、詳細をスキップして、例に進みます。長方形のマップ内に配置された64、16、および4つのランダムポイントのソリューションの図を次に示します。

代替テキスト

代替テキスト

代替テキスト

あなたが見ることができるように、ソリューションが取得するように見えるよりよい先のポイントの数が増加するにつれて。n = 4 の解は、ベアリングの均等な間隔を明確に示しています。この場合、間隔は360/4 = 90度に等しく、明らかに間隔が正確に達成されています。

この解決策は完璧ではありません。おそらく、グラフィックを改善するために手動で調整できるいくつかのアークを識別することができます。しかし、それはひどい仕事をしないで、本当に良いスタートのようです。

このアルゴリズムには、シンプルであるというメリットもあります。最も複雑な部分は、目的地に応じて目的地をソートすることです。


コーディング

私はPostGISを知りませんが、おそらく例を描画するために使用したコードは、PostGIS(または他のGIS)でこのアルゴリズムを実装するためのガイドとして役立つ可能性があります。

以下は擬似コードであると考えてください(ただし、Mathematicaはそれを実行します:-)。(このサイトはTeXにサポートされている場合、数学、統計、およびTCSのものがそうであるように、私はこれを作ることができる多くの、より読みやすい。)表記は含まれています:

  • 変数名と関数名は大文字と小文字が区別されます。
  • [Alpha]は小文字のギリシャ文字です。([Pi]には、あるべきだと思う価値があります。)
  • x [[i]]は、配列x(1から始まるインデックス)の要素iです。
  • f [a、b]は、関数fを引数aおよびbに適用します。「Min」や「Table」などの適切なケースの関数はシステム定義です。「angles」や「offset」などの最初の小文字の関数は、ユーザー定義です。コメントは、あいまいなシステム機能(「Arg」など)を説明します。
  • Table [f [i]、{i、1、n}]は配列{f [1]、f [2]、...、f [n]}を作成します。
  • Circle [o、r、{a、b}]は、半径rのoを中心とする角度aから角度b(真東から反時計回りにラジアン単位)の円弧を作成します。
  • Ordering [x]は、xのソートされた要素のインデックスの配列を返します。x [[Ordering [x]]]はxのソートされたバージョンです。yがxと同じ長さの場合、y [[Ordering [x]]]はyをxと並行してソートします。

コードの実行可能部分は、20行未満という非常に短いものです。これは、その半分以上が宣言オーバーヘッドまたはコメントであるためです。

地図を描く

z宛先のリストでyあり、発信元です。

circleMap[z_List, y_] := 
Module[{\[Alpha] = angles[y,z], \[Beta], \[Delta], n},
    (* Sort the destinations by bearing *)
    \[Beta] = Ordering[\[Alpha]];
    x = z[[\[Beta] ]]; (* Destinations, sorted by bearing from y *)
    \[Alpha] = \[Alpha][[\[Beta]]]; (* Bearings, in sorted order *)
    \[Delta] = offset[\[Alpha]];
    n = Length[\[Alpha]];
    Graphics[{(* Draw the lines *)
        Gray, Table[circle[y, x[[i]],2 \[Pi] i / n + \[Delta] - \[Alpha][[i]]], 
             {i, 1, Length[\[Alpha]]}],
        (* Draw the destination points *)
        Red, PointSize[0.02], Table[Point[u], {u, x}]
    }]
]

x-> y方位に対する角度で始まる点から点xへの円弧を作成します。y\[Beta]

circle[x_, y_, \[Beta]_] /; -\[Pi] < \[Beta] < \[Pi] := 
Module[{v,  \[Rho], r, o, \[Theta], sign},
    If[\[Beta]==0, Return[Line[{x,y}]]];

    (* Obtain the vector from x to y in polar coordinates. *)
    v = y - x; (* Vector from x to y *)
    \[Rho] = Norm[v]; (* Length of v *)
    \[Theta] = Arg[Complex @@ v]; (* Bearing from x to y *)

    (* Compute the radius and center of the circle.*)
    r = \[Rho] / (2 Sin[\[Beta]]); (* Circle radius, up to sign *)
    If[r < 0, sign = \[Pi], sign = 0];
    o = (x+y)/2 + (r/\[Rho]) Cos[\[Beta]]{v[[2]], -v[[1]]}; (* Circle center *)

    (* Create a sector of the circle. *)
    Circle[o, Abs[r], {\[Pi]/2 - \[Beta] + \[Theta] + sign, \[Pi] /2 + \[Beta] + \[Theta] + sign}]
]

原点からポイントのリストまでの方位を計算します。

angles[origin_, x_] := Arg[Complex@@(#-origin)] & /@ x;

ベアリングのセットの残差のミッドレンジを計算します。

xソートされた順序のベアリングのリストです。理想的には、x [[i]]〜2 [Pi] i / n。

offset[x_List] :=
Module[
    {n = Length[x], y},
    (* Compute the residuals. *)
    y = Table[x[[i]] - 2 \[Pi] i / n, {i, 1, n}];
    (* Return their midrange. *)
    (Max[y] + Min[y])/2
]

このソリューションでは、目的地が多かれ少なかれ出発地を取り囲んでいると想定していることに言及する必要があります。そうでない場合、(等間隔のベアリングの)アイデア全体は良いアイデアではありません。しかし、角度のあるギャップ内にいくつかの偽の目的地を導入し、後でそれらの目的地(およびそのアーク)を削除することにより、簡単に修正できます。このプロセスは、ベアリング間の平均距離を計算し、それを使用して大きなギャップなどを識別することにより自動化できます。
whuber

素敵なグラフィック。航空会社が機内誌の裏に示されている路線図を作成するときに自動化ツールを使用するのだろうか。
カーククイケンダル

1
@Kirk彼らはおそらく誰かに地図作成を手作業で行ってもらいます:-)。この質問に触発されて、単純なアプローチでかなり良いグラフィックを作成できるかどうかを確認しました。答えは有望に見えます。ところで、これらのグラフィックスはMathematica 8 によって、CircleおよびPointプリミティブと、円の中心を見つけるための小さなベクトル演算を使用して作成されました。
whuber

私はあなたが示した結果が大好きで、これが道です。正直なところ、私は自分自身を技術的だと考えていますが、与えられた式で少し迷子になったので、それをPostGISコードに変換する方法はほとんど不可能になります。whuberのコンセプトを実行可能なコードに変換する方法についてのアイデアはありますか?確認して試してみますが、助けていただければ幸いです。
ライアンダルトン

@ whuber-更新された擬似コードをありがとう。PostGISで実際に実装できるかどうかを確認する必要があります。
ライアンダルトン



3

結局、@ NicklasAvénが提案したように、ST_CurveToLine関数を使用して「2点」の線ストリングのセットをカーブさせようとしました。

次の3つの座標セットをST_OffsetCurve関数に渡しました。

  1. 元の行の始まり
  2. 元のラインに平行なラインオフセットの中点
  3. 元の行の終わり

この例では、ST_OffsetCurve関数を使用して、オフセット(元の行の長さの1/10)を計算しました。

以下は、元の直線から曲線を生成するために使用したSQLです。

    ST_CurveToLine('CIRCULARSTRING(' || st_x(st_startpoint(the_geom)) || ' ' || st_y(st_startpoint(the_geom)) || ', ' || st_x(st_centroid(ST_OffsetCurve(the_geom, st_length(the_geom)/10, 'quad_segs=4 join=bevel'))) || ' ' || st_y(st_centroid(ST_OffsetCurve(the_geom, st_length(the_geom)/10, 'quad_segs=4 join=bevel'))) || ', ' || st_x(st_endpoint(the_geom)) || ' ' ||  st_y(st_endpoint(the_geom)) || ')') AS the_curved_geom

本当に便利ですが、何らかの理由で結果は私のsridを尊重しません。理由は何ですか?
DMS02

詳細を教えてください-入力ジオメトリのsrid、出力sridが欠落、異なる、エラーが生成されました(どのアプリケーション-QGIS、PostgreSQL)。
ブレントエドワーズ

結果の曲線を挿入するテーブルには、enforce_srid_geom制約があります。クエリを実行すると、このクエリがその制約に違反しているというエラーが表示されます。その制約のないテーブルで、それは動作しますが、QGISにそれを追加するとき、それはSRID 0.私のクエリでリストされている:INSERT INTOテスト(the_curved_geom)[ここにあなたのSQL]ラインの中から選択
DMS02

ジオメトリ列(the_curved_geom)でpostgis.net/docs/ST_GeometryType.htmlおよびpostgis.net/docs/ST_SRID.html関数を実行してみて、テストテーブルとenforce_srid_geomとの競合がないか確認してください。その場合、必要に応じてジオメトリ/ Sridを変換するか、テストテーブル/制約を変更できます。
ブレントエドワーズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.