我最近一直在查看航空公司的网页,这些网页显示了他们从某个城市飞往其服务的所有其他城市的航线。我希望能够在点之间创建类似的弯曲路线。有没有人创建脚本或函数来生成像本示例中显示的那样的弧形?



在PostGIS中,是否有ST_MakeLine的实现可让您指定连接2个点时要使用的曲线量?

评论

有人知道这有什么不错的实现吗?例子还是什么?

#1 楼

创造大圈子可以为您带来理想的效果。

也许类似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/)



评论


我喜欢这个主意,尽管圆圈很大,但遇到的问题是,在较短的距离处,您最终仍会得到一条直线。我希望能够控制放置在行中的弧的数量(即arclength = distance * 2)。

– RyanKDalton
2011年1月17日9:00



这是简单使用大圆圈就可以解决问题的一个很好的例子:gc.kls2.com/cgi-bin/…

– RyanKDalton
2011年1月17日9:01



经过一些额外的研究,我发现这篇文章可能对协助此方法很有用。 mail-archive.com/postgis-users@postgis.refractions.net/…

– RyanKDalton
2011年1月17日19:47

为了将来的读者使用,我想我将继续前进并链接到@underdark最近的博客文章,其中涉及该主题。 underdark.wordpress.com/2011/08/20/…

– RyanKDalton
2011年9月9日在4:51



那很棒!!在我的项目中用于在用户签到和场所位置之间绘制线条,这些线条是从Forsquare拾取的

–洛伦佐·巴巴格利(Lorenzo Barbagli)
15年11月23日在10:14

#2 楼

问题在于弄清楚弯曲弧度以提高视觉分辨率的方法。让我们考虑从共同原点发出的所有弧。弧线在这里最拥挤。为了最好地分离它们,让我们对其进行排列,以便它们以均等的角度展开。如果我们绘制从原点到目的地的直线段,这是一个问题,因为通常会有沿不同方向的目的地簇。让我们利用自由的角度来弯曲圆弧,以便尽可能均匀地隔开离开的角度。
为简单起见,我们在地图上使用圆弧。从点y到点x的弧中“弯曲”的自然度量是其在y处的方位与从y到x处的方位之间的差。这样的弧是y和x都位于其上的圆的一个扇区;基本几何显示弯曲角等于圆弧中夹角的一半。
要描述一种算法,我们需要多一点符号。设y为原点(在地图上投影),设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:
这是要使用的弯曲。
从y到x绘制一个圆弧,其对角为2 b_i,这是基本几何的问题,因此我将跳过细节,直接看一个示例。这是放置在矩形地图中的64、16和4个随机点的解决方案的说明。
随着目的地点数量的增加。 n = 4的解决方案清楚地表明了轴承是如何均匀分布的,在这种情况下,间距等于360/4 = 90度,并且显然可以精确实现间距。
这种解决方案并不完美:您可能会发现可以手动调整几个弧来改善图形。但是它不会做得很糟糕,而且似乎是一个很好的开始。
该算法还具有简单的优点:最复杂的部分是根据目的地的方位对目的地进行排序。

编码
我不了解PostGIS,但是也许我用来绘制示例的代码可以作为在PostGIS(或任何其他GIS)中实现此算法的指南。
考虑一下以下为伪代码(但Mathematica将执行它:-)。 (如果该站点支持TeX,如数学,统计信息和TCS一样,我可以使其更具可读性。)表示法包括:

变量和函数名区分大小写。 br /> [Alpha]是小写的希腊字母。 ([Pi]具有您认为应该具有的值。)
x [[i]]是数组x的元素i(索引从1开始)。
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的圆,以从角度a到角度b的弧度为中心(均从正东逆时针弧度)。
Ordering [x]返回一个x排序元素的索引数组。 x [[Ordering [x]]]是x的排序版本。当y与x的长度相同时,y [[Ordering [x]]]与y并行地对y进行排序。因为其中一半以上是声明性开销或注释。
绘制地图
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π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
]
 


评论


我应该提到的是,此解决方案假定目的地或多或少围绕起点。如果不是这种情况,那么整个想法(等距轴承)并不是一个好主意。但是,可以通过在角度间隙内引入一些伪造的目标并随后删除这些目标(及其弧线)来轻松解决问题。该过程可以通过计算轴承之间的平均距离并使用该平均距离来识别大的间隙等来实现自动化。

– hu
2011年1月17日在19:09

漂亮的图形。我想知道航空公司在绘制机上杂志背面显示的路线图时是否使用自动化工具。

– Kirk Kuykendall
2011年1月17日在20:14

@Kirk他们可能付钱给人手动做地图:-)。这个问题启发了我,看看简单的方法是否可以创建合理的图形。答案看起来很有希望。顺便说一下,这些图形是由Mathematica 8使用其Circle和Point基元以及一些矢量算法来找到圆心而生成的。

– hu
2011年1月17日在20:33

我喜欢您显示的结果,这是我要走的路。不过,老实说,我认为自己是技术人员,但是您给出的公式让我有些迷茫,因此如何将其转换为PostGIS代码几乎变得不可能。有人对如何将whuber的概念转换为可行的代码有任何想法吗?我将尝试进行审查并尝试一下,但将不胜感激。

– RyanKDalton
11年1月27日在21:21



@ whuber-感谢更新的伪代码。我们必须看看我们是否可以在PostGIS中实际实现它。

– RyanKDalton
2011-2-11在0:16

#3 楼

尝试使用ST_CurveToLine

类似的东西: //www.postgisonline.org/map.php

评论


我最终尝试了一下,以弯曲一组“两点”线串。

–布伦特·爱德华兹
15年4月7日在18:40

#4 楼

我最终尝试使用@NicklasAvén建议的使用ST_CurveToLine函数弯曲一组“两点”线串。

我将以下3个坐标集传递给ST_OffsetCurve函数: >

原始线的起点
平行于原始线的线偏移的中点
原始线的终点

我使用了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


评论


确实有用,但由于某种原因,结果不尊重我的要求。知道为什么吗?

– DMS02
16-10-26在14:13

您能否提供更多详细信息-输入几何图形,输出图形缺失,不同,生成错误(哪些应用程序-QGIS,PostgreSQL)。

–布伦特·爱德华兹
16-10-27在14:52



我要在其中插入结果曲线的表格具有force_srid_geom约束。当我执行查询时,我收到一条错误消息,说该查询违反了该约束。对于没有此约束的表,它可以工作,但随后将其添加到QGIS时,其编号为srid 0。

– DMS02
16-10-28在6:47



尝试在几何列(the_curved_geom)上运行postgis.net/docs/ST_GeometryType.html和postgis.net/docs/ST_SRID.html函数,并检查测试表和force_srid_geom是否存在冲突。如果是这样,您可以根据需要变换几何形状/纬线或修改测试表/约束。

–布伦特·爱德华兹
16-10-28在12:38

#5 楼

我认为您只想使用一些矢量数学,http://en.wikipedia.org/wiki/B%C3%A9zier_curve来滚动自己的折线,或者如果您的gis具有ICurve界面。