Ok, com alguns problemas iniciais resolvidos, a tarefa é relativamente simples.
Escala, representada como f.ex 1: 50000, significa que uma unidade no mapa corresponde a 50.000 unidades no mundo real.
Para um mapa em papel impresso em uma escala de 1: 50000, isso significa que 1 metro no mapa corresponde a 50.000 metros no mundo real, ou para facilitar: 1 cm no mapa corresponde a 50 metros no mundo real. Por enquanto, tudo bem.
Quando o computador (ou a tela do telefone) entra no programa, é muito mais difícil: a unidade de medida na tela é um pixel, que não é mapeado diretamente em centímetros. Os OpenLayers estão (ou pelo menos onde) usando os "Pontos por polegada" e assumem que uma polegada corresponde a 72 pixels (isso faz algum sentido em telas de 72 dpi, mas está errado em, por exemplo, Retina Displays. Mas, por enquanto, vamos nos ater ao 72 dpi (como é o que a maioria das bibliotecas de mapeamento faz (acho, as correções são bem-vindas)).
OpenLayers tem uma função OpenLayers.Util.getResolutionFromScale (consulte a fonte ):
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;
};
Com units = "degrees" (que é EPSG: 4490, pelo que eu deduzo), obtemos inches_per unit = 4374754 (OpenLayers.INCHES_PER_UNIT ["degrees"])
uma escala de 1: 50000 (que corresponde a 1/50000 = 0,00002) (é o que penLayers.Util.normalizeScale calcula) fornece normScale = 0,00002
- OpenLayers.DOTS_PER_INCH = 72
Podemos então calcular a resolução como
1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453
Sabendo o ponto central (lon = 100, lat = 30), o tamanho de pixel da viewport (w = 400, h = 600) e a resolução, podemos usar a função calculBounds do OpenLayers.Map (consulte a fonte ):
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 podemos reduzir para:
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
};
}
Chamar isso com nossos valores fornece:
calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{
left: 99.96825218311957,
bottom: 29.95237827467937,
right: 100.03174781688043,
top: 30.04762172532063
}
Podemos então combinar tudo isso a uma função que funciona em graus com 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
};
}