使用OpenLayers在日期线上分割线串


9

几年前,我发布了国际日期变更线,@jdeolive 建议我在dateLine 拆分功能。所以我尝试了。

当我尝试在日期线上使用splitWith拆分卫星轨道时,我回来了null。我知道我的分裂是正确的,因为当我在格林威治线上分裂时,我得到了预期的结果。

有人知道我如何才能使用OpenLayers在日期线上以编程方式正确分割Linestring吗?我寻求示例代码(如果有)。

我已经尝试过了,wrapDateLine但是尽管我的向量层是这样的,但它似乎在向量层上似乎没有作用:

vectorLayer = new OpenLayers.Layer.Vector("GroundTracks", {
    renderers: ['Canvas', 'VML'],
    wrapDateLine: true}); // <-- shoud be wraping.

在此处输入图片说明

这是我的代码:

var features = [];
var format = new OpenLayers.Format.WKT({
    'internalProjection': map.baseLayer.projection,
    'externalProjection': prjGeographic
});
var satTrack = format.read("LINESTRING (95.538611 13.286511, 94.730711 16.908947, 93.901095 20.528750, 93.043594 24.145177, 92.150978 27.757436, 91.214579 31.364666, 90.223791 34.965899, 89.165364 38.560019, 88.022401 42.145679, 86.772901 45.721205, 85.387568 49.284424, 83.826433 52.832413, 82.033480 56.361087, 79.927797 59.864504, 77.388419 63.333664, 74.227306 66.754285, 70.139140 70.102478, 64.605267 73.335774, 56.712904 76.373458, 44.881134 79.052803, 26.939886 81.047314, 02.704174 81.839241, -21.686285 81.101751, -39.887660 79.141947, -51.906937 76.480894, -59.912477 73.452897, -65.514482 70.225089, -69.645366 66.880243, -72.834535 63.461797, -75.393132 59.994131, -77.512464 56.491789, -79.315407 52.963919, -80.884039 49.416549, -82.275114 45.853820, -83.529088 42.278691, -84.675583 38.693355, -85.736827 35.099503, -86.729876 31.498490, -87.668095 27.891443, -88.562176 24.279331, -89.420849 20.663020, -90.251389 17.043303, -91.059999 13.420926, -91.852092 09.796602, -92.632515 06.171020, -93.405728 02.544857, -94.175960 -01.081217, -94.947343 -04.706542, -95.724045 -08.330456, -96.510402 -11.952298, -97.311065 -15.571400, -98.131162 -19.187081, -98.976502 -22.798638, -99.853829 -26.405335, -100.771148 -30.006378, -101.738172 -33.600889, -102.766925 -37.187866, -103.872602 -40.766117, -105.074803 -44.334175, -106.399366 -47.890158, -107.881153 -51.431559, -109.568417 -54.954914, -111.529886 -58.455253, -113.866668 -61.925160, -116.733085 -65.353081, -120.374635 -68.720132, -125.199754 -71.993642, -131.916790 -75.113368, -141.772276 -77.960803, -156.750096 -80.294831, -178.475596 -81.673196, 156.248392 -81.611421, 135.042323 -80.136505, 120.556535 -77.748172, 111.014840 -74.872356, 104.485504 -71.737081, 99.775637 -68.454400, 96.208126 -65.081545, 93.391438 -61.649716, 91.089380 -58.177038, 89.152970 -54.674643, 87.484294 -51.149703, 86.016609 -47.607042, 84.702947 -44.050030, 83.509299 -40.481112, 82.410411 -36.902133, 81.387093 -33.314533, 80.424442 -29.719485, 79.510644 -26.117981, 78.636145 -22.510889, 77.793053 -18.898997, 76.974710 -15.283040, 76.175371 -11.663718, 75.389950 -08.041709, 74.613831 -04.417680, 73.842693 -00.792294, 73.072378 02.833789, 72.298749 06.459907, 71.517566 10.085391, 70.724342 13.709564, 69.914194 17.331733, 69.081655 20.951185, 68.220447 24.567170, 67.323194 28.178891, 66.381031 31.785476, 65.383084 35.385943, 64.315735 38.979152, 63.161579 42.563725, 61.897893 46.137940, 60.494337 49.699551, 58.909396 53.245525, 57.084691 56.771602, 54.935577 60.271560, 52.334964 63.735923, 49.084320 67.149569, 44.859585 70.487030, 39.107498 73.702694, 30.852243 76.709182, 18.420695 79.329532, -00.339911 81.212453, -25.028018 81.831766)");

