บรรทัดวันที่สากลล้อมรอบ


13

เมื่อใช้ OpenLayers ฉันเพิ่มเลเยอร์ WFS (บน GeoServer) ด้วยตัวกรองที่ส่งคืนฟีเจอร์ทั้งหมด (สีดำ) ที่ตัดกันรูปหลายเหลี่ยมของฉัน (สีเหลือง) ที่วางอยู่เหนือประเทศละตินอเมริกาบางแห่งภายในวันที่กำหนด

ป้อนคำอธิบายรูปภาพที่นี่

อย่างไรก็ตามคุณสมบัติที่ข้ามในแนวนอนบนแผนที่ไม่ได้ตัดกับรูปหลายเหลี่ยมของฉัน คุณลักษณะนี้อยู่ที่ไหนสักแห่งในมหาสมุทรแปซิฟิกระหว่างฮาวายและฟิจิและไม่ใช่ในละตินอเมริกา ปัญหาคือแทนที่จะข้ามเส้นวันที่ระหว่างประเทศกำลังแสดงผลบนแผนที่โดยล้อมรอบทั้งโลก

คุณสมบัติ problamatic ถูกกำหนด:

POLYGON ((- 179.700417 14.202717, -178.687422 13.992875,179.024138 8.24716, -179.98241 8.035567, -179.700417 14.202717)

ฉันมีคุณสมบัติของเส้นวันที่ที่เป็นปัญหาเช่นนี้ แต่มีการ จำกัด ให้แคบลงเป็นตัวอย่างนี้ ฉันไม่สามารถเพิกเฉยได้ในแอปพลิเคชันของฉันเพราะฉันมีหลายอย่าง

ฉันได้ลองใช้ "wrapDateLine: true" ในชั้นฐานและชั้น WFS ด้วยผลลัพธ์เดียวกัน

ไม่แน่ใจว่านี่จะเป็นปัญหา GeoServer หรือปัญหา OpenLayers

ไม่มีใครรู้วิธีการแก้ปัญหาบรรทัดวันที่ระหว่างประเทศของฉัน?


2
ฉันไม่รู้ว่าทำไมซอฟท์แวร์ถึงมีปัญหาเช่นนี้โลกแบนราบใช่มั้ย!
DavidF

อาจจะควรมีพารามิเตอร์ทิศทาง
CaptDragon

@CaptDragon แก้ปัญหานี้ได้อย่างไร?
Anil

@Anil ยังไม่มี โปรดแจ้งให้เราทราบหากคุณพบ
CaptDragon

คำตอบ:


6

น่าเสียดายที่นี่เป็นปัญหาที่ทราบกันดี ปัญหาคือรูปทรงเรขาคณิตที่ข้ามเส้นวันเช่นนี้ไม่ชัดเจน ตัวแสดง OL และ GeoServer ไม่มีวิธีที่ง่ายในการรู้ว่าความตั้งใจคือการใช้วิธี "สั้น" ทั่วโลกดังนั้นพวกเขาจึงตีความเช่น 170 ถึง -170 เป็นวิธี "ปกติ" และไปไกลทั่วโลก

น่าเสียดายที่ไม่มีวิธีแก้ปัญหาที่ดีสำหรับเรื่องนี้ยกเว้นการแยกรูปทรงเรขาคณิตของคุณที่อยู่ตรงข้ามวันที่


ขอบคุณ +1 ฉันเห็นด้วย แต่ฉันไม่สามารถแยกรูปทรงเรขาคณิตของฉันได้ มาดูกันว่าใครมีแนวคิดอื่น
CaptDragon

ฉันคิดหาวิธีที่จะแยกพวกเขาเป็นอย่างดีใน OpenLayers
CaptDragon

7

ปฏิเสธแผนที่ของคุณอีกครั้งเพื่อใช้การฉายภาพซึ่งแบ่งที่ Greenwich Meridian (หรือที่อื่น ๆ ) เพื่อให้รูปหลายเหลี่ยมที่คุณสนใจไม่ข้ามความไม่ต่อเนื่องในแผนที่ของคุณ


รูปหลายเหลี่ยมที่ครอบคลุมโลกค่อนข้างดีจะมีรูปหลายเหลี่ยมที่จะข้ามเส้น แต่คุณรู้หรือไม่ว่าการคาดการณ์ใด ๆ ที่ไม่ได้แยกออกเป็นเช่นนี้?
CaptDragon

1
การคาดการณ์ทั้งหมดจะต้องแยกโลกที่ไหนสักแห่งมันเป็นนัยในวิชาคณิตศาสตร์ (ลอกส้มถ้าคุณไม่เชื่อฉัน :-)) สิ่งที่คุณทำได้คือเลือกการฉายภาพที่ดีที่สุดสำหรับงานของคุณ
Ian Turton

