Changeset 5522 in josm for trunk/src/org/openstreetmap/josm/data/validation
- Timestamp:
- 2012-09-30T22:47:57+02:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/BuildingInBuilding.java
r5300 r5522 5 5 6 6 import java.util.Collection; 7 import java.util.HashSet; 7 8 import java.util.LinkedList; 8 9 import java.util.List; 10 import java.util.Set; 9 11 10 import org.openstreetmap.josm.data.coor.LatLon;11 12 import org.openstreetmap.josm.data.osm.Node; 12 13 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 21 22 import org.openstreetmap.josm.tools.FilteredCollection; 22 23 import org.openstreetmap.josm.tools.Geometry; 24 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; 23 25 import org.openstreetmap.josm.tools.Predicate; 24 26 … … 48 50 } 49 51 52 @Override 53 public void visit(Relation r) { 54 if (r.isUsable() && r.isMultipolygon() && isBuilding(r)) { 55 primitivesToCheck.add(r); 56 for (RelationMember m : r.getMembers()) { 57 if (m.getRole().equals("outer") && m.getType().equals(OsmPrimitiveType.WAY)) { 58 index.add(m.getWay()); 59 } 60 } 61 } 62 } 63 50 64 private static boolean isInPolygon(Node n, List<Node> polygon) { 51 65 return Geometry.nodeInsidePolygon(n, polygon); 52 66 } 53 67 54 /** 55 * Return true if w is in polygon. 56 */ 57 private static boolean isInPolygon(Way w, List<Node> polygon) { 58 // Check that all nodes of w are in polygon 59 for (Node n : w.getNodes()) { 60 if (!isInPolygon(n, polygon)) 61 return false; 68 protected class MultiPolygonMembers { 69 public final Set<Way> outers = new HashSet<Way>(); 70 public final Set<Way> inners = new HashSet<Way>(); 71 public MultiPolygonMembers(Relation multiPolygon) { 72 for (RelationMember m : multiPolygon.getMembers()) { 73 if (m.getType().equals(OsmPrimitiveType.WAY)) { 74 if (m.getRole().equals("outer")) { 75 outers.add(m.getWay()); 76 } else if (m.getRole().equals("inner")) { 77 inners.add(m.getWay()); 78 } 79 } 80 } 62 81 } 63 // All nodes can be inside polygon and still, w outside: 64 // +-------------+ 65 // /| | 66 // / | | 67 // / | | 68 // / w | | 69 // +----+----+ | 70 // | polygon | 71 // |_______________________| 72 // 73 for (int i=1; i<w.getNodesCount(); i++) { 74 LatLon center = w.getNode(i).getCoor().getCenter(w.getNode(i-1).getCoor()); 75 if (center != null && !isInPolygon(new Node(center), polygon)) 76 return false; 82 } 83 84 protected boolean sameLayers(Way w1, Way w2) { 85 String l1 = w1.get("layer") != null ? w1.get("layer") : "0"; 86 String l2 = w2.get("layer") != null ? w2.get("layer") : "0"; 87 return l1.equals(l2); 88 } 89 90 protected boolean isWayInsideMultiPolygon(Way object, Relation multiPolygon) { 91 // Extract outer/inner members from multipolygon 92 MultiPolygonMembers mpm = new MultiPolygonMembers(multiPolygon); 93 // Test if object is inside an outer member 94 for (Way out : mpm.outers) { 95 PolygonIntersection inter = Geometry.polygonIntersection(object.getNodes(), out.getNodes()); 96 if (inter == PolygonIntersection.FIRST_INSIDE_SECOND || inter == PolygonIntersection.CROSSING) { 97 boolean insideInner = false; 98 // If inside an outer, check it is not inside an inner 99 for (Way in : mpm.inners) { 100 if (Geometry.polygonIntersection(in.getNodes(), out.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND && 101 Geometry.polygonIntersection(object.getNodes(), in.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND) { 102 insideInner = true; 103 break; 104 } 105 } 106 // Inside outer but not inside inner -> the building appears to be inside a buiding 107 if (!insideInner) { 108 // Final check on "layer" tag. Buildings of different layers may be superposed 109 if (sameLayers(object, out)) { 110 return true; 111 } 112 } 113 } 77 114 } 78 return true;115 return false; 79 116 } 80 117 81 118 @Override 82 119 public void endTest() { 83 120 for (final OsmPrimitive p : primitivesToCheck) { 84 121 Collection<Way> outers = new FilteredCollection<Way>(index.search(p.getBBox()), new Predicate<Way>() { 122 123 protected boolean evaluateNode(Node n, Way object) { 124 return isInPolygon(n, object.getNodes()) || object.getNodes().contains(n); 125 } 126 127 protected boolean evaluateWay(Way w, Way object) { 128 if (w.equals(object)) return false; 129 130 // Get all multipolygons referencing object 131 Collection<OsmPrimitive> buildingMultiPolygons = new FilteredCollection<OsmPrimitive>(object.getReferrers(), new Predicate<OsmPrimitive>() { 132 @Override 133 public boolean evaluate(OsmPrimitive object) { 134 return primitivesToCheck.contains(object); 135 } 136 }) ; 137 138 // if there's none, test if w is inside object 139 if (buildingMultiPolygons.isEmpty()) { 140 PolygonIntersection inter = Geometry.polygonIntersection(w.getNodes(), object.getNodes()); 141 // Final check on "layer" tag. Buildings of different layers may be superposed 142 return (inter == PolygonIntersection.FIRST_INSIDE_SECOND || inter == PolygonIntersection.CROSSING) && sameLayers(w, object); 143 } else { 144 // Else, test if w is inside one of the multipolygons 145 for (OsmPrimitive bmp : buildingMultiPolygons) { 146 if (bmp instanceof Relation) { 147 if (isWayInsideMultiPolygon(w, (Relation) bmp)) { 148 return true; 149 } 150 } 151 } 152 return false; 153 } 154 } 155 156 protected boolean evaluateRelation(Relation r, Way object) { 157 MultiPolygonMembers mpm = new MultiPolygonMembers((Relation) p); 158 for (Way out : mpm.outers) { 159 if (evaluateWay(out, object)) { 160 return true; 161 } 162 } 163 return false; 164 } 165 85 166 @Override 86 167 public boolean evaluate(Way object) { … … 88 169 return false; 89 170 else if (p instanceof Node) 90 return isInPolygon((Node) p, object.getNodes()) || object.getNodes().contains(p);171 return evaluateNode((Node) p, object); 91 172 else if (p instanceof Way) 92 return isInPolygon((Way) p, object.getNodes()) && !isInInnerWay((Way)p, object); 93 else 94 return false; 173 return evaluateWay((Way) p, object); 174 else if (p instanceof Relation) 175 return evaluateRelation((Relation) p, object); 176 return false; 95 177 } 96 178 }); 179 97 180 if (!outers.isEmpty()) { 98 181 errors.add(new TestError(this, Severity.WARNING, … … 103 186 super.endTest(); 104 187 } 105 106 private boolean isInInnerWay(Way w, Way outer) {107 for (OsmPrimitive r : outer.getReferrers()) {108 if (r instanceof Relation && ((Relation)r).isMultipolygon()) {109 for (RelationMember m : ((Relation)r).getMembers()) {110 if (m.hasRole() && m.getRole().equals("inner") && m.getType().equals(OsmPrimitiveType.WAY)) {111 // Only check inner ways actually inside the current outer112 Way inner = m.getWay();113 if (isInPolygon(inner, outer.getNodes())) {114 // If the tested way is inside this inner, outer is a false positive115 if (isInPolygon(w, inner.getNodes()))116 return true;117 }118 }119 }120 }121 }122 return false;123 }124 188 }
Note:
See TracChangeset
for help on using the changeset viewer.