Uluslararası Tarih Satırı


13

OpenLayers kullanarak, belirli tarihler içinde bazı Latin Amerika ülkeleri üzerine yerleştirilen çokgenimi (sarı) kesen tüm özellikleri (siyah) döndüren bir filtreye sahip bir WFS katmanı (GeoServer'da) ekledim.

resim açıklamasını buraya girin

Ancak, harita boyunca yatay olarak geçen özellik aslında benim çokgeni KESMEZ. Bu özellik Hawaii ve Fiji arasındaki pasifik okyanusunda bir yerdedir ve Latin Amerika'da DEĞİLDİR. Sorun şu ki, Uluslararası Tarih Çizgisini geçmek yerine, tüm dünyayı sararak harita üzerinde oluşturuluyor.

Prolamatik özellik tanımlanmıştır:

POLİGON ((- 179.700417 14.202717, -178.687422 13.992875.179.024138 8.24716, -179.98241 8.035567, -179.700417 14.202717))

Bunun gibi birçok sorunlu tarih satırı özellikleri var ama bu örnek için bunu daralttı. Uygulamamda görmezden gelemem çünkü birçoğuna sahibim.

Ben aynı sonuçlarla taban katmanı ve WFS katmanı "wrapDateLine: true" kullanarak denedim.

Bunun bir GeoServer sorunu veya OpenLayers sorunu olup olmadığından emin değilim.

Uluslararası tarih çizgisi sorunuma bir çözüm bilen var mı?


2
Yazılımın neden böyle bir problemi olduğunu bilmiyorum, dünya düz, değil mi ?!
DavidF

Belki bir yön parametresi olmalı.
CaptDragon

@CaptDragon Bu sorunun çözümü var mı?
Anıl

@Anil Henüz yok. Lütfen bulursanız bana bildirin.
CaptDragon

Yanıtlar:


6

Ne yazık ki bu bilinen bir sorundur. Mesele, tarih çizgisini bu şekilde geçen geometrilerin belirsiz olmasıdır. OL ve GeoServer oluşturucularının, niyetin dünyanın "kısa" yoluna gitmek olduğunu bilmenin kolay bir yolu yoktur, bu yüzden örneğin 170 ila -170'ı "normal" yolla yorumlamak ve dünyanın dört bir yanına gitmek.

Ne yazık ki, bu dateline karşı uzanan geometrilerinizi ayırmak dışında iyi bir çözüm yoktur.


+1 teşekkürler, katılıyorum ama geometrilerimi bölemiyorum. Bakalım başka kimsenin başka fikri var mı.
CaptDragon

Onları OpenLayers'da güzelce bölmenin bir yolunu buldum .
CaptDragon

7

İlgilendiğiniz çokgenlerin haritanızdaki süreksizliği geçmemesi için Greenwich meridyenine (veya başka bir yere) bölünmüş bir projeksiyon kullanmak için haritanızı yeniden yönlendirin.


çokgenler dünyayı oldukça iyi kaplarlar, her zaman bir çizgiyi aşacak çokgenler olacaktır. Yine de, böyle bölünmemiş herhangi bir projeksiyon biliyor musunuz?
CaptDragon

1
Tüm projeksiyonlar dünyayı bir yere bölmeli, matematikte örtüktür (bana inanmıyorsanız bir portakal soyun :-)). Yapabileceğiniz tek şey, göreviniz için en iyi projeksiyonu seçmek.
Ian Turton

Evet, haklısın. Bunu birkaç gün açık bırakacağım ve başka fikirlerin ortaya çıkıp çıkmadığını göreceğim. Önerin için teşekkürler. :-)
CaptDragon

2

