ThinkGeo.com    |     Blog    |     Wiki    |     Support

FileGeoDatabase - Shape Does Not Pass Simple Validation

MapSuite Team,

I’m currently implementing FileGeoDatabaseFeatureLayer for the first time. I’m using the latest ThinkGeo V10.5.x modules.

The “Shape Does Not Pass Simple Validation” error appears only when a label is applied to the Building_Poly layer.

The Drawn & Drawing Exceptions are set for both LayerOverlay and Layer with the exception being captured by the LayerOverlay.

This error is also encountered when invoking QueryTools.GetFeaturesNearestTo, whether or not there is a label configured for the layer.

The IsGeometryValid method does return false on a number of features.

This data is from a third-party so it will prove difficult to have repaired.

Is there some way to detect and ignore this error during the rendering process? Is it possible to populate the FeatureSource.FeatureIdsToExclude collection with the invalid features so that said features are excluded from rendering?

I downloaded a modified version of your original DisplayFileGeoDatabaseSample-ForWpf-master to my MapSuite File Station, which shows the behavior. It is located in the Applications Folder.

Thanks,
Dennis

Hi Dennis,

I don’t know which step your data met validation, so I am not sure whether FeatureIdsToExclude is useful. I think you did a quickly test, or you can upload a sample data, we can check that.

And I don’t know about the modified version of the sample: https://github.com/ThinkGeo/DisplayFileGeoDatabaseSample-ForWpf

It looks currently version don’t contains the logic you mentioned, but if the sample works, I think you can just use its code.

Regards,

Ethan

hi Ethan,

I uploaded a modified version of your original DisplayFileGeoDatabaseSample-ForWpf-master to my MapSuite File Station, which shows the behavior. It is located in the Applications Folder.

The project has been modified such that it demonstrates the behavior I’ve described.

Thanks,
Dennis

Hi Dennis,

I have a little confused about it, it looks the modified version just implemented the DrawnException and DrawingException event for both overlay and layer, if it works for your scenario, I think you can move this logic to your project.

Because without test data so I am not sure whether it works for your broken data, but I think we hadn’t modify related logic about the events.

Regards,

Ethan

Ethan,

The modified version of the sample I uploaded implements more than just the Drawn & Drawing Exceptions.

It renders the layer name BUILDING_POLY with an area and label.

The data is included in the application directory structure.

What does not work for my project is what I stated in my original post, namely “The “Shape Does Not Pass Simple Validation” error appears only when a label is applied to the Building_Poly layer”.

The other issue arises when there is more than just the BUILDING_POLY layer being rendered. When there are more layers and this error is encountered the other layers stop being rendered.

To make this clearer I have modified the code so that you can see the issue. Copy the code below and replace the exiting map_loaded with this code. This code renders the BUILDING_POLY and WATER layers. The code below as is does not label the BUILDING_POLY layer, hence, both layers are rendered.

So execute the code as is and you will see both layers.

Next go in and uncomment the line with the words Remove Comment, recompile the code and execute. Now you will see only the BUILDING_POLY layer rendered with labels and with errors on the map itself. When labels appear and the error is encountered all other rendering of the map stops.

Does my explanation make sense now?

Thanks,
Dennis

