Shp File Overlay using non static Google or Bing Map?

Topics: Data Access, General Topics, SharpMap Project, SharpMap v2.0, Web Controls, WinForms Controls
May 12, 2011 at 3:46 PM

I don't suppose there is any way to load the shp file as an overlay to Google or Bing Maps that are "non-static" is there?

I currently have the overlay being created, but it is fetching all the tiles from Google or Bing, creating a static image as a layer, and then adding the shp file overlay as a layer on top of this.  There is no pan option and if you zoom in or out it takes what seems like an eternity to load. 

Is there any way to accomplish this?  Like say adding the layer to a web browser component that has the live maps running off of that?  Or will I need to convert to KML in order to do this and if so is there kml conversion functionality built in to SharpMap?

Thanks in advance.

Developer
May 15, 2011 at 8:34 PM

If you want to work within a web browser, you can use OpenLayers. Its JS with out of the box support for Google maps, Bing Maps and OpenstreetMap and you can overlay WMS, WFS, GML files, KML files and a lot of other kinds of layers. It supports panning zooming etc.
You can make your data available via a WMS server, which SharpMap can do for you, or you can convert your shapefile to a GML or KML file and load it from a regular webserver into OpenLayers.

The advantage of WMS would be that you can have almost unlimited features to be rendered in OpenLayers, since the rendering takes place at your server and you can use spatial indexes and things like that.
The advantage of GML is that you can put the data into the Google projection (EPSG:900913) when you generate the file, but the downside is that the styling of the map has to be done in OpenLayers, which is sometimes difficult. You are also limited in the amount of features you want to display due to file size and because Internet Explorer 8 and older don't support Canvas or SVG and therefore can only render <100 features with proper speed. This is the same for KML by the way.
KML has the advantage of the styling being within the file, but all the data is in latlon, so it has to be reprojected to web mercator, which slows rendering a bit down.

Hope this helps you, since I don't know exactly what you want to do.

May 16, 2011 at 1:35 PM
Edited May 16, 2011 at 2:22 PM

WMS would be the route I would want to take, but this is where I am stuck at.  How would you go about setting up the WMS using SharpMap and OpenLayers?  Is there an example of this anywhere?

Developer
May 16, 2011 at 7:54 PM
Edited May 16, 2011 at 7:54 PM

The Demowebsite part of the source code will get you started on the server part. Have a look at wms.ashx and the maphelper.cs in the App code to see how things are done there.

For the OpenLayers part you can take a look at this code below. This JS script assumes you have a DIV with id "mapDIV" and a given height and width to render to.

As you can see, I do some transformations from latlon to webmercator (which is not necessary) and I use EPSG:900913. You must give your layers in de sharpMap the same SRID number. If you don't see an image, try to get the url of it and load it separately, because if something's wrong, you will get a error message.
The website of openlayers does contain a lot of information on all these objects and methods, so please have a look there as well.

Hope this example will get you started :)

var map = new OpenLayers.Map("mapDIV", {
                maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
                numZoomLevels: 18,
                maxResolution: 156543.0339,
                units: 'm',
                projection: "EPSG:900913",
                displayProjection: new OpenLayers.Projection("EPSG:4326")
            })
            var layer = new OpenLayers.Layer.OSM("Simple OSM Map");
            map.addLayer(layer);
            map.setCenter(
                new OpenLayers.LonLat(5.908813, 52.891009).transform(
                    new OpenLayers.Projection("EPSG:4326"),
                    map.getProjectionObject()
                ), 12
            );
            var layer0 = new OpenLayers.Layer.WMS(
					"LocalhostSharpMap2",
					"GetMap.ashx?",
					{ layers: 'Radarpixels', version: '1.3.0', CRS: "EPSG:900913", transparent: true, format: 'image/gif' }
				);
            map.addLayers([layer0]);

            map.addControl(new OpenLayers.Control.LayerSwitcher());
            map.addControl(new OpenLayers.Control.MousePosition());
            var proj = new OpenLayers.Projection("EPSG:4326");
            var bounds = new OpenLayers.Bounds(3.87, 50.79, 6.781, 52.168)
            bounds.transform(proj, map.getProjectionObject());

