Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine the correct zoom level for Bing Maps when there is only one pushpin?

Tags:

I add a number of pushpins to a map and then "rightsize" or "right zoom" it so that all the pushpins show but so that the ones on the far edges are barely within the boundaries, like so:

enter image description here

However, if there is only one pushpin (as in the following case with Iowa, which only had the one civil war battle), rather than zero in on that as close as possible, it zooms out all the way to Skylab, like so:

enter image description here

This is the code I use to "right size" the map:

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

How can I get a one-pushpin map to not only center, but also zoom in as far as possible?

UPDATE

After adding parens to both references to Count, and adding an "if" in the else block so that it would compile, I still get two errors with this code:

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

They are:

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

BTW, I'm not seeing any errors anymore in Visual Studio until I compile the project (it stopped finding errors as they were entered). I don't know why ... I changed no settings...

UPDATE 2

This is the code I'm using now, which does not take just one pushpin into account, but does work (note that "SetView" doesn't throw an exception here):

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);
        }
    }
like image 553
B. Clay Shannon-B. Crow Raven Avatar asked Feb 27 '21 06:02

B. Clay Shannon-B. Crow Raven


People also ask

How do I measure area on Bing Maps?

The Bing Maps website has this feature: on the map canvas, right click or tap and hold, then click or tap Measure Distance (can be used for lines and areas).

What coordinate system does Bing Maps use?

Each of the Bing Maps services uses a projected coordinate system called Mercator Auxiliary Sphere, which uses GCS_WGS_1984 as its geographic coordinate system. The Bing Maps web service projects on the fly and can be transformed to match your data precisely in the same way as any other data source.

What resolution is Bing Maps?

Bing Maps aerial and satellite imagery is among the best available for online mapping platforms, with global coverage imagery up to 30cm/pixel resolution.

How do I edit Bing Maps?

Sign in to the Bing Maps Dev Center. Click Update or view account details to view your account details, and then click Edit. Make your changes to the account information, and then click Save.


2 Answers

There is no single zoom level for a single pin, the best zoom level would depend on your scenario or what the pin is meant to represent, as well as the size of the map since both zoom and map size determine the viewable area. For example, if your pin represented a house you may want the map to be zoomed in more than if it represented a city.

That said, here is a modified version of your code that will handle the single pin scenario and use a static zoom level of your choosing:

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);
    }
}
like image 50
rbrundritt Avatar answered Oct 05 '22 19:10

rbrundritt


The answer in the other post shares the idea, but unfortunately is has(had) some syntax errors, and the logic of the if/else is wrong. As I mentioned in the comments, these are some points to which you should pay attention:

  1. locations in your code is IEnumerable<Location> and it doesn't have Count property, instead, you can use Count() extension method on it.
  2. locations doesn't have indexer like arrays and you cannot use locations[0] to get the first element, instead you need to use locations.First().
  3. If you first check for Count()>0, then Count()==1 will never hit. So you need to change the conditions, for example first locations.Count() ==1 and then locations.Count() >1.
  4. Make sure you add useing System.Linq; so you can use Count() and First() methods.

Here is the modified version of your code:

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);
    }
}
like image 30
Reza Aghaei Avatar answered Oct 05 '22 17:10

Reza Aghaei