지도에 둘 이상의 점을 표시하기 위해 최적의 줌 레벨을 계산하는 방법


12

정적지도에 여러 개의 마커를 표시하고 Google지도와 같이 최적의 줌 레벨을 계산하려고합니다. 경계 사각형과지도의 중심점을 이미 계산했지만 이제 전체 경계 사각형을 표시하기 위해 올바른 확대 / 축소 수준을 계산하기가 어렵습니다. 누군가 올바른 방향으로 우리를 가리킬 수 있습니까?


매우 정교하지는 않지만 MBR에 120 %를 곱하고 확대하는 것이 어떻습니까? "최적"의 정의에 따라 다른 것이 있습니까?
ThomM

ThomM의 아이디어에 +1. 이것이 바로 ArcGIS가하는 일입니다.
Ragi Yaser Burhum

1
죄송하지만이 MBR은 무엇입니까?
로드리고

답변:


5

확대 / 축소 수준을 얻으려면지도의 픽셀 크기를 알아야합니다. 구형 메르카토르 좌표에서 수학을 수행해야합니다.

  1. 위도, 경도를 구형 메르카토르 x, y로 변환합니다.
  2. 구형 메르카토르에서 두 지점 사이의 거리를 확보하십시오.
  3. 적도의 길이는 약 40m이며 투영 된 타일의 너비는 256 픽셀이므로 지정된 줌 레벨에서 해당 맵의 픽셀 길이는 약 256 * distance / 40000000 * 2 ^ zoom 입니다. 거리가지도의 픽셀 크기에 비해 너무 길 때까지 zoom = 0, zoom = 1, zoom = 2를 사용해보십시오.

1
당신이 실제로 요구하는 것을 원격으로 이해하기를 바랍니다. = \
Michal Migurski

이 답변을 찾는 동안이 질문을 찾았습니다. 감사합니다.
BenjaminGolder

@MichalMigurski 구면 메르카토르에서 두 점 사이의 거리를 계산하는 방법을 설명 할 수 있습니까? 특히 x 좌표 ... 고마워요.
otmezger

5

이것은 Maperitive 에서 사용하는 C # 코드입니다 .

    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: Long / lat Coords의 경계 상자 (x = long, y = lat)
  • paddingFactor: ThomM이 참조하는 "120 %"효과를 얻는 데 사용할 수 있습니다. 1.2의 값은 120 %가됩니다.

내 경우 zoom에는 실수가 될 수 있습니다. 웹 맵의 경우 정수 확대 / 축소 값이 필요하므로 (int)Math.Floor(zoom)이를 얻는 것과 같은 것을 사용해야 합니다.

물론이 코드는 Web Mercator 투영에만 적용됩니다.


1
고마워 CenterMapOnPoint의 코드를 사용할 수 있습니까?
mcintyre321 14

완전한! 이것을 사용하여 OsmDroid SDK에서 BoundingBox의 확대 / 축소를 계산했으며 작동합니다.)
Billda

이 라이브러리는 어디에서 찾을 수 있습니까? GeometryUtils 또는 Bounds2 어셈블리를 찾을 수 없습니다. maperitive에서 무언가를 다운로드해야합니까? 거기에 앱만 있습니다.
Dowlers

@Dowlers GeometryUtils는 여기에서도를 라디안으로 변환하고 다시 변환하는 데 사용되며 간단한 수학 공식입니다. Bounds2기본적으로 사각형 구조입니다. 이 코드는 직접 복사하여 붙여 넣을 수있는 것보다 의사 코드로 제공되었습니다.
Igor Brejc

1
감사합니다 @ IgorBrejc- 정말 고마워요! 다른 사람들이 파이썬 코드를 작성하는 경우를 대비하여 여기에서 파이썬으로 변환했습니다. gist.github.com/mappingvermont/d534539fa3ebe4a1e242644e528bf7b9
Charlie Hofmann

1

OpenLayers를 사용 Map.getZoomForExtent하는 경우 맵에서 전체 범위에 맞는 가장 높은 줌 레벨을 계산합니다. extent필요는지도의 투영한다. a fill_factor를 사용 하여지도 가장자리에 점이 표시되지 않도록 max_zoom하고 가능한 확대 / 축소를 제한 할 수 있습니다.

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

이것은 내 문제를 해결하지 못했지만 Leaflet의 fitBounds 메소드를 찾게되어 하루를 절약했습니다.
SamuelDev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.