-1

我正在研究 openlayers,当我尝试在地图上添加线串时出现问题,该线串多次穿过日期线。

为了在连续段中显示跨越两个世界的线串,我添加了一个函数,该函数HandleDateline()返回修改后的(移动到左或右世界)坐标。

但是,当您将左侧世界放大到当前固定视图时,线串会消失。此外,如果您尝试将地图向左移动,这条线就会消失。

奇怪的是,如果线交叉超过 1 次,左侧世界的线串就会消失,否则右侧世界也会发生同样的情况。也请注意,删除datelinecrossing[]我将发布的前 3 点或后 3 点。

我期待一条连续的线串穿过国际日期变更线,而不会出现任何消​​失等问题。

如果有更好的方法来解决这个问题,我对所有想法持开放态度。这是垃圾箱:ol dateline problem

4

3 回答 3

2

您必须在日期线上以编程方式分割穿过日期线的线。

var points = [
  [-170, -10],
  [170, 0],
  [-170, 10]
];

var vectorSource = new ol.source.Vector();
vectorSource.addFeature(createFeature(points));

var vectorLayer = new ol.layer.Vector({
  source: vectorSource,
  style: new ol.style.Style({
    stroke: new ol.style.Stroke({
      width: 2,
      color: "red"
    })
  })
});

var osmLayer = new ol.layer.Tile({
  source: new ol.source.OSM()
});

var map = new ol.Map({
  layers: [osmLayer, vectorLayer],
  target: document.getElementById("map"),
  view: new ol.View({
    center: ol.proj.transform([180, 0], "EPSG:4326", "EPSG:3857"),
    zoom: 3
  })
});

var graticule = new ol.Graticule({
  strokeStyle: new ol.style.Stroke({
    color: "rgba(255,120,0,0.9)",
    width: 1.5,
    lineDash: [0.5, 4]
  }),
  showLabels: true
});
graticule.setMap(map);

// -------------------------------------------------

function createFeature(points) {
  var pointsSplitted = [];
  var pointsArray = [];
  pointsSplitted.push(points[0]);
  var lastLambda = points[0][0];

  for (var i = 1; i < points.length; i++) {
    var lastPoint = points[i - 1];
    var nextPoint = points[i];
    if (Math.abs(nextPoint[0] - lastLambda) > 180) {
      var deltaX = xToValueRange(nextPoint[0] - lastPoint[0]);
      var deltaY = nextPoint[1] - lastPoint[1];
      var deltaXS = xToValueRange(180 - nextPoint[0]);
      var deltaYS;
      if (deltaX === 0) {
        deltaYS = 0;
      } else {
        deltaYS = deltaY / deltaX * deltaXS;
      }
      var sign = lastPoint[0] < 0 ? -1 : 1;
      pointsSplitted.push([180 * sign, nextPoint[1] + deltaYS]);
      pointsArray.push(pointsSplitted);
      pointsSplitted = [];
      pointsSplitted.push([-180 * sign, nextPoint[1] + deltaYS]);
    }
    pointsSplitted.push(nextPoint);
    lastLambda = nextPoint[0];
  }

  pointsArray.push(pointsSplitted);
  var geom = new ol.geom.MultiLineString(pointsArray);
  geom.transform("EPSG:4326", "EPSG:3857");
  var feature = new ol.Feature({
    geometry: geom
  });
  return feature;
}

function xToValueRange(x) {
  if (Math.abs(x) > 180) {
    var sign = x < 0 ? -1 : 1;
    return x - 2 * 180 * sign;
  } else {
    return x;
  }
}
html,
body,
#map {
  width: 100%;
  height: 100%;
  overflow: hidden
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>

<body>
  <div id="map" class="map" tabindex="0"></div>
</body>

于 2019-02-07T11:50:42.433 回答
1

简化HandleDateline后,所有坐标要么位于正常世界的西部,要么位于左侧世界的东部,似乎可以修复它(因此,如果几何体越过日期变更线,则范围从左侧世界开始)

 function HandleDateline(array) {
        for (var i = 0; i < array.length ; i++) {
            if (array[i][0] > 0) {
                array[i][0] -= 360;
            }
        }
    }

然而,在右边的世界中,日期线以西的点似乎被渲染到线串下方,而日期线以东的点则在其上方。移到HandleDateline(datelinecrossing);上面datelinecrossing.forEach可以解决这个问题。

您可能还需要考虑对点使用多点几何(除非您需要它们可以单独选择)。

HandleDateline(datelinecrossing);
var pdlcrossing = new ol.Feature({
    geometry: new ol.geom.MultiPoint(datelinecrossing).transform('EPSG:4326', 'EPSG:3857')
});
drawingSource.addFeature(pdlcrossing);
var dlcrossing = new ol.Feature({
    geometry: new ol.geom.LineString(datelinecrossing).transform('EPSG:4326', 'EPSG:3857')
});
drawingSource.addFeature(dlcrossing);

在右侧世界的日期变更线以西放大仍然存在问题,所以我认为每个几何图形都需要两组,一组向左偏移,另一组向右偏移 360 度:

function PlotGeometries(datelinecrossing){
  var pgeom = new ol.geom.MultiPoint(datelinecrossing);
  var pdlcrossing = new ol.Feature({
    geometry: pgeom.clone().transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(pdlcrossing);
  pgeom.translate(360,0);
  var pdlcrossing2 = new ol.Feature({
    geometry: pgeom.transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(pdlcrossing2);
  var geom = new ol.geom.LineString(datelinecrossing);
  var dlcrossing = new ol.Feature({
    geometry: geom.clone().transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(dlcrossing);
  geom.translate(360,0);
  var dlcrossing2 = new ol.Feature({
    geometry: geom.transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(dlcrossing2);
}
于 2019-02-07T12:06:42.030 回答
0

只需为您正在处理的世界的一部分设置地图视图的范围。

于 2019-02-07T11:22:24.683 回答