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

Reply via email to