用于将2D多边形的横截面变为一维几何的工具或库?

时间:2013-12-01 18:26:06

标签: javascript mapping openlayers intersection geojson

我是一名从事某些空域建模实验的业余飞行员。我想要实现的是一个轻松创建空域横截面的工具,即3D空域到2D。所以最后我希望有一个类似于这个创建的图像:airspace example。准确性并不重要,因为这些横截面不会用于导航目的,而只能用于培训/可视化。因此坐标几何就足够了,不需要测地线计算。

目前,我在我的数据库中存储GeoJSON 2D几何图形(所有多边形),其中包含每个空域元素的较低和较高海拔高度限制的附加元数据。因此,我实际上只在我的OpenLayers和Leaflet.js地图上显示2D数据。

我希望用户能够在地图上绘制线串(请参见下图中的绿色线串,为了演示目的,笔划宽度显着增加)。我可以使用OpenLayers或Leaflet。结果应该是与用户绘制的线相交的2D元素的一维横截面,就像我在这个艺术插图中一样:

Cross section 2D -> 1D

澄清:如果输出的1维横截面的长度是例如1L,那么示例中的横截面的内容应该是以下几何的集合:1)0.1L和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 个答案:

答案 0 :(得分:0)

发布我自己的问题的答案以供将来参考。我能够提出一个创建空域横截面的解决方案。它基于坐标几何。

1)输入数据是横截面的起点和终点坐标。

2)遍历所有区域并检查起始和/或结束坐标是否落在任何空域区域(多边形)内。 PHP代码从另一个SO答案略微修改,以检查一个点是否在多边形内:

// 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坐标。