ThinkGeo.com    |     Documentation    |     Premium Support

Converting Bing coordinates to srid 4326?

 Hello,



I'm replacing a Bing map control in an existing application with a ThinkGeo one. This is my first ever project that has to do with anything Geo related. I'm trying to keep all the existing plumbing in place and only alter the few things that are Bing/THinkGeo specific.



Currently the application uses "Bing" coordinates:


private double _minLat = 90.0d;
private double _minLong = 180.0d;
private double _maxLat = -90.0d;
private double _maxLong = -180.0d;



PointShape topLeft = new PointShape(_minLat - 0.05, _minLong - 0.05);
PointShape bottomRight = new PointShape(_maxLat + 0.05, _maxLong + 0.05);
BoundingRectangle = new RectangleShape(topLeft, bottomRight);



On the last line I get an out of bounds exception, Maxx etc.. From what I understand, I need to convert the initial coordinates (and then the database ones too) to srid 4326, but how exactly do I do this?



One of the samples has this:



ManagedProj4Projection proj4Projection = new ManagedProj4Projection(); 

proj4Projection.InternalProjectionParametersString = ManagedProj4Projection.GetEpsgParametersString(4326); 

proj4Projection.ExternalProjectionParametersString = ManagedProj4Projection.GetEpsgParametersString(2163); 

ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(@"..\..\SampleData\Data\Countries02.shp");  worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1; 

worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;    worldLayer.FeatureSource.Projection = proj4Projection;    



But I am using Bing Layer for maps:

 



        
  • var bingMapsOverlay = new BingMapsOverlay();

  •     
  • bingMapsOverlay.ApplicationId = <>;

  •     
  • bingMapsOverlay.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.AerialWithLabels;

  •     
  • bingMapsOverlay.Name = "BingMapOverlay";

  •     
  • bingMapsOverlay.TimeoutInSeconds = 60;

  •     
  •  wpfMap1.MapUnit = GeographyUnit.Meter;

        

        And I can't do  

        

         

  •     
  • bingMapsOverlay.FeatureSource.Projection = proj4Projection;

        

        So, how exactly do I set my bingMapsOverlay to srid 4326 coordinate system?

        

        Thanks


 




 



Hi Certus,


Thanks for your questions!


You have the right idea about needing to reproject some part of your information so that 'it all lines up' when displayed on the map. Although it might be possible to use some of our Beta RasterReprojection logic to reproject the BingMaps data I would not recommend this due to the complexity and also the potential performance issues of reprojecting thousands of BingMaps Tiles!


Perhaps a better solution would be to reproject all of your other data to the BingMaps projection?


This can be conducted in two ways. You could reproject all of your data all at once and resubmit to your database so that it is stored in the correct projection, or you could conduct all the reprojection on-the-fly thus keeping the data in the database in the original form.


To start you might just want to create a Proj4Projection object and setup your Internal and ExternalProjectionParameterStrings. Bing and Google use exactly the same projection parameters so in the code below you will see we are using GetGoogleMapParametersString to get the BingMaps projection information. Then you can setup a loop to simply pass each of your Features into. Proj4Projection proj4;
proj4.InternalProjectionParametersString = Proj4Projection.GetDecimalDegreesParametersString();
proj4.ExternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString();
//Loop through all your features and convert them to the BingMapsProjection (same as GoogleMaps Projection)
Feature newFeature = proj4.ConvertToExternalProjection(myFeature);
InMemoryFeatureLayer mapShapeLayer = new InMemoryFeatureLayer();
mapShapeLayer.InternalFeatures.Add(newFeature);

You could then take your reprojected feature and add it to an InMemoryFeatureLayer which can be added over the top of the BingMapsOverlay. In this way all your features should line up properly over the BingMaps data.



 Ryan,




Thanks for the reply. But before I even get to adding features (that means Markers or in Bingspeak Pushpins, correct?) to the Overlay, how do I set the map itself to the correct coordinate system at the very begining?



The initialization is like this:



var bingMapsOverlay = new BingMapsOverlay();


bingMapsOverlay.ApplicationId = <>;


bingMapsOverlay.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.AerialWithLabels;


bingMapsOverlay.Name = "BingMapOverlay";


bingMapsOverlay.TimeoutInSeconds = 60;


 


 


var bingMapsOverlayRoads = new BingMapsOverlay();


bingMapsOverlayRoads.ApplicationId = <>;


bingMapsOverlayRoads.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.Road;


bingMapsOverlayRoads.Name = "BingMapOverlay";


bingMapsOverlayRoads.TimeoutInSeconds = 60;


 


