001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.ArrayList; 007import java.util.Collection; 008import java.util.Collections; 009 010import org.openstreetmap.josm.data.osm.QuadBuckets; 011import org.openstreetmap.josm.data.osm.Way; 012import org.openstreetmap.josm.data.validation.Severity; 013import org.openstreetmap.josm.data.validation.Test; 014import org.openstreetmap.josm.data.validation.TestError; 015import org.openstreetmap.josm.gui.mappaint.ElemStyles; 016import org.openstreetmap.josm.tools.Geometry; 017import org.openstreetmap.josm.tools.Predicate; 018import org.openstreetmap.josm.tools.Utils; 019 020/** 021 * Checks if areas overlap. 022 * @since 4448 023 */ 024public class OverlappingAreas extends Test { 025 026 protected static final int OVERLAPPING_AREAS = 2201; 027 protected final QuadBuckets<Way> index = new QuadBuckets<Way>(); 028 029 /** 030 * Constructs a new {@code OverlappingAreas} test. 031 */ 032 public OverlappingAreas() { 033 super(tr("Overlapping Areas"), tr("This test checks if areas overlap.")); 034 } 035 036 @Override 037 public void visit(Way w) { 038 if (w.isUsable() && w.isArea() && ElemStyles.hasAreaElemStyle(w, false)) { 039 index.add(w); 040 } 041 } 042 043 @Override 044 public void endTest() { 045 for (final Way w : index) { 046 Collection<Way> overlaps = Utils.filter( 047 index.search(w.getBBox()), 048 new Predicate<Way>() { 049 050 @Override 051 public boolean evaluate(Way wi) { 052 if (w.equals(wi)) 053 return false; 054 else 055 return Geometry.polygonIntersection(w.getNodes(), wi.getNodes()) 056 == Geometry.PolygonIntersection.CROSSING; 057 } 058 }); 059 if (!overlaps.isEmpty()) { 060 Collection<Way> overlapsWater = new ArrayList<Way>(); 061 Collection<Way> overlapsOther = new ArrayList<Way>(); 062 063 String natural1 = w.get("natural"); 064 String landuse1 = w.get("landuse"); 065 boolean isWaterArea = "water".equals(natural1) || "wetland".equals(natural1) || "coastline".equals(natural1) || "reservoir".equals(landuse1); 066 boolean isWaterArea2 = false; 067 068 for (Way wayOther : overlaps) { 069 String natural2 = wayOther.get("natural"); 070 String landuse2 = wayOther.get("landuse"); 071 boolean isWaterAreaTest = "water".equals(natural2) || "wetland".equals(natural2) || "coastline".equals(natural2) || "reservoir".equals(landuse2); 072 073 if (!isWaterArea2) { 074 isWaterArea2 = isWaterAreaTest; 075 } 076 077 if (isWaterArea && isWaterAreaTest) { 078 overlapsWater.add(wayOther); 079 } else { 080 overlapsOther.add(wayOther); 081 } 082 } 083 084 if (!overlapsWater.isEmpty()) { 085 errors.add(new TestError(this, Severity.WARNING, tr("Overlapping Water Areas"), 086 OVERLAPPING_AREAS, Collections.singletonList(w), overlapsWater)); 087 } 088 089 if (!overlapsOther.isEmpty()) { 090 errors.add(new TestError(this, Severity.OTHER, tr("Overlapping Areas"), 091 OVERLAPPING_AREAS, Collections.singletonList(w), overlapsOther)); 092 } 093 } 094 } 095 096 index.clear(); 097 098 super.endTest(); 099 } 100 101}