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)
TopologyException
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