[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