using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; using GisSharpBlog.NetTopologySuite.Geometries.Utilities; namespace GisSharpBlog.NetTopologySuite.Precision { /// /// Reduces the precision of a Geometry /// according to the supplied {PrecisionModel}, without /// attempting to preserve valid topology. /// The topology of the resulting point may be invalid if /// topological collapse occurs due to coordinates being shifted. /// It is up to the client to check this and handle it if necessary. /// Collapses may not matter for some uses. An example /// is simplifying the input to the buffer algorithm. /// The buffer algorithm does not depend on the validity of the input point. /// public class SimpleGeometryPrecisionReducer { private readonly PrecisionModel newPrecisionModel = null; private bool removeCollapsed = true; /// /// /// /// public SimpleGeometryPrecisionReducer(PrecisionModel pm) { ChangePrecisionModel = false; newPrecisionModel = pm; } /// /// Sets whether the reduction will result in collapsed components /// being removed completely, or simply being collapsed to an (invalid) /// Geometry of the same type. /// public bool RemoveCollapsedComponents { get { return removeCollapsed; } set { removeCollapsed = value; } } /// /// Gets/Sets whether the PrecisionModel of the new reduced Geometry /// will be changed to be the PrecisionModel supplied to /// specify the reduction. /// The default is to not change the precision model. /// public bool ChangePrecisionModel { get; set; } /// /// /// /// /// public IGeometry Reduce(IGeometry geom) { GeometryEditor geomEdit; if (ChangePrecisionModel) { GeometryFactory newFactory = new GeometryFactory(newPrecisionModel); geomEdit = new GeometryEditor(newFactory); } else { // don't change point factory geomEdit = new GeometryEditor(); } return geomEdit.Edit(geom, new PrecisionReducerCoordinateOperation(this)); } /// /// /// private class PrecisionReducerCoordinateOperation : GeometryEditor.CoordinateOperation { private readonly SimpleGeometryPrecisionReducer container = null; /// /// /// /// public PrecisionReducerCoordinateOperation(SimpleGeometryPrecisionReducer container) { this.container = container; } /// /// /// /// /// /// public override ICoordinate[] Edit(ICoordinate[] coordinates, IGeometry geom) { if (coordinates.Length == 0) { return null; } ICoordinate[] reducedCoords = new ICoordinate[coordinates.Length]; // copy coordinates and reduce for (int i = 0; i < coordinates.Length; i++) { ICoordinate coord = new Coordinate(coordinates[i]); container.newPrecisionModel.MakePrecise(coord); reducedCoords[i] = coord; } // remove repeated points, to simplify returned point as much as possible CoordinateList noRepeatedCoordList = new CoordinateList(reducedCoords, false); ICoordinate[] noRepeatedCoords = noRepeatedCoordList.ToCoordinateArray(); /* * Check to see if the removal of repeated points * collapsed the coordinate List to an invalid length * for the type of the parent point. * It is not necessary to check for Point collapses, since the coordinate list can * never collapse to less than one point. * If the length is invalid, return the full-length coordinate array * first computed, or null if collapses are being removed. * (This may create an invalid point - the client must handle this.) */ int minLength = 0; if (geom is ILineString) { minLength = 2; } if (geom is ILinearRing) { minLength = 4; } ICoordinate[] collapsedCoords = reducedCoords; if (container.removeCollapsed) { collapsedCoords = null; } // return null or orginal length coordinate array if (noRepeatedCoords.Length < minLength) { return collapsedCoords; } // ok to return shorter coordinate array return noRepeatedCoords; } } } }