Adventures in C Programming Extending Juan DoNeblos Webservice for Virtual Earth

Topics: SharpMap v0.9 / v1.x, SharpMap v2.0
May 11, 2009 at 6:30 PM

I have had a lot of people contacting me in reguards to my adventures in extending Juan DoNeblos sharpmap shapefile reader for Virtual Earth.  This has been an adventure for me because this is my first exposure to C programming ...  I thought I would post my new additions to the web service in repayment for all the wonderful help I have recieved and to gain critisims to make it better...

I ran into a small problem of reading attribute data from the shapefiles based upon the sharpmap ExecuteIntersectionQuery.  It worked but it always returned either more features than user selected or the user had to click well off the target feature to return an item.  This sites discussions and how to pages lead me to using NTS to perform the Intersection Query.  Those of you who have been following my adventures (lol), and who are using the sharpmap.dll provided by Juan has been using an undocumented v2 Beta variant.  Much to my disgrin, trying to learn "delegates" I found that this version fails and cannot use delegates so that had put me off using the NTS Intersection routines (they or at least the examples) used Delegates.  So having a few spare momements, I modified the web service code to work with sharpmap v .9  since I am still having problems with Geo api of version 2 (future work).

So in using Juan D. template, I left the bounding box to grow only if  the shape is a point, otherwise, I grew each feature of the shape by .0001 decimal degrees to make a bigger target for the user to select.  This I found in my case to be a useable balanced experience for my users.  What follows is my version of the "QueryPoint" Method from Juan DoNeblos template (feel free to commend so I my learn better techniques)  this is just my thankyou for the help I have recieved.:

   public string QueryPoint(string filePath, double lat, double lon)
   {
      ShapeFile sf = null;
      try
      {

         sf = new ShapeFile(filePath);
         if (!sf.IsOpen)
            sf.Open();

         /* This is the SharpMap object that will contain the query results */
         FeatureDataSet ds = new FeatureDataSet();
         /* This is the extents of the map upon which we want to perform the query.
          * In our case, it will simply be the point where the user clicked. */
         BoundingBox bbox = new SharpMap.Geometries.Point(lon, lat).GetBoundingBox();


         if (sf.ShapeType == ShapeType.Point)
         {

            bbox = bbox.Grow(.0002);

         }
         else
         {
            Geometry geoPoints = new SharpMap.Geometries.Point(lon, lat);
            /* Create an NTS GeometryFactory */
            GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory geometryFactory = new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory();

            /* Using bbox as sharpmap geometry convert it to NTS geometry */
            GisSharpBlog.NetTopologySuite.Geometries.Geometry geoAsNTS = GeometryConverter.ToNTSGeometry(geoPoints, geometryFactory);

            /* Set the shapefiles provider FilterDelegate property to a new anonymous method */
            /* This Delegate method will be called for each potential row */
            sf.FilterDelegate = delegate(FeatureDataRow FeatureDataRow)
            {
               /* Get the geometry from the featureDataRow */
               SharpMap.Geometries.Geometry rowGeometry = FeatureDataRow.Geometry;
               /* Convert it to the equivalent NTS geometry */
               GisSharpBlog.NetTopologySuite.Geometries.Geometry compareGeoAsNTS =
                  GeometryConverter.ToNTSGeometry(rowGeometry, geometryFactory);
               /* Do the test geoAsNTS is availible because it is declared in the same scope as anonymous method */
               /* Add a small buffer to the geometry so that close point clicks retrieve expected results */
               bool intersects = geoAsNTS.Intersects(compareGeoAsNTS.Buffer(.0001));
               return intersects;
            };
         }
         /* Call ExecuteIntersectionQuery.  The FilterDelegate will be used to limit the result set */
         sf.ExecuteIntersectionQuery(bbox, ds);

         /* This actually executes the query and puts the results into the FeatureDataSet */

         //sf.ExecuteIntersectionQuery(bbox, ds);
         DataTable table = ds.Tables[0];
         if (table.Rows.Count < 1)
            return null;

         /* Here we format the query results in a simple HTML table to be shown in the
          * MessageBox on the map for demo purposes */
         StringBuilder sb = new StringBuilder();
         sb.AppendLine("<table>");
         foreach (DataRow row in table.Rows)
         {
            foreach (DataColumn column in table.Columns)
            {
               sb.AppendFormat("<tr><td style='background-color:#113;'>{0}</td><td>{1}</td></tr>", column.ColumnName, row[column]);
            }
            sb.AppendFormat("<tr style='height:10px;'></tr>");
         }
         sb.AppendLine("</table>");
         return sb.ToString();
      }
      finally
      {
         if (sf != null)
            sf.Close();
      }
   }