001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.validation.spatial;
017:
018: import java.util.logging.Level;
019: import java.util.logging.Logger;
020:
021: import org.geotools.feature.Feature;
022: import org.geotools.feature.FeatureType;
023: import org.geotools.validation.DefaultFeatureValidation;
024: import org.geotools.validation.ValidationResults;
025:
026: import com.vividsolutions.jts.geom.Coordinate;
027: import com.vividsolutions.jts.geom.GeometryFactory;
028: import com.vividsolutions.jts.geom.LineString;
029:
030: /**
031: * LineNoSelfIntersectFeatureValidation purpose.
032: *
033: * <p>
034: * Tests to see if a geometry crosses itself. It does not detect if a
035: * segment of a LineString doubles back on itself for one segment, then
036: * terminates. A different validation is needed to test overlapping. Uses JTS'
037: * crosses routine.
038: * </p>
039: *
040: * <p>
041: * Example Use:
042: * <pre><code>
043: * LineNoSelfIntersectFeatureValidation x = new LineNoSelfIntersectFeatureValidation("noSelfIntersectRoads", "Tests to see if a
044: * geometry intersects itself", new String[] {"road"});
045: * </code></pre>
046: * </p>
047: *
048: * @author bowens, Refractions Research, Inc.
049: * @author $Author: jive $ (last modification)
050: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/validation/src/main/java/org/geotools/validation/spatial/LineNoSelfIntersectValidation.java $
051: * @version $Id: LineNoSelfIntersectValidation.java 27862 2007-11-12 19:51:19Z desruisseaux $
052: * - bowens: changed intersects to crosses
053: */
054: public class LineNoSelfIntersectValidation extends
055: DefaultFeatureValidation {
056: /** The logger for the validation module. */
057: private static final Logger LOGGER = org.geotools.util.logging.Logging
058: .getLogger("org.geotools.validation");
059:
060: /**
061: * LineNoSelfIntersectFeatureValidation constructor.
062: *
063: * <p>
064: * Description
065: * </p>
066: */
067: public LineNoSelfIntersectValidation() {
068: }
069:
070: /**
071: * Override getPriority.
072: *
073: * <p>
074: * Sets the priority level of this validation. This is set by the
075: * programmer and is a measure of the expense of this plugin
076: * </p>
077: *
078: * @return A made up priority for this validation.
079: *
080: * @see org.geotools.validation.Validation#getPriority()
081: */
082: public int getPriority() {
083: return PRIORITY_COMPLEX;
084: }
085:
086: /**
087: * Override validate.
088: *
089: * <p>
090: * Tests to see if a geometry intersects itself. It does not detect if a
091: * segment of a LineString doubles back on itself for one segment, then
092: * terminates. A different validation is needed to test overlapping. Uses
093: * JTS' intersect routine.
094: * </p>
095: *
096: * @param feature The Feature to be validated.
097: * @param type The FeatureTypeInfo of the feature.
098: * @param results The storage for error messages.
099: *
100: * @return True if the feature does not self intersect.
101: *
102: * @see org.geotools.validation.FeatureValidation#validate(org.geotools.feature.Feature,
103: * org.geotools.feature.FeatureTypeInfo,
104: * org.geotools.validation.ValidationResults)
105: */
106: public boolean validate(Feature feature, FeatureType type,
107: ValidationResults results) {
108: LOGGER.setLevel(Level.ALL);
109:
110: LineString line = null;
111: try {
112: line = getDefaultLineString(feature);
113: } catch (ClassCastException unLine) {
114: results.error(feature,
115: "Geometry is required to be a LineString");
116: System.out
117: .println(feature.getID() + " name: " + getName());
118: System.out.println(feature.getID() + " ref: "
119: + getTypeRef());
120: System.out.println(feature.getID() + " ref: "
121: + getTypeRefs());
122: }
123: if (line == null) {
124: // Ignore null geometry (user can check with nullZero )
125: return true;
126: }
127: if (line.getNumPoints() < 2) {
128: results.warning(feature,
129: "LineString contains too few points");
130: return false;
131: }
132: GeometryFactory gf = new GeometryFactory();
133:
134: int numPoints = line.getNumPoints();
135:
136: // break up the LineString into line segments
137: LineString[] segments = new LineString[numPoints - 1];
138:
139: for (int i = 0; i < (numPoints - 1); i++) {
140: Coordinate[] coords = new Coordinate[] {
141: line.getCoordinateN(i), line.getCoordinateN(i + 1) };
142: segments[i] = gf.createLineString(coords);
143: }
144:
145: // intersect all of the line segments with each other
146: for (int i = 0; i < segments.length; i++) // for each line segment
147: {
148: for (int j = 0; j < segments.length; j++) // intersect with every other line segment
149: {
150: if ((i != j) && ((i - 1) != j) && ((i + 1) != j)) // if they aren't the same segment
151: {
152: if (segments[i].crosses(segments[j])) // changed to crosses - bowens
153: {
154: // log the error and return
155: results.error(feature,
156: "LineString crossed itself");
157: return false;
158: }
159: }
160: }
161: }
162: return true;
163: }
164: }
|