# [mapguide-users] Markup perpendicular

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

```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
>
> 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,
>>>
>>>
>>>     }
>>>
>>>
>>> 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();
>>>
>>> 	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:
>>> 			{
>>> 			}
>>> 			break;
>>> 		case MgGeometryType.Polygon:
>>> 			{
>>> 				MgCoordinateIterator iter =
>>> ((MgPolygon)geom).ExteriorRing.Coordinates;
>>> 				while(iter.MoveNext())
>>> 				{
>>> 				}
>>> 			}
>>> 			break;
>>> 		case MgGeometryType.CurvePolygon:
>>> 			{
>>> 				MgCoordinateIterator iter =
>>> ((MgCurvePolygon)geom).ExteriorRing.Coordinates;
>>> 				while(iter.MoveNext())
>>> 				{
>>> 				}
>>> 			}
>>> 			break;
>>> 		case MgGeometryType.LineString:
>>> 			{
>>> 				MgLineString lstr = (MgLineString)geom;
>>> 			}
>>> 			break;
>>> 		case MgGeometryType.CurveString:
>>> 			{
>>> 				MgLineString lstr = (MgLineString)geom;
>>> 			}
>>> 			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;
>>>     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.
>>>         {
>>> 			//We have a match.
>>>             int featureId = reader.GetInt32("FeatId"); //Assuming
>>> FeatureId is the identity property
>>>
>>> 			//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);
>>>
>>>                     }
>>>                 }
>>>             }
>>>         }
>>>
>>> 		//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)
>>>     //{
>>>     //    MgPropertyCollection PropertyCollection = new
>>> MgPropertyCollection();
>>>     //    MgGeometryProperty geometryProperty = new
>>>
>>>     //    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();
>>>
>>>     //    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
>

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