May 17, 2011 at 8:43 PM
Edited May 17, 2011 at 9:29 PM

I am getting conceptually confused with how this all is put together, which is making this pretty difficult for me to grasp. 

Let’s say I have my C# application. I want to drag a web browser control on the form which I want to have an Open Layers map with and a .shp file layer that is being served through SharpMap via a WMS server. 

I am assuming the code you posted below would be used in the actual html of the web page? If I use the wms.ashx example included in the Demowebsite how do I call the ProcessRequest for this to generate the layer and everything? Where do I come up with the HttpContext that is being sent in the ProcessRequest call? Finally how do I send the layer to the OpenLayer? 

I am guessing that the ProcessRequest fires off a “local host” copy of the WMS and that is how you are accessing it through the LocalhostSharpMap2 call you made in the new OpenLayer.WMS, but how does it know what to identify the as LocalhostSharpMap2? 

I’m a bit lost here. 

Thanks.

May 17, 2011 at 9:34 PM

Okay, I've been fumbling around with this and I think I am getting a bit closer.

Looking at the code from the example I have now hacked up parts of the example into my own code as is so as to try and grasp how this functions.  I created my own InitializeMap function and simply call it as follows:

Map myMap = InitializeMap();

My InitializeMap function looks like:

            HttpContext context = HttpContext.Current;
            //Get the path of this page
            string url = (context.Request.Url.Query.Length > 0
                              ? context.Request.Url.AbsoluteUri.Replace(context.Request.Url.Query, "")
                              : context.Request.Url.AbsoluteUri);
            Capabilities.WmsServiceDescription description =
                new Capabilities.WmsServiceDescription("Acme Corp. Map Server", url);

            // The following service descriptions below are not strictly required by the WMS specification.

            // Narrative description and keywords providing additional information 
            description.Abstract =
                "Map Server maintained by Acme Corporation. Contact: webmaster@wmt.acme.com. High-quality maps showing roadrunner nests and possible ambush locations.";
            description.Keywords = new string[3];
            description.Keywords[0] = "bird";
            description.Keywords[1] = "roadrunner";
            description.Keywords[2] = "ambush";

            //Contact information 
            description.ContactInformation.PersonPrimary.Person = "John Doe";
            description.ContactInformation.PersonPrimary.Organisation = "Acme Inc";
            description.ContactInformation.Address.AddressType = "postal";
            description.ContactInformation.Address.Country = "Neverland";
            description.ContactInformation.VoiceTelephone = "1-800-WE DO MAPS";
            //Impose WMS constraints
            description.MaxWidth = 1000; //Set image request size width
            description.MaxHeight = 500; //Set image request size height


            //Call method that sets up the map
            //We just add a dummy-size, since the wms requests will set the image-size
            Map myMap = new Map(new Size(1,1));

            //Parse the request and create a response
            WmsServer.ParseQueryString(myMap, description);

            #region Shp File Layer
            #region Retrieve Shp File from SQL Server
            string connStr = "Server=192.168.0.115;Database=GIS;User ID=EMCollector;Password=9o0(O)";

            SqlConnection sqlConn = new SqlConnection();
            sqlConn.ConnectionString = connStr;

            SqlCommand sqlComm = new SqlCommand();
            sqlComm.Connection = sqlConn;
            sqlComm.CommandText = "SELECT projection FROM cen_lines_projection";

            sqlConn.Open();

            SqlDataReader dr = sqlComm.ExecuteReader();

            string wkt = "";
            dr.Read();
            if (dr.HasRows)
            {
                wkt = dr.GetValue(0).ToString();
            }

            SharpMap.Data.Providers.SqlServer2008 sql = new SharpMap.Data.Providers.SqlServer2008(connStr, "cen_lines", "WKB_Geometry", "oid");

            sql.Open();
            #endregion
            #region Create Projections
            var ctf = new CoordinateTransformationFactory();
            var shpProj = new CoordinateSystemFactory().CreateFromWkt(wkt);
            var epsg3785 = new CoordinateSystemFactory().CreateFromWkt(
                "PROJCS[\"Popular Visualisation CRS / Mercator\", " +
                "GEOGCS[\"Popular Visualisation CRS\", " +
                "DATUM[\"Popular Visualisation Datum\", " +
                "SPHEROID[\"Popular Visualisation Sphere\", 6378137, 0, AUTHORITY[\"EPSG\",\"7059\"]], " +
                "TOWGS84[0, 0, 0, 0, 0, 0, 0], " +
                "AUTHORITY[\"EPSG\",\"6055\"]], " +
                "PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\", \"8901\"]], " +
                "UNIT[\"degree\", 0.0174532925199433, AUTHORITY[\"EPSG\", \"9102\"]], " +
                "AXIS[\"E\", EAST], AXIS[\"N\", NORTH], " +
                "AUTHORITY[\"EPSG\",\"4055\"]], " +
                "PROJECTION[\"Mercator\"], " +
                "PARAMETER[\"False_Easting\", 0], " +
                "PARAMETER[\"False_Northing\", 0], " +
                "PARAMETER[\"Central_Meridian\", 0], " +
                "PARAMETER[\"Latitude_of_origin\", 0], " +
                "UNIT[\"metre\", 1, AUTHORITY[\"EPSG\", \"9001\"]], " +
                "AXIS[\"East\", EAST], AXIS[\"North\", NORTH], " +
                "AUTHORITY[\"EPSG\",\"3785\"]]");
            #endregion
            #region Load Shape File and Change Projection
            VectorLayer shp = new VectorLayer("Shape File");
            shp.DataSource = sql;
            shp.CoordinateTransformation = ctf.CreateFromCoordinateSystems(shpProj, epsg3785);
            #endregion
            #region Add Shape File Layer to Map
            this.mapBox1.Map.Layers.Add(shp);
            #endregion
            #endregion

            return myMap;
