Bien, con algunos problemas iniciales aclarados la tarea es relativamente simple.
La escala, prepresentada como f.ex 1:50000 significa que una unidad en el mapa corresponde a 50.000 unidades en el mundo real.
Para un mapa de papel impreso a escala 1:50000 esto significa que 1 metro en el mapa corresponde a 50.000 metros en el mundo real, o para hacerlo más fácil: 1 cm en el mapa corresponde a 50 metros en el mundo real. Hasta ahora, todo bien.
Cuando las pantallas de ordenador (o de teléfono) entran en el espectáculo es mucho más difícil: la unidad de medida de una pantalla es un píxel, que no se mapea directamente a centímetros. Los OpenLayers están (o al menos donde) usando los "Puntos por pulgada", y asumieron que una pulgada corresponde a 72 píxeles (esto tiene algo de sentido en pantallas de 72 dpi, pero está mal en i.e. Retina Displays. Pero por ahora, vamos a atenernos a 72 dpi (ya que esto es lo que hace la mayoría de las bibliotecas de mapas (creo que las correcciones son bienvenidas)).
OpenLayers tiene una función OpenLayers.Util.getResolutionFromScale (ver fuente ):
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;
};
-
Con unidades = "grados" (que EPSG:4490 es, por lo que deduzco) obtenemos pulgadas_por unidad = 4374754 (OpenLayers.INCHES_PER_UNIT["grados"])
-
una escala de 1:50000 (que corresponde a 1/50000 = 0.00002) (esto es lo que calcula penLayers.Util.normalizeScale) da normScale = 0.00002
-
OpenLayers.DOTS_PER_INCH = 72
Podemos entonces calcular la resolución como
1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453
Conociendo el punto central (lon=100, lat=30), el tamaño del píxel de la ventana (w=400, h=600) y la resolución, podemos usar la función calculateBounds de OpenLayers.Map (ver fuente ):
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;
},
a la que podemos reducir:
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
};
}
Llamar a esto con nuestros valores da:
calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{
left: 99.96825218311957,
bottom: 29.95237827467937,
right: 100.03174781688043,
top: 30.04762172532063
}
Podemos entonces combinar todo esto a una función que funciona para los grados con el denominador de escala dado:
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
};
}