วิธีการคำนวณระดับการซูมที่ดีที่สุดเพื่อแสดงจุดสองจุดขึ้นไปบนแผนที่


12

เราต้องการแสดงเครื่องหมายหลายอันบนแผนที่แบบคงที่และต้องการคำนวณระดับการซูมที่เหมาะสมอย่างที่ Google แผนที่ทำ เราคำนวณสี่เหลี่ยมผืนผ้าที่มีขอบเขตและจุดกึ่งกลางของแผนที่อยู่แล้ว แต่ตอนนี้เรามีเวลายากในการคำนวณ zoomlevel ที่ถูกต้องเพื่อแสดงสี่เหลี่ยมผืนผ้าทั้งหมด ใครช่วยชี้เราไปในทิศทางที่ถูกต้องได้ไหม?


มันไม่ซับซ้อนมาก แต่ทำไมไม่เพียงแค่คูณ MBR ด้วย 120% แล้วซูมไปที่นั้น มีอะไรอีกที่ขึ้นอยู่กับคำนิยามของคุณว่า "ดีที่สุด" ใช่ไหม
ThomM

+1 ตามแนวคิดของ ThomM นี่คือสิ่งที่ ArcGIS ทำ
Ragi Yaser Burhum

1
ขออภัย MBR นี้คืออะไร
Rodrigo

คำตอบ:


5

ในการรับระดับการซูมคุณต้องทราบขนาดพิกเซลของแผนที่ คุณจะต้องทำคณิตศาสตร์ของคุณในพิกัดปรอททรงกลม

  1. แปลงละติจูด, ลองติจูดเป็นปรอททรงกลม x, y
  2. รับระยะห่างระหว่างจุดสองจุดของคุณด้วย Mercator ทรงกลม
  3. เส้นศูนย์สูตรเป็นเรื่องเกี่ยวกับที่คาดการณ์เมตร 40m ยาวและกระเบื้อง 256 พิกเซลกว้างเพื่อให้ความยาวของพิกเซลที่แผนที่ที่ขยายถึงระดับที่กำหนดเป็นเรื่องเกี่ยวกับ256 * ระยะทาง / 40000000 * 2 ลองซูม = 0, ซูม = 1, ซูม = 2 จนกระทั่งระยะทางยาวเกินไปสำหรับขนาดพิกเซลของแผนที่ของคุณ

1
หวังว่าฉันจะเข้าใจสิ่งที่คุณขอจากระยะไกล = \
Michal Migurski

พบคำถามนี้ในขณะที่มองหาคำตอบนี้ขอบคุณ
BenjaminGolder

@MichalMigurski คุณสามารถอธิบายวิธีการคำนวณระยะห่างระหว่าง 2 คะแนนใน Mercator ทรงกลมได้หรือไม่? พิเศษพิกัด x ... ฉันติดอยู่ขอบคุณ
otmezger

5

นี่คือรหัส C # ที่ฉันใช้ในMaperitive :

    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: ขอบเขตของกล่องใน coords ยาว / lat (x = ยาว, y = lat)
  • paddingFactor: สามารถใช้เพื่อให้ได้ผล "120%" ThomM หมายถึง ค่า 1.2 คุณจะได้รับ 120%

โปรดทราบว่าในกรณีของฉันzoomอาจเป็นจำนวนจริง ในกรณีของ Web แผนที่ที่คุณจำเป็นต้องมีค่าจำนวนเต็มซูมดังนั้นคุณควรใช้สิ่งที่ต้องการ(int)Math.Floor(zoom)จะได้รับมัน

แน่นอนว่ารหัสนี้ใช้กับการประมาณการ Web Mercator เท่านั้น


1
ขอบคุณสำหรับสิ่งนี้. มีรหัสสำหรับ CenterMapOnPoint หรือไม่
mcintyre321

ที่สมบูรณ์แบบ! ฉันใช้สิ่งนี้เพื่อคำนวณการย่อ / ขยายของ BoundingBox ใน OsmDroid SDK และใช้งานได้ :)
Billda

ฉันจะหาห้องสมุดเหล่านี้ได้ที่ไหน ฉันไม่พบชุดประกอบ GeometryUtils หรือ Bounds2 ฉันจำเป็นต้องดาวน์โหลดบางสิ่งบางอย่างจาก maperitive หรือไม่ ฉันเห็นแอพที่นั่นเท่านั้น
Dowlers

@Dowlers GeometryUtilsใช้เพื่อแปลงองศาเป็นเรเดียนและแปลงกลับเป็นสูตรทางคณิตศาสตร์อย่างง่าย Bounds2เป็นเพียงโครงสร้างสี่เหลี่ยมผืนผ้า รหัสนี้ให้เป็นรหัสเทียมมากกว่าบางอย่างที่คัดลอกได้โดยตรง
Igor Brejc

1
นี่มันยอดเยี่ยม @ IgorBrejc- ขอบคุณมาก! ฉันแปลงเป็นงูหลามที่นี่ในกรณีที่คนอื่นเขียนรหัสไพธ อน
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);

สิ่งนี้ไม่ได้แก้ไขปัญหาของฉัน แต่มันทำให้ฉันพบวิธีการ fitBounds ของ Leaflet ซึ่งช่วยชีวิตฉันไว้
SamuelDev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.