Now the question is what do I do from this point?

Developer
May 19, 2011 at 6:38 AM

You're still missing the .ashx handler. (add it to a web project via generic handlers). Have a look at wms.ashx in the demo code. And you need a html page with the Div for the map and the javascript I posted.

My HTML code with the javascript is located at the same location as this handler, but if this isn't the case, you can replace the GetMap.ashx? with a full URL pointing to the location where you've got your website including the handler published.

For more examples on how to use OpenLayer, you can have a look at the OL demo page: http://dev.openlayers.org/releases/OpenLayers-2.10/examples/

May 19, 2011 at 7:22 PM
Edited May 19, 2011 at 7:39 PM

So assuming I have the wms.ashx handler in my code, what do I do to use it? 

My objective would be to have a windows form page with a web browser control on it that points to the web page with the OpenLayer map. Then to use SharpMap as a WMS server top add the overlay that was read in from the shape file to the OpenLayer map. 

I had my Init map function set up as defined above. And I could easily add an open layer map with a regular map. 

I am assuming I set up my WMS server for SharpMap correctly in my post above? Now what do I do? Added the wms.ashx doesn’t seem like it is going to do anything else?  Is that getMap call the part I need to set up?  So if I used wms.ashx do I call GetMap.ashx? ?  When is that page hosted when I build my project? 

Now I could set up a CommVisible in the Application as well as the Web page to allow my main program to send objects back and forth between the code and c#. Should I do this and pass the WMS object that SharpMap created to the map’s javascript and set the layer to this or what? I’m failing to see how any of this makes the final connection to each other and the source code in the samples isn’t compiling or fails to load all of the setup correctly so I really don’t have a lot to go on example wise. 

Any suggestions?

May 19, 2011 at 7:42 PM

