¿Cálculo del cuadro delimitador por centro y escala dados en Android?

8

Dadas estas condiciones:

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

¿Cómo puedo calcular el cuadro delimitador de la ventana gráfica?


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

Queremos mostrarlos en una proyección diferente como Mercator o latitude_longitude_projection (tal vez este es el supuesto no proyectado).

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

Giser
fuente
¿En qué proyección está tu mapa? Web Mercator? ¿O muestra un mapa no proyectado en lat / lon? Y el tamaño de su ventana gráfica, ¿es eso en píxeles? ¿La escala está en pieles? ¿Utiliza algún marco / biblioteca de mapeo que pueda tener una función para esto?
atlefren
¿Qué software y versión de SIG está utilizando para intentar hacer esto?
PolyGeo
@atlefren: upadte la publicación.
Giser
@PolyGeo: Ninguno, intentamos mostrar los datos del mapa en Android. Y no hemos encontrado ninguna biblioteca.
Giser
1
Android, ¿estás utilizando la API de Google Maps o simplemente estás mostrando una imagen? También recomendaría no usar un sistema de coordenadas no proyectado para mostrar su mapa, ya que se verá muy distorsionado.
atlefren

Respuestas:

9

Ok, con algunos problemas iniciales resueltos, la tarea es relativamente simple.

Escala, representada como f.ex 1: 50000 significa que una unidad en el mapa corresponde a 50,000 unidades en el mundo real.

Para un mapa en papel impreso en una escala de 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 aquí todo bien.

Cuando la computadora (o las pantallas del teléfono) entran al programa, es mucho más difícil: la unidad de medida en una pantalla es un píxel, que no se asigna directamente a centímetros. Los OpenLayers están (o al menos donde) usando los "Puntos por pulgada", y se supone que una pulgada corresponde a 72 píxeles (esto tiene sentido en pantallas de 72 ppp, pero es incorrecto en pantallas Retina. Pero por ahora, sigamos con 72 ppp (ya que esto es lo que hace la mayoría de las bibliotecas de mapeo (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 es EPSG: 4490, 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

Entonces podemos calcular la resolución como

1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453

Conociendo el punto central (lon = 100, lat = 30), el tamaño de píxel de la ventana gráfica (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;
    },

que podemos reducir a:

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
}

Luego podemos combinar todo esto en una función que funcione para 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
    };
}
atlefren
fuente
Maravillosa respuesta. De hecho, parece que el punto clave aquí es el dpivalor. ¿No es así?
Giser
Oh, ¿qué tal la proyección? Parece que los códigos anteriores se utilizan para calcular el grado directamente.
Giser
Si, eso es correcto. Mientras sus usuarios no esperen usar el mapa de la misma manera que un mapa en papel (es decir, medirlo), se puede usar cualquier valor (y creo que la mayoría de las bibliotecas de mapas usan 72 o 96)
atlefren
lo único que necesita saber sobre la proyección son sus unidades, OpenLayers usa la matriz OpenLayers.INCHES_PER_UNIT [units] en Utils.js. web mercator utiliza medidores como unidad, lo que significa 39.37 en lugar de 4374754 para calcular la resolución
atlefren
@atlerfren: Hola, parece que eres un experto en openlayers, me encuentro con algunos problemas relacionados. ¿Puedes dedicar algo de tiempo para echar un vistazo a esta publicación? gis.stackexchange.com/q/61256/12681
Giser