4

I recently asked a similiar question on this, however I needed to know if there is a way to solve this if I only have a IPolyline Feature, and not the whole layer.

I want to know if I can determine if a point lays within my Polyline feature.

I tried using both intersect and difference from ITopologicalOperator, but still no use.

Please Help:

  private bool PointLaysWithinLine(IPolyline currentPath, IPoint iPoint)
    {
        IPolyline newLine = new PolylineClass();
        ((IPointCollection)newLine).AddPoint(iPoint);
        newLine.Project(currentPath.SpatialReference);

//This doesn't work
        IPolyline intersection = ((ITopologicalOperator)currentPath).Intersect(newLine, esriGeometryDimension.esriGeometryNoDimension) as IPolyline;

//This also doesn't work
        IPolyline difference = ((ITopologicalOperator)currentPath).Difference(newLine) as IPolyline;

        return currentPath.Length != difference.Length; 
    }

*************************UPDATE*************************

So after playing around for 2 days with user's comments and ideas. I came up with this code (thanks jakub)

point.SpatialReference = IMap.SpatialReference;
ISpatialFilter spatialFilter = new SpatialFilter();
spatialFilter.Geometry = point;
spatialFilter.GeometryField = ((IFeatureLayer)layer).FeatureClass.ShapeFieldName;
spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
IFeatureCursor flowPathCursor = ((IFeatureLayer)layer).FeatureClass.Search(spatialFilter, true);

if (flowPathCursor.NextFeature() != null)
   result = true;

The above code works for MOST time, however, some rare case it still CANNOT find the feature. Note that I USED snapping (vertices/edges) so it should be dead on.

Also I tried using the slope y=mx+b method, and IIdentify2.Identify. They all work MOST time but some rare case (i notice it happening most often on straight EDGES).

Any one have any idea? This is driving me insane.

5
  • 1
    Do you want to know if the point lies on (in) the polyline, but it doesn't have to fall exactly on one of the polyline's vertices? A note based on your other question, which implies that the data may be projected on-the-fly. You can get different answers, in different coordinate systems, but more likely with 'long' lines.
    – mkennedy
    Jun 18, 2011 at 0:29
  • The "Topological Operator" approach could work but it will not be very efficient. I don't do C# (just VB) but I just don't understand what is going on in your code? Are you making a polyline from the incoming point and only adding one point? Why project the polyline? Does the Spatial Reference of the two geomtries differ? You should maybe debug this on features that share the same spatial reference first. Also, you might want to use iTopologicalOperator5 instead since it supersedes the version you are using. Jun 18, 2011 at 4:03
  • Before calling IGeometry.Project on a new polyline, I think you need to assign IGeometry.SpatialReference. Jun 20, 2011 at 16:05
  • Also, you might try calling IGeometry.SnaptoSpatialReference on the point before assigning it to the spatialfilter. Jun 23, 2011 at 13:37
  • Thanks Kirk, So i got rid of project, and just assigned spatial reference, also called snaptospatialreference. It didn't help though. It still cannot find the feature =(
    – Kev84
    Jun 23, 2011 at 13:44

4 Answers 4

2

Use IRelationalOperator, either touches or not disjoint.

1
  • hi I actually tried to use touch, not disjoint and IsNear. All of them don't give me my desire result. The problem is i guess my ipoint does not lie on a vertex of the polyine.
    – Kev84
    Jun 20, 2011 at 14:18
2

Testing if the point is on the polyline

The following code will take a polyline, a point that you would like to test if it falls on one of the lines that make up the polyline, and a tolerance value used to say how close you need the point to be to the line for it to be coincident with it. The tolerance value should probably not be zero due to rounding issues introduced via computer math.

The idea here is to take each line segment that makes up the polyline and compute the slope and offset, i.e. change the line to a y = mx + b form. The code then subtracts the y value from the passed point to the y value computed by using the point's x value in the line formula. If the resultant value is less than the tolerance, the point is said to be on the line.

private bool PointLaysOnLine(IPolyline currentPath, IPoint iPoint, double tolerance)
{
    IPointCollection points = currentPath as IPointCollection;

    for (int pos = 1; pos < points.PointCount; pos++)
    {
        SlopeAndOffset so = new SlopeAndOffset(points.Points[pos].X, 
                                                points.Points[pos].Y,
                                                points.Points[pos - 1].X, 
                                                points.Points[pos - 1].Y);

        if (Math.Abs(iPoint.Y - (so.Slope * iPoint.X + so.B)) <
            Math.Abs(tolerance))
        {
            return true;
        }
    }

    return false;
}

public class SlopeAndOffset
{
    public double Slope { get; private set; }
    public double B { get; private set; }

    SlopeAndOffset(double x1, double y1, double x2, double y2)
    {
        Slope = (y2 - y1) / (x2 - x1);
        B = y1 - Slope * x1;
    }
}

