001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2004 TOPP - www.openplans.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.validation.relate;
018:
019: import java.io.IOException;
020: import java.util.HashSet;
021: import java.util.Map;
022: import java.util.logging.Logger;
023:
024: import org.geotools.feature.FeatureIterator;
025: import org.geotools.data.FeatureSource;
026: import org.geotools.factory.FactoryConfigurationError;
027: import org.geotools.feature.Feature;
028: import org.geotools.feature.FeatureCollection;
029: import org.geotools.feature.FeatureIterator;
030: import org.geotools.feature.FeatureType;
031: import org.geotools.filter.AttributeExpression;
032: import org.geotools.filter.BBoxExpression;
033: import org.geotools.filter.Filter;
034: import org.geotools.filter.FilterFactory;
035: import org.geotools.filter.FilterFactoryFinder;
036: import org.geotools.filter.GeometryFilter;
037: import org.geotools.filter.IllegalFilterException;
038: import org.geotools.validation.ValidationResults;
039:
040: import com.vividsolutions.jts.geom.Envelope;
041: import com.vividsolutions.jts.geom.Geometry;
042:
043: /**
044: * CrossesIntegrity<br>
045: * @author bowens, ptozer<br>
046: * Created Apr 27, 2004<br>
047: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/validation/src/main/java/org/geotools/validation/relate/CrossesIntegrity.java $
048: * @version <br>
049: *
050: * <b>Puropse:</b><br>
051: * <p>
052: * Tests to see if a Geometry crosses another Geometry.
053: *
054: * <b>Description:</b><br>
055: * <p>
056: * If only one layer is provided, the geometries of that layer are compared with each other.
057: * If two layers are provided, then the geometries are compared across the layers.
058: * </p>
059: *
060: * <b>Usage:</b><br>
061: * <p>
062: * CrossesIntegrity cross = new CrossesIntegrity();
063: * cross.setExpected(false);
064: * cross.setGeomTypeRefA("my:line");
065: *
066: * Map map = new HashMap();
067: * try
068: * {
069: * map.put("my:line", mds.getFeatureSource("line"));
070: * } catch (IOException e1)
071: * {
072: * e1.printStackTrace();
073: * }
074: *
075: * try
076: * {
077: * assertFalse(cross.validate(map, lineBounds, vr));
078: * } catch (Exception e)
079: * {
080: * e.printStackTrace();
081: * }
082: * </p>
083: */
084: public class CrossesIntegrity extends RelationIntegrity {
085: private static final Logger LOGGER = org.geotools.util.logging.Logging
086: .getLogger("org.geotools.validation");
087: private static HashSet usedIDs;
088:
089: /**
090: * CrossesIntegrity Constructor
091: *
092: */
093: public CrossesIntegrity() {
094: super ();
095: usedIDs = new HashSet(); //TODO: remove me later, memory inefficient
096: }
097:
098: /* (non-Javadoc)
099: * @see org.geotools.validation.IntegrityValidation#validate(java.util.Map, com.vividsolutions.jts.geom.Envelope, org.geotools.validation.ValidationResults)
100: */
101: public boolean validate(Map layers, Envelope envelope,
102: ValidationResults results) throws Exception {
103: LOGGER.finer("Starting test " + getName() + " ("
104: + getClass().getName() + ")");
105: String typeRef1 = getGeomTypeRefA();
106: LOGGER.finer(typeRef1 + ": looking up FeatureSource ");
107: FeatureSource geomSource1 = (FeatureSource) layers
108: .get(typeRef1);
109: LOGGER.finer(typeRef1 + ": found "
110: + geomSource1.getSchema().getTypeName());
111:
112: String typeRef2 = getGeomTypeRefB();
113: if (typeRef2 == EMPTY || typeRef1.equals(typeRef2))
114: return validateSingleLayer(geomSource1, isExpected(),
115: results, envelope);
116: else {
117: LOGGER.finer(typeRef2 + ": looking up FeatureSource ");
118: FeatureSource geomSource2 = (FeatureSource) layers
119: .get(typeRef2);
120: LOGGER.finer(typeRef2 + ": found "
121: + geomSource2.getSchema().getTypeName());
122: return validateMultipleLayers(geomSource1, geomSource2,
123: isExpected(), results, envelope);
124: }
125:
126: }
127:
128: /**
129: * <b>validateMultipleLayers Purpose:</b> <br>
130: * <p>
131: * This validation tests for a geometry crosses another geometry.
132: * Uses JTS' Geometry.crosses(Geometry) method.
133: * The DE-9IM intersection matrix for crosses is
134: * T*T****** (for a point and a curve, a point and an area or a line and an area)
135: * 0******** (for two curves)
136: * </p>
137: *
138: * <b>Description:</b><br>
139: * <p>
140: * The function filters the FeatureSources using the given bounding box.
141: * It creates iterators over both filtered FeatureSources. It calls overlaps() and contains()using the
142: * geometries in the FeatureSource layers. Tests the results of the method call against
143: * the given expected results. Returns true if the returned results and the expected results
144: * are true, false otherwise.
145: *
146: * </p>
147: *
148: * Author: bowens<br>
149: * Created on: Apr 27, 2004<br>
150: * @param featureSourceA - the FeatureSource to pull the original geometries from. This geometry is the one that is tested for overlaping with the other
151: * @param featureSourceB - the FeatureSource to pull the other geometries from - these geometries will be those that may overlap the first geometry
152: * @param expected - boolean value representing the user's expected outcome of the test
153: * @param results - ValidationResults
154: * @param bBox - Envelope - the bounding box within which to perform the overlaps() and contains()
155: * @return boolean result of the test
156: * @throws Exception - IOException if iterators improperly closed
157: */
158: private boolean validateMultipleLayers(
159: FeatureSource featureSourceA, FeatureSource featureSourceB,
160: boolean expected, ValidationResults results, Envelope bBox)
161: throws Exception {
162: boolean success = true;
163:
164: FilterFactory ff = FilterFactoryFinder.createFilterFactory();
165: Filter filter = null;
166:
167: //JD: fix this!!
168: //filter = (Filter) ff.createBBoxExpression(bBox);
169:
170: FeatureCollection featureResultsA = featureSourceA
171: .getFeatures(filter);
172: FeatureCollection featureResultsB = featureSourceB
173: .getFeatures(filter);
174:
175: FeatureIterator fr1 = null;
176: FeatureIterator fr2 = null;
177: try {
178: fr1 = featureResultsA.features();
179:
180: if (fr1 == null)
181: return success;
182:
183: while (fr1.hasNext()) {
184: Feature f1 = fr1.next();
185: Geometry g1 = f1.getDefaultGeometry();
186: fr2 = featureResultsB.features();
187:
188: while (fr2 != null && fr2.hasNext()) {
189: Feature f2 = fr2.next();
190: Geometry g2 = f2.getDefaultGeometry();
191: //System.out.println("Do the two overlap?->" + g1.overlaps(g2));
192: //System.out.println("Does the one contain the other?->" + g1.contains(g2));
193: if (g1.overlaps(g2) != expected
194: || g1.contains(g2) != expected) {
195: results.error(f1, f1.getDefaultGeometry()
196: .getGeometryType()
197: + " "
198: + getGeomTypeRefA()
199: + " overlapped "
200: + getGeomTypeRefB()
201: + "("
202: + f2.getID()
203: + "), Result was not " + expected);
204: success = false;
205: }
206: }
207: }
208: } finally {
209: fr1.close();
210: if (fr2 != null)
211: fr2.close();
212: }
213:
214: return success;
215: }
216:
217: /**
218: * <b>validateSingleLayer Purpose:</b> <br>
219: * <p>
220: * This validation tests for a geometry crosses another geometry.
221: * Uses JTS' Geometry.crosses(Geometry) method.
222: * The DE-9IM intersection matrix for crosses is
223: * T*T****** (for a point and a curve, a point and an area or a line and an area)
224: * 0******** (for two curves)
225: * </p>
226: *
227: * <b>Description:</b><br>
228: * <p>
229: * The function filters the FeatureSource using the given bounding box.
230: * It creates iterators over the filtered FeatureSource. It calls overlaps() and contains() using the
231: * geometries in the FeatureSource layer. Tests the results of the method calls against
232: * the given expected results. Returns true if the returned results and the expected results
233: * are true, false otherwise.
234: *
235: * </p> *
236: * Author: bowens<br>
237: * Created on: Apr 27, 2004<br>
238: * @param featureSourceA - the FeatureSource to pull the original geometries from. This geometry is the one that is tested for overlapping itself
239: * @param expected - boolean value representing the user's expected outcome of the test
240: * @param results - ValidationResults
241: * @param bBox - Envelope - the bounding box within which to perform the overlaps() and contains()
242: * @return boolean result of the test
243: * @throws Exception - IOException if iterators improperly closed
244: */
245: private boolean validateSingleLayer(FeatureSource featureSourceA,
246: boolean expected, ValidationResults results, Envelope bBox)
247: throws Exception {
248: boolean success = true;
249:
250: FeatureType ft = featureSourceA.getSchema();
251:
252: Filter filter = filterBBox(bBox, ft);
253:
254: //FeatureResults featureResults = featureSourceA.getFeatures(filter);
255: FeatureCollection featureResults = featureSourceA.getFeatures();
256:
257: FeatureIterator fr1 = null;
258: FeatureIterator fr2 = null;
259: try {
260: fr1 = featureResults.features();
261:
262: if (fr1 == null)
263: return success;
264:
265: while (fr1.hasNext()) {
266: //System.out.println("Single layer Outer loop count: " + loopCt1);
267: Feature f1 = fr1.next();
268: // System.out.println("overlapFilter " + overlapsFilter.contains(f1));
269: // System.out.println("containsFilter " + containsFilter.contains(f1));
270: //System.out.println("Filter " + filter.contains(f1));
271: // System.out.println("f1 = " + f1.getDefaultGeometry().getEnvelope());
272: // System.out.println("env1 = " + bBox);
273:
274: Geometry g1 = f1.getDefaultGeometry();
275: Filter filter2 = filterBBox(g1.getEnvelope()
276: .getEnvelopeInternal(), ft);
277:
278: //FeatureResults featureResults2 = featureSourceA.getFeatures(filter2);
279: FeatureCollection featureResults2 = featureSourceA
280: .getFeatures();
281: fr2 = featureResults2.features();
282: while (fr2 != null && fr2.hasNext()) {
283: Feature f2 = fr2.next();
284: //System.out.println("Filter2 " + filter2.contains(f2));
285: Geometry g2 = f2.getDefaultGeometry();
286: //System.out.println("Do the two overlap?->" + g1.overlaps(g2));
287: //System.out.println("Does the one contain the other?->" + g1.contains(g2));
288: if (!usedIDs.contains(f2.getID())) {
289:
290: if (!f1.getID().equals(f2.getID())) // if they are the same feature, move onto the next one
291: {
292: if (g1.crosses(g2) != expected) {
293: //results.error( f1, f1.getDefaultGeometry().getGeometryType()+" "+getGeomTypeRefA()+"("+f1.getID()+")"+" crossed "+getGeomTypeRefA()+"("+f2.getID()+"), Result was not "+expected );
294: results.error(f1, getGeomTypeRefA()
295: + "(" + f1.getID() + ")"
296: + " crossed "
297: + getGeomTypeRefA() + "("
298: + f2.getID() + ")");
299: System.out.println(f1
300: .getDefaultGeometry()
301: .getGeometryType()
302: + " "
303: + getGeomTypeRefA()
304: + "("
305: + f1.getID()
306: + ")"
307: + " crossed "
308: + getGeomTypeRefA()
309: + "("
310: + f2.getID()
311: + "), Result was not "
312: + expected);
313: success = false;
314: }
315: }
316: }
317: }
318: usedIDs.add(f1.getID());
319: }
320: } finally {
321: fr1.close();
322: if (fr2 != null)
323: fr2.close();
324: }
325:
326: return success;
327: }
328:
329: private Filter filterBBox(Envelope bBox, FeatureType ft)
330: throws FactoryConfigurationError, IllegalFilterException {
331: FilterFactory ff = FilterFactoryFinder.createFilterFactory();
332: BBoxExpression bboxExpr = ff.createBBoxExpression(bBox);
333: AttributeExpression geomExpr = ff.createAttributeExpression(ft,
334: ft.getDefaultGeometry().getName());
335: GeometryFilter containsFilter = ff
336: .createGeometryFilter(Filter.GEOMETRY_DISJOINT);
337: containsFilter.addLeftGeometry(bboxExpr);
338: containsFilter.addRightGeometry(geomExpr);
339:
340: // GeometryFilter overlapsFilter = ff.createGeometryFilter(Filter.GEOMETRY_OVERLAPS);
341: // overlapsFilter.addLeftGeometry(bboxExpr);
342: // overlapsFilter.addRightGeometry(geomExpr);
343: // Filter filter = containsFilter.or(overlapsFilter);
344: Filter filter = containsFilter.and(containsFilter);
345: return filter;
346: }
347: }
|