var featGreenwichLine = format.read("LINESTRING(0 -89, 0 89)");
var featDateLine = format.read("LINESTRING(180 -89, 180 89)");

features.push(featGreenwichLine);
features.push(featDateLine);
features.push(satTrack);

var resultsGreenwich = satTrack.geometry.splitWith(featGreenwichLine.geometry);
var resultsDateLine = satTrack.geometry.splitWith(featDateLine.geometry);

console.log(resultsGreenwich); //<--RETURNS EXPECTED RESULTS.
console.log(resultsDateLine);//<--RETURNS NULL.

vectorLayer.addFeatures(features);

我的问题不是该问题的重复,因为他们想知道如何在ogr2ogr中进行操作

更新:

这是我使用的典型数据集的样子(24小时卫星航迹):可以在此处找到Linestring wkt 。

在此处输入图片说明


您正在使用哪个版本的openlayers?
Plux

@Plux 2.13.1(最新)
CaptDragon 2014年

1
根据他们的API,wrapDateLine仅应在基础层上使用,因此也就怪不得它在矢量层上不起作用。但是,我不知道如何使它在矢量层上工作。我自己也遇到了类似的问题,即跨越日期线的多面体。
Plux

1
@Plux签出我的解决方案
CaptDragon 2014年

不错的解决方案。不幸的是,这不适用于我的问题,我认为我的问题更多是在地理服务器端,并且我的多边形包含在日期线“另一侧”的坐标,例如-180.00000000000003 90.00000190734869,这会在我认为的地理服务器中造成一些问题。我没有在我的地图上显示此问题(我有一个执行此操作的wms),但我想将这些用作wfs查询中到geoserver的过滤器:)
Plux

Answers:


2

问题是从OpenLayers角度来看,您的功能不会越过日期线,因此拆分线不会与您的功能相交。来自您的数据的示例:

..., -178.475596 -81.673196, 156.248392 -81.611421,...

您从-178上升到156,从OpenLayers角度看,这不会越过日期线。而不是在日期行拆分,您应该拆分最小X值。

// Build the splitting line based on the min and max coordinates of the vector to split
var minX = 999999999;
var minY = -20037508.34 // minimum value of the spherical mercator projection
var maxY = 20037508.34  // maximum value of the spherical mercator projection
//Extract the minimum X from the data as bounds seems to be rounded.
for(var i=0; i<satTrack.geometry.components.length; i++) {
    if(satTrack.geometry.components[i].x < minX)
        minX = satTrack.geometry.components[i].x;
}
var pointList = [
    new OpenLayers.Geometry.Point(minX, minY),
    new OpenLayers.Geometry.Point(minX, maxY)
];
var featDateLine = new OpenLayers.Feature.Vector(
    new OpenLayers.Geometry.LineString(pointList)
);

我在这里建立了一个示例,将您的卫星轨道成功地分为了两个功能:http : //jsfiddle.net/6XJ5A/

现在,要在更新中将WKT与多行一起使用,而不是使用直线,您必须遍历整个数据集并使用跨越日期线的所有坐标来构建分割线。通过在多条线内构建小线,您可以分割应该跨越日期线的所有坐标。这是更新后的示例:http : //jsfiddle.net/Jc274/

和代码:

// Build the splitting line based on the min and max coordinates of the vector to split
var pointList = [];
var lastPoint = satTrack.geometry.components[0];
//Extract the minimum X from the data as bounds seems to be rounded.
for (var i = 1; i < satTrack.geometry.components.length; i++) {
    if (Math.abs(satTrack.geometry.components[i].x - lastPoint.x) > 10000000) {
        pointList.push(satTrack.geometry.components[i]);
    }
    lastPoint = satTrack.geometry.components[i];
}

var lineList = [];
for(var i=0; i<pointList.length; i++) {
    lineList.push(new OpenLayers.Geometry.LineString([
        new OpenLayers.Geometry.Point(pointList[i].x, pointList[i].y-0.00001), 
        new OpenLayers.Geometry.Point(pointList[i].x, pointList[i].y+0.00001)
    ]));
}

var featDateLine = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.MultiLineString(lineList), null, split_style);

这将在“跨越”日期线的所有点上返回一条分割线

请注意,我还遍历坐标以删除穿过地图连接2个坐标的线:

