“Advanced Shapes” (i.e. Donut Polygons) on Bing Maps

I notice that the MSDN Reference for Bing Maps was recently updated to include details of a new “Advanced Shapes” API. I don’t know exactly when this came out and I’ve not seen any releases from the product team about it, but it seems basically to be an official release of the code written by Ricky Brundritt a few years back.

After loading the Advanced Shapes module, the functionality of the default Microsoft.Maps.Polygon object is extended to allow for MultiPolygons and Polygons containing interior rings. (i.e. holes).

It’s nice that this feature has finally been officially incorporated into the Bing Maps code – it’s surprising how often you need to define these sorts of shapes. For example, the following code listing defines a polygon representing the shape of South Africa which, thanks to the Advanced Shapes API, can now correctly exclude the fully-enclosed Lesotho by defining an interior ring around it:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
  <script type="text/javascript">

    var MM = Microsoft.Maps;
    var map = null;

    function GetMap() {
      // Create a new map
      map = new Microsoft.Maps.Map(
        document.getElementById("mapDiv"),
        {
          credentials: "At3aYXF4p6L___G3tY3r0wnFr!ggingK3y___oKURkDSvOeRs",
          center: new Microsoft.Maps.Location(0, 0),
          zoom: 2
        }
      );

      // Load the Advanced Shapes API
      Microsoft.Maps.loadModule('Microsoft.Maps.AdvancedShapes', { callback: shapesModuleLoaded });

    }

    // Callback function
    function shapesModuleLoaded() {

      // Create polygon (South Africa) containing interior ring (Lesotho)
      var SouthAfrica = new Microsoft.Maps.Polygon([

        /* Exterior Ring */
        [new MM.Location(-28.6906,16.5234), new MM.Location(-29.4587,17.0947), new MM.Location(-30.2211,17.2705), new MM.Location(-31.0529,17.666), new MM.Location(-31.6908,18.1494), new MM.Location(-32.1384,18.3691), new MM.Location(-32.6949,18.3691), new MM.Location(-32.9165,18.2373), new MM.Location(-32.8427,18.0176), new MM.Location(-33.3213,18.1934), new MM.Location(-33.8339,18.5449), new MM.Location(-34.2708,18.457), new MM.Location(-34.0891,18.8086), new MM.Location(-34.597,19.3359), new MM.Location(-34.8859,19.9951), new MM.Location(-34.4522,20.7861), new MM.Location(-34.4884,21.9287), new MM.Location(-34.0891,22.5439), new MM.Location(-34.1618,23.291), new MM.Location(-33.9798,23.7744), new MM.Location(-34.2708,24.873), new MM.Location(-33.9798,25.1367), new MM.Location(-34.1254,25.6201), new MM.Location(-33.9069,25.8838), new MM.Location(-33.8339,26.7627), new MM.Location(-33.2479,27.8174), new MM.Location(-32.3243,28.96), new MM.Location(-31.7282,29.4873), new MM.Location(-30.6379,30.7178), new MM.Location(-29.6881,31.377), new MM.Location(-29.3056,31.5088), new MM.Location(-28.7291,32.3877), new MM.Location(-28.1107,32.6953), new MM.Location(-27.2937,32.915), new MM.Location(-26.9417,33.0029), new MM.Location(-26.9025,32.2119), new MM.Location(-27.3327,32.0361), new MM.Location(-27.3327,31.2891), new MM.Location(-27.1374,31.0693), new MM.Location(-26.7848,30.8936), new MM.Location(-26.4312,30.9814), new MM.Location(-26.037,31.2012), new MM.Location(-25.7999,31.5088), new MM.Location(-25.879,31.6846), new MM.Location(-25.958,32.0361), new MM.Location(-25.0856,32.168), new MM.Location(-24.2069,32.0361), new MM.Location(-23.4834,31.6846), new MM.Location(-22.3501,31.333), new MM.Location(-22.3907,30.498), new MM.Location(-22.1874,29.9707), new MM.Location(-22.1874,29.0918), new MM.Location(-22.5126,29.0479), new MM.Location(-22.6748,28.3447), new MM.Location(-23.0393,27.9932), new MM.Location(-23.4431,27.6416), new MM.Location(-23.6445,27.1582), new MM.Location(-24.287,26.9385), new MM.Location(-24.687,26.1035), new MM.Location(-25.4433,25.7959), new MM.Location(-25.7603,25.4883), new MM.Location(-25.879,24.8291), new MM.Location(-25.7999,24.3018), new MM.Location(-25.6415,23.8623), new MM.Location(-25.3639,23.4229), new MM.Location(-25.4433,22.9834), new MM.Location(-26.037,22.6758), new MM.Location(-26.3919,22.4121), new MM.Location(-26.6671,22.1924), new MM.Location(-26.9025,21.665), new MM.Location(-26.9417,21.2256), new MM.Location(-26.8633,20.9619), new MM.Location(-26.9808,20.8301), new MM.Location(-26.5885,20.6982), new MM.Location(-26.0765,21.0059), new MM.Location(-25.5226,20.7422), new MM.Location(-25.0856,20.4785), new MM.Location(-24.8864,20.127), new MM.Location(-28.4977,20.1709), new MM.Location(-28.5749,19.7754), new MM.Location(-28.7677,19.3799), new MM.Location(-28.9985,19.3799), new MM.Location(-28.9601,18.9844), new MM.Location(-28.9216,18.5449), new MM.Location(-28.9601,17.9736), new MM.Location(-28.8062,17.7539), new MM.Location(-28.7677,17.4902), new MM.Location(-28.5363,17.3584), new MM.Location(-28.3817,17.4023), new MM.Location(-28.1107,17.2266), new MM.Location(-28.1107,17.0508), new MM.Location(-28.3431,16.9189), new MM.Location(-28.5363,16.8311), new MM.Location(-28.5749,16.6992), new MM.Location(-28.6906,16.5234)],

        /* Interior Ring */
        [new MM.Location(-29.6403,27.0374), new MM.Location(-29.5257,27.356), new MM.Location(-29.2864,27.5098), new MM.Location(-29.0274,27.7185), new MM.Location(-28.8735,27.9492), new MM.Location(-28.8735,28.0481), new MM.Location(-28.7195,28.2019), new MM.Location(-28.7195,28.3887), new MM.Location(-28.6327,28.4546), new MM.Location(-28.5749,28.7073), new MM.Location(-28.9216,29.0369), new MM.Location(-29.1234,29.3445), new MM.Location(-29.363,29.5093), new MM.Location(-29.497,29.3665), new MM.Location(-29.5926,29.3665), new MM.Location(-29.6881,29.2126), new MM.Location(-29.8311,29.1467), new MM.Location(-29.9359,29.2017), new MM.Location(-30.1451,28.7622), new MM.Location(-30.1641,28.4326), new MM.Location(-30.278,28.2458), new MM.Location(-30.3729,28.3008), new MM.Location(-30.4392,28.2019), new MM.Location(-30.6852,28.103), new MM.Location(-30.6379,27.7515), new MM.Location(-30.3539,27.4219), new MM.Location(-30.1831,27.4329), new MM.Location(-30.0406,27.2681), new MM.Location(-29.8406,27.2021), new MM.Location(-29.6403,27.0374)]
      ], 

      // Set a few styling options
      {fillColor: new MM.Color(120, 0, 180, 0)}
);
      // Place the shape on the map
      map.entities.push(SouthAfrica);
    }
  </script>
