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.Date;
021: import java.util.HashSet;
022: import java.util.Map;
023: import java.util.logging.Logger;
024:
025: import org.geotools.feature.FeatureIterator;
026: import org.geotools.feature.FeatureCollection;
027: import org.geotools.data.FeatureSource;
028: import org.geotools.factory.FactoryConfigurationError;
029: import org.geotools.feature.Feature;
030: import org.geotools.feature.FeatureType;
031: import org.geotools.filter.AttributeExpression;
032: import org.geotools.filter.BBoxExpression;
033: import org.opengis.filter.Filter;
034: import org.geotools.filter.FilterFactory;
035: import org.geotools.filter.FilterFactoryFinder;
036: import org.geotools.filter.FilterType;
037: import org.geotools.filter.GeometryFilter;
038: import org.geotools.filter.IllegalFilterException;
039: import org.geotools.validation.ValidationResults;
040:
041: import com.vividsolutions.jts.geom.Envelope;
042: import com.vividsolutions.jts.geom.Geometry;
043:
044: /**
045: * OverlapsIntegrity<br>
046: * @author bowens, ptozer<br>
047: * Created Apr 27, 2004<br>
048: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/validation/src/main/java/org/geotools/validation/relate/OverlapsIntegrity.java $
049: * @version <br>
050: *
051: * <b>Puropse:</b><br>
052: * <p>
053: * Tests to see if a Geometry overlaps, partially or entirely, with another Geometry.
054: *
055: * <b>Description:</b><br>
056: * <p>
057: * If only one layer is provided, the geometries of that layer are compared with each other.
058: * If two layers are provided, then the geometries are compared across the layers.
059: * </p>
060: *
061: * <b>Usage:</b><br>
062: * <p>
063: * OverlapsIntegrity overlap = new OverlapsIntegrity();
064: * overlap.setExpected(false);
065: * overlap.setGeomTypeRefA("my:line");
066: *
067: * Map map = new HashMap();
068: * try
069: * {
070: * map.put("my:line", mds.getFeatureSource("line"));
071: * } catch (IOException e1)
072: * {
073: * e1.printStackTrace();
074: * }
075: *
076: * try
077: * {
078: * assertFalse(overlap.validate(map, lineBounds, vr));
079: * } catch (Exception e)
080: * {
081: * e.printStackTrace();
082: * }
083: * </p>
084: */
085: public class OverlapsIntegrity extends RelationIntegrity {
086: private static final Logger LOGGER = org.geotools.util.logging.Logging
087: .getLogger("org.geotools.validation");
088: private static HashSet usedIDs;
089: private boolean showPrintLines = true;
090:
091: /**
092: * OverlapsIntegrity Constructor
093: *
094: */
095: public OverlapsIntegrity() {
096: super ();
097: usedIDs = new HashSet(); //TODO: remove me later, memory inefficient
098: }
099:
100: /* (non-Javadoc)
101: * @see org.geotools.validation.IntegrityValidation#validate(java.util.Map, com.vividsolutions.jts.geom.Envelope, org.geotools.validation.ValidationResults)
102: */
103: public boolean validate(Map layers, Envelope envelope,
104: ValidationResults results) throws Exception {
105: LOGGER.finer("Starting test " + getName() + " ("
106: + getClass().getName() + ")");
107: String typeRef1 = getGeomTypeRefA();
108: LOGGER.finer(typeRef1 + ": looking up FeatureSource");
109: FeatureSource geomSource1 = (FeatureSource) layers
110: .get(typeRef1);
111: LOGGER.finer(typeRef1 + ": found "
112: + geomSource1.getSchema().getTypeName());
113:
114: String typeRef2 = getGeomTypeRefB();
115: if (typeRef2 == EMPTY || typeRef1.equals(typeRef2))
116: return validateSingleLayer(geomSource1, isExpected(),
117: results, envelope);
118: else {
119: LOGGER.warning(typeRef2 + ": looking up FeatureSource ");
120: FeatureSource geomSource2 = (FeatureSource) layers
121: .get(typeRef2);
122: LOGGER.finer(typeRef2 + ": found "
123: + geomSource2.getSchema().getTypeName());
124: return validateMultipleLayers(geomSource1, geomSource2,
125: isExpected(), results, envelope);
126: }
127:
128: }
129:
130: /**
131: * <b>validateMultipleLayers Purpose:</b> <br>
132: * <p>
133: * This validation tests for a geometry overlaps another geometry.
134: * Uses JTS' Geometry.overlaps(Geometry) and Geometry.contains(Geometry)method.
135: * The DE-9IM intersection matrix for overlaps is:
136: * T*T***T** (for two points or two surfaces)
137: * 1*T***T** (for two curves)
138: * Contains DE-9IM intersection matrix is T*F**F***.
139: * </p>
140: *
141: * <b>Description:</b><br>
142: * <p>
143: * The function filters the FeatureSources using the given bounding box.
144: * It creates iterators over both filtered FeatureSources. It calls overlaps() and contains()using the
145: * geometries in the FeatureSource layers. Tests the results of the method call against
146: * the given expected results. Returns true if the returned results and the expected results
147: * are true, false otherwise.
148: *
149: * </p>
150: *
151: * Author: bowens<br>
152: * Created on: Apr 27, 2004<br>
153: * @param featureSourceA - the FeatureSource to pull the original geometries from. This geometry is the one that is tested for overlaping with the other
154: * @param featureSourceB - the FeatureSource to pull the other geometries from - these geometries will be those that may overlap the first geometry
155: * @param expected - boolean value representing the user's expected outcome of the test
156: * @param results - ValidationResults
157: * @param bBox - Envelope - the bounding box within which to perform the overlaps() and contains()
158: * @return boolean result of the test
159: * @throws Exception - IOException if iterators improperly closed
160: */
161: private boolean validateMultipleLayers(
162: FeatureSource featureSourceA, FeatureSource featureSourceB,
163: boolean expected, ValidationResults results, Envelope bBox)
164: throws Exception {
165: boolean success = true;
166: int errors = 0;
167: int countInterval = 100;
168: int counter = 0;
169: FeatureType ft = featureSourceA.getSchema();
170:
171: Filter filter = filterBBox(bBox, ft);
172:
173: //FeatureCollection FeatureCollection = featureSourceA.getFeatures(filter);
174: FeatureCollection collectionA = featureSourceA.getFeatures();
175:
176: FeatureIterator fr1 = null;
177: FeatureIterator fr2 = null;
178: try {
179: fr1 = collectionA.features();
180:
181: if (fr1 == null)
182: return success;
183:
184: while (fr1.hasNext()) {
185: counter++;
186: Feature f1 = fr1.next();
187:
188: Geometry g1 = f1.getDefaultGeometry();
189: Filter filter2 = filterBBox(g1.getEnvelope()
190: .getEnvelopeInternal(), ft);
191:
192: FeatureCollection collectionB = featureSourceB
193: .getFeatures(filter2);
194:
195: fr2 = collectionB.features();
196: try {
197: while (fr2 != null && fr2.hasNext()) {
198: Feature f2 = fr2.next();
199: Geometry g2 = f2.getDefaultGeometry();
200: if (!usedIDs.contains(f2.getID())) {
201:
202: if (!f1.getID().equals(f2.getID())) // if they are the same feature, move onto the next one
203: {
204: if (g1.overlaps(g2) != expected
205: || g1.contains(g2) != expected) {
206: //results.error( f1, f1.getDefaultGeometry().getGeometryType()+" "+getGeomTypeRefA()+"("+f1.getID()+")"+" overlapped "+getGeomTypeRefA()+"("+f2.getID()+"), Result was not "+expected );
207: results.error(f1, getGeomTypeRefA()
208: + "(" + f1.getID() + ")"
209: + " overlapped "
210: + getGeomTypeRefB() + "("
211: + f2.getID() + ")");
212: if (showPrintLines) {
213: //System.out.println(f1.getDefaultGeometry().getGeometryType()+" "+getGeomTypeRefA()+"("+f1.getID()+")"+" overlapped "+getGeomTypeRefA()+"("+f2.getID()+"), Result was not "+expected);
214: //System.out.println(f1.getID().substring(8)+ " " + f2.getID().substring(8));
215: }
216: success = false;
217: errors++;
218: }
219: }
220: }
221: }
222: usedIDs.add(f1.getID());
223: if (counter % countInterval == 0 && showPrintLines)
224: System.out.println("count: " + counter);
225:
226: } finally {
227: collectionB.close(fr2);
228: }
229: }// end while 1
230: } finally {
231: collectionA.close(fr1);
232: }
233:
234: return success;
235: }
236:
237: /**
238: * <b>validateSingleLayer Purpose:</b> <br>
239: * <p>
240: * This validation tests for a geometry that overlaps with itself.
241: * Uses JTS' Geometry.overlaps(Geometry) and Geometry.contains(Geometry)method.
242: * The DE-9IM intersection matrix for overlaps is:
243: * T*T***T** (for two points or two surfaces)
244: * 1*T***T** (for two curves)
245: * Contains DE-9IM intersection matrix is T*F**F***.
246: * </p>
247: *
248: * <b>Description:</b><br>
249: * <p>
250: * The function filters the FeatureSource using the given bounding box.
251: * It creates iterators over the filtered FeatureSource. It calls overlaps() and contains() using the
252: * geometries in the FeatureSource layer. Tests the results of the method calls against
253: * the given expected results. Returns true if the returned results and the expected results
254: * are true, false otherwise.
255: *
256: * </p> *
257: * Author: bowens<br>
258: * Created on: Apr 27, 2004<br>
259: * @param featureSourceA - the FeatureSource to pull the original geometries from. This geometry is the one that is tested for overlapping itself
260: * @param expected - boolean value representing the user's expected outcome of the test
261: * @param results - ValidationResults
262: * @param bBox - Envelope - the bounding box within which to perform the overlaps() and contains()
263: * @return boolean result of the test
264: * @throws Exception - IOException if iterators improperly closed
265: */
266: private boolean validateSingleLayer(FeatureSource featureSourceA,
267: boolean expected, ValidationResults results, Envelope bBox)
268: throws Exception {
269: boolean success = true;
270: int errors = 0;
271: Date date1 = new Date();
272: int countInterval = 100;
273: int counter = 0;
274: FeatureType ft = featureSourceA.getSchema();
275:
276: System.out
277: .println("---------------- In Overlaps Integrity ----------------");
278:
279: FeatureCollection collectionA = null;
280:
281: if (bBox != null && !bBox.isNull() && bBox.getHeight() != 0.0
282: && bBox.getWidth() != 0.0) {
283: Filter filter = filterBBox(bBox, ft);
284: collectionA = featureSourceA.getFeatures(filter);
285: } else
286: collectionA = featureSourceA.getFeatures();
287:
288: FeatureIterator fr1 = null;
289: FeatureIterator fr2 = null;
290: try {
291: fr1 = collectionA.features();
292: if (fr1 == null)
293: return success;
294:
295: while (fr1.hasNext()) {
296: counter++;
297: Feature f1 = fr1.next();
298:
299: Geometry g1 = f1.getDefaultGeometry();
300: Filter filter2 = filterBBox(g1.getEnvelope()
301: .getEnvelopeInternal(), ft);
302:
303: FeatureCollection collectionB = featureSourceA
304: .getFeatures(filter2);
305:
306: fr2 = collectionB.features();
307: try {
308: while (fr2 != null && fr2.hasNext()) {
309: Feature f2 = fr2.next();
310: Geometry g2 = f2.getDefaultGeometry();
311: if (!usedIDs.contains(f2.getID())) {
312:
313: if (!f1.getID().equals(f2.getID())) // if they are the same feature, move onto the next one
314: {
315: //if(g1.overlaps(g2) != expected || g1.contains(g2) != expected)
316: if (g1.relate(g2, "1********") != expected) {
317: //results.error( f1, f1.getDefaultGeometry().getGeometryType()+" "+getGeomTypeRefA()+"("+f1.getID()+")"+" overlapped "+getGeomTypeRefA()+"("+f2.getID()+"), Result was not "+expected );
318: if (results != null) {
319: results.error(f1, ""
320: + getGeomTypeRefA()
321: + "(" + f1.getID()
322: + ")" + " overlapped "
323: + getGeomTypeRefA()
324: + "(" + f2.getID()
325: + ")");
326: }
327: if (showPrintLines) {
328: //System.out.println(f1.getDefaultGeometry().getGeometryType()+" "+getGeomTypeRefA()+"("+f1.getID()+")"+" overlapped "+getGeomTypeRefA()+"("+f2.getID()+"), Result was not "+expected);
329: //System.out.println(f1.getID().substring(11)+ " " + f2.getID().substring(11));
330: }
331: success = false;
332: errors++;
333: }
334: }
335: }
336: }
337: usedIDs.add(f1.getID());
338: //if (counter%countInterval == 0 && showPrintLines)
339: // System.out.println("count: " + counter);
340:
341: } finally {
342: collectionB.close(fr2);
343: }
344: }// end while 1
345: } finally {
346: Date date2 = new Date();
347: float dt = date2.getTime() - date1.getTime();
348: if (showPrintLines) {
349: System.out.println("########## Validation duration: "
350: + dt);
351: System.out.println("########## Validation errors: "
352: + errors);
353: }
354:
355: collectionA.close(fr1);
356: }
357:
358: return success;
359: }
360:
361: /** Try and Filter by the provided bbox, will default to Filter.EXCLUDE if null */
362: static public Filter filterBBox(Envelope bBox, FeatureType ft)
363: throws FactoryConfigurationError, IllegalFilterException {
364: if (bBox == null) {
365: return Filter.INCLUDE;
366: }
367: FilterFactory ff = FilterFactoryFinder.createFilterFactory();
368: BBoxExpression bboxExpr = ff.createBBoxExpression(bBox);
369: //GeometryFilter bbFilter = ff.createGeometryFilter(Filter.GEOMETRY_BBOX);
370: AttributeExpression geomExpr = ff.createAttributeExpression(ft,
371: ft.getDefaultGeometry().getName());
372: GeometryFilter disjointFilter = ff
373: .createGeometryFilter(FilterType.GEOMETRY_DISJOINT);
374: disjointFilter.addLeftGeometry(geomExpr);
375: disjointFilter.addRightGeometry(bboxExpr);
376: Filter filter = disjointFilter.not();
377:
378: return filter;
379: }
380: }
|