private void map_Loaded(object sender, RoutedEventArgs e)
{
    string TheLogMessage;

    string ThePath;
    string TheTable;

    Collection<string> TheGeoDatabaseTableNames;

    System.Type                            TheSystemType;
    ThinkGeo.MapSuite.Shapes.WellKnownType TheWellKnownType;
    ThinkGeo.MapSuite.Shapes.Projection    TheProjection;

    map.MapUnit = GeographyUnit.DecimalDegree;
    map.MapUnit = GeographyUnit.Feet;

    AreaStyle areaStyle;
    FileGeoDatabaseFeatureLayer fileGeoDatabaseFeatureLayer;

    LayerOverlay layerOverlay = new LayerOverlay();

    // catch MapSuite Drawing Exceptions
    layerOverlay.DrawingExceptionMode = DrawingExceptionMode.DrawException;
    layerOverlay.DrawnException      += new EventHandler<DrawnExceptionTileOverlayEventArgs>  (TheLayerOverlay_DrawnException  );
    layerOverlay.DrawingException    += new EventHandler<DrawingExceptionTileOverlayEventArgs>(TheLayerOverlay_DrawingException);

    ThePath = string.Format("{0}", "../../AppData/Shapes.gdb");
    TheTable = string.Format("{0}", "states");

    ThePath = string.Format("{0}", "../../AppData/Airport.gdb");

    TheTable = string.Format("{0}", "WATER");
    TheTable = string.Format("{0}", "BUILDING_POLY");

    try
    {
        TheGeoDatabaseTableNames = FileGeoDatabaseFeatureLayer.GetTableNames(ThePath);
    }
    catch (Exception ex)
    {
        TheLogMessage = string.Format("FileGeoDatabaseFeatureLayer.GetTableNames({0}{1}Message={1})", ThePath, Environment.NewLine, ex.Message);
    }

    // first layer with issue
    fileGeoDatabaseFeatureLayer = new FileGeoDatabaseFeatureLayer(ThePath, TheTable);
    fileGeoDatabaseFeatureLayer.Open();

    // catch MapSuite Drawing Exceptions
    fileGeoDatabaseFeatureLayer.DrawingExceptionMode = DrawingExceptionMode.DrawException;
    fileGeoDatabaseFeatureLayer.DrawnException      += new EventHandler<DrawnExceptionLayerEventArgs>  (FileGeoDatabaseFeatureLayer_DrawnException  );
    fileGeoDatabaseFeatureLayer.DrawingException    += new EventHandler<DrawingExceptionLayerEventArgs>(FileGeoDatabaseFeatureLayer_DrawingException);

    TheSystemType    = fileGeoDatabaseFeatureLayer.FeatureSource.GetType();
    TheWellKnownType = fileGeoDatabaseFeatureLayer.FeatureSource.GetFirstFeaturesWellKnownType();
    TheProjection    = fileGeoDatabaseFeatureLayer.FeatureSource.Projection;

    areaStyle                      = new AreaStyle();
    areaStyle.FillSolidBrush       = new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214));
    areaStyle.OutlinePen           = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1);
    areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid;
    fileGeoDatabaseFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle;

    // label
    // Remove Comment fileGeoDatabaseFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.CreateSimpleTextStyle("NUMBER", "Arial", 08, DrawingFontStyles.Bold, GeoColor.StandardColors.Black, 1, 1);

    fileGeoDatabaseFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

    layerOverlay.Layers.Add(fileGeoDatabaseFeatureLayer);

    // second layer does not have issue
    TheTable = string.Format("{0}", "WATER");
    fileGeoDatabaseFeatureLayer = new FileGeoDatabaseFeatureLayer(ThePath, TheTable);
    fileGeoDatabaseFeatureLayer.Open();

    // catch MapSuite Drawing Exceptions
    fileGeoDatabaseFeatureLayer.DrawingExceptionMode = DrawingExceptionMode.DrawException;
    fileGeoDatabaseFeatureLayer.DrawnException += new EventHandler<DrawnExceptionLayerEventArgs>(FileGeoDatabaseFeatureLayer_DrawnException);
    fileGeoDatabaseFeatureLayer.DrawingException += new EventHandler<DrawingExceptionLayerEventArgs>(FileGeoDatabaseFeatureLayer_DrawingException);

    TheSystemType = fileGeoDatabaseFeatureLayer.FeatureSource.GetType();
    TheWellKnownType = fileGeoDatabaseFeatureLayer.FeatureSource.GetFirstFeaturesWellKnownType();
    TheProjection = fileGeoDatabaseFeatureLayer.FeatureSource.Projection;

    areaStyle = new AreaStyle();
    areaStyle.FillSolidBrush = new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean);
    areaStyle.OutlinePen = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1);
    areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid;
    fileGeoDatabaseFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle;

    fileGeoDatabaseFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
    layerOverlay.Layers.Add(fileGeoDatabaseFeatureLayer);

    map.Overlays.Add(layerOverlay);

    map.CurrentExtent = fileGeoDatabaseFeatureLayer.GetBoundingBox();
    map.Refresh();
}

Hi Dennis,

That make sense, the reason is 16 items in your data is invalid, so it cannot pass our validation when you try to render label for them.

The solution is simple like this:

Collection<Feature> fs = fileGeoDatabaseFeatureLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.NoColumns);
        
        foreach (Feature f in fs)
        {
            ShapeValidationResult validationResult = f.GetShape().Validate(ShapeValidationMode.Simple);
            if (!validationResult.IsValid)
            {
                fileGeoDatabaseFeatureLayer.FeatureIdsToExclude.Add(f.Id);                    
            }
        }

Then it should works well.

Regards,

Ethan

Ethan,

I incorporated your code snippet and now it works.

Thanks,
Dennis

Hi Dennis,

I am glad to hear that works.

Regards,

Ethan

hi Ethan,

As I stated prior I’ve implemented your suggestion and rendering with labels works fine.

However, when doing a spatial query (based on coordinates at user MouseDown Event) an exception is encountered when one of the invalid features is encountered. The exception is caught in the following code:

        try
        {
            TheQueryExternalFeatures = TheFeatureLayer.QueryTools.GetFeaturesNearestTo(SearchFromPoint, TheMapUnit, 20, TheFeatureColumnsToReturn, TheToleranceX, DistanceUnit.Feet);
        }
        catch (Exception ex)
        {
            oMapLayerItem.cQueryExternalFeatures = null;

            TheLogMessage = string.Format("Unable to QueryTools.GetFeaturesNearestTo{0}Database={1}, MapLayer={2}, LayerName={3}, Lat={4}, Long={5}", Environment.NewLine, oMapLayerItem.ShapeFileDirectoryData, oMapLayerItem.iMapLayer, oMapLayerItem.sGeoDataSet, myVertex.Y, myVertex.X);
            }

The exception encountered is:

2019-08-23 20:14:00,894 ERROR OriStarVisionMapSuite - OriStarVisionMapSuite->SpatialSearches.IdentifyInPlaceLayer:
Unable to QueryTools.GetFeaturesNearestTo
Database=C:\OriStar\Chicago\OriStarVisionMapSuite\MapGeoDatabase\Airport.gdb, MapLayer=10000033, LayerName=Pavement_Poly
System.InvalidOperationException: The shape you provided does not pass our simple validation.This ring is not closed.  To close a ring the last point must be the same as the first point.  All rings must have at least four points.
   at ThinkGeo.MapSuite.ValidatorHelper.CheckShapeIsValidForOperation(BaseShape shape)
   at ThinkGeo.MapSuite.Shapes.BaseShape.GetDistanceTo(BaseShape targetShape, GeographyUnit shapeUnit, DistanceUnit distanceUnit)
   at ThinkGeo.MapSuite.Layers.FeatureSource.GetFeaturesWithinDistanceOfCore(BaseShape targetShape, GeographyUnit unitOfData, DistanceUnit distanceUnit, Double distance, IEnumerable`1 returningColumnNames)
   at ThinkGeo.MapSuite.Layers.FeatureSource.GetFeaturesWithinDistanceOf(BaseShape targetShape, GeographyUnit unitOfData, DistanceUnit distanceUnit, Double distance, IEnumerable`1 returningColumnNames)
   at ThinkGeo.MapSuite.Layers.FeatureSource.GetFeaturesNearestTo(BaseShape targetShape, GeographyUnit unitOfData, Int32 maxItemsToFind, IEnumerable`1 returningColumnNames, Double searchRadius, DistanceUnit unitOfSearchRadius)
   at ThinkGeo.MapSuite.Layers.QueryTools.GetFeaturesNearestTo(BaseShape targetShape, GeographyUnit unitOfData, Int32 maxItemsToFind, IEnumerable`1 returningColumnNames, Double searchRadius, DistanceUnit unitOfSearchRadius)
   at OriStarVisionMapSuite.SpatialSearches.IdentifyInPlaceLayer(PointShape SearchFromPoint) in C:\OriStarMappingIncMapSuiteV10.5\OriStarVisionMapSuite\OriStarVisionMapSuite\cfSpatialSearches.cs:line 416

I would have thought that FeatureIdsToExclude applies to spatial queries as well as Rendering.

Regards,
Dennis

Hi Dennis,

The FeatureIdsToExclude only works for render shapes but not works for other API, if possible please fix invalid shapes to avoid met the same problem.

And in your scenario, if you want to make it works, you can override GetAllFeaturesCore, then remove the features included by FeatureIdsToExclude from return collection.

Regards,

Ethan

Thanks for the explanation.

Hi Dennis,

If you met other problem after override it please feel free to let us know.

Regards,

Ethan