for (var i = 0; i < resultsDateLine.length; i++) {
    // Remove the first (or last) point of the line, the one that cross the dateline
    if (Math.abs(resultsDateLine[i].components[0].x - resultsDateLine[i].components[1].x) > 10000000) {
        resultsDateLine[i].removeComponent(resultsDateLine[i].components[0]);
    }
    if (Math.abs(resultsDateLine[i].components[resultsDateLine[i].components.length - 1].x - resultsDateLine[i].components[resultsDateLine[i].components.length - 2].x) > 10000000) {
        resultsDateLine[i].removeComponent(resultsDateLine[i].components[resultsDateLine[i].components.length - 1]);
    }
    features.push(new OpenLayers.Feature.Vector(resultsDateLine[i], null, style_array[i]));
}

更新: 我更新了第一个示例,仅添加了被拆分的行。我也相应地更新了说明。对于您提供的24小时卫星跟踪,这种方法不是防弹的,但是我正在努力。

更新2: 我更新了第二个示例。通过使用多行分割和循环遍历结果以删除分割添加的额外坐标,我们获得了一组永远不会跨越日期线的要素。


+1可以帮助您解决问题,但您的地图示例似乎无法解决问题。您的示例地图上的卫星轨道仍然跨越整个地球,而不是遵循卫星轨道的自然路径。我肯定错过了什么?
CaptDragon 2014年

您可能会误解该问题,因为..., -178.475596 -81.673196, 156.248392 -81.611421,...绝对超出了日期范围。看到这里
CaptDragon 2014年

让我更新代码和解释。我知道它应该越过数据线,但是OpenLayers不支持这一点。从OL的角度来看,它没有越过日期线。
朱利安·塞缪尔·拉克鲁瓦

那就对了。那就是问题所在。我将需要欺骗OpenLayers并分割线,以便它直接到达边缘,然后在原本应该的另一边继续。
CaptDragon 2014年

2

我在@Dane的github上找到了一个很好的解决方案。它称为Arc.js,用于计算大圆弧路线。不仅如此,它还会在日期线上分割行,并为您提供在日期线上相遇的两个线串,OpenLayers可以轻松地映射它们。我希望他站出来要求赏金。

这是我的结果:

在此处输入图片说明 在此处输入图片说明


1

splitWith功能不知道地球的三维形状。它仅在二维世界中运行。在您的情况下,所有LINESTRINGX坐标都在-180到180之间。因此,从OpenLayers的二维角度来看,线串实际上从未与拆分的几何体(日期线)交叉,并且通过返回告诉了您null

我相信您将必须编写一些自定义代码来进行拆分。我正在想象一个循环遍历您的顶点的算法,构建如下的输出行字符串:

  • 对于每个相邻的顶点对,确定它们之间的线段是否穿过日期线。
  • 如果不是,则保持该段不变,然后将其添加到“当前”输出行字符串中。
  • 如果是这样,请将线段分为两部分。将一部分添加到“当前”行字符串中,开始一个新的“当前”行字符串,并将另一部分添加到该新行字符串中。

确定一对顶点是否穿过日期线的一种合理启发法是查看X坐标之间的差是否大于180度。(尽管这样做可能会出错,例如在极地地区。也许您很幸运没有很高的纬度。)

将线段分为两部分的操作可能与线性插值一样简单(如果您不太在乎轨迹的准确性)。当您检测到该线段越过日期线时,您将复制第二个顶点并移动其X坐标(通过添加或减去360度),然后插值Y坐标。

编辑:这是一个JSFiddle,它可以对您的数据演示上述算法:http : //jsfiddle.net/85vjS/


0

如果它与格林威治兼容,那是因为您位于CRS的范围之内。因此,我首先建议与您所指向的帖子中相同的解决方法:

var featDateLine = format.read("LINESTRING(179.99 -89, 179.99 89)");

有可能

var featDateLine = format.read("LINESTRING(-179.99 -89, -179.99 89)");

换另一侧。

另一个解决方案是在日期线上不“超出范围”的CRS中工作。然后,您应该能够毫无问题地拆分数据。


我已经尝试过两者LINESTRING(179.99 -89, 179.99 89),但LINESTRING(-179.99 -89, -179.99 89)都没有成功。关于CRS,不幸的是,这对我的目的不起作用,因为我正在绘制遍及全球的卫星轨道的地图。因此,所有CRS都被拆分到某个位置,而在拆分它的任何位置,我都会遇到相同的问题。感谢您的输入。
CaptDragon 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.