wpfMap1.Overlays.Add("BingMapOverlay", bingMapsOverlay);


wpfMap1.Overlays.Add("BingMapsOverlayRoads", bingMapsOverlayRoads);


 


wpfMap1.MapUnit = GeographyUnit.Meter;


 


this.wpfMap1.CurrentExtent = (_viewModel.BoundingRectangle);


 


and at this point it would get an exception going into setting BoundingRectangle method:



private double _minLat = 89.0d;


private double _minLong = 179.0d;


private double _maxLat = -89.0d;


private double _maxLong = -179.0d;


<...>


PointShape topLeft = new PointShape(_minLat - 0.05, _minLong - 0.05);


PointShape bottomRight = new PointShape(_maxLat + 0.05, _maxLong + 0.05);


BoundingRectangle = new RectangleShape(topLeft, bottomRight);




So, how do I apply projection to the map itself? And layers and overlays that are not containing features?



Thanks

 


                    


    




Certus,


First I would not recommend adding two BingOverlays to the Map, rather you should be able to simply change the MapType depending on what your users choose.


Second, since BingMaps uses Meters for its coordinate system the values that you are passing to your CurrentExtent cannot be DecimalDegree values, so you will need to convert those from DecimalDegrees to Meters.


You can do this using something like the following:

RectangleShape test = new RectangleShape(-133.2515625, 89.2484375, 126.9046875, -88.290625);
Proj4Projection proj = new Proj4Projection();            proj.InternalProjectionParametersString = Proj4Projection.GetLatLongParametersString();
proj.ExternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString();
proj.Open();
RectangleShape test2 = proj.ConvertToExternalProjection(test);
wpfMap1.CurrentExtent = test2;



The BingMapsOverlay is already in the correct projection so no changes need/can be made to it.

 


Other Layers should have a Layer.FeatureSource.Projection value that can be set like the following:
RectangleShape test = new RectangleShape(-133.2515625, 89.2484375, 126.9046875, -88.290625);
Proj4Projection proj = new Proj4Projection();
//Be Sure to verify the current projection of your shapfile and set the InternalProjectionParameterString to match.
//The Countries02 shapefile we provide in our sample applications is in Geodetic/WGS84.
proj.InternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString();
proj.ExternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString();
proj.Open();
ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(@"..\..\SampleData\Data\Countries02.shp");
worldLayer.FeatureSource.Projection = proj;



 Thanks for the reply, Ryan.


 


I've tried to follow your suggestion: "First I would not recommend adding two BingOverlays to the Map, rather you should be able to simply change the MapType depending on what your users choose.", but it's not working for me.



I'm doing this in wpfMap1_Loaded:



var bingMapsOverlay = new BingMapsOverlay();


 bingMapsOverlay.ApplicationId = <>;


 bingMapsOverlay.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.AerialWithLabels;


bingMapsOverlay.Name = "BingMapOverlay";


bingMapsOverlay.TimeoutInSeconds = 60;


wpfMap1.MapUnit = GeographyUnit.DecimalDegree;


wpfMap1.Overlays.Add("BingMapOverlay", bingMapsOverlay);


SimpleMarkerOverlay markerOverlay = new SimpleMarkerOverlay();


 wpfMap1.Overlays.Add("MarkerOverlay", markerOverlay);


foreach (Marker pin in _viewModel.Pushpins)


                    {


                        markerOverlay.Markers.Add(pin);   


 


                    }


this.wpfMap1.CurrentExtent = (_viewModel.BoundingRectangle);


wpfMap1.Refresh(wpfMap1.Overlays["BingMapOverlay"]);


 wpfMap1.Refresh();





And then in handlers:



private void Road_Click(object sender, System.Windows.RoutedEventArgs e)


        {


            BingMapsOverlay overlay2 = (BingMapsOverlay)wpfMap1.Overlays["BingMapOverlay"];


                overlay2.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.Road;


 


                wpfMap1.Refresh(wpfMap1.Overlays["BingMapOverlay"]);


            


        }



 private void Aerial_Click(object sender, System.Windows.RoutedEventArgs e)


        {


            BingMapsOverlay overlay2 = (BingMapsOverlay)wpfMap1.Overlays["BingMapOverlay"];


            overlay2.MapType = ThinkGeo.MapSuite.Core.BingMapsMapType.Aerial;


            wpfMap1.Refresh(wpfMap1.Overlays["BingMapOverlay"]);


            


        }



I get an exception:  The process cannot access file BIngMapsMetadata.xml because it is being used by another process.



Please, advise






Hi Certus,


