# [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
>>
>> 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
>>
>
>

-----
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.
```