Class GeometryNoder

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12  
 13 package org.locationtech.jts.noding.snapround;
 14  
 15 import java.util.ArrayList;
 16 import java.util.Collection;
 17 import java.util.Iterator;
 18 import java.util.List;
 19  
 20 import org.locationtech.jts.geom.Geometry;
 21 import org.locationtech.jts.geom.GeometryFactory;
 22 import org.locationtech.jts.geom.LineString;
 23 import org.locationtech.jts.geom.PrecisionModel;
 24 import org.locationtech.jts.geom.util.LinearComponentExtracter;
 25 import org.locationtech.jts.noding.NodedSegmentString;
 26 import org.locationtech.jts.noding.Noder;
 27 import org.locationtech.jts.noding.NodingValidator;
 28 import org.locationtech.jts.noding.SegmentString;
 29  
 30 /**
 31  * Nodes the linework in a list of {@link Geometry}s using Snap-Rounding
 32  * to a given {@link PrecisionModel}.
 33  * <p>
 34  * The input coordinates are expected to be rounded
 35  * to the given precision model.
 36  * This class does not perform that function.
 37  * <code>GeometryPrecisionReducer</code> may be used to do this.
 38  * <p>
 39  * This class does <b>not</b> dissolve the output linework,
 40  * so there may be duplicate linestrings in the output.  
 41  * Subsequent processing (e.g. polygonization) may require
 42  * the linework to be unique.  Using <code>UnaryUnion</code> is one way
 43  * to do this (although this is an inefficient approach).
 44  * 
 45  * 
 46  */
 47 public class GeometryNoder
 48 {
 49   private GeometryFactory geomFact;
 50   private PrecisionModel pm;
 51   private boolean isValidityChecked = false;
 52  
 53   /**
 54    * Creates a new noder which snap-rounds to a grid specified
 55    * by the given {@link PrecisionModel}.
 56    * 
 57    * @param pm the precision model for the grid to snap-round to
 58    */
 59   public GeometryNoder(PrecisionModel pm) {
 60     this.pm = pm;
 61   }
 62  
 63   /**
 64    * Sets whether noding validity is checked after noding is performed.
 65    * 
 66    * @param isValidityChecked
 67    */
 68   public void setValidate(boolean isValidityChecked)
 69   {
 70       this.isValidityChecked = isValidityChecked;
 71   }
 72   
 73   /**
 74    * Nodes the linework of a set of Geometrys using SnapRounding. 
 75    * 
 76    * @param geoms a Collection of Geometrys of any type
 77    * @return a List of LineStrings representing the noded linework of the input
 78    */
 79   public List node(Collection geoms)
 80   {
 81     // get geometry factory
 82     Geometry geom0 = (Geometry) geoms.iterator().next();
 83     geomFact = geom0.getFactory();
 84  
 85     List segStrings = toSegmentStrings(extractLines(geoms));
 86     //Noder sr = new SimpleSnapRounder(pm);
 87     Noder sr = new MCIndexSnapRounder(pm);
 88     sr.computeNodes(segStrings);
 89     Collection nodedLines = sr.getNodedSubstrings();
 90  
 91     //TODO: improve this to check for full snap-rounded correctness
 92     if (isValidityChecked) {
 93         NodingValidator nv = new NodingValidator(nodedLines);
 94         nv.checkValid();
 95     }
 96  
 97     return toLineStrings(nodedLines);
 98   }
 99  
100   private List toLineStrings(Collection segStrings)
101   {
102     List lines = new ArrayList();
103     for (Iterator it = segStrings.iterator(); it.hasNext(); ) {
104       SegmentString ss = (SegmentString) it.next();
105       // skip collapsed lines
106       if (ss.size() < 2)
107           continue;
108       lines.add(geomFact.createLineString(ss.getCoordinates()));
109     }
110     return lines;
111   }
112  
113   private List extractLines(Collection geoms)
114   {
115     List lines = new ArrayList();
116     LinearComponentExtracter lce = new LinearComponentExtracter(lines);
117     for (Iterator it = geoms.iterator(); it.hasNext(); ) {
118       Geometry geom = (Geometry) it.next();
119       geom.apply(lce);
120     }
121     return lines;
122   }
123  
124   private List toSegmentStrings(Collection lines)
125   {
126     List segStrings = new ArrayList();
127     for (Iterator it = lines.iterator(); it.hasNext(); ) {
128       LineString line = (LineString) it.next();
129       segStrings.add(new NodedSegmentString(line.getCoordinates(), null));
130     }
131     return segStrings;
132   }
133 }
134