Openlayers日期线交叉线串消失

时间:2019-02-07 11:13:27

标签: javascript openlayers openlayers-3 openlayers-5 angular-openlayers

我在openlayers上工作,当我尝试在地图上添加多次跨越日期线的线串时出现问题。

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

但是,当您在左侧世界中放大到当前的固定视图时,线串消失了。另外,如果您尝试将地图向左移动,该线也会消失。

奇怪的是,如果线相交超过1次,则左侧世界上的线串消失,否则右侧世界上的情况相同。太注意了,从我将要发布的datelinecrossing[]中删除前3点或后3点。

我希望连续的线串跨越国际日期变更线,而不会出现任何消​​失的问题。

如果有更好的方法,我愿意接受所有想法。 这是垃圾箱:ol dateline problem

3 个答案:

答案 0 :(得分:1)

您必须以编程方式在日期线上分割与日期线交叉的线。

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>

答案 1 :(得分: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);
}

答案 2 :(得分:0)

只需为您正在研究的世界的一部分设置地图视图的范围即可。