/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.revolsys.geometry.noding;
import java.util.Collection;
import java.util.List;
import com.revolsys.geometry.algorithm.LineIntersector;
import com.revolsys.geometry.algorithm.RobustLineIntersector;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.TopologyException;
import com.revolsys.record.io.format.wkt.EWktWriter;
/**
* Validates that a collection of {@link SegmentString}s is correctly noded.
* Indexing is used to improve performance.
* In the most common use case, validation stops after a single
* non-noded intersection is detected,
* but the class can be requested to detect all intersections
* by using the {@link #setFindAllIntersections(boolean)} method.
* <p>
* The validator does not check for a-b-a topology collapse situations.
* <p>
* The validator does not check for endpoint-interior vertex intersections.
* This should not be a problem, since the JTS noders should be
* able to compute intersections between vertices correctly.
* <p>
* The client may either test the {@link #isValid()} condition,
* or request that a suitable {@link TopologyException} be thrown.
*
* @version 1.7
*/
public class FastNodingValidator {
private boolean findAllIntersections = false;
private boolean isValid = true;
private final LineIntersector li = new RobustLineIntersector();
private InteriorIntersectionFinder segInt = null;
private final Collection segStrings;
/**
* Creates a new noding validator for a given set of linework.
*
* @param segStrings a collection of {@link SegmentString}s
*/
public FastNodingValidator(final Collection segStrings) {
this.segStrings = segStrings;
}
private void checkInteriorIntersections() {
/**
* MD - It may even be reliable to simply check whether
* end segments (of SegmentStrings) have an interior intersection,
* since noding should have split any true interior intersections already.
*/
this.isValid = true;
this.segInt = new InteriorIntersectionFinder(this.li);
this.segInt.setFindAllIntersections(this.findAllIntersections);
final MCIndexNoder noder = new MCIndexNoder();
noder.setSegmentIntersector(this.segInt);
noder.computeNodes(this.segStrings);
if (this.segInt.hasIntersection()) {
this.isValid = false;
return;
}
}
/**
* Checks for an intersection and throws
* a TopologyException if one is found.
*
* @throws TopologyException if an intersection is found
*/
public void checkValid() {
execute();
if (!this.isValid) {
final String errorMessage = getErrorMessage();
final Point interiorIntersection = this.segInt.getInteriorIntersection();
throw new TopologyException(errorMessage, interiorIntersection);
}
}
private void execute() {
if (this.segInt != null) {
return;
}
checkInteriorIntersections();
}
/**
* Returns an error message indicating the segments containing
* the intersection.
*
* @return an error message documenting the intersection location
*/
public String getErrorMessage() {
if (this.isValid) {
return "no intersections found";
}
final Point[] intSegs = this.segInt.getIntersectionSegments();
return "found non-noded intersection between " + EWktWriter.lineString(intSegs[0], intSegs[1])
+ " and " + EWktWriter.lineString(intSegs[2], intSegs[3]);
}
public List getIntersections() {
return this.segInt.getIntersections();
}
/**
* Checks for an intersection and
* reports if one is found.
*
* @return true if the arrangement contains an interior intersection
*/
public boolean isValid() {
execute();
return this.isValid;
}
public void setFindAllIntersections(final boolean findAllIntersections) {
this.findAllIntersections = findAllIntersections;
}
}