1 | package org.openstreetmap.josm.data.validation.tests;
|
---|
2 |
|
---|
3 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
4 |
|
---|
5 | import java.util.Collection;
|
---|
6 | import java.util.LinkedList;
|
---|
7 | import java.util.List;
|
---|
8 |
|
---|
9 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
10 | import org.openstreetmap.josm.data.osm.Node;
|
---|
11 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
12 | import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
|
---|
13 | import org.openstreetmap.josm.data.osm.QuadBuckets;
|
---|
14 | import org.openstreetmap.josm.data.osm.Relation;
|
---|
15 | import org.openstreetmap.josm.data.osm.RelationMember;
|
---|
16 | import org.openstreetmap.josm.data.osm.Way;
|
---|
17 | import org.openstreetmap.josm.data.validation.Severity;
|
---|
18 | import org.openstreetmap.josm.data.validation.Test;
|
---|
19 | import org.openstreetmap.josm.data.validation.TestError;
|
---|
20 | import org.openstreetmap.josm.tools.FilteredCollection;
|
---|
21 | import org.openstreetmap.josm.tools.Geometry;
|
---|
22 | import org.openstreetmap.josm.tools.Predicate;
|
---|
23 |
|
---|
24 | public class BuildingInBuilding extends Test {
|
---|
25 |
|
---|
26 | protected static final int BUILDING_INSIDE_BUILDING = 2001;
|
---|
27 | protected List<OsmPrimitive> primitivesToCheck = new LinkedList<OsmPrimitive>();
|
---|
28 | protected QuadBuckets<Way> index = new QuadBuckets<Way>();
|
---|
29 |
|
---|
30 | public BuildingInBuilding() {
|
---|
31 | super(tr("Building inside building"), tr("Checks for building areas inside of buildings."));
|
---|
32 | }
|
---|
33 |
|
---|
34 | @Override
|
---|
35 | public void visit(Node n) {
|
---|
36 | if (n.isUsable() && isBuilding(n)) {
|
---|
37 | primitivesToCheck.add(n);
|
---|
38 | }
|
---|
39 | }
|
---|
40 |
|
---|
41 | @Override
|
---|
42 | public void visit(Way w) {
|
---|
43 | if (w.isUsable() && w.isClosed() && isBuilding(w)) {
|
---|
44 | primitivesToCheck.add(w);
|
---|
45 | index.add(w);
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | private static boolean isInPolygon(Node n, List<Node> polygon) {
|
---|
50 | return Geometry.nodeInsidePolygon(n, polygon);
|
---|
51 | }
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * Return true if w is in polygon.
|
---|
55 | */
|
---|
56 | private static boolean isInPolygon(Way w, List<Node> polygon) {
|
---|
57 | // Check that all nodes of w are in polygon
|
---|
58 | for (Node n : w.getNodes()) {
|
---|
59 | if (!isInPolygon(n, polygon))
|
---|
60 | return false;
|
---|
61 | }
|
---|
62 | // All nodes can be inside polygon and still, w outside:
|
---|
63 | // +-------------+
|
---|
64 | // /| |
|
---|
65 | // / | |
|
---|
66 | // / | |
|
---|
67 | // / w | |
|
---|
68 | // +----+----+ |
|
---|
69 | // | polygon |
|
---|
70 | // |_______________________|
|
---|
71 | //
|
---|
72 | for (int i=1; i<w.getNodesCount(); i++) {
|
---|
73 | LatLon center = w.getNode(i).getCoor().getCenter(w.getNode(i-1).getCoor());
|
---|
74 | if (center != null && !isInPolygon(new Node(center), polygon))
|
---|
75 | return false;
|
---|
76 | }
|
---|
77 | return true;
|
---|
78 | }
|
---|
79 |
|
---|
80 | @Override
|
---|
81 | public void endTest() {
|
---|
82 | for (final OsmPrimitive p : primitivesToCheck) {
|
---|
83 | Collection<Way> outers = new FilteredCollection<Way>(index.search(p.getBBox()), new Predicate<Way>() {
|
---|
84 | @Override
|
---|
85 | public boolean evaluate(Way object) {
|
---|
86 | if (p.equals(object))
|
---|
87 | return false;
|
---|
88 | else if (p instanceof Node)
|
---|
89 | return isInPolygon((Node) p, object.getNodes()) || object.getNodes().contains(p);
|
---|
90 | else if (p instanceof Way)
|
---|
91 | return isInPolygon((Way) p, object.getNodes()) && !isInInnerWay((Way)p, object);
|
---|
92 | else
|
---|
93 | return false;
|
---|
94 | }
|
---|
95 | });
|
---|
96 | if (!outers.isEmpty()) {
|
---|
97 | errors.add(new TestError(this, Severity.WARNING,
|
---|
98 | tr("Building inside building"), BUILDING_INSIDE_BUILDING, p));
|
---|
99 | }
|
---|
100 | }
|
---|
101 |
|
---|
102 | super.endTest();
|
---|
103 | }
|
---|
104 |
|
---|
105 | private boolean isInInnerWay(Way w, Way outer) {
|
---|
106 | for (OsmPrimitive r : outer.getReferrers()) {
|
---|
107 | if (r instanceof Relation && ((Relation)r).isMultipolygon()) {
|
---|
108 | for (RelationMember m : ((Relation)r).getMembers()) {
|
---|
109 | if (m.hasRole() && m.getRole().equals("inner") && m.getType().equals(OsmPrimitiveType.WAY)) {
|
---|
110 | // Only check inner ways actually inside the current outer
|
---|
111 | Way inner = m.getWay();
|
---|
112 | if (isInPolygon(inner, outer.getNodes())) {
|
---|
113 | // If the tested way is inside this inner, outer is a false positive
|
---|
114 | if (isInPolygon(w, inner.getNodes()))
|
---|
115 | return true;
|
---|
116 | }
|
---|
117 | }
|
---|
118 | }
|
---|
119 | }
|
---|
120 | }
|
---|
121 | return false;
|
---|
122 | }
|
---|
123 | }
|
---|