AnsweredAssumed Answered

Bad buffer geometry throwing COMException in SelectFeatures()

Question asked by geonetadmin on Jan 6, 2011
Latest reply on Jan 26, 2011 by ramgarden
Original User: ramgarden

Here's the deal:
We are trying to select all the poles that are within a given distance from the primary conductors of a given FEEDERID.
The way we do it and has worked just fine so far is:
1. Get all the primary conductor features with the given FEEDERID and put them in a geometrybag.
2. Union all the conductor features together into one giant polyline.
3. Buffer this giant polyline with the given distance (usually 100 ft).
4. Use this buffer in a spatial filter given to the IFeatureSelection.SelectFeatures() method.
This works 99% of the time perfectly just as it should. BUT for CERTAIN CIRCUITS it creates the buffer in strange, malformed ways
and when trying to use the buffer in the SelectFeatures() method it throws a COMException with this error code:
-2147215968.

After some searching it looks like this error code has to do with overlapping polygons or bad geometry in general.
Even after calling Simplify() on the buffer polygon after setting the IsKnownSimple_2 = false it still throws this error.

There is even a weird thing where if we use 100 for the buffer size it makes a small buffer around one or two of the lines instead of all of them, but if we subtract 1 from the size and try again over and over it will eventually get to something like 91 or some magic distance and is different for each of these problem FEEDERIDs and it will create the buffer just fine.  But even then it still throws the COMException when trying to select with it.

Is there something I need to do to better check and fix the geometry of the primary conductors and/or the buffer it creates?

Here is a screenshot of when it creates two small buffers instead of one big one around the whole thing (buffersize = 100): Attachment BadBufferZoomedIn.png

Here's a shot of when it creates the buffer correctly around the whole circuit: Attachment GoodBufferZoomedIn.png

Here's the code that creates the buffer:
private IPolygon BufferGeometryBag(double bufferDistance, IGeometryBag sourceGeometryBag)
        {
            //QI to IGeometryCollection
            IGeometryCollection geometryCollection = (IGeometryCollection)sourceGeometryBag;
            
            ITopologicalOperator2 pITopologicalOperator_Polygon = new Polygon() as ITopologicalOperator2;
            ITopologicalOperator topologicalOperator = sourceGeometryBag as ITopologicalOperator;
            IPolygon returnBuffer;

            //Construct a union of all polylines
            ITopologicalOperator2 topoOp_Polyline = new Polyline() as ITopologicalOperator2;
            topoOp_Polyline.ConstructUnion(sourceGeometryBag as IEnumGeometry);
            
            //simplify the polyline.
            topoOp_Polyline.IsKnownSimple_2 = false;
            topoOp_Polyline.Simplify();
            
            //buffer the polyline.  
            returnBuffer = topoOp_Polyline.Buffer(bufferDistance) as IPolygon;
            returnBuffer.SpatialReference = _SpatialReference;
            ITopologicalOperator2 topo2 = returnBuffer as ITopologicalOperator2;
            topo2.IsKnownSimple_2 = false;
            topo2.Simplify();
            returnBuffer = topo2 as IPolygon;
            returnBuffer.SimplifyPreserveFromTo();
            
            _Log4Net.Debug("conductor envelope width: " + _ConductorGeometries.Envelope.Width +
                    " height: " + _ConductorGeometries.Envelope.Height);
            _Log4Net.Debug("   buffer envelope width: " + returnBuffer.Envelope.Width +
                    " height: " + returnBuffer.Envelope.Height);

            //the buffer's envelope should always be twice the buffer distance greater than the
            // conductors' envelope. So if buffer distance is 100 then the buffer envelope's
            // width should be 200 feet greater than the conductors' envelope's width.
            // The height should also be 200 feet greater.
            while ( (returnBuffer.Envelope.Height < (_ConductorGeometries.Envelope.Height + (bufferDistance * 2))) &&
                    (returnBuffer.Envelope.Width < (_ConductorGeometries.Envelope.Width + (bufferDistance * 2))) )
            {
                bufferDistance -= 1; //subtract 1
                _Log4Net.Debug("Non-circuit buffer malformed. Trying again with bufferdistance: " + bufferDistance);
                returnBuffer = topoOp_Polyline.Buffer(bufferDistance) as IPolygon;
                returnBuffer.SpatialReference = _SpatialReference;
                topo2 = returnBuffer as ITopologicalOperator2;
                topo2.IsKnownSimple_2 = false;
                topo2.Simplify();
                returnBuffer = topo2 as IPolygon;
                returnBuffer.SimplifyPreserveFromTo();
                _Log4Net.Debug("conductor envelope width: " + _ConductorGeometries.Envelope.Width +
                    " height: " + _ConductorGeometries.Envelope.Height);
                _Log4Net.Debug("   buffer envelope width: " + returnBuffer.Envelope.Width +
                        " height: " + returnBuffer.Envelope.Height);
            }
            return returnBuffer;
   }


Here's the code that selects all the poles (in my DB the pole layer is the only one with the buffer print model name):

public void MakeBufferedFeatureLayers(IPolygon bufferPoly, string bufferPrintModelName, IWorkspace circuitWorkspace, 
            MXDManager mxdMan, FeederFeatureManager ffManager)
        {
            ISet bufferFeatLayerSet;

            bufferFeatLayerSet = GetLayersByModelName(bufferPrintModelName, mxdMan);
                        
            //ITable tempLayerTable;
            IFeatureClass tempLayerClass;
            ISpatialFilter bufferSpatialFilter;
            ISelectionSet featSelectionSet;

            if (bufferFeatLayerSet != null)
            {
                //for each layer, select all of the features that are within the buffer polygon
                bufferFeatLayerSet.Reset();
                IFeatureLayer bufferedFeaturesLayer = bufferFeatLayerSet.Next() as IFeatureLayer;
                while (bufferedFeaturesLayer != null)
                {
                    //select the features within the buffer
                    bufferSpatialFilter = new SpatialFilterClass();
                    bufferSpatialFilter.Geometry = bufferPoly as IGeometry;
                    bufferSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

                    try
                    {
                        IFeatureSelection featureSelection = bufferedFeaturesLayer as IFeatureSelection;
                        featureSelection.SelectFeatures(bufferSpatialFilter, esriSelectionResultEnum.esriSelectionResultNew, false);
                        featSelectionSet = featureSelection.SelectionSet;
                    }
                    catch(COMException ce)
                    {
                        //throw new Exception("Couldn't select non-circuit features using buffer. Try reducing or increasing non-circuit buffer size configuration setting.");
                        _Log4Net.Error("Couldn't select non-circuit features using buffer. Try reducing or increasing non-circuit buffer size configuration setting.");
                        return;
                    }

                    _Log4Net.Debug("selected " + featSelectionSet.Count + " features within the buffer.");

                    //then create a new layer out of these selected features.
                    mxdMan.CreateTemporaryLayerFromSelected(bufferedFeaturesLayer);

                    _Log4Net.Debug("created temporary layer OK");

                    //next layer with buffer print model name
                    bufferedFeaturesLayer = bufferFeatLayerSet.Next() as IFeatureLayer;
                }
                   
            }
            else
            {
                _Log4Net.Debug("Couldn't find any non-circuit feature classes with the " + bufferPrintModelName + " model name.");
            }


        }

Outcomes