Answers:
创建大圈子可以为您带来理想的效果。
也许在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/ )
问题在于弄清楚弯曲弧度以提高其视觉分辨率的程度。
这是一种解决方案(在许多可能的解决方案中)。让我们考虑从共同原点发出的所有弧。弧线在这里最拥挤。为了最好地分离它们,让我们对其进行排列,使它们以相等的角度分布。如果我们绘制从原点到目的地的直线段,这是一个问题,因为通常会有沿不同方向的目的地簇。让我们利用自由度来弯曲圆弧,以便尽可能均匀地隔开离去的角度。
为简单起见,让我们在地图上使用圆弧。从点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的人做的,我能做出这样一个很多更具可读性。)的符号包括:
该代码的可执行部分非常简短,少于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π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
]
例如:
SELECT ST_CurveToLine('CIRCULARSTRING(1 1,5 3,10 1)'::geometry) as the_geom;
您可以通过将查询处理到文本框中并在http://www.postgisonline.org/map.php上按Map1来可视化此内容。
我认为您只是想使用一些矢量数学(http://en.wikipedia.org/wiki/B%C3%A9zier_curve)滚动自己的折线,或者如果您的gis具有ICurve界面。
我最终尝试使用@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