Calcul du cadre de délimitation par centre et échelle donnés dans Android?

8

Compte tenu de ces conditions:

  • une échelle comme 1:50000
  • le centre de la fenêtre est 100°E, 20°N
  • la taille de la fenêtre est 400x600

Comment puis-je calculer le cadre de délimitation de la fenêtre?


Le système de coordonnées géographiques de la carte est EPSG: 4490.

Nous voulons les afficher dans une projection différente comme Mercator ou latitude_longitude_projection (c'est peut-être le soi-disant non projeté).

La taille de la fenêtre est en pixels.

giser
la source
Dans quelle projection se trouve votre carte? Web Mercator? Ou affichez-vous une carte non projetée en lat / lon? Et la taille de votre fenêtre, est-ce en pixels? L'échelle est-elle en piels? Utilisez-vous un framework / bibliothèque de cartographie qui pourrait avoir une fonction pour cela?
atlefren
Quel logiciel SIG et quelle version utilisez-vous pour essayer de le faire?
PolyGeo
@atlefren: J'ai mis à jour le message.
giser
@PolyGeo: Aucun, nous avons essayé d'afficher les données cartographiques dans Android. Et nous n'avons trouvé aucune bibliothèque.
giser
1
Android, utilisez-vous l'API Google Maps ou affichez-vous simplement une image? Je vous déconseille également d'utiliser un système de coordonnées non projeté pour afficher votre carte, car elle sera fortement déformée.
atlefren

Réponses:

9

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
    };
}
atlefren
la source
Magnifique réponse. En fait, il semble que le point clé ici soit la dpivaleur. N'est-ce pas?
giser
Oh, qu'en est-il de la projection? Il semble que les codes ci-dessus soient utilisés pour calculer directement le degré.
giser
Oui c'est correct. Tant que vos utilisateurs ne s'attendent pas à utiliser la carte de la même manière qu'une carte papier (c'est-à-dire à y mesurer), n'importe quelle valeur peut être utilisée (et je pense que la plupart des bibliothèques de cartographie utilisent 72 ou 96)
atlefren
la seule chose que vous devez savoir sur la projection est ses unités, OpenLayers utilise le tableau OpenLayers.INCHES_PER_UNIT [units] dans Utils.js. web mercator utilise les mètres comme unité, ce qui signifie 39,37 au lieu de 4374754 pour calculer la résolution
atlefren
@atlerfren: Salut, il semble que vous soyez un connaisseur des openlayers, je rencontre des problèmes liés à cela. Pouvez-vous gagner du temps pour avoir un checek à ce poste? gis.stackexchange.com/q/61256/12681
giser