ถูกของคุณ. ฉันจะปล่อยให้เปิดสองสามวันและดูว่าความคิดอื่น ๆ เกิดขึ้น ขอบคุณสำหรับคำแนะนำของคุณ :-)
CaptDragon

2

ฉันได้ทำการค้นคว้าปัญหานี้มาระยะหนึ่งแล้วเนื่องจากฉันได้พัฒนาแอพพลิเคชั่นที่อนุญาตให้ผู้ใช้สร้างสี่เหลี่ยมผืนผ้าของพื้นที่ที่น่าสนใจไม่ว่าจะผ่านการกระทำของ DragBox หรือพล็อตที่ผู้ใช้ป้อน เมื่อฉันเริ่มการผจญภัยครั้งนี้ฉันยังใหม่กับ OpenLayers อย่างสมบูรณ์ ปัญหาของคะแนนขอบเขตที่ป้อนด้วยตนเองคือถ้า AOI ครอบคลุม International Dateline การลากเส้นสี่เหลี่ยมจะถูกวาดผิดไปทั่วโลก ผู้ใช้ StackExchange จำนวนมากได้ถามเกี่ยวกับปัญหานี้เท่านั้นที่จะได้รับการบอกกล่าวจากผู้ตอบ OpenLayers ว่า (และฉันกำลังถอดความที่นี่) "OpenLayers ไม่มีหนทางที่จะรู้ถึงจุดประสงค์ทิศทางของจุดที่จะดึงออกมา เอ่อฉันต้องยกธง BS เกี่ยวกับคำตอบนั้นเนื่องจากฉันได้เรียนรู้มากพอเกี่ยวกับ OpenLayers ว่าเป็นอันตรายและปัญหานี้เกิดขึ้นกับฉัน ปัญหาที่ฉันมีเมื่อมีการตอบสนองคือฉันโหลดพิกัดในขอบเขตที่ตามคำจำกัดความระบุลองจิจูดบนขวาและละติจูดรวมถึงลองจิจูดล่างซ้ายและละติจูด ถ้าลองจิจูดด้านบนขวาตั้งอยู่บนฝั่งตะวันตกของ 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 แล้วนำคุณลักษณะนั้นไปใช้กับเวกเตอร์และในที่สุดก็พล็อตมันเท่านั้นที่จะพบว่ารูปหลายเหลี่ยมนั้นผิดไปทั่วโลก

ฉันต้องคิดว่าทำไมสิ่งนี้จึงเกิดขึ้นดังนั้นฉันจึงเข้าสู่วิธีการ ol.extent.boundingExtent นี้ในไลบรารี OpenLayers 4

