Haritada iki veya daha fazla noktayı görüntülemek için en uygun yakınlaştırma düzeyi nasıl hesaplanır


12

Statik bir haritada birkaç işaret görüntülemek istiyoruz ve Google Haritalar'ın yaptığı gibi en uygun yakınlaştırma seviyesini hesaplamak istiyoruz. Sınırlayıcı dikdörtgeni ve haritanın merkez noktasını zaten hesapladık, ancak şimdi tüm sınırlayıcı dikdörtgeni görüntülemek için doğru zum seviyesini hesaplamakta zorlanıyoruz. Birisi bizi doğru yöne yönlendirebilir mi?


Çok sofistike değil, ama neden MBR'yi% 120 ile çarpıp buna zum yapmıyorsunuz? Başka bir şey "optimal" tanımınıza bağlıdır, değil mi?
ThomM

ThomM'un fikrini + 1'leyin. ArcGIS tam da bunu yapıyor.
Ragi Yaser Burhum

1
Üzgünüm, ama bu MBR nedir?
Rodrigo

Yanıtlar:


5

Yakınlaştırma seviyesini elde etmek için haritanızın piksel boyutlarını bilmeniz gerekir. Ayrıca matematiğinizi küresel mercator koordinatlarında yapmanız gerekir.

  1. Enlem, boylamı küresel mercator x, y'ye dönüştürün.
  2. Küresel mercatorda iki noktanız arasında mesafe bulun.
  3. Ekvator yaklaşık 40 metre uzunluğunda yansıtılıyor ve karolar 256 piksel genişliğinde, bu nedenle belirli bir zum düzeyinde haritanın piksel uzunluğu yaklaşık 256 * mesafe / 40000000 * 2 ^ zum . Haritanızın piksel boyutları için mesafe çok uzun olana kadar zum = 0, zum = 1, zum = 2'yi deneyin.

1
Umarım ne istediğini uzaktan anladım. = \
Michal Migurski

Bu cevabı ararken bu soruyu buldum, teşekkürler.
BenjaminGolder

@MichalMigurski küresel mercatorda 2 nokta arasındaki mesafenin nasıl hesaplanacağını açıklayabilir misiniz? özellikle x koordinatları ... teşekkür sıkışmış.
otmezger

5

Bu Maperitive kullandığım C # kodu :

    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: uzun / lat koordinatlarında sınırlayıcı kutu (x = uzun, y = lat)
  • paddingFactor: bu ThomM'nin ifade ettiği "% 120" etkisini elde etmek için kullanılabilir. 1.2 değeri size% 120 elde edecektir.

Benim durumumda zoomgerçek bir sayı olabileceğini unutmayın . Web haritaları söz konusu olduğunda, bir tamsayı yakınlaştırma değerine ihtiyacınız vardır, bu nedenle bunu (int)Math.Floor(zoom)elde etmek için benzer bir şey kullanmalısınız .

Elbette, bu kod yalnızca Web Mercator projeksiyonu için geçerlidir.


1
Bunun için teşekkürler. CenterMapOnPoint kodu mevcut mu?
mcintyre321

Mükemmel! Ben OsmDroid SDK BoundingBox yakınlaştırma hesaplamak için kullandım ve işe yarıyor :)
Billda

Bu kütüphaneleri nerede bulabilirim? Bir GeometryUtils veya Bounds2 derlemesi bulamıyorum. Maperitive'den bir şey indirmem gerekiyor mu? Orada sadece bir uygulama görüyorum.
Dowlers

@Dowlers GeometryUtilssadece dereceleri radyan ve geri dönüştürmek için kullanılır, bu basit bir matematik formülüdür. Bounds2temelde sadece dikdörtgen bir yapıdır. Bu kod, doğrudan kopyalanabilen bir şeyden ziyade bir sahte kod olarak sağlandı.
Igor Brejc

1
Bu harika @ IgorBrejc- çok teşekkür ederim! Başkalarının python kodu yazması durumunda burada python'a
Charlie Hofmann

1

OpenLayers kullanıyorsanız Map.getZoomForExtent, haritadaki tüm boyuta sığabilecek en yüksek zoom seviyesini hesaplar. extentİhtiyaçlar haritanın projeksiyonda olmak. Ayrıca kullanabilirsiniz fill_factorharitanın kenarında noktalarını gösteren kaçınmak ve max_zoommümkün zoom sınırlamak için:

extent = extent.scale(1/fill_ratio);
var zoom = Math.min(map.getZoomForExtent(map_extent), max_zoom);
map.setCenter(extent.getCenterLonLat(), zoom);

bu sorunumu çözmedi, ancak günümü kurtaran Leaflet'in fitBounds yöntemini bulmamı sağladı.
SamuelDev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.