J'avais étudié ce problème pendant un bon moment car j'ai développé une application qui permet à l'utilisateur de générer un rectangle de zone d'intérêt via une action DragBox ou en traçant des points d'extension entrés par l'utilisateur. Quand j'ai commencé cette aventure, j'étais complètement nouveau sur OpenLayers. Le problème avec les points d'extension entrés manuellement était que si AOI couvrait la ligne de données internationale, le rectangle dessiné serait dessiné dans le mauvais sens à travers le monde. De nombreux utilisateurs de StackExchange ont posé des questions sur ce problème uniquement pour être informé par un répondeur OpenLayers que (et je paraphrase ici) "OpenLayers n'a aucun moyen de connaître l'intention directionnelle des points à dessiner, il est par défaut ...". Euh, je dois lever le drapeau BS sur cette réponse car j'ai maintenant suffisamment appris sur OpenLayers pour être dangereux et ce problème m'est arrivé. Le problème que j'ai avec leur réponse est que je charge les coordonnées dans une mesure qui, par définition, spécifie la longitude et la latitude supérieure droite ainsi que la longitude et la latitude inférieures gauche. Si la longitude en haut à droite se trouve du côté ouest de l'IDL et la longitude en bas à gauche se trouve du côté est de l'IDL, il est assez évident de quelle manière l'utilisateur veut tracer le polygone et pourtant OpenLayers insiste pour permuter les valeurs longitudinales et le dessin le polygone dans le mauvais sens autour du monde. Un exemple de déclaration d'étendue et d'appel de méthode OpenLayers problématique est présenté ci-dessous. Si la longitude en haut à droite se trouve du côté ouest de l'IDL et la longitude en bas à gauche se trouve du côté est de l'IDL, il est assez évident de quelle manière l'utilisateur veut tracer le polygone et pourtant OpenLayers insiste pour permuter les valeurs longitudinales et le dessin le polygone dans le mauvais sens autour du monde. Un exemple de déclaration d'étendue et d'appel de méthode OpenLayers problématique est présenté ci-dessous. Si la longitude en haut à droite se trouve du côté ouest de l'IDL et la longitude en bas à gauche se trouve du côté est de l'IDL, il est assez évident de quelle manière l'utilisateur veut tracer le polygone et pourtant OpenLayers insiste pour permuter les valeurs longitudinales et le dessin le polygone dans le mauvais sens autour du monde. Un exemple de déclaration d'étendue et d'appel de méthode OpenLayers problématique est présenté ci-dessous.
// 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__: []
Comme vous pouvez le voir, les coordonnées longitudinales sont inversées et donc après avoir créé la structure de coordonnées complète, un polygone. a polygonFeature, puis appliquez cette entité à un vecteur et finalement tracez-la uniquement pour découvrir que le polygone va dans le mauvais sens dans le monde.
J'avais besoin de comprendre pourquoi cela se produisait alors j'ai creusé dans cette méthode ol.extent.boundingExtent dans la bibliothèque 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__: []
Mon code calcule la zone de manière dynamique afin que je puisse déterminer si l'utilisateur a créé un polygone AOI de taille valide. Lorsque je traite une sélection générée par DragBox, je demande les coordonnées à la structure géométrique résultante et pour une projection EPSG: 4326 lorsqu'elle renvoie les coordonnées d'un monde enveloppé, les coordonnées après les 180 premiers degrés continuent à augmenter, ce qui explique le calcul du lonUR de 360,0 - 165,937 = 194,063. Mon chemin de codage de calcul de zone utilise le test IDL suivant et afin d'utiliser le même chemin de codage pour les coordonnées saisies manuellement, j'avais besoin de simuler la valeur de coordonnées comme si elle avait été renvoyée depuis l'appel DragBox getGeometry. Je suis en train de tester une structure polygonale GEOJSON qui est un tableau à 3 dimensions avec la 1ère dimension étant le numéro d'anneau,
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))) {
.
.
.
Si ces tests réussissent à ce stade, le code utilise l'algorithme que j'ai développé pour calculer la zone sur l'IDL, sinon il la calcule comme normale partout ailleurs.
J'utilise ensuite cette étendue pour créer un polygone, puis un polygoneFeature, puis j'applique cette entité à un vecteur et finalement le trace et cette fois, il est tracé correctement. Donc, le correctif que j'ai trouvé pour aider à résoudre le problème de calcul de surface que j'avais rencontré a également corrigé le problème de traçage.
Peut-être que cette solution aidera quelqu'un d'autre ou le fera réfléchir dans une direction différente. La solution m'est venue lorsque j'ai finalement réussi à diviser le problème de l'IDL en deux problèmes. Le calcul de l'aire réelle était un problème, l'autre étant le tracé du polygone sur l'IDL.