Mike, i have an unneeded invalid import visad.data.netcdf.in.Merger; now.
.. ede On 27.12.2015 17:02, jump-pilot-...@lists.sourceforge.net wrote: > Revision: 4696 > http://sourceforge.net/p/jump-pilot/code/4696 > Author: michaudm > Date: 2015-12-27 16:02:32 +0000 (Sun, 27 Dec 2015) > Log Message: > ----------- > Improvements to MakeValidOp (work in progress) > > Modified Paths: > -------------- > core/trunk/src/com/vividsolutions/jump/geom/MakeValidOp.java > core/trunk/src/org/openjump/core/ui/plugin/tools/MakeValidPlugIn.java > > Modified: core/trunk/src/com/vividsolutions/jump/geom/MakeValidOp.java > =================================================================== > --- core/trunk/src/com/vividsolutions/jump/geom/MakeValidOp.java > 2015-12-27 14:20:56 UTC (rev 4695) > +++ core/trunk/src/com/vividsolutions/jump/geom/MakeValidOp.java > 2015-12-27 16:02:32 UTC (rev 4696) > @@ -8,24 +8,46 @@ > import com.vividsolutions.jts.noding.IntersectionAdder; > import com.vividsolutions.jts.noding.MCIndexNoder; > import com.vividsolutions.jts.noding.NodedSegmentString; > +import com.vividsolutions.jts.operation.linemerge.LineMerger; > import com.vividsolutions.jts.operation.polygonize.Polygonizer; > +import visad.data.netcdf.in.Merger; > > -import java.util.ArrayList; > -import java.util.Arrays; > -import java.util.Collection; > -import java.util.List; > +import java.util.*; > + > import static > com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory.*; > > /** > * Operator to make a geometry valid. > + * <br/> > + * Making a geometry valid will remove duplicate points although duplicate > points > + * do not make a geometry invalid. > */ > public class MakeValidOp { > > private static final Coordinate[] EMPTY_COORD_ARRAY = new Coordinate[0]; > private static final LinearRing[] EMPTY_RING_ARRAY = new LinearRing[0]; > > + // If preserveGeomDim is true, geometry components with a dimension > lesser than > + // input geometry dimension are ignored (except if input geometry is an > heterogeneous > + // GeometryCollection) > + private boolean preserveGeomDim = false; > + > + // If preserveCoordDim is true, MakeValidOp preserves third and fourth > ordinates. > + // If preserveCoordDim is false, third dimension is preserved but not > fourth one. > + private boolean preserveCoordDim = false; > + > public MakeValidOp() {} > > + public MakeValidOp preserveGeomDim() { > + this.preserveGeomDim = true; > + return this; > + } > + > + public MakeValidOp preserveCoordDim() { > + this.preserveCoordDim = true; > + return this; > + } > + > /** > * Decompose a geometry recursively into simple components. > * @param geometry input geometry > @@ -40,9 +62,6 @@ > } > > > - public static Geometry makeValid(Geometry geometry) { > - return makeValid(geometry, true); > - } > > /** > * Repair an invalid geometry. > @@ -58,10 +77,9 @@ > * their M value after the noding or the polygonization phase. > * TODO add an option to return a geometry preserving input dimension > * @param geometry input geometry > - * @param removeDuplicate > * @return > */ > - public static Geometry makeValid(Geometry geometry, boolean > removeDuplicate) { > + public Geometry makeValid(Geometry geometry) { > List<Geometry> list = new > ArrayList<Geometry>(geometry.getNumGeometries()); > decompose(geometry, list); > List<Geometry> list2 = new ArrayList<Geometry>(); > @@ -71,19 +89,22 @@ > if (!p.isEmpty()) list2.add(p); > } > else if (component instanceof LineString) { > - Geometry geom = makeLineStringValid((LineString) component, > removeDuplicate); > + Geometry geom = makeLineStringValid((LineString) component); > for (int i = 0 ; i < geom.getNumGeometries() ; i++) { > if (!geom.getGeometryN(i).isEmpty()) > list2.add(geom.getGeometryN(i)); > } > } > else if (component instanceof Polygon) { > - Geometry geom = makePolygonValid((Polygon) component, > removeDuplicate); > + Geometry geom = makePolygonValid((Polygon) component); > for (int i = 0 ; i < geom.getNumGeometries() ; i++) { > if (!geom.getGeometryN(i).isEmpty()) > list2.add(geom.getGeometryN(i)); > } > } > else assert false : "Should never reach here"; > } > + if (preserveGeomDim && > !geometry.getClass().getSimpleName().equals("GeometryCollection")) { > + list2 = removeLowerDimension(list2, geometry.getDimension()); > + } > if (list2.isEmpty()) { > GeometryFactory factory = geometry.getFactory(); > if (geometry instanceof Point) return > factory.createPoint((Coordinate)null); > @@ -100,9 +121,23 @@ > } > } > > + // Remove geometries with a dimension less than dimension parameter > + private List<Geometry> removeLowerDimension(List<Geometry> geometries, > int dimension) { > + List<Geometry> list = new ArrayList<Geometry>(); > + for (Geometry geom : geometries) { > + if (geom.getDimension() == dimension) { > + list.add(geom); > + } > + } > + return list; > + } > + > // If X or Y is null, return an empty Point > - private static Point makePointValid(Point point) { > + private Point makePointValid(Point point) { > CoordinateSequence sequence = point.getCoordinateSequence(); > + // The case where sequence contains more than one point is not > + // processed (it will return an empty point or the input point > + // unchanged) > if (Double.isNaN(sequence.getOrdinate(0, 0)) || > Double.isNaN(sequence.getOrdinate(0, 1))) { > return point.getFactory().createPoint(DOUBLE_FACTORY.create(0, > sequence.getDimension())); > } else { > @@ -169,14 +204,11 @@ > * <ul> > * <li>an empty LineString if input CoordinateSequence has no valid > point</li> > * <li>a Point if input CoordinateSequence has a single valid > Point</li> > - * <li>a LineString retaining or not duplicate coordinates depending > on > - * removeDuplicate parameter</li> > * </ul> > * @param lineString > - * @param removeDuplicate > * @return > */ > - private static Geometry makeLineStringValid(LineString lineString, > boolean removeDuplicate) { > + private Geometry makeLineStringValid(LineString lineString) { > CoordinateSequence sequence = lineString.getCoordinateSequence(); > CoordinateSequence sequenceWithoutDuplicates = > makeSequenceValid(sequence, true, false); > if (sequenceWithoutDuplicates.size() == 0) { > @@ -185,12 +217,9 @@ > } else if (sequenceWithoutDuplicates.size() == 1) { > // a single valid point -> returns a Point > return > lineString.getFactory().createPoint(sequenceWithoutDuplicates); > - } else if (removeDuplicate) { > + } else { > // we use already calculated sequenceWithoutDuplicates > return > lineString.getFactory().createLineString(sequenceWithoutDuplicates); > - } else { > - // we need to recompute a sequence retaining duplicates but not > coordinates with NaN X or Y > - return > lineString.getFactory().createLineString(makeSequenceValid(sequence, false, > false)); > } > } > > @@ -205,15 +234,14 @@ > * <li>a GeometryCollection if input has degenerate parts (ex. > degenerate holes)</li> > * </ul> > * @param polygon > - * @param removeDuplicate > * @return > */ > - private static Geometry makePolygonValid(Polygon polygon, boolean > removeDuplicate) { > + private Geometry makePolygonValid(Polygon polygon) { > //This first step analyze linear components and create degenerate > geometries > //of dimension 0 or 1 if they do not form valid LinearRings > //If degenerate geometries are found, it may produce a > GeometryCollection with > //heterogeneous dimension > - Geometry geom = makePolygonComponentsValid(polygon, removeDuplicate); > + Geometry geom = makePolygonComponentsValid(polygon); > List<Geometry> list = new ArrayList<Geometry>(); > for (int i = 0 ; i < geom.getNumGeometries() ; i++) { > Geometry component = geom.getGeometryN(i); > @@ -241,19 +269,18 @@ > * GeometryCollection of heterogeneous dimension. > * </p> > * @param polygon > - * @param removeDuplicate > * @return > */ > - private static Geometry makePolygonComponentsValid(Polygon polygon, > boolean removeDuplicate) { > + private Geometry makePolygonComponentsValid(Polygon polygon) { > GeometryFactory factory = polygon.getFactory(); > CoordinateSequence outerRingSeq = > makeSequenceValid(polygon.getExteriorRing().getCoordinateSequence(), true, > true); > // The validated sequence of the outerRing does not form a valid > LinearRing > // -> build valid 0-dim or 1-dim geometry from all the rings > if (outerRingSeq.size() == 0 || outerRingSeq.size() < 4) { > List<Geometry> list = new ArrayList<Geometry>(); > - if (outerRingSeq.size() > 0) > list.add(makeLineStringValid(polygon.getExteriorRing(), removeDuplicate)); > + if (outerRingSeq.size() > 0) > list.add(makeLineStringValid(polygon.getExteriorRing())); > for (int i = 0 ; i < polygon.getNumInteriorRing() ; i++) { > - Geometry g = > makeLineStringValid(polygon.getInteriorRingN(i), removeDuplicate); > + Geometry g = > makeLineStringValid(polygon.getInteriorRingN(i)); > if (!g.isEmpty()) list.add(g); > } > if (list.isEmpty()) return factory.createPolygon(outerRingSeq); > @@ -290,7 +317,7 @@ > * @param geometry the geometry from which polygonal components wil be > extracted > * @param list the list into which polygonal components will be added. > */ > - protected static void extractPolygons(Geometry geometry, List<Polygon> > list) { > + protected void extractPolygons(Geometry geometry, List<Polygon> list) { > for (int i = 0 ; i < geometry.getNumGeometries() ; i++) { > Geometry g = geometry.getGeometryN(i); > if (g == null) continue; // null components are > discarded > @@ -323,7 +350,7 @@ > * <li>remove Geometries computed from noded interior boundaries</li> > * </ul> > */ > - protected static Geometry nodePolygon(Polygon polygon) { > + protected Geometry nodePolygon(Polygon polygon) { > LinearRing exteriorRing = (LinearRing)polygon.getExteriorRing(); > Geometry geom = getMultiPolygonFromLinearRing(exteriorRing); > for (int i = 0 ; i < polygon.getNumInteriorRing() ; i++) { > @@ -341,18 +368,21 @@ > * </ul> > * This is used to repair auto-intersecting Polygons > */ > - protected static MultiPolygon getMultiPolygonFromLinearRing(LinearRing > ring) { > + protected Geometry getMultiPolygonFromLinearRing(LinearRing ring) { > if (ring.isSimple()) { > return ring.getFactory().createMultiPolygon(new Polygon[]{ > ring.getFactory().createPolygon(ring, EMPTY_RING_ARRAY) > }); > } > else { > - // TODO according to MD, we need to remove duplicate linestring > before polygonizing > Polygonizer polygonizer = new Polygonizer(); > polygonizer.add(nodeLineString(ring.getCoordinates(), > ring.getFactory())); > - Collection<Polygon> polys = polygonizer.getPolygons(); > - return ring.getFactory().createMultiPolygon(polys.toArray(new > Polygon[polys.size()])); > + Collection<Geometry> geoms = new ArrayList<Geometry>(); > + geoms.addAll(polygonizer.getPolygons()); > + geoms.addAll(polygonizer.getCutEdges()); > + geoms.addAll(polygonizer.getDangles()); > + geoms.addAll(polygonizer.getInvalidRingLines()); > + return ring.getFactory().buildGeometry(geoms); > } > } > > @@ -366,7 +396,7 @@ > * @param gf geometryFactory to use > * @return a list of noded LineStrings > */ > - protected static List<LineString> nodeLineString(Coordinate[] coords, > GeometryFactory gf) { > + protected Set<LineString> nodeLineString(Coordinate[] coords, > GeometryFactory gf) { > MCIndexNoder noder = new MCIndexNoder(); > noder.setSegmentIntersector(new IntersectionAdder(new > RobustLineIntersector())); > List<NodedSegmentString> list = new ArrayList<NodedSegmentString>(); > @@ -378,31 +408,50 @@ > ((NodedSegmentString)segmentString).getCoordinates() > )); > } > - return lineStringList; > + > + // WARNING : merger loose original linestrings > + // It is useful for LinearRings but should not be used for > (Multi)LineStrings > + LineMerger merger = new LineMerger(); > + merger.add(lineStringList); > + lineStringList = (List<LineString>)merger.getMergedLineStrings(); > + > + // Remove duplicate linestrings preserving main orientation > + Set<LineString> lineStringSet = new HashSet<LineString>(); > + for (LineString line : lineStringList) { > + if (lineStringSet.contains(line) || > lineStringSet.contains(line.reverse())) { > + continue; > + } else { > + lineStringSet.add(line); > + } > + } > + return lineStringSet; > } > > > > public static void main(String[] args) throws ParseException { > GeometryFactory factory = new GeometryFactory(); > + MakeValidOp op = new MakeValidOp(); > + MakeValidOp opClean = new MakeValidOp().preserveGeomDim(); > + Geometry input, result; > > // check makePointValid > Point p1 = factory.createPoint(new Coordinate(0,0)); > - Point p2 = makePointValid(p1); > + Point p2 = op.makePointValid(p1); > assert p1.equals(p2); > > p1 = factory.createPoint(new Coordinate(Double.NaN,0)); > - p2 = makePointValid(p1); > + p2 = op.makePointValid(p1); > assert !p1.isEmpty(); > assert p2.isEmpty(); > > p1 = factory.createPoint(new Coordinate(0, Double.NaN)); > - p2 = makePointValid(p1); > + p2 = op.makePointValid(p1); > assert !p1.isEmpty(); > assert p2.isEmpty(); > > p1 = factory.createPoint(DOUBLE_FACTORY.create(new > double[]{0,1,2,3}, 4)); > - p2 = makePointValid(p1); > + p2 = op.makePointValid(p1); > assert p1.getCoordinateSequence().getOrdinate(0,3) == > p2.getCoordinateSequence().getOrdinate(0,3); > > // check makeSequenceValid > @@ -446,19 +495,36 @@ > assert cs2.getOrdinate(3,3) == 3 : cs2.getOrdinate(3,3); > > WKTReader reader = new WKTReader(); > - Geometry geometry = reader.read("LINESTRING(0 0, 10 0, 20 0, 20 0, > 30 0)"); > - assert geometry.getNumPoints() == 5; > - List<LineString> list = nodeLineString(geometry.getCoordinates(), > geometry.getFactory()); > - assert list.size() == 1; > - assert list.get(0).getCoordinates().length == 5; > + // invalid polygon (single linearRing drawing 2 triangles joined by > a line) > + input = reader.read("POLYGON (( 322 354, 322 348, 325 351, 328 351, > 331 348, 331 354, 328 351, 325 351, 322 354 ))"); > + result = op.makeValid(input); > + assert result.getNumGeometries() == 3; > + result = opClean.makeValid(input); > + assert result.getNumGeometries() == 2; > > - geometry = reader.read("LINESTRING(0 0, 20 0, 20 20, 20 20, 10 > -10)"); > - assert geometry.getNumPoints() == 5; > - list = nodeLineString(geometry.getCoordinates(), > geometry.getFactory()); > - assert list.size() == 5; // creates a degenerate segment from 20 20 > to 20 20 > + reader = new WKTReader(); > + // invalid polygon (single linearRing drawing 2 triangles joined by > a line, first triangle has duplicated segments) > + input = reader.read("POLYGON (( 322 354, 322 348, 322 354, 322 348, > 325 351, 328 351, 331 348, 331 354, 328 351, 325 351, 322 354 ))"); > + result = op.makeValid(input); > + assert result.getNumGeometries() == 3; > + result = opClean.makeValid(input); > + assert result.getNumGeometries() == 2; > > + > + reader = new WKTReader(); > + input = reader.read("LINESTRING(0 0, 10 0, 20 0, 20 0, 30 0)"); > + assert input.getNumPoints() == 5; > + Set<LineString> set = op.nodeLineString(input.getCoordinates(), > input.getFactory()); > + assert set.size() == 1; > + assert set.iterator().next().getCoordinates().length == 4; // > removed duplicate coordinate > + > + input = reader.read("LINESTRING(0 0, 20 0, 20 20, 20 20, 10 -10)"); > + assert input.getNumPoints() == 5; > + set = op.nodeLineString(input.getCoordinates(), input.getFactory()); > + assert set.size() == 3; // node + merge -> 3 line strings > + > Polygonizer polygonizer = new Polygonizer(); > - polygonizer.add(list); > + polygonizer.add(set); > Collection<Polygon> polys = polygonizer.getPolygons(); > System.out.println(polys); > > > Modified: > core/trunk/src/org/openjump/core/ui/plugin/tools/MakeValidPlugIn.java > =================================================================== > --- core/trunk/src/org/openjump/core/ui/plugin/tools/MakeValidPlugIn.java > 2015-12-27 14:20:56 UTC (rev 4695) > +++ core/trunk/src/org/openjump/core/ui/plugin/tools/MakeValidPlugIn.java > 2015-12-27 16:02:32 UTC (rev 4696) > @@ -108,7 +108,7 @@ > MakeValidOp makeValidOp = new MakeValidOp(); > for (Object o : result1.getFeatures()) { > Feature feature = (Feature)o; > - Geometry validGeom = > MakeValidOp.makeValid(feature.getGeometry()); > + Geometry validGeom = new > MakeValidOp().makeValid(feature.getGeometry()); > if (removeDegenerateParts) validGeom = > removeDegenerateParts(feature.getGeometry(), validGeom); > feature.setGeometry(validGeom); > } > > > ------------------------------------------------------------------------------ > _______________________________________________ > Jump-pilot-devel mailing list > Jump-pilot-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel > ------------------------------------------------------------------------------ _______________________________________________ Jump-pilot-devel mailing list Jump-pilot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel