ThinkGeo.com    |     Documentation    |     Premium Support

TopologyException

Hello,



I have an issue with validating shapes/features that I hope you can help resolve.  In our application we can edit features and the scenario that is failing is:



1.  Start with a PolygonShape with a single inner ring like figure 1 in attachment.

2.  Edit and save the shape by dragging a node from the inner ring outside the outer ring like figure 2 in attachment

3.  Before trying to edit the shape again do a feature.IsTopologicallyEqual(searchResult) test and get an exception (see below)

4.  I have tried checking the shape before savings using the following:

    feature.IsValid() >> Always returns TRUE

    feature.CanMakeValid >> Again TRUE plus feature.MakeValid() >> appears to run OK.

   Also  PolygonShape.Validate(ShapeValidationMode.Advanced) return no validation errors.



Pushing this type of edit further you can get some odd results, such as dragging all inner nodes outside and it still passes the validation tests.

Is such a shape really valid? and if not how can I test it? 



Thanks,

Jonathan

----------------------------------------------------------------------------------------------------------------------------------

GisSharpBlog.NetTopologySuite.Geometries.TopologyException was unhandled by user code
  HResult=-2146232832
  Message=side location conflict [ (469999.95575114, 213204.462079924, NaN) ]
  Source=NetTopologySuite
  StackTrace:
       at GisSharpBlog.NetTopologySuite.GeometriesGraph.EdgeEndStar.PropagateSideLabels(Int32 geomIndex)
       at GisSharpBlog.NetTopologySuite.GeometriesGraph.EdgeEndStar.ComputeLabelling(GeometryGraph[] geom)
       at GisSharpBlog.NetTopologySuite.Operation.Relate.RelateComputer.LabelNodeEdges()
       at GisSharpBlog.NetTopologySuite.Operation.Relate.RelateComputer.ComputeIM()
       at GisSharpBlog.NetTopologySuite.Operation.Relate.RelateOp.get_IntersectionMatrix()
       at GisSharpBlog.NetTopologySuite.Operation.Relate.RelateOp.Relate(IGeometry a, IGeometry b)
       at GisSharpBlog.NetTopologySuite.Geometries.Geometry.Relate(IGeometry g)
       at GisSharpBlog.NetTopologySuite.Geometries.Geometry.Equals(IGeometry g)
       at ThinkGeo.MapSuite.Core.Feature.IsTopologicallyEqual(Feature targetFeature)
       at enzo.MapEditing.MapStateEdit.EditFeatures() in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapStateEdit.cs:line 106
       at enzo.MapEditing.MapStateEdit.SetStateOn() in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapStateEdit.cs:line 34
       at enzo.MapEditing.MapEdit.SwitchState(MapState newMapState) in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapEdit.cs:line 154
       at enzo.MapEditing.MapEdit.SetMapState(possibleMapStates newState) in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapEdit.cs:line 141
       at enzo.MapEditing.MapEdit.CmdEdit() in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapEdit.cs:line 319
       at enzo.MapEditing.cMapObserver.CheckMessage(InternalMessage message) in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\MapEdit\MapObserver.cs:line 96
       at enzo.MessageManagement.MessageManager.Send(InternalMessage toolMessage) in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\TooManagement\MessageManager.cs:line 102
       at enzo.FrmEnzo.mainRibbon_ToolClick(Object sender, ToolClickEventArgs e) in c:\Users\Jonathan\Source\Workspaces\Pear Technology\Enzo\enzo\FrmEnzo.cs:line 262
       at Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.OnToolClick(ToolClickEventArgs e)
       at Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.FireEvent(ToolbarEventIds id, EventArgs e)
       at Infragistics.Win.UltraWinToolbars.ToolBase.OnToolClick()
       at Infragistics.Win.UltraWinToolbars.ButtonToolUIElement.DoClickProcessing(MouseEventArgs e)
       at Infragistics.Win.UltraWinToolbars.ButtonToolUIElement.OnMouseUp(MouseEventArgs e)
       at Infragistics.Win.ControlUIElementBase.ProcessMouseUpHelper(Object sender, MouseEventArgs e)
       at Infragistics.Win.ControlUIElementBase.ProcessMouseUp(Object sender, MouseEventArgs e)
       at Infragistics.Win.Utilities.ProcessEvent(Control control, ProcessEvent eventToProcess, EventArgs e)
       at Infragistics.Win.UltraControlBase.OnMouseUp(MouseEventArgs e)
       at Infragistics.Win.UltraWinToolbars.UltraToolbarsDockArea.OnMouseUp(MouseEventArgs e)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
  InnerException: 




Shapes.docx (22.6 KB)