Okay, I have an html page in the project and a WebBrowser component pointing to that page.

Using your example from your javascript, it loads the OpenLayer tiles pretty well (for some reason there's an x in the top left hand corner of each tile and the controls don't load the images, but that can wait).

Here is what I have:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
	<head>
		<title></title>
        <script type="text/javascript" src="OpenLayer.js"></script>
        <script type="text/javascript">
            function InitMap() 
            {
                var map = new OpenLayers.Map("mapDIV", {
                    maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
                    numZoomLevels: 18,
                    maxResolution: 156543.0339,
                    units: 'm',
                    projection: "EPSG:900913",
                    displayProjection: new OpenLayers.Projection("EPSG:4326")
                })
                var layer = new OpenLayers.Layer.OSM("Simple OSM Map");
                map.addLayer(layer);
                map.setCenter(
                new OpenLayers.LonLat(5.908813, 52.891009).transform(
                    new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()),
                    12);
                var layer0 = new OpenLayers.Layer.WMS(
					"LocalhostSharpMap2",
					"wms.ashx?",
					{ layers: 'ShapeFile', version: '1.3.0', CRS: "EPSG:900913", transparent: true, format: 'image/gif' }
				);
                map.addLayers([layer0]);

                map.addControl(new OpenLayers.Control.LayerSwitcher());
                map.addControl(new OpenLayers.Control.MousePosition());
                var proj = new OpenLayers.Projection("EPSG:4326");
                var bounds = new OpenLayers.Bounds(3.87, 50.79, 6.781, 52.168)
                bounds.transform(proj, map.getProjectionObject());

            }
        </script>
	</head>
	<body onload="InitMap();" style="margin:0px; padding:0px;">
	    <div id='mapDIV' style='margin:0px; padding:0px; width: 100%; height: 100%;'></div>	
	</body>
</html>

Now, I have added the default wms.ashx that was included in demo, it is verbatim what was in the example.

My InitMap call is the same as I posted earlier.  What do I have to do to serve the SharpMap layer I created in the code I posted in the earlier post to this OpenLayers now?

May 19, 2011 at 8:03 PM

I redeployed this under a web app and I get the same error when trying to run the sample included in the source:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ServiceExceptionReport version="1.3.0xsi:schemaLocation="http://www.opengis.net/ogc http://schemas.opengis.net/wms/1.3.0/exceptions_1_3_0.xsd">
<ServiceException>Required parameter REQUEST not specified</ServiceException>
</ServiceExceptionReport>

Any ideas?

Developer
May 20, 2011 at 7:00 AM

Seems you're almost there :-)

First for your last message: The OGC WMS spec allows three kinds of requests to a WMS-service: GetMap (returning an image), GetCapabilities (giving an xml-doc with the capabilities of the WMS) and GetFeatureInfo (which gives more information about a specific point in the map image of GetMap. However, you  don't give a request to the WMS, so its complaining you don't give one;-) Try the GetCapabilities by adding this in the address bar of your browser:

?request=getcapabilities&version=1.3.0&service=WMS  It should give you a XML-document with the capabilities of your WMS.

Now to the previous message, because your almost there. You say for some reason there's an x in the top left hand corner of each tile. Well, this is because OpenLayers can't render the error message and instead tells the browser to display the image-not-found-image. If you request the url of this image and go to this url directly in you browser, you will get the XML-style error again, but now with another error message.

I'm not sure which error, because I see two mismatches between your WMS-server ashx  and maphelper on the one side and the JS on the other side.

  •  The layer name should be exactly the same and because I'm not sure whether spaces are allowed in the name I suggest you change
    this: VectorLayer shp = new VectorLayer("Shape File"); 
    to this: VectorLayer shp = new VectorLayer("ShapeFile");
  • The EPSG-codes must match: your WMS uses epsg3785 while your JS uses CRS: "EPSG:900913". Technically, they're the same projection, but the last one is an unofficial code. Although it's unofficial, it's currently better supported in OpenLayers, so I suggest the following change:
    this: shp.CoordinateTransformation = ctf.CreateFromCoordinateSystems(shpProj, epsg3785);
    to this: shp.CoordinateTransformation = ctf.CreateFromCoordinateSystems(shpProj, epsg3785);
               shp.SRID = 900913;

