我是一名业余飞行员,从事一些空域建模实验。我正在尝试实现的工具是轻松创建空域横截面的工具,即3D空域到2D。最后,我想创建一个与此图像类似的图像:airspace example。精度并不重要,因为这些横截面不会用于导航目的,而仅用于培训/可视化。因此,坐标几何就足够了,不需要测地线计算。
目前,我将GeoJSON 2D几何(所有多边形)与其他元数据存储在数据库中,这些元数据包含每个空域元素的海拔高度上下限。因此,我实际上只在OpenLayers和Leaflet.js地图上显示2D数据。
我希望用户能够在地图上绘制线串(请参见下图的绿色线串,为演示起见,笔划宽度已大大增加)。我可以使用OpenLayers或Leaflet来做。结果应该是与用户绘制的线相交的2D元素的一维横截面,如我的这张非常艺术性的插图所示:
澄清:如果输出的一维横截面的长度例如为1L,则示例中横截面的内容应为以下几何形状的集合:1)0.1L和0.5L之间的黑线;以及2)红线介于0.7L和0.825L之间。
用户界面部分是可行的,它将在OpenLayers或Leaflet之上运行。我还发现了多种语言的几种算法,用于确定两条线是否相交,甚至找出相交点。我可以使用Raphael.js然后绘制横截面。
我应该在一两天内就能完成所有这一切……但是我想知道是否有更简单的方法?例如,是否有人知道一个软件库,该软件库可以计算出我要实现的横截面?哦,请不要提及那些价值10,000美元的GIS软件包:-)。
由于这将是一个Web应用程序,因此我主要研究Javascript,Perl或PHP解决方案。 GeoJSON Utilities for JavaScript在计算相交方面看起来很有前途,但我想知道是否还有其他人?
最佳答案
发布我自己的问题的答案以供将来参考。我能够提出一种创建空域横截面的解决方案。它基于坐标几何。
1)输入数据是横截面的起点和终点。
2)遍历所有区域,并检查起点和/或终点坐标是否落在任何空域区域(多边形)内。从另一个SO答案中稍微修改了PHP代码,以检查点是否在多边形内:
// Point class, storage of lat/long-pairs
class Point {
var $lat;
var $long;
function Point($lat, $long) {
$this->lat = $lat;
$this->long = $long;
}
}
function pointInPolygon($p, $polygon) {
$c = 0;
$p1 = $polygon[0];
$n = count($polygon);
for ($i=1; $i<=$n; $i++) {
$p2 = $polygon[$i % $n];
if ($p->long > min($p1->long, $p2->long)
&& $p->long <= max($p1->long, $p2->long)
&& $p->lat <= max($p1->lat, $p2->lat)
&& $p1->long != $p2->long) {
$xinters = ($p->long - $p1->long) * ($p2->lat - $p1->lat) / ($p2->long - $p1->long)
if ($p1->lat == $p2->lat || $p->lat <= $xinters) {
$c++;
}
}
$p1 = $p2;
}
// if the number of edges we passed through is even, then it's not in the poly.
return $c%2!=0;
}
3)遍历包含空域数据的每个区域(多边形)的所有线段。从另一个SO答案稍作修改的PHP代码返回了两个线段的交点:
function Det2($x1, $x2, $y1, $y2) {
return ($x1 * $y2 - $y1 * $x2);
}
function lineIntersection ($v1Y, $v1X, $v2Y, $v2X, $v3Y, $v3X, $v4Y, $v4X) {
$tolerance = 0.000001;
$a = Det2($v1X - $v2X, $v1Y - $v2Y, $v3X - $v4X, $v3Y - $v4Y);
if (abs($a) < $tolerance) return null; // Lines are parallel
$d1 = Det2($v1X, $v1Y, $v2X, $v2Y);
$d2 = Det2($v3X, $v3Y, $v4X, $v4Y);
$x = Det2($d1, $v1X - $v2X, $d2, $v3X - $v4X) / $a;
$y = Det2($d1, $v1Y - $v2Y, $d2, $v3Y - $v4Y) / $a;
if ($x < min($v1X, $v2X) - $tolerance || $x > max($v1X, $v2X) + $tolerance) return null;
if ($y < min($v1Y, $v2Y) - $tolerance || $y > max($v1Y, $v2Y) + $tolerance) return null;
if ($x < min($v3X, $v4X) - $tolerance || $x > max($v3X, $v4X) + $tolerance) return null;
if ($y < min($v3Y, $v4Y) - $tolerance || $y > max($v3Y, $v4Y) + $tolerance) return null;
return array($x, $y);
}
4)如果存在相交的线段,请找出相交点(作为上一步的结果)与横截面起始坐标的距离。将其除以横截面的总长度即可得到空域区域边界在横截面上的相对位置。
5)根据点2和点4的结果,绘制SVG多边形。相对交点位置被转换为多边形的X坐标,海拔数据(上下限)成为多边形的Y坐标。