Ok, avec quelques problèmes initiaux résolus, la tâche est relativement simple.
L'échelle, pré-présentée comme f.ex 1: 50000 signifie qu'une unité sur la carte correspond à 50 000 unités dans le monde réel.
Pour une carte papier imprimée à l'échelle 1: 50000, cela signifie que 1 mètre sur la carte correspond à 50 000 mètres dans le monde réel, ou pour plus de facilité: 1 cm sur la carte correspond à 50 mètres dans le monde réel. Jusqu'ici tout va bien.
Lorsque l'ordinateur (ou les écrans de téléphone) entrent dans l'émission, c'est beaucoup plus difficile: l'unité de mesure sur un écran est un pixel, qui ne correspond pas directement aux centimètres. Les OpenLayers utilisent (ou au moins où) en utilisant les "points par pouce", et supposaient qu'un pouce correspond à 72 pixels (cela a du sens sur les écrans à 72 dpi, mais c'est faux sur les écrans Retina, par exemple. Pour l'instant, restons sur 72 dpi (car c'est ce que font la plupart des bibliothèques de cartographie (je pense, les corrections sont les bienvenues)).
OpenLayers a une fonction OpenLayers.Util.getResolutionFromScale (voir source ):
OpenLayers.Util.getResolutionFromScale = function (scale, units) {
var resolution;
if (scale) {
if (units == null) {
units = "degrees";
}
var normScale = OpenLayers.Util.normalizeScale(scale);
resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
* OpenLayers.DOTS_PER_INCH);
}
return resolution;
};
Avec unités = "degrés" (dont EPSG: 4490 est, d'après ce que je comprends), nous obtenons pouces_par unité = 4374754 (OpenLayers.INCHES_PER_UNIT ["degrés"])
une échelle de 1: 50000 (ce qui correspond à 1/50000 = 0,00002) (c'est ce que calcule penLayers.Util.normalizeScale) donne normScale = 0,00002
- OpenLayers.DOTS_PER_INCH = 72
On peut alors calculer la résolution comme
1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453
Connaissant le point central (lon = 100, lat = 30), la taille de pixel de la fenêtre d'affichage (w = 400, h = 600) et la résolution, nous pouvons ensuite utiliser la fonction CalculateBounds d'OpenLayers.Map (voir source ):
calculateBounds: function(center, resolution) {
var extent = null;
if (center == null) {
center = this.getCachedCenter();
}
if (resolution == null) {
resolution = this.getResolution();
}
if ((center != null) && (resolution != null)) {
var halfWDeg = (this.size.w * resolution) / 2;
var halfHDeg = (this.size.h * resolution) / 2;
extent = new OpenLayers.Bounds(center.lon - halfWDeg,
center.lat - halfHDeg,
center.lon + halfWDeg,
center.lat + halfHDeg);
}
return extent;
},
que nous pouvons réduire à:
function calculateBounds(center, resolution, size) {
var halfWDeg = (size.w * resolution) / 2;
var halfHDeg = (size.h * resolution) / 2;
return {
"left": center.lon - halfWDeg,
"bottom": center.lat - halfHDeg,
"right": center.lon + halfWDeg,
"top": center.lat + halfHDeg
};
}
Appeler cela avec nos valeurs donne:
calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{
left: 99.96825218311957,
bottom: 29.95237827467937,
right: 100.03174781688043,
top: 30.04762172532063
}
Nous pouvons ensuite combiner tout cela à une fonction qui fonctionne pour les degrés avec un dénominateur d'échelle donné:
function calculateBounds(center, scaleDenominator, size) {
var resolution = 1 / ((1 / scaleDenominator) * 4374754 * 72)
var halfWDeg = (size.w * resolution) / 2;
var halfHDeg = (size.h * resolution) / 2;
return {
"left": center.lon - halfWDeg,
"bottom": center.lat - halfHDeg,
"right": center.lon + halfWDeg,
"top": center.lat + halfHDeg
};
}