Testing if the point is one of the vertices of the polyline

This code loops through each point in the polyline and compares it to the passed point. If the points match, it returns true. If it gets through the entire polyline and doesn't find the point, it returns false.

private bool PointLaysWithinLine(IPolyline currentPath, IPoint iPoint)
{
    IPointCollection points = currentPath as IPointCollection;

    for (int pos = 0; pos < points.PointCount; pos++)
    {
        if (points.Point[pos].X == iPoint.X &&
            points.Point[pos].Y == iPoint.Y)
        {
            return true;
        }
    }

    return false;
}
1
  • thanks, but the main problem is that the iPoint does not lay on a vertex of the line. Hence, the above method will not be able to get me my desired results.
    – Kev84
    Jun 20, 2011 at 14:17
1

You could use Spatial Filter to query for intersecting features. (Your basic spatial query) Use the ISpatialFilter interface SpatialRel Property. The property takes in a esriSpatialRelEnum constant parameter. To get a cursor of intersecting features you use the esriSpatialRelIntersects constant.

If the returned FeatureCursor contains no features then no intersecting features were found. If the cursor contains more then one feature you can iterate through the features in the cursor and compare the iFeature.OID to find your polyline. You can find detailed information and lot's of C# and VB .Net examples here: http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#/Get_All_Features_from_Point_Search_in_GeoFeatureLayer_Snippet/004900000078000000/

The above should work fine but iHitTest may be a more efficient way to do this. I have suggested this in your last post. Have you tried it?

2
  • Thanks I tried your spatial filter method, it worked but not flawlessly, see my updated post. Also, can you provide an example on how i can implement this using IHitTest
    – Kev84
    Jun 23, 2011 at 13:33
  • @Kev84 If the returned cursor does not contain any features then the features do not intersect. You could try buffering the input geometry using the same topological operator to create a search perimeter. Here is a iHitTest example. You can also specify search distance, and obtain the actual segment of the polyline and from that the neaest vertex, etc.. Jun 23, 2011 at 14:16
1

I never search for a polyline that intersects a point. Instead I create a search envelope using a tolerance, loop through all the polylines that intersect the envelope and determine which one is closest to the specified point. The code below works with arcmap, but should also be adapted to work in arcengine.

protected override void OnMouseUp(Tool.MouseEventArgs arg)
{
    try
    {
        var searchTol = GetSearchTol();
        var fLayer = ArcMap.Document.FocusMap.get_Layer(0) as IFeatureLayer;
        var av = ArcMap.Document.FocusMap as IActiveView;
        var pnt = av.ScreenDisplay.DisplayTransformation.ToMapPoint(arg.X,arg.Y);

        var nearestFeat = FindNearestFeature(pnt, searchTol, fLayer);
        ((IFeatureSelection)fLayer).Clear();
        if (nearestFeat != null)
        {
            ((IFeatureSelection)fLayer).Add(nearestFeat);
            Debug.Print("oid = {0}", nearestFeat.OID);
        }
        else
            Debug.Print("no feature found");
        av.Refresh();
    }
    catch (Exception ex)
    {
        Debug.Print(ex.Message);
    }
}
private IFeature FindNearestFeature(IPoint pnt, double searchTol, IFeatureLayer fLayer)
{
    // get a copy of the envelope
    var env = pnt.Envelope.Envelope;
    env.Expand(searchTol,searchTol,false);

    // make a filter with the envelope (not the point)
    ISpatialFilter sf = new SpatialFilterClass();
    sf.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
    sf.Geometry = env;
    sf.set_OutputSpatialReference(fLayer.FeatureClass.ShapeFieldName,env.SpatialReference);

    IFeatureCursor fCur = null;
    IFeature nearestFeat = null;
    var proxOp = pnt as IProximityOperator;
    try
    {
        fCur = fLayer.FeatureClass.Search(sf,false);
        IFeature feat;
        double nearestDist = double.MaxValue;
        while((feat=fCur.NextFeature())!= null)
        {
            double dist = proxOp.ReturnDistance(feat.Shape);
            if(dist < nearestDist)
            {
                nearestFeat = feat;
                nearestDist = dist;
            }
        }
    }
    catch
    {
        throw;
    }
    finally
    {
        if(fCur != null)
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
    }
    return nearestFeat;
}

private double GetSearchTol()
{
    // don't use this since arcengine doesn't have it 
    //return ArcMap.Document.SearchTolerance;

    // make a search envelope several pixels large
    int searchTolPixels = 3;
    var av = ArcMap.Document.FocusMap as IActiveView;
    var rect = av.ScreenDisplay.DisplayTransformation.get_DeviceFrame();
    var resolution = av.ScreenDisplay.DisplayTransformation.FittedBounds.Width / Math.Abs(rect.right - rect.left);
    return resolution * searchTolPixels;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.