9 votos

¿Cómo se calcula el cuadro delimitador por un centro y una escala dados en Android?

Dadas estas condiciones:

  • una escala como 1:50000
  • el centro del mirador es 100°E, 20°N
  • el tamaño de la ventana es 400x600

¿Cómo puedo calcular el cuadro delimitador del visor?


Actualización después del comentario de Atlefren:

El sistema de coordenadas geográficas del mapa es EPSG:4490.

Queremos mostrarlos en una proyección diferente como Mercator o proyección de latitud y longitud (tal vez este es el tan dicho no proyectado).

El tamaño de la ventana está en píxeles.

10voto

pufferfish Puntos 679

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
    };
}

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X