Hi Jonathan, 
  
 Our validation API mainly work for simple shape which don’t contains inner ring. 
  
 If you want to do that, I think you can create a simple function like the customValidate in the sample code as below: 
  
  
  
  private void ModifyFeature_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;

            winformsMap1.CurrentExtent = new RectangleShape(-10, 10, 10, -10);
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.StandardColors.White);


            PolygonShape polygonShape = new PolygonShape();
            polygonShape.OuterRing.Vertices.Add(new Vertex(0, 0));
            polygonShape.OuterRing.Vertices.Add(new Vertex(0, 10));
            polygonShape.OuterRing.Vertices.Add(new Vertex(10, 10));
            polygonShape.OuterRing.Vertices.Add(new Vertex(10, 0));

            RingShape ring = new RingShape();
            ring.Vertices.Add(new Vertex(1, 1));
            ring.Vertices.Add(new Vertex(1, 5));
            ring.Vertices.Add(new Vertex(5, 5));
            ring.Vertices.Add(new Vertex(5, 1));

            polygonShape.InnerRings.Add(ring);

            winformsMap1.EditOverlay.EditShapesLayer.InternalFeatures.Add(new Feature(polygonShape));
            winformsMap1.EditOverlay.FeatureDragged += EditOverlay_FeatureDragged;

            winformsMap1.Refresh();
        }

        void EditOverlay_FeatureDragged(object sender, FeatureDraggedEditInteractiveOverlayEventArgs e)
        {
            Feature f = winformsMap1.EditOverlay.EditShapesLayer.InternalFeatures[0];
            
 
  
 Wish that’s helpful. 
  
 Regards, 
  
 Don

Hi Jonathan,  
  
 Our validation API mainly work for simple shape which don’t contains inner ring.  
  
 If you want to do that, I think you can create a simple function like the customValidate in the sample code as below:  
  
  private void ModifyFeature_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;

            winformsMap1.CurrentExtent = new RectangleShape(-10, 10, 10, -10);
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.StandardColors.White);


            PolygonShape polygonShape = new PolygonShape();
            polygonShape.OuterRing.Vertices.Add(new Vertex(0, 0));
            polygonShape.OuterRing.Vertices.Add(new Vertex(0, 10));
            polygonShape.OuterRing.Vertices.Add(new Vertex(10, 10));
            polygonShape.OuterRing.Vertices.Add(new Vertex(10, 0));

            RingShape ring = new RingShape();
            ring.Vertices.Add(new Vertex(1, 1));
            ring.Vertices.Add(new Vertex(1, 5));
            ring.Vertices.Add(new Vertex(5, 5));
            ring.Vertices.Add(new Vertex(5, 1));

            polygonShape.InnerRings.Add(ring);

            winformsMap1.EditOverlay.EditShapesLayer.InternalFeatures.Add(new Feature(polygonShape));
            winformsMap1.EditOverlay.FeatureDragged += EditOverlay_FeatureDragged;

            winformsMap1.Refresh();
        }

        void EditOverlay_FeatureDragged(object sender, FeatureDraggedEditInteractiveOverlayEventArgs e)
        {
            Feature f = winformsMap1.EditOverlay.EditShapesLayer.InternalFeatures[0];
            bool isValid = customValidate(f.GetShape() as PolygonShape);
        }

        private bool customValidate(PolygonShape polygon)
        {
            if (polygon.InnerRings.Count > 0)
            {
                bool isvalid = polygon.OuterRing.Validate(ShapeValidationMode.Simple).IsValid;

                foreach (RingShape ring in polygon.InnerRings)
                {
                    if (!polygon.OuterRing.ToPolygon().Contains(ring.ToPolygon()))
                    {
                        isvalid = false;
                        break;
                    }
                }

                return isvalid;
            }
            else
            {
                return polygon.Validate(ShapeValidationMode.Simple).IsValid;
            }
        } 
 
  
 Wish that’s helpful.  
  
 Regards,  
  
 Don

Thanks,



After posting I did add some extra validation to check that all inner rings are contained within the outer ring but did it at the end of editing rather than as the vertices were dragged.  The code for the actual checking is similar, although I allowed for the possibility of having a MultiPolygon or a simple Polygon and the contains statement was slightly different.



I used: polygon.OuterRing.Contains(ring) rather than using .ToPolygon() on the rings.  This appeared to work but is it OK?



Regards,

Jonathan

Hi Jonathan, 
  
 Yes you can do that, I used to Polygon is my habit, in fact the ring shape is based on area shape. 
  
 Regards, 
  
 Don

OK, thanks. 
 Jonathan

Hi Jonathan, 
  
 Any question please feel free to let us know. 
  
 Regards, 
  
 Don