[mapguide-users] Markup perpendicular

Jackie Ng jumpinjackie at gmail.com
Tue Jan 5 17:40:53 EST 2010


This ClosestVertex of the ClosestFeature with the smallest distance should
the your point in question.

Also I'm a bit fuzzy with my spatial operators: WITHIN, TOUCHES, CONTAINS,
CROSSES (and possibly others) all seem to be legitimate operators for this
scenario.

- Jackie


Jamo wrote:
> 
> Thanks for your help Jackie,
> 
> I've gone through your quick freehand code :) very well done
> 
> Perhaps a problem that the FDO provider "SDF" doesn't support Spatial
> operator TOUCHES or WITHIN
> after removing Touches I now get an error when adding entries to the
> matches list.
> If i expand the iterations it could be finding a result but not writting
> it to the collection?
> 
> 
> I can find the nearest road easy enough by doing a distance measurement
> form the point digitized to the nearest road.
> 
> Create a feature reader use current view extents as spatial filter select
> all road features within screen then iterate through each one and use the
> smallest distance to find the closest road.
> 
> but what I need to do is for the distance measured to return the point it
> has found as being the closest point? it only returns the distance....
> would have thought it would know the point of intersection with the road
> as well if it has found the distance to the nearest geometry?
> 
> using System;
> using System.Collections.Generic;
> using System.Linq;
> using System.Web;
> using System.Web.UI;
> using System.Web.UI.WebControls;
> using OSGeo.MapGuide;
> using System.Text;
> using System.Collections.Specialized;
> 
> public partial class markup_distancebetween_Default : System.Web.UI.Page
> {
>     static String sessionID;
>     static String mapName;
>     static double x;
>     static double y;
> 
>     class ClosestFeature
>     {
>         public double Distance { get; set; }
>         public MgProperty FeatureId { get; set; }
>         public MgCoordinate ClosestVertex { get; set; }
>     }
> 
>     protected void Page_Load(object sender, EventArgs e)
>     {
>         Response.Charset = "utf-8";
>         if (Page.IsPostBack == false)
>             GetRequestParameters();
>         
>        
> MapGuideApi.MgInitializeWebTier(Request.ServerVariables["APPL_PHYSICAL_PATH"]
> + "../webconfig.ini");
>         MgUserInformation cred = new MgUserInformation(sessionID);
> 
>         //connect to the site and get a feature service and a resource
> service instances
>         MgSiteConnection site = new MgSiteConnection();
>         site.Open(cred);
>         MgResourceService resourceSrvc =
> site.CreateService(MgServiceType.ResourceService) as MgResourceService;
>         MgFeatureService featureSrvc =
> site.CreateService(MgServiceType.FeatureService) as MgFeatureService;
> 
>         //Create a temporary map runtime object, locate the layer
>         MgMap map = new MgMap(site);
>         map.Open(mapName);
> 
>         Response.Write(GetClosestFeature(map, 10, 50,
> "plnCLRoads").FeatureId);
> 
> 
>     }
> 
> 
> MgGeometry CreateTestCircle(double joinDist)
> {
> 	MgGeometryFactory GF = new MgGeometryFactory();
> 	MgCoordinate arcPt1 = GF.CreateCoordinateXY(x + joinDist,  y);
> 
> 	MgCoordinate arcPt2 = GF.CreateCoordinateXY(x - joinDist,  y);
> 	MgCoordinate arcPt3 = GF.CreateCoordinateXY(x, y + joinDist);
> 	MgCoordinate arcPt4 = GF.CreateCoordinateXY(x, y - joinDist);
> 	MgArcSegment newGeom = GF.CreateArcSegment(arcPt1,arcPt2,arcPt3);
> 	MgArcSegment newGeom1 = GF.CreateArcSegment(arcPt2, arcPt1, arcPt4);
> 
> 	MgCurveSegmentCollection myCurve = new MgCurveSegmentCollection();
> 	myCurve.Add(newGeom);
> 	myCurve.Add(newGeom1);
> 
> 	MgCurvePolygon myPoly =
> GF.CreateCurvePolygon(GF.CreateCurveRing(myCurve), null);
> 
> 	return myPoly;
> }
> 
> //
> // Gets the outermost coordinates of a given geometry
> //
> List<MgCoordinate> GetOuterCoordinates(MgGeometry geom)
> {
>     List<MgCoordinate> coords = new List<MgCoordinate>();
> 	switch(geom.GeometryType)
> 	{
> 		case MgGeometryType.Point:
> 			{
> 				coords.Add(((MgPoint)geom).Coordinate);
> 			}
> 			break;
> 		case MgGeometryType.Polygon:
> 			{
> 				MgCoordinateIterator iter =
> ((MgPolygon)geom).ExteriorRing.Coordinates;
> 				while(iter.MoveNext())
> 				{
> 					coords.Add(iter.GetCurrent());
> 				}
> 			}
> 			break;
> 		case MgGeometryType.CurvePolygon:
> 			{
> 				MgCoordinateIterator iter =
> ((MgCurvePolygon)geom).ExteriorRing.Coordinates;
> 				while(iter.MoveNext())
> 				{
> 					coords.Add(iter.GetCurrent());
> 				}
> 			}
> 			break;
> 		case MgGeometryType.LineString:
> 			{
> 				MgLineString lstr = (MgLineString)geom;
> 				coords.Add(lstr.StartCoordinate);
> 				coords.Add(lstr.EndCoordinate);
> 			}
> 			break;
> 		case MgGeometryType.CurveString:
> 			{
> 				MgLineString lstr = (MgLineString)geom;
> 				coords.Add(lstr.StartCoordinate);
> 				coords.Add(lstr.EndCoordinate);
> 			}
> 			break;
> 		default: //MgMulti* geometry types
> 			{
> 			    //I'm not bothering to code this :-P
> 				//But you'd basically go through each sub-geometry and aggregate its
> coordinates
> 				//If sub-geometry is polygon, aggregate its exterior ring coordinates.
> 			}
> 			break;
> 	}
> 	return coords;
> }
> 
> // Gets the closest road feature from the map at the given point.
> //
> // A test circle is constructed to test for touching road features. If no
> features are found, the
> // circle is "inflated" by the specified distance. This is repeated until
> there are results, or
> // the max number of iterations has been reached.
> //
> // Returns the closes matching feature (ID, and its distance) or null if
> no result is found after
> // the specified number of iterations.
> //
> ClosestFeature GetClosestFeature(MgMap map, int maxIterations, double
> incrementDist, String layerName)
> {
>     MgLayer roadLayer = map.GetLayers().GetItem(layerName) as MgLayer;
> 	MgCoordinateSystem mapCs = new
> MgCoordinateSystemFactory().Create(map.GetMapSRS().ToString());
>     SortedList<double, ClosestFeature> matches = new SortedList<double,
> ClosestFeature>();
>     double distance = 1.0;
>     int iterations = 0;
>     MgWktReaderWriter wktIO = new MgWktReaderWriter();
>     MgAgfReaderWriter agfIO = new MgAgfReaderWriter();
>     MgGeometryFactory geomFact = new MgGeometryFactory();
> 	
>     do
>     {
>         MgFeatureQueryOptions options = new MgFeatureQueryOptions();
> 
>         //Create our test circle.
>         MgGeometry testCircle = CreateTestCircle(distance);
>         string testWkt = wktIO.Write(testCircle);
>         options.SetFilter("Geometry WITHIN GeomFromText('" + testWkt +
> "')");
> 
> 		//Run Query, see if there are any matches.
>         MgFeatureReader reader = roadLayer.SelectFeatures(options);
>         while (reader.ReadNext())  
>         {
> 			//We have a match. 
>             int featureId = reader.GetInt32("FeatId"); //Assuming
> FeatureId is the identity property
>             MgByteReader agf = reader.GetGeometry("Geometry");
>             MgGeometry matchGeom = agfIO.Read(agf);
> 			
> 			//Get its outermost coordinates 
>             List<MgCoordinate> outerCoords =
> GetOuterCoordinates(matchGeom);
>             if (outerCoords.Count > 0)
>             {
>                 foreach (MgCoordinate coord in outerCoords)
>                 {
>                     MgPoint testPoint = geomFact.CreatePoint(coord);          
> 					
> 					//If touches or within our test circle, record this result
>                     if (testCircle.Touches(testPoint) ||
> testCircle.Contains(testPoint))
>                     {
> 
>                         double dist =
> mapCs.MeasureEuclideanDistance(coord, geomFact.CreateCoordinateXY(x, y));
>                     
>                         ClosestFeature result = new ClosestFeature();
>                         result.Distance = dist;
>                         result.ClosestVertex = coord;
>                         result.FeatureId = new MgInt32Property("FeatId",
> featureId);
> 
>                         matches.Add(distance, result);
>                     }
>                 }  
>             }
>         }
> 		
> 		//We have at least one result, we can stop iterating.
> 		if (matches.Count > 0)
> 			break;
> 		
> 		//Otherwise, inflate our test circle.
>         iterations++;
>         distance += incrementDist;
>     } 
> 	while (matches.Count == 0 && iterations < maxIterations);
> 
> 	//If there are results, return the first one.
>     if (matches.Count > 0)
>     {
>          return matches.Values[0]; //First entry is the closest since
> entries are sorted by distance.
>     }
> 	
>     return null; //Couldn't find a result after maxIteration attempts,
> return null.
> }
> 
>     //MgInsertFeatures addThis(String geomCol, MgGeometry geom)
>     //{
>     //    MgAgfReaderWriter agfReaderWriter = new MgAgfReaderWriter();
>     //    MgPropertyCollection PropertyCollection = new
> MgPropertyCollection();
>     //    //add geometry
>     //    //Response.Write(road.GeometryType);
>     //    MgByteReader geometryByteReader = agfReaderWriter.Write(geom);
>     //    MgGeometryProperty geometryProperty = new
> MgGeometryProperty(geomCol, geometryByteReader);
>     //    PropertyCollection.Add(geometryProperty);
> 
>     //    MgInsertFeatures insertFeatures = new MgInsertFeatures("test",
> PropertyCollection);
>     //    return insertFeatures;
>     //}
> 
>     //MgGeometry shortGeometry(MgPoint click, MgGeometry closest, double
> joinDist)
>     //{
>     //    MgGeometryFactory GF = new MgGeometryFactory();
>     //    joinDist = joinDist + 0.001;
>     //    MgCoordinate arcPt1 = GF.CreateCoordinateXY(click.Coordinate.X +
> joinDist,  click.Coordinate.Y);
> 
>     //    MgCoordinate arcPt2 = GF.CreateCoordinateXY(click.Coordinate.X -
> joinDist,  click.Coordinate.Y);
>     //    MgCoordinate arcPt3 = GF.CreateCoordinateXY(click.Coordinate.X,
> click.Coordinate.Y + joinDist);
>     //    MgCoordinate arcPt4 = GF.CreateCoordinateXY(click.Coordinate.X,
> click.Coordinate.Y - joinDist);
>     //    MgArcSegment newGeom =
> GF.CreateArcSegment(arcPt1,arcPt2,arcPt3);
>     //    MgArcSegment newGeom1 = GF.CreateArcSegment(arcPt2, arcPt1,
> arcPt4);
> 
>     //    MgCurveSegmentCollection myCurve = new
> MgCurveSegmentCollection();
>     //    myCurve.Add(newGeom);
>     //    myCurve.Add(newGeom1);
> 
>     //    MgCurvePolygon myPoly =
> GF.CreateCurvePolygon(GF.CreateCurveRing(myCurve), null);
> 
>     //    Response.Write(closest.Intersects(myPoly));
> 
>     //    return myPoly;
>     //   
> //Response.Write(myPoly.Intersection(closest).Centroid.Coordinate.X + " "
> + myPoly.Intersection(closest).Centroid.Coordinate.Y);
>     //}
> 
>     void GetRequestParameters()
>     {
>         if (Request.HttpMethod == "POST")
>             GetParameters(Request.Form);
>         else
>             GetParameters(Request.QueryString);
>     }
> 
>     void GetParameters(NameValueCollection parameters)
>     {
>         mapName = GetParameter(parameters, "MAPNAME");
>         sessionID = GetParameter(parameters, "SESSION");
>         x = GetDouble(parameters, "x0");
>         y = GetDouble(parameters, "y0");
>     }
>     String GetParameter(NameValueCollection parameters, String name)
>     {
>         String strval = parameters[name];
>         if (null == strval)
>             return "";
> 
>         return strval.Trim();
>     }
> 
>     double GetDouble(NameValueCollection parameters, String name)
>     {
>         double strval = Convert.ToDouble(parameters[name]);
>         if (null == strval)
>             return 0;
> 
>         return strval;
>     }
> 
> }
> 
> 

-- 
View this message in context: http://n2.nabble.com/Markup-perpendicular-tp4253574p4257913.html
Sent from the MapGuide Users mailing list archive at Nabble.com.


More information about the mapguide-users mailing list