So berechnen Sie die optimale Zoomstufe, um zwei oder mehr Punkte auf einer Karte anzuzeigen

11

Wir möchten mehrere Markierungen auf einer statischen Karte anzeigen und die optimale Zoomstufe berechnen, wie dies bei Google Maps der Fall ist. Wir haben bereits das Begrenzungsrechteck und den Mittelpunkt der Karte berechnet, aber jetzt fällt es uns schwer, die richtige Zoomstufe für die Anzeige des gesamten Begrenzungsrechtecks ​​zu berechnen. Kann uns bitte jemand in die richtige Richtung weisen?

Tobias Schwarz
quelle
Es ist nicht sehr raffiniert, aber warum nicht einfach den MBR mit 120% multiplizieren und darauf zoomen? Alles andere hängt von Ihrer Definition von "optimal" ab, nicht wahr?
ThomM
+1 auf ThomMs Idee. Genau das macht ArcGIS.
Ragi Yaser Burhum
1
Sorry, aber was ist das für ein MBR?
Rodrigo

Antworten:

4

Um die Zoomstufe zu erhalten, müssen Sie die Pixelabmessungen Ihrer Karte kennen. Sie müssen auch in sphärischen Mercator-Koordinaten rechnen.

  1. Konvertieren Sie Breite und Länge in sphärischen Mercator x, y.
  2. Holen Sie sich Abstand zwischen Ihren beiden Punkten in sphärischen Mercator.
  3. Der Äquator ist ungefähr 40 m lang und die Kacheln sind 256 Pixel breit, sodass die Pixellänge dieser Karte bei einer bestimmten Zoomstufe ungefähr 256 * Entfernung / 40000000 * 2 ^ Zoom beträgt . Versuchen Sie zoom = 0, zoom = 1, zoom = 2, bis der Abstand für die Pixelabmessungen Ihrer Karte zu groß ist.
Michal Migurski
quelle
1
Ich hoffe, ich habe aus der Ferne verstanden, was Sie tatsächlich fragen. = \
Michal Migurski
Ich habe diese Frage gefunden, als ich nach dieser Antwort gesucht habe. Danke.
Benjamin
@MichalMigurski Kannst du erklären, wie man den Abstand zwischen 2 Punkten im sphärischen Mercator berechnet? speziell die x-Koordinaten ... ich stecke fest, danke.
Otmezger
4

Dies ist der C # -Code, den ich in Maperitive verwende :

    public void ZoomToArea (Bounds2 mapArea, float paddingFactor)
    {
        double ry1 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MinY)) + 1) 
            / Math.Cos(GeometryUtils.Deg2Rad(mapArea.MinY)));
        double ry2 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MaxY)) + 1) 
            / Math.Cos(GeometryUtils.Deg2Rad(mapArea.MaxY)));
        double ryc = (ry1 + ry2) / 2;
        double centerY = GeometryUtils.Rad2Deg(Math.Atan(Math.Sinh(ryc)));

        double resolutionHorizontal = mapArea.DeltaX / Viewport.Width;

        double vy0 = Math.Log(Math.Tan(Math.PI*(0.25 + centerY/360)));
        double vy1 = Math.Log(Math.Tan(Math.PI*(0.25 + mapArea.MaxY/360)));
        double viewHeightHalf = Viewport.Height/2.0f;
        double zoomFactorPowered = viewHeightHalf
            / (40.7436654315252*(vy1 - vy0));
        double resolutionVertical = 360.0 / (zoomFactorPowered * 256);

        double resolution = Math.Max(resolutionHorizontal, resolutionVertical) 
            * paddingFactor;
        double zoom = Math.Log(360 / (resolution * 256), 2);
        double lon = mapArea.Center.X;
        double lat = centerY;

        CenterMapOnPoint(new PointD2(lon, lat), zoom);
    }
  • mapArea: Begrenzungsrahmen in langen / lat-Koordinaten (x = lang, y = lat)
  • paddingFactor: Dies kann verwendet werden, um den "120%" -Effekt zu erzielen, auf den sich ThomM bezieht. Ein Wert von 1,2 würde Ihnen die 120% bringen.

Beachten Sie, dass in meinem Fall zoomeine reelle Zahl sein kann. Bei Webkarten benötigen Sie einen ganzzahligen Zoomwert, daher sollten Sie so etwas wie verwenden (int)Math.Floor(zoom), um ihn abzurufen.

Dieser Code gilt natürlich nur für die Web Mercator-Projektion.

Igor Brejc
quelle
1
Danke dafür. Ist der Code für CenterMapOnPoint verfügbar?
mcintyre321
Perfekt! Ich habe dies verwendet, um den Zoom von BoundingBox im OsmDroid SDK zu berechnen und es funktioniert :)
Billda
Wo finde ich diese Bibliotheken? Ich kann keine GeometryUtils- oder Bounds2-Assemblys finden. Muss ich etwas von maperitive herunterladen? Ich sehe dort nur eine App.
Dowlers
@ Dowlers GeometryUtilswird hier nur verwendet, um Grad in Bogenmaß umzuwandeln, und zurück, es ist eine einfache mathematische Formel. Bounds2ist im Grunde nur eine Rechteckstruktur. Dieser Code wurde eher als Pseudocode als als direkt kopierbarer Code bereitgestellt.
Igor Brejc
Ahh hast du. Ich muss zugeben, dass ich, nachdem ich die Frage gestellt hatte, ein bisschen in der maperitiven App herumgestöbert und die DLLs gefunden habe, die ich brauchte. Aber ich habe die Lizenzbeschränkungen bemerkt und bin einen anderen Weg gegangen. Ich habe stattdessen den Code aus diesem Artikel verwendet: rbrundritt.wordpress.com/2009/07/21/…
Dowlers
1

Wenn Sie OpenLayers verwenden, Map.getZoomForExtentwird die höchste Zoomstufe berechnet, die für die gesamte Ausdehnung auf der Karte geeignet ist. Das extentmuss in der Projektion der Karte sein. Sie können a auch verwenden fill_factor, um die Anzeige von Punkten am Rand der Karte zu vermeiden und max_zoomden möglichen Zoom zu begrenzen:

extent = extent.scale(1/fill_ratio);
var zoom = Math.min(map.getZoomForExtent(map_extent), max_zoom);
map.setCenter(extent.getCenterLonLat(), zoom);
Alex Morega
quelle
Dies hat mein Problem nicht behoben, aber es hat mich dazu gebracht, die fitBounds-Methode von Leaflet zu finden, die mir den Tag gerettet hat.
SamuelDev