- Timestamp:
- 2012-09-30T22:47:57+02:00 (12 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 2 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 } -
trunk/src/org/openstreetmap/josm/tools/Geometry.java
r5313 r5522 2 2 package org.openstreetmap.josm.tools; 3 3 4 import java.awt.Rectangle; 5 import java.awt.geom.Area; 4 6 import java.awt.geom.Line2D; 7 import java.awt.geom.Path2D; 5 8 import java.math.BigDecimal; 6 9 import java.math.MathContext; 7 10 import java.util.ArrayList; 8 11 import java.util.Comparator; 9 import java.util.HashSet;10 12 import java.util.LinkedHashSet; 11 13 import java.util.List; … … 369 371 } 370 372 373 private static Area getArea(List<Node> polygon) { 374 Path2D path = new Path2D.Double(); 375 376 boolean begin = true; 377 for (Node n : polygon) { 378 if (begin) { 379 path.moveTo(n.getEastNorth().getX(), n.getEastNorth().getY()); 380 begin = false; 381 } else { 382 path.lineTo(n.getEastNorth().getX(), n.getEastNorth().getY()); 383 } 384 } 385 path.closePath(); 386 387 return new Area(path); 388 } 389 371 390 /** 372 391 * Tests if two polygons intersect. … … 374 393 * @param second 375 394 * @return intersection kind 376 * TODO: test segments, not only points377 * TODO: is O(N*M), should use sweep for better performance.378 395 */ 379 396 public static PolygonIntersection polygonIntersection(List<Node> first, List<Node> second) { 380 Set<Node> firstSet = new HashSet<Node>(first); 381 Set<Node> secondSet = new HashSet<Node>(second); 382 383 int nodesInsideSecond = 0; 384 int nodesOutsideSecond = 0; 385 int nodesInsideFirst = 0; 386 int nodesOutsideFirst = 0; 387 388 for (Node insideNode : first) { 389 if (secondSet.contains(insideNode)) { 390 continue; 391 //ignore touching nodes. 392 } 393 394 if (nodeInsidePolygon(insideNode, second)) { 395 nodesInsideSecond ++; 396 } 397 else { 398 nodesOutsideSecond ++; 399 } 400 } 401 402 for (Node insideNode : second) { 403 if (firstSet.contains(insideNode)) { 404 continue; 405 //ignore touching nodes. 406 } 407 408 if (nodeInsidePolygon(insideNode, first)) { 409 nodesInsideFirst ++; 410 } 411 else { 412 nodesOutsideFirst ++; 413 } 414 } 415 416 if (nodesInsideFirst == 0) { 417 if (nodesInsideSecond == 0){ 418 if (nodesOutsideFirst + nodesInsideSecond > 0) 419 return PolygonIntersection.OUTSIDE; 420 else 421 //all nodes common 422 return PolygonIntersection.CROSSING; 423 } else 424 return PolygonIntersection.FIRST_INSIDE_SECOND; 425 } 426 else 427 { 428 if (nodesInsideSecond == 0) 429 return PolygonIntersection.SECOND_INSIDE_FIRST; 430 else 431 return PolygonIntersection.CROSSING; 397 398 Area a1 = getArea(first); 399 Area a2 = getArea(second); 400 401 Area inter = new Area(a1); 402 inter.intersect(a2); 403 404 Rectangle bounds = inter.getBounds(); 405 406 if (inter.isEmpty() || bounds.getHeight()*bounds.getWidth() <= 1.0) { 407 return PolygonIntersection.OUTSIDE; 408 } else if (inter.equals(a1)) { 409 return PolygonIntersection.FIRST_INSIDE_SECOND; 410 } else if (inter.equals(a2)) { 411 return PolygonIntersection.SECOND_INSIDE_FIRST; 412 } else { 413 return PolygonIntersection.CROSSING; 432 414 } 433 415 }
Note:
See TracChangeset
for help on using the changeset viewer.