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

5
我在地图上添加了许多图钉,然后通过“rightsize”或“right zoom”来调整地图的大小,以便所有的图钉都能显示出来,但是边缘上的图钉仅在边界内露出一点,就像这样: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, 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);
    }
}

它们是:

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,155,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, margin, 0);
            currentZoomLevel = Convert.ToInt32(map.ZoomLevel);
            UncheckAllZoomLevelToolstripMenuItems();
            SetZoomMenuItem();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }
    }

@CaiusJard “这样所有的图钉都能显示出来,但是边缘上的那些图钉只能在边界内部。” - B. Clay Shannon-B. Crow Raven
1
你已经学习了有关于单个点的 SetView,可以在此处查看(https://stackoverflow.com/a/65513589/3110834),因此你可以检查位置中是否有单个点,通过传递 locations.First() 来使用接受单个位置的重载,否则,通过传递 locations 使用使用位置的IEnumerable的重载。选择单个点的缩放级别由你决定。 - Reza Aghaei
使用以下代码:if (locations.Count() == 1) { map.SetView(locations.First(), 12); } else if (locations.Count() > 1) { map.SetView(locations, margin, 0); } else { MessageBox.Show("无点。"); } - Reza Aghaei
1
下面的答案分享了这个想法,但不幸的是它有一些语法错误,而且if/else的逻辑也是错误的。如我所提到的,要检查计数,您需要使用locations.Count(),要获取第一个,您不能使用[],您需要使用locations.First(),此外条件应该是locations.Count() ==1locations.Count() >1 - Reza Aghaei
@Reza:是的,就像上面的更新所示,我已经将它改成了那样。但是,尽管使用“更新”代码,我仍然收到那些错误消息,因此现在正在使用“更新2”中的内容。如果您能给我另一个有效的答案(就像您过去一直做的那样),我会给您赏金,但时间不多了... - B. Clay Shannon-B. Crow Raven
显示剩余4条评论
2个回答

3

对于单个标记,没有一个唯一的缩放级别,最佳的缩放级别取决于您的场景或标记所代表的内容,以及地图的大小,因为缩放级别和地图大小都决定了可视区域。例如,如果您的标记代表一个房子,您可能希望地图的缩放比代表城市的标记更高。

话虽如此,以下是您代码的修改版本,将处理单个标记场景并使用您选择的静态缩放级别:

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);
    }
}

我在这行代码上收到了“error CS0019:运算符'>'不能应用于类型为'method group'和'int'的操作数”的错误提示:if (locations.Count > 0)。 - B. Clay Shannon-B. Crow Raven
1
@B.ClayShannon 应该是 Count() - Reza Aghaei
1
由于locations.Count为1也满足“if locations.Count> 0”的条件,因此您可以首先检查count == 1并在else中处理多个位置。 - jaro
@jaroslaw:是的,但只有1个计数可能非常罕见。 - B. Clay Shannon-B. Crow Raven
1
如果按照这个答案中提供的条件,对于“1”根本不起作用。此外,您需要将位置设置为列表,这样就不必再次枚举位置以进行计数。 var locations = map.Children.OfType<Pushpin>().Select(x => x.Location).ToList() <- 然后在“if”语句中使用Count而不是() - jaro
@jaroslaw:哦,没错,你说得对;我本应该注意到这一点——"1"这部分现在永远不会被执行了。不过,我的代码还存在其他问题,这些问题阻碍了我继续前进(如果感兴趣的话,请查看我问题的更新)。 - B. Clay Shannon-B. Crow Raven

1
在另一篇帖子中的答案分享了这个想法,但不幸的是它有一些语法错误,并且if/else的逻辑是错误的。正如我在评论中提到的,这些是你应该注意的一些要点:
  1. 你代码中的locationsIEnumerable<Location>类型,它没有Count属性,而是可以在其上使用Count()扩展方法。
  2. locations没有像数组一样的索引器,因此您不能使用locations[0]来获取第一个元素,而需要使用locations.First()
  3. 如果您首先检查Count()>0,那么then Count()==1将永远不会命中。因此,您需要更改条件,例如首先是locations.Count() ==1,然后是locations.Count() >1
  4. 确保您添加了using 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, h, w / 2, 0);

            //Set view
            map.SetView(locations, margin, 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);
    }
}

有一点可能不相关,但我猜 map.ZoomLevel 在调用 SetView 后不会立即更新。 - Reza Aghaei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接