Still getting the image-not-found images? Just retrieve the URL of the image and load it directly into the browser to see where things go wrong.

May 20, 2011 at 2:15 PM
Edited May 20, 2011 at 4:11 PM

Thanks, that is getting me even closer. 

If I run the asp project I get the original message I posted still.  If I add the request line you mentioned to the address bar it loads I get this error:

 

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<!--
Capabilities generated by SharpMap v. 0.9.4149.18028
-->
<WMS_Capabilities version="1.3.0xsi:schemaLocation="http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd">
<Service>
<Name>WMS</Name>
<Title>Acme Corp. Map Server</Title>
<Abstract>
Map Server maintained by Acme Corporation. Contact: webmaster@wmt.acme.com. High-quality maps showing roadrunner nests and possible ambush locations.
</Abstract>
<KeywordList>
<Keyword>bird</Keyword>
<Keyword>roadrunner</Keyword>
<Keyword>ambush</Keyword>
</KeywordList>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx?request=getcapabilities&version=1.3.0&service=WMS"/>
<ContactInformation>
<ContactPersonPrimary>
<ContactPerson>John Doe</ContactPerson>
<ContactOrganization>Acme Inc</ContactOrganization>
</ContactPersonPrimary>
<ContactAddress>
<AddressType>postal</AddressType>
<Country>Neverland</Country>
</ContactAddress>
<ContactVoiceTelephone>1-800-WE DO MAPS</ContactVoiceTelephone>
</ContactInformation>
<MaxWidth>1000</MaxWidth>
<MaxHeight>500</MaxHeight>
</Service>
<Capability>
<Request>
<GetCapabilities>
<Format>text/xml</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Get>
<Post>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Post>
</HTTP>
</DCPType>
</GetCapabilities>
<GetFeatureInfo>
<Format>text/plain</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Get>
<Post>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Post>
</HTTP>
</DCPType>
</GetFeatureInfo>
<GetMap>
<Format>image/bmp</Format>
<Format>image/jpeg</Format>
<Format>image/gif</Format>
<Format>image/tiff</Format>
<Format>image/png</Format>
<DCPType>
<HTTP>
<Get>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Get>
<Post>
<OnlineResource xlink:type="simplexlink:href="http://localhost:54837/Default.aspx"/>
</Post>
</HTTP>
</DCPType>
</GetMap>
</Request>
<Exception>
<Format>text/xml</Format>
</Exception>
<Layer>
<Title>SharpMap</Title>
<CRS>EPSG:900913</CRS>
<BoundingBox minx="-9176923.68506216miny="3919114.4394692maxx="-9132638.98712442maxy="3964171.61557069CRS="EPSG:900913"/>
<EX_GeographicBoundingBox minx="-180miny="-90maxx="180maxy="90">
<westBoundLongitude>-180</westBoundLongitude>
<southBoundLatitude>-90</southBoundLatitude>
<eastBoundLongitude>180</eastBoundLongitude>
<northBoundLatitude>90</northBoundLatitude>
</EX_GeographicBoundingBox>
<Layer queryable="1">
<Name>ShapeFile</Name>
<Title>ShapeFile</Title>
<BoundingBox minx="-9176923.68506216miny="3919114.4394692maxx="-9132638.98712442maxy="3964171.61557069CRS="EPSG:900913"/>
</Layer>
</Layer>
</Capability>
</WMS_Capabilities>

I have my source at:

stcdata.com/temp/GisWeb.zip

if you want to take a look at it.  

Thanks

May 30, 2011 at 3:10 AM

That doesn't look like an error just looks like the WMS server is listing its capabilities to you