국제 날짜 줄 포장


13

OpenLayers를 사용하여 특정 날짜 내에 일부 라틴 아메리카 국가에 배치 된 다각형 (노란색)과 교차하는 모든 기능 (검정색)을 반환하는 필터가있는 WFS 레이어 (GeoServer)를 추가했습니다.

여기에 이미지 설명을 입력하십시오

그러나지도를 가로로 가로 지르는 지형지 물은 실제로 내 다각형과 교차하지 않습니다. 이 기능은 하와이와 피지 사이의 태평양 바다에 있으며 라틴 아메리카에서는 아닙니다. 문제는 국제 날짜 표시 줄을 건너는 대신 전 세계를 감싸서지도에 표시된다는 것입니다.

확률 적 특징은 다음과 같이 정의됩니다.

폴리곤 ((-179.700417 14.202717, -178.687422 13.992875,179.024138 8.24716, -179.98241 8.035567, -179.700417 14.202717))

이와 같은 문제가있는 날짜 줄 기능이 많이 있지만이 예제에서는이 기능을 좁혔습니다. 응용 프로그램에서 많은 것을 가지고 있기 때문에 무시할 수 없습니다.

기본 레이어와 WFS 레이어에서 "wrapDateLine : true"를 동일한 결과로 사용해 보았습니다.

이것이 GeoServer 문제인지 OpenLayers 문제인지 확실하지 않습니다.

국제 날짜 표시 줄 문제에 대한 해결책을 아는 사람이 있습니까?


2
소프트웨어에 왜 이런 문제가 있는지 모르겠습니다. 세상은 평평합니다.!
DavidF

방향 매개 변수가 있어야합니다.
CaptDragon

@CaptDragon이 문제에 대한 해결책은 무엇입니까?
Anil

@Anil 아직 없습니다. 하나를 찾으면 알려주십시오.
CaptDragon

답변:


6

불행히도 이것은 알려진 문제입니다. 문제는 이와 같이 날짜 줄을 지나는 도형이 모호하다는 것입니다. OL 및 GeoServer 렌더러는 의도가 전 세계적으로 "짧은"길을 가고 있다는 것을 쉽게 알 수 없기 때문에 예를 들어 170에서 -170으로 "일반적인"길을 해석하고 전 세계로 먼 길을갑니다.

불행하게도 날짜 표시 줄에있는 도형을 분할하는 것 외에는 이에 대한 좋은 해결책이 없습니다.


고맙습니다 +1, 동의하지만 도형을 나눌 수 없습니다. 다른 사람이 다른 아이디어를 가지고 있는지 보자.
CaptDragon

OpenLayers에서 잘 나누는 방법을 찾았습니다 .
CaptDragon

7

그리니치 자오선 (또는 다른 곳)에서 분할 된 투영을 사용하도록 맵을 다시 투영하여 관심있는 다각형이 맵의 불연속성을 넘지 않도록하십시오.


다각형은 세상을 아주 잘 덮고 있으며 항상 일부 선을 가로 지르는 다각형이 있습니다. 그러나 이렇게 분할되지 않은 투영에 대해 알고 있습니까?
CaptDragon

1
모든 투영법은 세상을 어딘가로 나눠야합니다. 수학에는 암시 적입니다. 당신이 할 수있는 일은 당신의 작업에 가장 적합한 투영을 선택하는 것입니다.
Ian Turton

그래, 당신 말이 맞아. 나는 이것을 며칠 동안 열어두고 다른 아이디어가 나오면 볼 것입니다. 귀하의 제안에 감사드립니다. :-)
CaptDragon

2

