Berechnung des Begrenzungsrahmens nach gegebener Mitte und Skalierung in Android?

8

Unter diesen Bedingungen:

  • eine Skala wie 1:50000
  • Die Mitte des Ansichtsfensters ist 100°E, 20°N
  • Die Größe des Ansichtsfensters ist 400x600

Wie kann ich den Begrenzungsrahmen des Ansichtsfensters berechnen?


Das geografische Koordinatensystem der Karte lautet EPSG: 4490.

Wir möchten sie in einer anderen Projektion wie Mercator oder latitude_longitude_projection anzeigen (vielleicht ist dies die so genannte nicht projizierte).

Die Größe des Ansichtsfensters ist in Pixel angegeben.

giser
quelle
In welcher Projektion befindet sich Ihre Karte? Web Mercator? Oder zeigen Sie eine nicht projizierte Karte in lat / lon an? Und die Größe Ihres Ansichtsfensters ist das in Pixel? Ist die Skala in Piels? Verwenden Sie ein Mapping-Framework / eine Mapping-Bibliothek, die möglicherweise eine Funktion dafür hat?
Atlefren
Mit welcher GIS-Software und -Version versuchen Sie dies?
PolyGeo
@atlefren: Ich habe den Beitrag aktualisiert.
Giser
@PolyGeo: Keine, wir haben versucht, die Kartendaten in Android anzuzeigen. Und wir haben keine Bibliothek gefunden.
Giser
1
Android, verwenden Sie die Google Maps-API oder zeigen Sie einfach ein Bild an? Ich würde auch empfehlen, kein nicht projiziertes Koordinatensystem zur Anzeige Ihrer Karte zu verwenden, da diese stark verzerrt aussieht.
Atlefren

Antworten:

9

Ok, mit einigen anfänglichen Problemen ist die Aufgabe relativ einfach.

Maßstab, dargestellt als f.ex 1: 50000, bedeutet, dass eine Einheit auf der Karte 50.000 Einheiten in der realen Welt entspricht.

Für eine Papierkarte im Maßstab 1: 50000 bedeutet dies, dass 1 Meter auf der Karte 50.000 Metern in der realen Welt entspricht, oder um es einfacher zu machen: 1 cm auf der Karte entspricht 50 Metern in der realen Welt. So weit, ist es gut.

Wenn Computer (oder Telefonbildschirme) die Show betreten, ist es viel schwieriger: Die Maßeinheit auf einem Bildschirm ist ein Pixel, das nicht direkt auf Zentimeter abgebildet wird. OpenLayers verwenden (oder zumindest wo) die "Punkte pro Zoll" und gehen davon aus, dass ein Zoll 72 Pixel entspricht (dies ist auf 72-dpi-Bildschirmen sinnvoll, auf Retina-Displays jedoch falsch. Aber bleiben wir vorerst bei 72 dpi (wie es die meisten Mapping-Bibliotheken tun (ich denke, Korrekturen sind willkommen)).

OpenLayers hat eine Funktion OpenLayers.Util.getResolutionFromScale (siehe Quelle ):

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;
};
  • Mit Einheiten = "Grad" (was EPSG: 4490 ist, nach dem, was ich erfahre) erhalten wir Zoll_per Einheit = 4374754 (OpenLayers.INCHES_PER_UNIT ["Grad"])

  • Ein Maßstab von 1: 50000 (entspricht 1/50000 = 0,00002) (dies berechnet penLayers.Util.normalizeScale) ergibt normScale = 0,00002

  • OpenLayers.DOTS_PER_INCH = 72

Wir können dann die Auflösung als berechnen

1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453

Wenn wir den Mittelpunkt (lon = 100, lat = 30), die Pixelgröße des Ansichtsfensters (w = 400, h = 600) und die Auflösung kennen, können wir die Funktion berechne Grenzen aus OpenLayers.Map verwenden (siehe Quelle ):

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

was wir reduzieren können auf:

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

Wenn wir dies mit unseren Werten bezeichnen, erhalten wir:

calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{ 
    left: 99.96825218311957, 
    bottom: 29.95237827467937,
    right: 100.03174781688043,
    top: 30.04762172532063
}

Wir können all dies dann zu einer Funktion kombinieren, die für Grade mit angegebenem Skalennenner funktioniert:

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
quelle
Wunderbare Antwort. Tatsächlich scheint der entscheidende Punkt hier der dpiWert zu sein. Ist es nicht?
Giser
Oh, wie wäre es mit der Projektion? Es scheint, dass die obigen Codes verwendet werden, um den Grad direkt zu berechnen.
Giser
Ja, das ist richtig. Solange Ihre Benutzer nicht erwarten, die Karte auf die gleiche Weise wie eine Papierkarte zu verwenden (dh darauf zu messen), kann jeder Wert verwendet werden (und ich denke, die meisten
Kartenbibliotheken
Das einzige, was Sie über die Projektion wissen müssen, sind ihre Einheiten. OpenLayers verwendet das Array OpenLayers.INCHES_PER_UNIT [Einheiten] in Utils.js. Web Mercator verwendet Meter als Einheit, was 39,37 anstelle von 4374754 bedeutet, um die Auflösung zu berechnen
atlefren
@atlerfren: Hallo, es scheint, dass Sie ein Experimentator von Openlayern sind, ich stoße auf einige Probleme, die damit zusammenhängen. Können Sie sich etwas Zeit nehmen, um diesen Beitrag zu lesen? gis.stackexchange.com/q/61256/12681
Giser