当只有一个图钉时,如何确定 Bing 地图的正确缩放级别?

问题描述

我在地图上添加了一些图钉,然后“调整大小”或“正确缩放”它,以便显示所有图钉,但使远边缘的图钉几乎不在边界内,如下所示:

enter image description here

然而,如果只有一个图钉(如爱荷华州的以下案例,它只有一场内战),而不是尽可能接近零,它会一直缩小到 Skylab,像这样:

enter image description here

这是我用来“调整大小”地图的代码

private void RightsizeZoomLevelForAllpushpins()
{
    try
    {
        // Set the view so that all pushpins are displayed,with a bit of a margin around them
        // from https://stackoverflow.com/questions/65779504/how-to-set-the-zoom-level-of-bing-map-to-just-wide-enough-to-display-all-pushpin/65781319#65781319
        var map = this.userControl11.myMap;
        var locations = map.Children.OfType<pushpin>().Select(x => x.Location);
        //Margin
        var w = new pushpin().Width;
        var h = new pushpin().Height;
        var margin = new Thickness(w / 2,h,w / 2,0);

        //Set view
        map.SetView(locations,margin,0);
        currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
        UncheckAllZoomLevelToolstripMenuItems();
        SetZoomMenuItem();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}

如何使单图钉地图不仅居中而且尽可能放大?

更新

在对 Count 的两个引用添加括号,并在 else 块中添加一个“if”以便编译后,我仍然收到以下代码的两个错误

private void RightsizeZoomLevelForAllpushpins()
{
    try
    {
        // Set the view so that all pushpins are displayed,with a bit of a margin around them
        var map = this.userControl11.myMap;
        var locations = map.Children.OfType<pushpin>().Select(x => x.Location);

        if (locations.Count() == 1)
        {
            map.setView(locations[0],singlePinZoom);                
        }
        else if (locations.Count() > 1) 
        {
            //Margin
            var w = new pushpin().Width;
            var h = new pushpin().Height;
            var margin = new Thickness(w / 2,0);

            //Set view
            map.SetView(locations,0);
        }    
        currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
        UncheckAllZoomLevelToolstripMenuItems();
        SetZoomMenuItem();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}

他们是:

1>C:\Users\bclay\source\repos\mymaps\mymaps\Form1.cs(155,33,155,45): error CS0021: Cannot apply indexing with [] to an expression of type 'IEnumerable<Location>'
1>C:\Users\bclay\source\repos\mymaps\mymaps\Form1.cs(155,25,32): error CS1061: 'Map' does not contain a deFinition for 'setView' and no accessible extension method 'setView' accepting a first argument of type 'Map' Could be found (are you missing a using directive or an assembly reference?)

顺便说一句,在编译项目之前,我在 Visual Studio 中看不到任何错误(在输入错误时它停止发现错误)。我不知道为什么......我没有改变任何设置......

更新 2

这是我现在使用的代码,它不只考虑一个图钉,但确实有效(请注意,“SetView”在此处不会引发异常):

private void RightsizeZoomLevelForAllpushpins()
    {
        const int LEFT_TOP_RIGHT_MARGIN_ADDITION = 16;
        const int BottOM_MARGIN_ADDITION = 48;
        try
        {
            // Set the view so that all pushpins are displayed,with a bit of a margin around them
            // from https://stackoverflow.com/questions/65779504/how-to-set-the-zoom-level-of-bing-map-to-just-wide-enough-to-display-all-pushpin/65781319#65781319
            var map = this.userControl11.myMap;
            var locations = map.Children.OfType<pushpin>().Select(x => x.Location);
            //Margin
            var w = new pushpin().Width;
            var h = new pushpin().Height;
            var margin = new Thickness((w / 2) + LEFT_TOP_RIGHT_MARGIN_ADDITION,h + LEFT_TOP_RIGHT_MARGIN_ADDITION,(w / 2) + LEFT_TOP_RIGHT_MARGIN_ADDITION,0 + BottOM_MARGIN_ADDITION);
            //Set view
            map.SetView(locations,0);
            currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
            UncheckAllZoomLevelToolstripMenuItems();
            SetZoomMenuItem();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }
    }

解决方法

单个图钉没有单一的缩放级别,最佳缩放级别取决于您的场景或图钉的含义,以及地图的大小,因为缩放和地图大小都决定了可视区域.例如,如果您的图钉代表一所房子,您可能希望地图放大得比代表城市时放大。

也就是说,这是您的代码的修改版本,它将处理单针场景并使用您选择的静态缩放级别:

private double singlePinZoom = 15;

private void RightsizeZoomLevelForAllPushpins()
{
    try
    {
        // Set the view so that all pushpins are displayed,with a bit of a margin around them
        var map = this.userControl11.myMap;
        var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);

        if(locations.Count() > 0) {
            //Margin
            var w = new Pushpin().Width;
            var h = new Pushpin().Height;
            var margin = new Thickness(w / 2,h,w / 2,0);

            //Set view
            map.SetView(locations,margin,0);
        } else(locations.Count == 1) {
            map.setView(locations[0],singlePinZoom);
        }   
        
        currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
        UncheckAllZoomLevelToolstripMenuItems();
        SetZoomMenuItem();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}
,

另一篇文章中的答案分享了这个想法,但不幸的是有一些语法错误,并且 if/else 的逻辑是错误的。正如我在评论中提到的,您应该注意以下几点:

  1. locations 在您的代码中是 IEnumerable<Location> 并且它没有 Count 属性,相反,您可以对其使用 Count() 扩展方法。
  2. locations 没有像数组那样的索引器,您不能使用 locations[0] 来获取第一个元素,而是需要使用 locations.First()
  3. 如果您首先检查 Count()>0,则永远不会命中 then Count()==1。因此您需要更改条件,例如先locations.Count() ==1,然后是locations.Count() >1
  4. 确保添加 useing System.Linq; 以便您可以使用 Count()First() 方法。

这是您的代码的修改版本:

private void RightsizeZoomLevelForAllPushpins()
{
    try
    {
        var map = this.userControl11.myMap;
        var locations = map.Children.OfType<Pushpin>().Select(x => x.Location);
        if(locations.Count()==1)
        {
            //Your preferred zoom level
            var zoomLevel = 12; 

            //Set view
            map.SetView(locations.First(),zoomLevel );
        }
        else if (locations.Count()>1)
        {
            //Margin
            var w = new Pushpin().Width;
            var h = new Pushpin().Height;
            var margin = new Thickness(w / 2,0);
        }
        else
        {
            //Not necessary
            System.Windows.Forms.MessageBox.Show("No pushpin.");
        }
        currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
        UncheckAllZoomLevelToolstripMenuItems();
        SetZoomMenuItem();
    }
    catch (Exception ex)
    {
        //Not necessary
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}