DragBox 작업을 통해 또는 사용자가 입력 한 확장 점을 플롯하여 관심 영역 사각형을 생성 할 수있는 응용 프로그램을 개발하면서이 문제를 꽤 오랫동안 연구 해 왔습니다. 이 모험을 시작했을 때 저는 OpenLayers를 처음 접했습니다. 수동으로 입력 한 확장 점의 문제는 AOI가 국제 날짜 표시 줄을 덮으면 그려진 사각형이 전 세계에 잘못된 방식으로 그려 질 수 있다는 것입니다. 수많은 StackExchange 사용자는 OpenLayers 응답자 만이 문제에 대해 물어 보았습니다. "(여기에서 설명하고 있습니다.)"OpenLayers는 그려 질 점의 방향 의도를 알 수 없으므로 기본값입니다. " 어, OpenLayers에 대해 충분히 배웠고이 문제가 저에게 일어나면서 그 응답에 대해 BS 깃발을 올려야합니다. 응답에 대한 문제는 정의에 따라 왼쪽 위 경도 및 위도뿐만 아니라 오른쪽 위 경도 및 위도를 지정하는 범위의 좌표를로드한다는 것입니다. 오른쪽 위 경도가 IDL의 서쪽에 있고 왼쪽 아래 경도가 IDL의 동쪽에있는 경우 사용자가 다각형을 플롯하려는 방법은 분명하지만 OpenLayers는 경도 값을 바꾸고 드로잉을 요구합니다. 전 세계에서 다각형이 잘못된 방식으로 익스텐트 선언 및 문제가있는 OpenLayers 메소드 호출 샘플이 아래에 표시되어 있습니다. 오른쪽 위 경도가 IDL의 서쪽에 있고 왼쪽 아래 경도가 IDL의 동쪽에있는 경우 사용자가 다각형을 플롯하려는 방법은 분명하지만 OpenLayers는 경도 값을 바꾸고 드로잉을 요구합니다. 전 세계에서 다각형이 잘못된 방식으로 익스텐트 선언 및 문제가있는 OpenLayers 메소드 호출 샘플이 아래에 표시되어 있습니다. 오른쪽 위 경도가 IDL의 서쪽에 있고 왼쪽 아래 경도가 IDL의 동쪽에있는 경우 사용자가 다각형을 플롯하려는 방법은 분명하지만 OpenLayers는 경도 값을 바꾸고 드로잉을 요구합니다. 전 세계에서 다각형이 잘못된 방식으로 익스텐트 선언 및 문제가있는 OpenLayers 메소드 호출 샘플이 아래에 표시되어 있습니다.

// I would start out with the following entered values as an example
lonLL = 175.781; // minX
latLL = 13.992;  // minY
lonUR = -165.937;// maxX
latUR = 25.945;  // maxY

// I would then make the following call
var manCoordEntryExtent = ol.extent.boundingExtent([[lonLL,latLL], [lonUR, latUR]]);

// Looking at the resulting structure in the debugger I get:
0: -165.937   // minX
1: 13.992     // minY
2: 175.781    // maxX
3: 25.945     // maxY
length: 4
__proto__: []

보시다시피 세로 좌표가 반전되어 전체 좌표 구조 인 다각형을 만듭니다. polygonFeature를 클릭 한 다음 해당 지형지 물을 벡터에 적용하고 마지막으로 다각형이 전 세계에서 잘못된 방향으로 이동 함을 알기 위해 플롯합니다.

OpenLayers 4 라이브러리에서이 ol.extent.boundingExtent 메소드를 파헤쳐 서 왜 이런 일이 발생했는지 알아 내야했습니다.

/**
 * Build an extent that includes all given coordinates.
 *
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @return {ol.Extent} Bounding extent.
 * @api
 */
ol.extent.boundingExtent = function(coordinates) {
  var extent = ol.extent.createEmpty();
  for (var i = 0, ii = coordinates.length; i < ii; ++i) {
    ol.extent.extendCoordinate(extent, coordinates[i]);
  }
  return extent;
};

It first calls ol.extent.createEmpty to initially create an extent structure

/**
 * Create an empty extent.
 * @return {ol.Extent} Empty extent.
 * @api
 */
ol.extent.createEmpty = function() {
  return [Infinity, Infinity, -Infinity, -Infinity];
};

// It then iterates thru the number of coordinates and fills in the extent   structure values, however...
// Here is where the problem is.  Notice the complete lack of any explanation as to what the hell this
// method is doing.  Why is it doing what it does?  All I know is that it cannot handle plots across 
// the IDL and it corrupts your extent structure if you try.

/**
 * @param {ol.Extent} extent Extent.
 * @param {ol.Coordinate} coordinate Coordinate.
 */
ol.extent.extendCoordinate = function(extent, coordinate) {
  if (coordinate[0] < extent[0]) {
    extent[0] = coordinate[0];
  }
  if (coordinate[0] > extent[2]) {
    extent[2] = coordinate[0];
  }
  if (coordinate[1] < extent[1]) {
    extent[1] = coordinate[1];
  }
  if (coordinate[1] > extent[3]) {
    extent[3] = coordinate[1];
  }
};