Here is my code without the markers, and it works properly, notice I'm using the Meter unit,



        private void WpfMap_Loaded(object sender, RoutedEventArgs e)
        {
            Map1.MapUnit = GeographyUnit.Meter;
            Map1.CurrentExtent = new RectangleShape(-5000000, 5000000, 5000000, -5000000);
            BingMapsOverlay bing = new BingMapsOverlay("id");
            bing.MapType = BingMapsMapType.AerialWithLabels;
            Map1.Overlays.Add("bing", bing);
            Map1.Refresh();
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            BingMapsOverlay bing = Map1.Overlays["bing"] as BingMapsOverlay;
            bing.MapType = BingMapsMapType.Road;
            Map1.Refresh(Map1.Overlays["bing"]);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            BingMapsOverlay bing = Map1.Overlays["bing"] as BingMapsOverlay;
            bing.MapType = BingMapsMapType.Aerial;
            Map1.Refresh(Map1.Overlays["bing"]);
        }

Could you please describe tell us that when and how did you get the exception?


Thanks,


Edgar



 Edgar, the exception is thrown is I click on either of the buttons (Road or Aerial) more than once, does not have to be in a row (clicking the same button more than once at a time).



Hi Certus,


I was unable to create a situation where I receieved the same exception. Please add the MapSuiteCore.dll and WpfDesktopEdition.dll to the attached sample to check out how the switching of the map types takes place.



BingMapsTest.7z (48.8 KB)

 

Ryan, when I run the project and click on a button, I get the same exception:



The process cannot access the file 'c:\temp\BingMapsMetadata.xml' because it is being used by another process. It happens immediately after I successfully step through the lines in the _Click handler.



Please, advise.

 



 To clarify: the exception happens on the fourth click: first I successfully click on Roads, Aerial, AerialWithLabels, - once on each, then, on the fourth click on Roads the exception occurs.

 



Hi Certus, 



You are correct! This only occurs when the cacheDirectory property is utilized so this is a bug and will be submitted as an internal ticket. My apologies as I did not make it clear in my sample application that the cacheDirectory was not used.


You can also workaround this issue by setting the bingMapsOverlay.TileType = TileType.SingleTile. This will cause the map to get all the Bing tile data before it renders a single tile, rather than the tile-by-tile loading that is provide by the TileType.MultipleTile.


 



 Ryan, the workaround works for me, thanks.



However, there's a new scenario where an exception is thrown:



If I navigate away from the map page and then come back, wpfMap1_Loaded is executed again, but this time on the very last line, wpfMap1.Refresh(); it throws an InvalidOperationException. "specified element is already the logical child of another element. Disconnect it first."



Please, advise.



The code:


private void wpfMap1_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
 
            try
            {
                if (_viewModel != null)
                {
 
                    string applicationID = "<...>";
                    string cacheDirectory = @"c:\temp\";
                    BingMapsOverlay bingMapsOverlay = new BingMapsOverlay(applicationID, BingMapsMapType.AerialWithLabels, cacheDirectory);
                    bingMapsOverlay.TileType = TileType.SingleTile;
                    bingMapsOverlay.Name = "BingMapOverlay";
                    wpfMap1.MapUnit = GeographyUnit.Meter;
                    wpfMap1.CurrentExtent = DefaultRoamingExtent;
                    wpfMap1.Overlays.Add("BingMapOverlay", bingMapsOverlay);
                    wpfMap1.Overlays.Add("MarkerOverlay", markerOverlay); 
                    foreach (Marker pin in _viewModel.Pushpins)
                   {
                        pin.MouseDoubleClick += new System.Windows.Input.MouseButtonEventHandler(pin_MouseDoubleClick);
                        pin.Visibility = System.Windows.Visibility.Visible;
                        markerOverlay.Markers.Add(pin);
                    }
                     try{
                            wpfMap1.Refresh();
                         }
                    catch (InvalidOperationException excp)
                    {
                        // Ignore.
                        //System.Windows.MessageBox.Show(ex.ToString());
                    }
 
                }
 
            }
            catch (Exception ex)
            {
                // Ignore.
                //System.Windows.MessageBox.Show(ex.ToString());
            }
        }

Hi Certus,


Thanks for your reply but a new thread should really be created for this question as is it is unrelated to the Bing Map's issues in the current thread. To test this type of issue it would be very helpful to have a working Visual Studio project that can recreate the issue.


I do have an update on the BingMaps issue. The 6.0.210.0+ Development Build or the 6.0.0.211+ Production Build should resolve the "BingMapsMetadata.xml' because it is being used by another process.' issue. You can download these later builds from the Customer Portal at helpdesk.thinkgeo.com.