</head>
<body onload="GetMap();">
  <div id='mapDiv' style="position: relative; width: 540px; height: 480px;"></div>
</body>
</html>

and here’s what it looks like:

image

About these ads
This entry was posted in Bing Maps and tagged . Bookmark the permalink.

9 Responses to “Advanced Shapes” (i.e. Donut Polygons) on Bing Maps

  1. Xavier says:

    Thanks for sharing Alastair.
    Do you know if It this available/possible in the Bing Maps WPF control as well ?

  2. Ryan says:

    Alastair, I asked a question about this blog post on msdn. Wasn’t sure if I should put it here or if it would be more useful there…

    http://social.msdn.microsoft.com/Forums/en-US/bingmapsajax/thread/13f83f1d-34ed-4962-a5aa-97f2a4eff8d1

    thanks!

  3. mike liddell says:

    Why is the interior ring not recognized when defined in the following manner:
    interiorRing = []
    interRingCoordinates = “-29.6403,27.0374,-29.5257,27.356,-29.2864,27.5098,-29.0274,27.7185,-28.8735,27.9492,-28.8735,28.0481,-28.7195,28.2019,-28.7195,28.3887,-28.6327,28.4546,-28.5749,28.7073,-28.9216,29.0369,-29.1234,29.3445,-29.363,29.5093,-29.497,29.3665,-29.5926,29.3665,-29.6881,29.2126,-29.8311,29.1467,-29.9359,29.2017,-30.1451,28.7622,-30.1641,28.4326,-30.278,28.2458,-30.3729,28.3008,-30.4392,28.2019,-30.6852,28.103,-30.6379,27.7515,-30.3539,27.4219,-30.1831,27.4329,-30.0406,27.2681,-29.8406,27.2021,-29.6403,27.0374″;
    coordinateCount = interRingCoordinates .split(“,”);
    for( var i =0; i < coordinateCount;i+=2)
    interiorRing.push( new MM.Location( i,i+1))

  4. mike liddell says:

    Sorry, forgot to extract from interRingCoordinates!

  5. mike liddell says:

    OK, the revised equivalent ( snippet below ) does not result in an inner ring!
    interiorRing = []
    coordinates = “-29.6403,27.0374,-29.5257,27.356,-29.2864,27.5098,-29.0274,27.7185,-28.8735,27.9492,-28.8735,28.0481,-28.7195,28.2019,-28.7195,28.3887,-28.6327,28.4546,-28.5749,28.7073,-28.9216,29.0369,-29.1234,29.3445,-29.363,29.5093,-29.497,29.3665,-29.5926,29.3665,-29.6881,29.2126,-29.8311,29.1467,-29.9359,29.2017,-30.1451,28.7622,-30.1641,28.4326,-30.278,28.2458,-30.3729,28.3008,-30.4392,28.2019,-30.6852,28.103,-30.6379,27.7515,-30.3539,27.4219,-30.1831,27.4329,-30.0406,27.2681,-29.8406,27.2021,-29.6403,27.0374″;
    coordinateCount = c.split(“,”);
    for( var i =0; i < coordinateCount;i+=2)
    interiorRing.push( new MM.Location( coordinates[i],coordinates[i+1]))
    rings.push(interiorRing );
    var SouthAfrica = new Microsoft.Maps.Polygon(rings, …

  6. maya says:

    Sorry, I’m a newbie in spatial db’s… Do I need manually get all these coordinates for particular country (e.g.-29.6403,27.0374,-29.5257,27.356,-29.2864,27.5098..) or there is a method to get it from world_borders database ?As I see only lat/lon for particular point on the map and nothing for the whole contry board (I mean border line)…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s