// The solution was for me to test for IDL myself and if found then create an empty extent and populate it myself manually.

// Using the same extent coordinates as before
lonLL = 175.781; // minX
latLL = 13.992;  // minY
lonUR = -165.937;// maxX
latUR = 25.945;  // maxY

// I test for Dateline instance (Dont have to worry about the potential of there being a polygon covering both Meridian 
// and Anti-meridian as a valid polygon is limited to a maximum size of just over 12 million square kilometers.)
if ((lonLL > 0.0) && (lonUR < 0.0)) {
    // Manually build the coordinates for the Area calculation as the boundingExtent 
    // codepath corrupts an extent to be plotted across the Dateline
    var manCoordEntryExtent = ol.extent.createEmpty();
    manCoordEntryExtent[0] = lonLL;
    manCoordEntryExtent[1] = latLL;
    manCoordEntryExtent[2] = lonUR + 360.0;
    manCoordEntryExtent[3] = latUR;
} else {
    var manCoordEntryExtent = ol.extent.boundingExtent([[lonLL,latLL], [lonUR, latUR]]);
}

// Looking at the resulting structure in the debugger I get:
0: 175.781 // minX
1: 13.992  // minY
2: 194.063 // maxX
3: 25.945  // maxY
length: 4
__proto__: []

내 코드는 사용자가 유효한 크기의 AOI 다각형을 만들 었는지 확인할 수 있도록 영역을 동적으로 계산합니다. DragBox 생성 선택을 처리 할 때 결과 지오메트리 구조에서 좌표를 요청하고 EPSG : 4326 투영을 위해 래핑 된 세계에서 좌표를 반환 할 때 처음 180.0도를 지난 좌표는 계속 증가하므로 lonUR 계산의 이유는 360.0-165.937 = 194.063. 내 영역 계산 코드 경로는 다음 IDL 테스트를 사용하며 DragBox getGeometry 호출에서 반환 된 것처럼 좌표 값을 시뮬레이션하는 데 필요한 수동 입력 좌표에 동일한 코드 경로를 사용합니다. 실제로 GEOJSON 다각형 구조를 테스트하고 있는데, 1 차원은 링 번호이며

 function getArea(coords, extent) {

  // Test for Western side of Dateline instance
  if (((coords[0][0][0] <= -180.0) && (coords[0][2][0] > -180.0)) ||
      // Test for Eastern side of Dateline instance
      ((coords[0][0][0] < 180.0) && (coords[0][2][0] >= 180.0))) {
 .
 .
 .

이 테스트가이 시점을 통과하면 코드는 IDL을 통해 면적을 계산하기 위해 개발 한 알고리즘을 사용합니다. 그렇지 않으면 다른 곳에서는 정상적으로 계산합니다.

그런 다음이 범위를 사용하여 다각형을 작성한 다음 polygonFeature를 만든 다음 해당 기능을 벡터에 적용하고 마지막으로 플롯하면 이번에는 올바르게 플롯됩니다. 그래서 내가 해결 한 영역 계산 문제를 해결하는 데 도움이되는 수정도 플로팅 문제를 수정했습니다.

이 솔루션은 다른 사람에게 도움이되거나 다른 방향으로 생각하게 할 수 있습니다. 마침내 IDL 문제를 두 가지 문제로 나눌 수 있었을 때 해결책이 나에게 왔습니다. 실제 면적 계산은 IDL에 다각형을 플로팅하는 문제 중 하나였습니다.


1
OL은> = 연산자를 사용하여 플로팅 할 때 어느 쪽을 가야하는지 알 수 있습니다. 170과 190을 주면 짧게 갈 것입니다. 170 -170을 주면 먼 길을 갈 것입니다. 경도를 항상 -180에서 180 사이로 "정규화"하면 정보가 손실됩니다. 정보를 되 찾을 수있는 한 가지 방법은 점 사이의 거리가> 180이 될 수 없도록 지시하는 것입니다.
Rivenfall

1

해결 방법 : 예

var mapserv = new OpenLayers.Layer.MapServer( "OpenLayers Basic",
                "http://vmap0.tiles.osgeo.org/wms/vmap0",
                {layers: 'basic'},
                {wrapDateLine: true} );

http://openlayers.org/dev/examples/wrapDateLine.html


WFS를 사용하여 게시 한 링크에 " 'Layer.WMS'또는 'Layer.MapServer'레이어를 사용하여 수행 할 수 있습니다"
CaptDragon

둘 다 지원되고 Layer.MapServer가 특별히 필요하지 않은 경우 Layer.WMS (MapServer에서 계속 제공 할 수 있음)를 사용하십시오.
DavidF

@DavidF : 감사합니다. 그러나 WFS의 벡터 기능을 사용해야합니다.
CaptDragon

1

2 년 후에도 벡터 레이어의 기능에 대해이 문제가 계속 발생했습니다. 나는 발견 이 파일 은 날짜 변경선을 넘어 경우 쇼가 어떻게 엔드 포인트를 플립하는 것을 코드의 조각을 함유 :

if(Math.abs(startPoint.x-endPoint.x) > 180) {
  if(startPoint.x < endPoint.x) {
    endPoint.x -= 360;
  } else {
    endPoint.x += 360;
  }
}

최신 정보:

실제로 위의 내용은 전 세계에서 하나 이상의 혁명에는 적용되지 않았습니다. 나는 일을 결국 본을 .

여기에 이미지 설명을 입력하십시오


1

나는 당신을 위해 작동하거나 작동하지 않을 수있는 내 자신의 프로젝트에서 이것에 대한 해결책을 생각해 냈습니다. LineStrings와 함께 작동한다는 사실을 알고 있지만 다른 지오메트리 유형에 대해서는 잘 모르겠습니다.

OpenLayers.Geometry.prototype.crossesDateLine = function() {
    var lastX = this.components[0];
    for (var i=0; i < this.components.length; i++) {
        if (Math.abs(this.components[i].x - lastX) > 180) return i;
        lastX = this.components[i].x;
    }
    return false;
};
OpenLayers.Geometry.prototype.dateLineFix = function() {
    var linestrings = [];
    if (this.crossesDateLine()) {
        var string1 = [];
        for (var i = 0; i < this.crossesDateLine(); i++)
            string1.push(this.components[i]);
        var ls1 = new OpenLayers.Geometry.LineString(string1);
        var string2 = [];
        for (var i = this.crossesDateLine(); i < this.components.length; i++)
            string2.push(this.components[i]);
        var ls2 = new OpenLayers.Geometry.LineString(string2);

        if (!ls1.crossesDateLine()) {
            linestrings.push(ls1);
        } else {
            var split = ls1.dateLineFix();
            for (var i = 0; i < split.components.length; i++)
                linestrings.push(split.components[i]);
        }
        if (!ls2.crossesDateLine()) {
            linestrings.push(ls2);
        } else {
            var split = ls2.dateLineFix();
            for (var i = 0; i < split.components.length; i++)
                linestrings.push(split.components[i]);
        }
    } else {
        linestrings.push(this);
    }
    return new OpenLayers.Geometry.MultiLineString(linestrings);
};

dateLineFix 함수는 날짜 행을 교차하는 세그먼트에 대해 주어진 LineString을 반복적으로 순회합니다. 그런 다음 날짜 표시 줄에서 두 개로 잘라 내고 모든 결과 세그먼트를 MultiLineString으로 반환합니다.

그것은 내 목적을 위해 완벽하게 작동했습니다 (극성 위도 격자 그리기).


0

나는 dateline에 거의 문제가 없었고 모든 문제를 해결했습니다. 당신은 다음을 시도 할 수 있습니다.

  1. GeoServer 레이어 경계 상자 값을 수동으로 업데이트하여 다각형을 중단하지 않고 문제를 해결하는지 확인하십시오.

  2. Openlayers에서 한 수정 중 하나는 + ve 경도에서 -ve로 날짜 줄을 전달할 때 타일이 누락되었습니다. http://trac.osgeo.org/openlayers/ticket/2754 WFS에 해당되는지 확실하지 않습니다. 최신 오픈 레이어 개발 버전을 다운로드하여 사용해 볼 수 있습니다.



0

EPSG : 3832 (WGS84 PDC)는 태평양 중심 투영입니다. 이는 주요 Meridian 교차 문제에 대한 IDL 교차 문제를 교환합니다. 묘사 한 내용에 따라 문제가되지 않을 수 있습니다. 나는 또한 북극과 남극권 근처에서 문제를 발견했습니다.

크레딧은 기사 로갑니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.