Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I have a polygon featureclass that has adjacent features. Using Arc10, I am turning those polygons into lines using the "Featureclass to Lines" tool.

Now I would like to select ONLY THE INTERIOR line(s) (color=grey) so that I can run some ADDITIONAL processes on them. The key is that some (but not all) feature may touch the boundary line (color=blue). I am trying to use "Select By Location", but I cannot come up with a way to accomplish this task.

I might just be overthinking this one, but I am stuck. Any suggestions?

enter image description here

share|improve this question
    
Would an arcobjects approach be acceptable? –  Kirk Kuykendall Oct 12 '11 at 15:16
    
@Kirk Kuykendall- For my purposes, the method I listed works, but I think others would certainly be interested in an ArcObject option. So yes, please submit. –  RyanDalton Oct 12 '11 at 16:05

3 Answers 3

The thing I miss about polygon coverages is the way you could BUILD them with the LINE option then set up two relates, one for LPOLY# and the other for RPOLY# to find arcs that separate different polygons of interest. As a workaround the code below populates the polyline featureclass being edited with edges from a polygon featureclass which participates in a topology. It calculates the Left_OID and Right_OID fields based on what it borders. After running this the interior polylines can be found by applying a Definition expression "Left_OID" <> -1 and "Right_OID" <> -1

You could also set up joins to find polylines that separate particular polygons.

protected override void OnClick()
{
    try
    {
        IMouseCursor mc = new MouseCursorClass();
        mc.SetCursor(2);
        var polygonLayer = ArcMap.Document.SelectedItem as IFeatureLayer;
        if (polygonLayer == null || polygonLayer.FeatureClass == null || polygonLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon)
        {
            MessageBox.Show("select a polygon featureclass in the TOC first");
            return;
        }
        var editor = ArcMap.Application.FindExtensionByName("ESRI Object Editor") as IEditor;
        if (editor.EditState != esriEditState.esriStateEditing)
        {
            MessageBox.Show("start editing first");
            return;
        }
        var edgeLayer = ((IEditLayers)editor).CurrentLayer;
        if (edgeLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPolyline)
        {
            MessageBox.Show("edit target layer must be polylines");
            return;
        }
        try
        {
            var tc = new CancelTrackerClass() as ITrackCancel;
            tc.CancelOnKeyPress = true;
            editor.StartOperation();
            DumpEdges(polygonLayer, edgeLayer,tc,ArcMap.Application.StatusBar);
            if (tc.Continue())
                editor.StopOperation("dump edges");
            else
                editor.AbortOperation();
        }
        catch
        {
            editor.AbortOperation();
            throw;
        }
    }
    catch (Exception ex)
    {
        StringBuilder sb = new StringBuilder();
        while (ex != null)
        {
            sb.AppendLine(ex.Message);
            //sb.AppendLine(ex.StackTrace);
            ex = ex.InnerException;
        }
        MessageBox.Show(sb.ToString());
    }
}

private void DumpEdges(IFeatureLayer polygonLayer, IFeatureLayer edgeLayer, ITrackCancel tc, IStatusBar sb)
{
    // write edges from polygonlayer to edgelayer, populating Left_OID and Right_OID

    var topoClass = polygonLayer.FeatureClass as ITopologyClass;
    if (!topoClass.IsInTopology)
        throw new Exception(polygonLayer.Name + " is not in a topology");

    int leftIdx = GetFieldIdx(edgeLayer.FeatureClass,"Left_OID");
    int rightIdx = GetFieldIdx(edgeLayer.FeatureClass, "Right_OID");

    var extent = ((IGeoDataset)topoClass).Extent;
    var graph = topoClass.Topology.Cache;
    sb.set_Message(0, "building topology ...");
    graph.Build(extent, false);
    var edges = graph.Edges;
    edges.Reset();

    sb.set_Message(0, "topology built");
    sb.ProgressBar.Position=0;
    sb.ShowProgressBar("dumping edges, press escape key to cancel",0,edges.Count,1,false);
    for (int i = 0; i < edges.Count; i++)
    {
        var edge = edges.Next();
        DumpEdge(polygonLayer, edgeLayer, leftIdx, rightIdx, edge);
        sb.ProgressBar.Position=i;
        if (!tc.Continue())
        {
            sb.set_Message(0, "canceled");
            break;
        }
    }
    sb.HideProgressBar();
}

private void DumpEdge(IFeatureLayer polygonLayer, IFeatureLayer edgeLayer, int leftIdx, int rightIdx, ITopologyEdge edge)
{
    int leftOID = GetOID(edge.get_LeftParents(false), polygonLayer.FeatureClass);
    int rightOID = GetOID(edge.get_RightParents(false), polygonLayer.FeatureClass);
    var edgeFeat = edgeLayer.FeatureClass.CreateFeature();
    edgeFeat.set_Value(leftIdx, leftOID);
    edgeFeat.set_Value(rightIdx, rightOID);
    var geom = ((IClone)edge.Geometry).Clone() as IGeometry;
    FixZs(geom);
    edgeFeat.Shape = geom;
    edgeFeat.Store();
}

private void FixZs(IGeometry geom)
{
    // no need for z's
    var zAware = geom as IZAware;
    if (zAware != null && zAware.ZAware)
    {
        zAware.ZAware = false;
        zAware.DropZs();
    }
}

private int GetFieldIdx(IFeatureClass fc,string fldName)
{
    int idx = fc.Fields.FindField(fldName);
    if (idx == -1)
        throw new Exception(String.Format("Field {0} not found on {1}", fldName, ((IDataset)fc).Name));
    return idx;
}

private int GetOID(IEnumTopologyParent parents, IFeatureClass parentFC)
{
    int oid = -1;
    for (int i = 0; i < parents.Count; i++)
    {
        var parent = parents.Next();
        if (parent.m_pFC.ObjectClassID == parentFC.ObjectClassID)
            oid = parent.m_FID;
    }
    return oid;
}
share|improve this answer
up vote 1 down vote accepted

In doing some brainstorming with a colleague, we finally came up with a solution to this problem.

  1. We exported all polygons to lines
  2. Dissolved the original polygons and preserved no attributes and not allowing multi-part features (giving the fewest # of single-part polygons possible).
  3. Select by Location, using the lines as the input layer, the dissolved polygons as the selection layer, and "SHARE_A_LINE_SEGMENT_WITH" as the selection method. This selected all features that were on the boundary.
  4. Switch the Selection. This gave us all interior lines that did not match the outer dissolved boundary.

While I have not tested it for 100% accuracy, it seems to have accomplished the task that we were after very well. Of course, to automate this task, I just dropped all of these functions into a ModelBuilder routine, which makes the task much less tedious for future operations.

share|improve this answer

If you select target features which intersect the source as your selection method all target features contained, partially contained, and sharing line segments with the source polygons will be selected.

share|improve this answer
    
I see what you are saying, but I only wanted to select the interior lines, NOT all lines that touch the boundary. So unfortunately this method does not produce the criteria results I am after. –  RyanDalton Oct 12 '11 at 14:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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