none
How to identify Coverage Area RRS feed

  • Question

  • Hello friends,

    I am using Bing Map API version 7.

    I have a requirement where I have to prompt user when he is navigating outside US area. I have the latitude and longitude of US map in JSON response.

    Does anyone has any idea about how to implement this or anybody worked upon similar kind of requirement?

    Any help is highly appreciated.

    Thanks,

    -Manuj

    Tuesday, February 5, 2013 6:26 PM

Answers

  • You will need to store the country boundaries for the US locally and then do an intersection test with the users location. I would recommend using the SQL server spatial tools (doesn't requiring having SQL server installed to use the tools as they are available as a dll. Microsoft.SqlServer.Types.dll). The spatial library can be used directly in .NET code. You can store the country boundaries for the US as Well Known Text and then turn that into a spatial object using the library. Then you can do an intersection test with your data point.

    Here are some useful resources:

    http://blogs.msdn.com/b/davidlean/archive/2008/10/30/sql-2008-spatial-samples-part-n-5-of-n-sql-builder-api.aspx

    http://technet.microsoft.com/en-us/library/bb933899.aspx


    http://rbrundritt.wordpress.com

    Tuesday, February 5, 2013 7:14 PM
  • Ok, in that case you will want to do a point in polygon search. Here is a code sample which I pulled from an old article I wrote (http://msdn.microsoft.com/en-us/library/cc451895.aspx).

    function pointInPolygon(points,lat,lon) 
    {
      var i;
      var j=points.length-1;
      var inPoly=false;
    
      for (i=0; i<points.length; i++) 
      {
        if (points[i].Longitude<lon && points[j].Longitude>=lon 
          || points[j].Longitude<lon && points[i].Longitude>=lon) 
        {
          if (points[i].Latitude+(lon-points[i].Longitude)/ 
            (points[j].Longitude-points[i].Longitude)*(points[j].Latitude 
              -points[i].Latitude)<lat) 
          {
            inPoly=!inPoly; 
          }
        }
        j=i; 
      }
      return inPoly; 
    }


    http://rbrundritt.wordpress.com

    • Proposed as answer by SSR1656 Tuesday, February 19, 2013 8:42 PM
    • Marked as answer by Ricky_Brundritt Wednesday, February 20, 2013 1:02 AM
    Wednesday, February 13, 2013 6:16 PM
  • It looks like your polygon crosses the international dateline. This makes things a lot more complex as the algorithm provided is meant for simple geometry situations. If you need to cross the international dateline then you will need to use a spatially accurate calculation. These are very complex however there are free libraries available to do this. What you would have to do is create a web service to pass the coordinates too and then do the check use a spatial library. SQL server express comes with a spatial library which you can use in .NET and do this type of search.

    Now you could go the spatially accurate route and make things complicated or simply change the number "178.383787" that's in your array of points to -180. At the end of the day this will only represent a difference of 100 or so kilometers due to the latitude value you have paired with this longitude.


    http://rbrundritt.wordpress.com

    Thursday, February 14, 2013 12:59 PM

All replies

  • You will need to store the country boundaries for the US locally and then do an intersection test with the users location. I would recommend using the SQL server spatial tools (doesn't requiring having SQL server installed to use the tools as they are available as a dll. Microsoft.SqlServer.Types.dll). The spatial library can be used directly in .NET code. You can store the country boundaries for the US as Well Known Text and then turn that into a spatial object using the library. Then you can do an intersection test with your data point.

    Here are some useful resources:

    http://blogs.msdn.com/b/davidlean/archive/2008/10/30/sql-2008-spatial-samples-part-n-5-of-n-sql-builder-api.aspx

    http://technet.microsoft.com/en-us/library/bb933899.aspx


    http://rbrundritt.wordpress.com

    Tuesday, February 5, 2013 7:14 PM
  • I think the question was little misunderstood or may be it was not articulated properly. Our requirement is to check if user pans outside of a certain area. The said area is already defined through an Array of lat/long values. We are currently using Microsoft.Maps.LocationRect.fromLocations(list of locations/array) to define the coverage area and then using CoverageArea.contains() to check if the specific point is within coverage area.

    But the problem here is, the coverage area is defined as a Rectangle and not as Polygon, we looked but could not find any API function to define the area as a polygon. Pasting code of a simple example, it alerts user if center point of the map is not within the coverage area (USA), but the problem arises when user pans to somewhere in Canada

    Would Appreciate any help

    <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">
    	function GetMap()
    	{
    		// Initialize the map
    		var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
    		{credentials:"Bing Map Key"});
    
    		var bBox_US = [-117.456057, 30.583359, -169.435837, 67.826458, -159.638066, 72.134632, -140.741582, 71.123832, -140.609746, 60.619250, -139.071660, 60.532894, -137.357793, 59.187108, -135.468144, 59.855775, -131.644902, 56.908920, -129.843144, 56.010582, -130.150762, 54.787930, -135.652832, 54.253929, -127.339148, 47.952616, -124.780673, 48.481416, -123.187656, 48.284409, -123.121738, 48.459564, -123.242587, 48.677660, -123.022861, 48.800831, -123.330478, 49.010249, -95.181742, 49.037365, -95.181742, 49.439059, -94.764261, 49.353256, -94.522562, 48.777408, -93.511820, 48.617878, -92.566996, 48.574283, -91.490335, 48.121589, -90.853128, 48.297303, -89.358988, 47.974701, -88.348246, 48.326530, -84.722757, 46.964736, -83.536234, 46.179300, -82.151956, 43.563916, -82.585916, 42.540375, -83.124247, 42.248284, -83.113260, 41.852626, -82.541971, 41.655925, -78.932962, 42.847217, -79.207621, 43.452362, -77.010355, 43.785477, -74.966898, 45.014760, -71.484232, 45.022526, -70.396585, 45.847400, -70.077982, 46.679069, -69.210062, 47.494419, -68.962870, 47.297339, -68.248758, 47.386674, -67.737894, 47.084563, -67.655497, 45.787871, -66.891947, 44.812475, -69.164403, 37.240583, -78.116547, 30.227410, -79.606115, 25.271078, -81.871454, 24.027510, -85.837518, 28.140891, -96.659051, 25.889975, -99.010126, 26.363434, -101.361200, 29.774972, -102.679559, 29.774972, -103.097040, 28.855364, -104.657098, 29.774972, -104.942743, 30.686212, -106.458856, 31.775914, -108.172723, 31.775914, -108.194696, 31.345295, -110.941278, 31.288981, -114.830438, 32.482991, -116.983758, 32.501524, -117.456057, 30.583359, ];
    
    		var vertices_US = new Array();
    		for(var i = 1; i < (bBox_US.length); i+=2){
    			vertices_US.push(new Microsoft.Maps.Location(bBox_US[i],bBox_US[i-1]));
    		}
    
    		var polygon_US = new Microsoft.Maps.Polygon(vertices_US,{fillColor: new Microsoft.Maps.Color(100,100,0,100), strokeColor: new Microsoft.Maps.Color(200,0,100,100), strokeThickness: 2});
    		// Add the shape to the map
    		map.entities.push(polygon_US);
    		// Set the view
    		map.setView({bounds: Microsoft.Maps.LocationRect.fromLocations(vertices_US)});
    		coverageArea_US = Microsoft.Maps.LocationRect.fromLocations(vertices_US);
    		Microsoft.Maps.Events.addHandler(map, 'viewchangeend', notifyUser);
    
    		function notifyUser(e){
    			if(!coverageArea_US.contains(map.getCenter())){
    				alert("OUT");
    			}
    		}
    	}
    </script>
    </head>
    <body onload="GetMap();">
    <div id='mapDiv' style="; width:600px; height:600px;"></div>
    </body>
    </html>

    Wednesday, February 13, 2013 3:20 AM
  • Since you are using bounding boxes using the LocationRect class with the contains method is to correct method to use. Not sure what the issue with panning to Canada? Do you want to notify the user if any part of the map is outside of the bounding box?


    http://rbrundritt.wordpress.com

    Wednesday, February 13, 2013 10:12 AM
  • Please refer to the attached image. Our Coverage area covers Continental United States & Alaska, we want the user to know if they are panning out of this coverage area. But the problem is that we define coverage area through LocationRect. Now this creates a Rectangle rather than a Polygon and also covers Canada. We don't want Canada to be in Coverage area.

    Please run the example, would give you a better understanding.


    • Edited by SSR1656 Wednesday, February 13, 2013 5:41 PM
    Wednesday, February 13, 2013 5:40 PM
  • Ok, in that case you will want to do a point in polygon search. Here is a code sample which I pulled from an old article I wrote (http://msdn.microsoft.com/en-us/library/cc451895.aspx).

    function pointInPolygon(points,lat,lon) 
    {
      var i;
      var j=points.length-1;
      var inPoly=false;
    
      for (i=0; i<points.length; i++) 
      {
        if (points[i].Longitude<lon && points[j].Longitude>=lon 
          || points[j].Longitude<lon && points[i].Longitude>=lon) 
        {
          if (points[i].Latitude+(lon-points[i].Longitude)/ 
            (points[j].Longitude-points[i].Longitude)*(points[j].Latitude 
              -points[i].Latitude)<lat) 
          {
            inPoly=!inPoly; 
          }
        }
        j=i; 
      }
      return inPoly; 
    }


    http://rbrundritt.wordpress.com

    • Proposed as answer by SSR1656 Tuesday, February 19, 2013 8:42 PM
    • Marked as answer by Ricky_Brundritt Wednesday, February 20, 2013 1:02 AM
    Wednesday, February 13, 2013 6:16 PM
  • Great! That's what we were looking for. Thanks a lot.

    But somehow this is not working on all defined coverage areas.

    The logic works for these values

    var bBox_US = [-117.456057, 30.583359, -169.435837, 67.826458, -159.638066, 72.134632, -140.741582, 71.123832, -140.609746, 60.619250, -139.071660, 60.532894, -137.357793, 59.187108, -135.468144, 59.855775, -131.644902, 56.908920, -129.843144, 56.010582, -130.150762, 54.787930, -135.652832, 54.253929, -127.339148, 47.952616, -124.780673, 48.481416, -123.187656, 48.284409, -123.121738, 48.459564, -123.242587, 48.677660, -123.022861, 48.800831, -123.330478, 49.010249, -95.181742, 49.037365, -95.181742, 49.439059, -94.764261, 49.353256, -94.522562, 48.777408, -93.511820, 48.617878, -92.566996, 48.574283, -91.490335, 48.121589, -90.853128, 48.297303, -89.358988, 47.974701, -88.348246, 48.326530, -84.722757, 46.964736, -83.536234, 46.179300, -82.151956, 43.563916, -82.585916, 42.540375, -83.124247, 42.248284, -83.113260, 41.852626, -82.541971, 41.655925, -78.932962, 42.847217, -79.207621, 43.452362, -77.010355, 43.785477, -74.966898, 45.014760, -71.484232, 45.022526, -70.396585, 45.847400, -70.077982, 46.679069, -69.210062, 47.494419, -68.962870, 47.297339, -68.248758, 47.386674, -67.737894, 47.084563, -67.655497, 45.787871, -66.891947, 44.812475, -69.164403, 37.240583, -78.116547, 30.227410, -79.606115, 25.271078, -81.871454, 24.027510, -85.837518, 28.140891, -96.659051, 25.889975, -99.010126, 26.363434, -101.361200, 29.774972, -102.679559, 29.774972, -103.097040, 28.855364, -104.657098, 29.774972, -104.942743, 30.686212, -106.458856, 31.775914, -108.172723, 31.775914, -108.194696, 31.345295, -110.941278, 31.288981, -114.830438, 32.482991, -116.983758, 32.501524, -117.456057, 30.583359];

    but not for these..

    var bBox_US = [-117.456057, 30.583359, -154.018557, 11.504038, -169.838870, 20.779027, 178.383787, 57.599692, -167.334353, 63.170673, -169.435837, 67.826458, -159.638066, 72.134632, -140.741582, 71.123832, -140.609746, 60.619250, -139.071660, 60.532894, -137.357793, 59.187108, -135.468144, 59.855775, -131.644902, 56.908920, -129.843144, 56.010582, -130.150762, 54.787930, -135.652832, 54.253929, -127.339148, 47.952616, -124.780673, 48.481416, -123.187656, 48.284409, -123.121738, 48.459564, -123.242587, 48.677660, -123.022861, 48.800831, -123.330478, 49.010249, -95.181742, 49.037365, -95.181742, 49.439059, -94.764261, 49.353256, -94.522562, 48.777408, -93.511820, 48.617878, -92.566996, 48.574283, -91.490335, 48.121589, -90.853128, 48.297303, -89.358988, 47.974701, -88.348246, 48.326530, -84.722757, 46.964736, -83.536234, 46.179300, -82.151956, 43.563916, -82.585916, 42.540375, -83.124247, 42.248284, -83.113260, 41.852626, -82.541971, 41.655925, -78.932962, 42.847217, -79.207621, 43.452362, -77.010355, 43.785477, -74.966898, 45.014760, -71.484232, 45.022526, -70.396585, 45.847400, -70.077982, 46.679069, -69.210062, 47.494419, -68.962870, 47.297339, -68.248758, 47.386674, -67.737894, 47.084563, -67.655497, 45.787871, -66.891947, 44.812475, -69.164403, 37.240583, -78.116547, 30.227410, -79.606115, 25.271078, -81.871454, 24.027510, -85.837518, 28.140891, -96.659051, 25.889975, -99.010126, 26.363434, -101.361200, 29.774972, -102.679559, 29.774972, -103.097040, 28.855364, -104.657098, 29.774972, -104.942743, 30.686212, -106.458856, 31.775914, -108.172723, 31.775914, -108.194696, 31.345295, -110.941278, 31.288981, -114.830438, 32.482991, -116.983758, 32.501524, -117.456057, 30.583359];

    The second one has few extra values for Hawaii..

    <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 vertices_US = new Array();
    	function GetMap()
    	{
    		// Initialize the map
    		var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
    		{credentials:"BING_MAPS_KEY"});
    
    		
    		var bBox_US = [-117.456057, 30.583359, -154.018557, 11.504038, -169.838870, 20.779027, 178.383787, 57.599692, -167.334353, 63.170673, -169.435837, 67.826458, -159.638066, 72.134632, -140.741582, 71.123832, -140.609746, 60.619250, -139.071660, 60.532894, -137.357793, 59.187108, -135.468144, 59.855775, -131.644902, 56.908920, -129.843144, 56.010582, -130.150762, 54.787930, -135.652832, 54.253929, -127.339148, 47.952616, -124.780673, 48.481416, -123.187656, 48.284409, -123.121738, 48.459564, -123.242587, 48.677660, -123.022861, 48.800831, -123.330478, 49.010249, -95.181742, 49.037365, -95.181742, 49.439059, -94.764261, 49.353256, -94.522562, 48.777408, -93.511820, 48.617878, -92.566996, 48.574283, -91.490335, 48.121589, -90.853128, 48.297303, -89.358988, 47.974701, -88.348246, 48.326530, -84.722757, 46.964736, -83.536234, 46.179300, -82.151956, 43.563916, -82.585916, 42.540375, -83.124247, 42.248284, -83.113260, 41.852626, -82.541971, 41.655925, -78.932962, 42.847217, -79.207621, 43.452362, -77.010355, 43.785477, -74.966898, 45.014760, -71.484232, 45.022526, -70.396585, 45.847400, -70.077982, 46.679069, -69.210062, 47.494419, -68.962870, 47.297339, -68.248758, 47.386674, -67.737894, 47.084563, -67.655497, 45.787871, -66.891947, 44.812475, -69.164403, 37.240583, -78.116547, 30.227410, -79.606115, 25.271078, -81.871454, 24.027510, -85.837518, 28.140891, -96.659051, 25.889975, -99.010126, 26.363434, -101.361200, 29.774972, -102.679559, 29.774972, -103.097040, 28.855364, -104.657098, 29.774972, -104.942743, 30.686212, -106.458856, 31.775914, -108.172723, 31.775914, -108.194696, 31.345295, -110.941278, 31.288981, -114.830438, 32.482991, -116.983758, 32.501524, -117.456057, 30.583359];
    
    		vertices_US = new Array();
    		for(var i = 1; i < (bBox_US.length); i+=2){
    			vertices_US.push(new Microsoft.Maps.Location(bBox_US[i],bBox_US[i-1]));
    		}
    		
    		var polygon_US = new Microsoft.Maps.Polygon(vertices_US,{fillColor: new Microsoft.Maps.Color(100,100,0,100), strokeColor: new Microsoft.Maps.Color(200,0,100,100), strokeThickness: 2});
    		// Add the shape to the map
    		map.entities.push(polygon_US);
    		// Set the view
    		map.setView({bounds: Microsoft.Maps.LocationRect.fromLocations(vertices_US)});
    		Microsoft.Maps.Events.addHandler(map, 'viewchangeend', notifyUser);
    
    		function notifyUser(e){
    			map.entities.removeAt(1);
    			var center = map.getCenter();
    			var pin = new Microsoft.Maps.Pushpin(center, {text: '1'});
    			map.entities.push(pin);
    			
    			var output = document.getElementById("output");
    			output.innerHTML = pointInPolygon(vertices_US,center.latitude, center.longitude);
    		}
    		
    		function pointInPolygon(points,lat,lon) 
    		{
    		  var i;
    		  var j=points.length-1;
    		  var inPoly=false;
    
    		  for (i=0; i<points.length; i++) 
    		  {
    			if (points[i].longitude<lon && points[j].longitude>=lon 
    			  || points[j].longitude<lon && points[i].longitude>=lon) 
    			{
    			  if (points[i].latitude+(lon-points[i].longitude)/ 
    				(points[j].longitude-points[i].longitude)*(points[j].latitude 
    				  -points[i].latitude)<lat) 
    			  {
    				inPoly=!inPoly; 
    			  }
    			}
    			j=i; 
    		  }
    		  return inPoly; 
    		}
    	}
    </script>
    </head>
    <body onload="GetMap();">
    <div id='mapDiv' style="; width:600px; height:600px;"></div>
    <div id='output'> </div> 
    </body>
    </html>

    Is there anything we are doing wrong?



    • Edited by Ricky_Brundritt Thursday, February 14, 2013 12:53 PM removing bing maps key
    Wednesday, February 13, 2013 9:42 PM
  • It looks like your polygon crosses the international dateline. This makes things a lot more complex as the algorithm provided is meant for simple geometry situations. If you need to cross the international dateline then you will need to use a spatially accurate calculation. These are very complex however there are free libraries available to do this. What you would have to do is create a web service to pass the coordinates too and then do the check use a spatial library. SQL server express comes with a spatial library which you can use in .NET and do this type of search.

    Now you could go the spatially accurate route and make things complicated or simply change the number "178.383787" that's in your array of points to -180. At the end of the day this will only represent a difference of 100 or so kilometers due to the latitude value you have paired with this longitude.


    http://rbrundritt.wordpress.com

    Thursday, February 14, 2013 12:59 PM
  • Thanks a lot Richard. Now we know exactly where the problem is. 

    -Cheers

    Tuesday, February 19, 2013 8:41 PM