Kullanıcının bir DragBox eylemi veya Kullanıcı tarafından girilen kapsam noktaları çizme yoluyla bir İlgi Alanı dikdörtgeni oluşturmasına izin veren bir uygulama geliştirdiğim için bu sorunu bir süredir araştırıyordum. Bu maceraya başladığımda OpenLayers için tamamen yeniydim. Manuel olarak girilen genişleme noktalarıyla ilgili sorun, AOI Uluslararası Tarih Çizgisi'ni kaplarsa çizilen dikdörtgenin dünya çapında yanlış çizilmesiydi. Çok sayıda StackExchange kullanıcıları bu soruyu yalnızca bir OpenLayers yanıtlayıcısı tarafından söylenmesini istedi (ve burada yeniden yorumluyorum) "OpenLayers, çizilecek noktaların yönel niyetini bilmenin bir yolu yok, bu yüzden varsayılan ...". OpenLayer'ların tehlikeli olmaları hakkında yeterince şey öğrendiğimden ve bu sorun benim başıma geldiğinden, bu yanıt üzerine BS bayrağını yükseltmem gerekiyor. Yanıtlarıyla ilgili sorunum, koordinatları tanım olarak Üst Sağ Boylam ve Enlem ile Alt Sol Boylam ve Enlem'i belirten bir dereceye kadar yüklememdir. Sağ Üst Boylam IDL'nin Batı tarafında yer alıyorsa ve Sol Alt Boy Boyu IDL'nin Doğu tarafında yer alıyorsa, kullanıcının hangi yolu çokgeni çizmek istediği oldukça açıktır, ancak OpenLayers Boylamsal değerleri değiştirmek ve çizim yapmakta ısrar ediyor çokgen dünya çapında yanlış bir şekilde. Kapsam bildirimi ve sorunlu OpenLayers yöntem çağrısı örneği aşağıda gösterilmiştir. Sağ Üst Boylam IDL'nin Batı tarafında yer alıyorsa ve Sol Alt Boy Boyu IDL'nin Doğu tarafında yer alıyorsa, kullanıcının hangi yolu çokgeni çizmek istediği oldukça açıktır, ancak OpenLayers Boylamsal değerleri değiştirmek ve çizim yapmakta ısrar ediyor çokgen dünya çapında yanlış bir şekilde. Kapsam bildirimi ve sorunlu OpenLayers yöntem çağrısı örneği aşağıda gösterilmiştir. Sağ Üst Boylam IDL'nin Batı tarafında yer alıyorsa ve Sol Alt Boy Boyu IDL'nin Doğu tarafında yer alıyorsa, kullanıcının hangi yolu çokgeni çizmek istediği oldukça açıktır, ancak OpenLayers Boylamsal değerleri değiştirmek ve çizim yapmakta ısrar ediyor çokgen dünya çapında yanlış bir şekilde. Kapsam bildirimi ve sorunlu OpenLayers yöntem çağrısı örneği aşağıda gösterilmiştir.

// 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__: []

Gördüğünüz gibi Boyuna koordinatlar tersine döner ve böylece tam koordinat yapısını (çokgen) oluşturduktan sonra. bir çokgenÖzellik ve ardından bu özelliği bir vektöre uygulayın ve son olarak yalnızca çokgenin dünya çapında yanlış yol aldığını bulmak için çizin.

OpenLayers 4 kitaplığında bu ol.extent.boundingExtent yöntemine kazdık neden bu olduğunu anlamak gerekiyordu.

