[mapguide-users] Markup perpendicular

Rodolfo Moreno rodolfoamoreno at gmail.com
Wed Jan 6 11:36:26 EST 2010


happy new year everybody.
It's a simple 2D math problem. According to what you have posted:
"in attached image it sort of shows whats happening, user clicks where the
red x is, then we find all red lines in view. now I use the
geomerty.distance(point) to find the shortest distance to all the red lines.
which tells me the red line on the left is the closest"
we have as data:
- red x(center of the circle): C(cx,cy)
- red line on the left is the closest. RLine

you can obtain the initial and end point of the RLine using MG API
- initial point x1,y1
- end point x2,y2

now we will create a perpendicular new line (using MG API) which is make up
by the Px and the new point  P(px,py) that this moment we will calculate:
angle= A = atan(-(y2-y1)/(x2-x1) )
px = cx + 10*cos(A) // 10 is placed arbitrarily since what we want is get
any point of the new line
py = cy + 10*sin(A)

finally we can intersect RLine with new line using MG API in order to get
the intersection point which is what you want.

Regards,



Jackie Ng wrote:
> 
> Ok, it seems there will be cases where the geometry satisfies the spatial
> condition, but its component vertices of that line do not. 
> 
> In that case, I guess you would iteratively break that line down into
> smaller components (via linear interpolation?) and test the resulting
> vertices. Eventually one of the resulting vertices must be touching or
> inside the test circle, and you can add these to the result set.
> 
> I can't think of an algorithm to do this because I am no longer the Math
> whiz that I once used to be in high school :-)
> 
> You would only do this, if when iterating through a matching geometry's
> coordinates, no new coordinates were added to the result set. This means
> that the geometry satisfied the required condition, but none of its
> component vertices matched the condition.
> 
> - Jackie
> 
> 
> Jamo wrote:
>> 
>> By closest vertex are you referring to the actual start and end point of
>> the line? or the intersection of the circle and the line.
>> in attached image it sort of shows whats happening, user clicks where the
>> red x is, then we find all red lines in view. now I use the
>> geomerty.distance(point) to find the shortest distance to all the red
>> lines.
>> which tells me the red line on the left is the closest. it gives me the
>> distance perpendicular to the point (where the circle intersects the
>> line) I would like to know the point of intersection or where it touches
>> would make sense?....
>> But when I re-create the circle with the distance it is said to be the
>> geometry does not cross/intersect?
>> 
>> 
>>         Response.Write("<BR/>Contains: " + closest.Contains(myPoly));
>>         Response.Write("<BR/>Crosses: " + closest.Crosses(myPoly));
>>         Response.Write("<BR/>Disjoint: " + closest.Disjoint(myPoly));
>>         Response.Write("<BR/>Intersects: " + closest.Intersects(myPoly));
>>         Response.Write("<BR/>Overlaps: " + closest.Overlaps(myPoly));
>>         Response.Write("<BR/>Touches: " + closest.Touches(myPoly));
>>         Response.Write("<BR/>Within: " + closest.Within(myPoly));
>> 
>> all return false .... except for disjoint :(
>> 
>> if i add a little to the radius I get two intersections where the circle
>> crosses the road.
>> 
>> I thought a vertex was the point of linestring change ? 
>> 
>> Jackie Ng wrote:
>>> 
>>> 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;
>>>>     }
>>>> 
>>>> }
>>>> 
>>>> 
>>> 
>>> 
>>  http://n2.nabble.com/file/n4258006/vertexIntersection.jpg
>> vertexIntersection.jpg 
>> 
> 
> 


-----
Rodolfo Moreno
CivilEng

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


More information about the mapguide-users mailing list