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

Posted

技术标签:

【中文标题】当只有一个图钉时,如何确定 Bing 地图的正确缩放级别?【英文标题】:How can I determine the correct zoom level for Bing Maps when there is only one pushpin? 【发布时间】:2021-05-29 10:43:22 【问题描述】:

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

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

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

private void RightsizeZoomLevelForAllPushpins()

    try
    
        // Set the view so that all pushpins are displayed, with a bit of a margin around them
        // from https://***.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://***.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 “这样所有的图钉都会显示出来,但远边缘的图钉几乎不会在边界内” 但如果只有一个图钉.. 你已经学习了关于SetView的单点here,所以你可以检查位置是否有单点,使用通过locations.First()接受单个位置的重载,否则通过传递locations 使用使用 IEnumerable 位置的重载。选择单个点的缩放级别由您决定。 下面的答案分享了这个想法,但不幸的是有一些语法错误而且 if/else 的逻辑是错误的。要检查我提到的计数,你需要使用locations.Count(),以获得第一,你不能使用[],你需要使用locations.First(),条件应该是locations.Count() ==1locations.Count() &gt;1跨度> 【参考方案1】:

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

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

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

【讨论】:

我在这一行得到“错误 CS0019:运算符'>'不能应用于'方法组'和'int'类型的操作数”:if (locations.Count > 0) @B.ClayShannon 应该是Count() ...并且因为 locations.Count 是一个也满足“if locations.Count > 0”的条件,您可以先检查 count == 1 并在 else 中处理多个位置跨度> @jaroslaw:是的,但只有 1 的计数可能极为罕见。 如果提供的条件在此答案中的顺序中对于“1”根本不起作用。此外,您还希望将位置列为列表,这样就不必再次枚举它来进行计数。 var locations = map.Children.OfType().Select(x => x.Location).ToList() 【参考方案2】:

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

    locations 在你的代码中是IEnumerable&lt;Location&gt; 并且它没有Count 属性,你可以在它上面使用Count() 扩展方法。 locations 没有类似数组的索引器,您不能使用 locations[0] 获取第一个元素,而是需要使用 locations.First()。 如果您首先检查Count()&gt;0then Count()==1 将永远不会命中。所以你需要改变条件,例如先locations.Count() ==1,然后locations.Count() &gt;1。 确保添加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, 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 后立即更新。

以上是关于当只有一个图钉时,如何确定 Bing 地图的正确缩放级别?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Bing 地图的缩放级别设置为足够宽以显示所有图钉?

如何在我的 Bing 地图图钉上添加标签?

在 Windows Phone 8 Bing 地图上设置图钉 (XAML C#)

如何在 MKMapView 中将图钉和地图保持在移动叠加层上方的中心

当用户点击地图图钉时动态更改图标图像文件:谷歌地图

部分邮政编码在 Bing 地图上返回正确的结果,而完整的邮政编码不返回