/**
 * 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__: []

Kodum alanı dinamik olarak hesaplar, böylece Kullanıcı geçerli boyutlu bir AOI çokgen oluşturup oluşturmadığını belirleyebilirim. DragBox tarafından oluşturulan bir seçimi işlerken, ortaya çıkan geometri yapısından koordinatları talep ediyorum ve bir EPSG: 4326 projeksiyonu için, sarılmış bir dünyadan koordinatları döndürdüğünde, ilk 180.0 dereceyi geçen koordinatlar artmaya devam ediyor. 360.0 - 165.937 = 194.063. Alan hesaplama kodyolum aşağıdaki IDL testini kullanır ve elle girilen koordinatlar için aynı kodyolunu kullanmak için DragBox getGeometry çağrısından döndürülmüş gibi koordinat değerini simüle etmem gerekiyordu. Ben aslında 1 boyutu Yüzük numarası olan 3 boyutlu bir dizi olan bir GEOJSON çokgen yapısını test ediyorum,

 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))) {
 .
 .
 .

Bu testler bu noktada geçerse, kod IDL üzerindeki alanı hesaplamak için geliştirdiğim algoritmayı kullanır, aksi takdirde sadece diğer her yerde normal olarak hesaplar.

Daha sonra bir poligon, daha sonra bir polygonFeature oluşturmak için bu kapsamı kullanın, daha sonra bu özelliği bir vektöre uygulayın ve son olarak çizin ve bu kez doğru bir şekilde çizdim. Bu yüzden alan hesaplama problemini çözmeye yardımcı olmak için bulduğum düzeltme, çizim problemini de düzeltti.

Belki bu çözüm başka birine yardımcı olacak ya da farklı bir yöne düşündürecek. Nihayetinde IDL sorununu iki konuya ayırabildiğimde çözüm geldi. Gerçek alan hesaplaması bir diğer sorun, diğerinin poligonun IDL üzerine çizilmesidir.


1
OL, çizim yaparken hangi tarafa gideceğinizi bilmek için> = operatörünü kullanır. 170'i 190 verirseniz kısa yoldan gidersiniz; 170 sonra -170 verirseniz, uzun yoldan gidecek. Boylamı her zaman -180 ile 180 arasında "normalleştirir "seniz, bilgi kaybedersiniz. Bilgiyi geri almanın bir yolu, noktalar arasındaki mesafelerin> 180
Rivenfall

1

Çalışma alanı: Örnek

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


Gönderdiğiniz bağlantı WFS kullanıyorum: "Bunu bir 'Layer.WMS' veya 'Layer.MapServer' katmanı ile yapabilirsiniz"
CaptDragon

Her ikisi de destekleniyorsa ve Layer.MapServer için özel bir gereksiniminiz yoksa, Layer.WMS (MapServer'dan hala sunulabilir) ile gidin.
DavidF

@DavidF: Teşekkürler, ancak WFS'nin vektör yeteneklerini kullanmam gerekiyor.
CaptDragon

1

İki yıl sonra, bir vektör katmanındaki özelliklerle bu sorunu yaşamaya devam ettim. Ben dateline geçti eğer bir bitiş noktası çevirmek gösteren bir kod pasajı içeren bu dosyayı buldum :

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

Güncelleme:

Aslında yukarıdakiler dünya çapında birden fazla devrim için işe yaramadı. Ben yapmaya başladık BU .

resim açıklamasını buraya girin


1

Sizin için çalışabilecek veya çalışmayabilecek kendi projelerimde bunun için bir çözüm buldum. LineStrings ile çalıştığını biliyorum ama diğer geometri türlerinden emin değilim.

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 işlevi, tarih çizgisini geçen tüm segmentler için verilen LineString'i özyinelemeli olarak dolaşır. Daha sonra bunları datelinde ikiye böler ve elde edilen tüm segmentleri bir MultiLineString olarak döndürür.

Amacım için mükemmel çalıştı (polar bir lat-ızgara çizerek).


0

Datine ile ilgili birkaç sorunum vardı ve hepsini düzeltmeyi başardım. Takip etmeyi deneyebilirsiniz.

  1. GeoServer katman sınırlama kutusu değerlerini çokgeni kesmeden el ile güncelleyin ve sorunun çözülüp çözülmediğine bakın.

  2. Openlayers'ta yaptığım düzeltmelerden biri datelini + ve boylamdan -ve'ye geçerken fayans eksik. http://trac.osgeo.org/openlayers/ticket/2754 WFS için geçerli olup olmadığından emin değilim. En son Openlayers geliştirme sürümünü alabilir ve deneyebilirsiniz.



0

EPSG: 3832 (WGS84 PDC), Pasifik Okyanusu merkezli bir projeksiyon. Bu, Başbakan Meridyen geçiş problemleri için IDL geçişi sorunlarının ticaretini yapacaktır. Neyi tasvir ettiğinize bağlı olarak bu bir sorun olmayabilir. Arktik ve Antarktik Çemberlerin yakınında da sorunlar buldum.

Kredi bu makaleye gidiyor .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.