/**
 * 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 องศาแรกเพิ่มขึ้นอย่างต่อเนื่อง 360.0 - 165.937 = 194.063 codepath การคำนวณพื้นที่ของฉันใช้การทดสอบ IDL ต่อไปนี้และเพื่อใช้ codepath เดียวกันสำหรับพิกัดที่ป้อนด้วยตนเองฉันจำเป็นต้องจำลองค่าพิกัดราวกับว่ามันถูกส่งคืนจากการเรียก DragBox getGeometry ฉันกำลังทดสอบโครงสร้างรูปหลายเหลี่ยมของ GEOJSON ซึ่งเป็นอาร์เรย์ 3 มิติโดยที่มิติที่ 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 ไม่เช่นนั้นจะคำนวณตามปกติทุกที่อื่น

จากนั้นฉันก็ใช้ขอบเขตนี้เพื่อสร้างรูปหลายเหลี่ยมจากนั้นรูปหลายเหลี่ยมคุณสมบัติแล้วนำคุณลักษณะนั้นไปใช้กับเวกเตอร์และในที่สุดก็พล็อตมันและคราวนี้มันถูกพล็อตถูกต้อง ดังนั้นการแก้ไขฉันมาด้วยเพื่อช่วยแก้ปัญหาการคำนวณพื้นที่ที่ฉันยังแก้ไขปัญหาการพล็อต

บางทีวิธีนี้อาจช่วยคนอื่นหรือทำให้พวกเขาคิดไปในทิศทางอื่น การแก้ปัญหามาถึงฉันเมื่อในที่สุดฉันก็สามารถแบ่งปัญหาของ 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

สองปีต่อมาฉันยังคงมีปัญหากับคุณสมบัติในเลเยอร์เวกเตอร์ ฉันพบไฟล์นี้ที่มีตัวอย่างของรหัสที่แสดงวิธีพลิกปลายทางถ้ามันข้าม dateline:

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 ที่กำหนดสำหรับเซ็กเมนต์ใด ๆ ที่ข้ามบรรทัดวันที่ จากนั้นจะตัดออกเป็นสองส่วนที่ dateline และส่งกลับกลุ่มผลลัพธ์ทั้งหมดเป็น MultiLineString

มันทำงานได้อย่างสมบูรณ์แบบสำหรับจุดประสงค์ของฉัน (วาดเส้นตาราง lat-lon ขั้วโลก)


0

ฉันมีปัญหาเล็กน้อยกับ dateline และจัดการแก้ไขได้ทั้งหมด คุณสามารถลองต่อไปนี้

  1. อัปเดตค่ากล่องขอบเขตเลเยอร์ GeoServer ด้วยตนเองเพื่อให้ครอบคลุมรูปหลายเหลี่ยมของคุณโดยไม่ทำให้แตกและดูว่าจะแก้ปัญหาได้หรือไม่

  2. หนึ่งในการแก้ไขที่ฉันทำใน Openlayers ขาดไทล์เมื่อส่งดาต้าไลน์จาก + ve ลองติจูดถึง -ve http://trac.osgeo.org/openlayers/ticket/2754 ไม่แน่ใจว่าใช้ได้กับ WFS หรือไม่ คุณสามารถรับรุ่นพัฒนา openlayers ล่าสุดและลอง


0

ฉันพบปัญหานี้กับ LineStrings และสร้างโซลูชันขึ้นมา ฉันไม่แน่ใจว่ามันจะช่วยให้คุณมีรูปหลายเหลี่ยม คุณสามารถดูได้ที่ repl.it ของฉันที่นี่: https://repl.it/@gpantic/OpenLayersSplitRouteOverPacific


1
หากตอบคำถามโปรดเพิ่มข้อมูลทั้งหมดลงในคำตอบของคุณแทนที่จะให้ลิงก์
BERA

0

กำไรต่อหุ้น: 3832 (WGS84 PDC) เป็นการประมาณการกึ่งกลางมหาสมุทรแปซิฟิก สิ่งนี้จะแลกเปลี่ยนปัญหาการข้าม IDL สำหรับปัญหาการข้าม Prime Meridian สิ่งนี้อาจไม่เป็นปัญหาขึ้นอยู่กับสิ่งที่คุณวาด ฉันยังพบปัญหาใกล้กับ Arctic และ Antarctic Circles

เครดิตไปนี้บทความ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.