Changeset 15745 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java
r15043 r15745 141 141 private void collectAddress(OsmPrimitive p) { 142 142 if (!isPOI(p)) { 143 String simplifiedAddress = getSimplifiedAddress(p); 144 if (!ignoredAddresses.contains(simplifiedAddress)) { 145 knownAddresses.computeIfAbsent(simplifiedAddress, x -> new ArrayList<>()).add(p); 143 for (String simplifiedAddress : getSimplifiedAddresses(p)) { 144 if (!ignoredAddresses.contains(simplifiedAddress)) { 145 knownAddresses.computeIfAbsent(simplifiedAddress, x -> new ArrayList<>()).add(p); 146 } 146 147 } 147 148 } … … 157 158 // ignore addresses of buildings that are connected to addr:unit nodes 158 159 // it's quite reasonable that there are more buildings with this address 159 String simplifiedAddress = getSimplifiedAddress(r); 160 if (!ignoredAddresses.contains(simplifiedAddress)) { 161 ignoredAddresses.add(simplifiedAddress); 162 } else if (knownAddresses.containsKey(simplifiedAddress)) { 163 knownAddresses.remove(simplifiedAddress); 160 for (String simplifiedAddress : getSimplifiedAddresses(r)) { 161 if (!ignoredAddresses.contains(simplifiedAddress)) { 162 ignoredAddresses.add(simplifiedAddress); 163 } else if (knownAddresses.containsKey(simplifiedAddress)) { 164 knownAddresses.remove(simplifiedAddress); 165 } 164 166 } 165 167 } … … 185 187 if (!isPOI(p) && hasAddress(p)) { 186 188 List<TestError> result = new ArrayList<>(); 187 String simplifiedAddress = getSimplifiedAddress(p); 188 if (!ignoredAddresses.contains(simplifiedAddress) && knownAddresses.containsKey(simplifiedAddress)) { 189 double maxDistance = MAX_DUPLICATE_DISTANCE.get(); 190 for (OsmPrimitive p2 : knownAddresses.get(simplifiedAddress)) { 191 if (p == p2) { 192 continue; 193 } 194 Severity severityLevel; 195 String city1 = p.get(ADDR_CITY); 196 String city2 = p2.get(ADDR_CITY); 197 double distance = getDistance(p, p2); 198 if (city1 != null && city2 != null) { 199 if (city1.equals(city2)) { 200 if ((!p.hasKey(ADDR_POSTCODE) || !p2.hasKey(ADDR_POSTCODE) || p.get(ADDR_POSTCODE).equals(p2.get(ADDR_POSTCODE))) 201 && (!p.hasKey(ADDR_SUBURB) || !p2.hasKey(ADDR_SUBURB) || p.get(ADDR_SUBURB).equals(p2.get(ADDR_SUBURB)))) { 189 for (String simplifiedAddress : getSimplifiedAddresses(p)) { 190 if (!ignoredAddresses.contains(simplifiedAddress) && knownAddresses.containsKey(simplifiedAddress)) { 191 double maxDistance = MAX_DUPLICATE_DISTANCE.get(); 192 for (OsmPrimitive p2 : knownAddresses.get(simplifiedAddress)) { 193 if (p == p2) { 194 continue; 195 } 196 Severity severityLevel; 197 String city1 = p.get(ADDR_CITY); 198 String city2 = p2.get(ADDR_CITY); 199 double distance = getDistance(p, p2); 200 if (city1 != null && city2 != null) { 201 if (city1.equals(city2)) { 202 if ((!p.hasKey(ADDR_POSTCODE) || !p2.hasKey(ADDR_POSTCODE) 203 || p.get(ADDR_POSTCODE).equals(p2.get(ADDR_POSTCODE))) 204 && (!p.hasKey(ADDR_SUBURB) || !p2.hasKey(ADDR_SUBURB) 205 || p.get(ADDR_SUBURB).equals(p2.get(ADDR_SUBURB)))) { 206 severityLevel = Severity.WARNING; 207 } else { 208 // address including city identical but postcode or suburb differs 209 // most likely perfectly fine 210 severityLevel = Severity.OTHER; 211 } 212 } else { 213 // address differs only by city - notify if very close, otherwise ignore 214 if (distance < maxDistance) { 215 severityLevel = Severity.OTHER; 216 } else { 217 continue; 218 } 219 } 220 } else { 221 // at least one address has no city specified 222 if (p.hasKey(ADDR_POSTCODE) && p2.hasKey(ADDR_POSTCODE) 223 && p.get(ADDR_POSTCODE).equals(p2.get(ADDR_POSTCODE))) { 224 // address including postcode identical 202 225 severityLevel = Severity.WARNING; 203 226 } else { 204 // address including city identical but postcode or suburb differs 205 // most likely perfectly fine 206 severityLevel = Severity.OTHER; 207 } 208 } else { 209 // address differs only by city - notify if very close, otherwise ignore 210 if (distance < maxDistance) { 211 severityLevel = Severity.OTHER; 212 } else { 213 continue; 227 // city/postcode unclear - warn if very close, otherwise only notify 228 // TODO: get city from surrounding boundaries? 229 if (distance < maxDistance) { 230 severityLevel = Severity.WARNING; 231 } else { 232 severityLevel = Severity.OTHER; 233 } 214 234 } 215 235 } 216 } else { 217 // at least one address has no city specified 218 if (p.hasKey(ADDR_POSTCODE) && p2.hasKey(ADDR_POSTCODE) && p.get(ADDR_POSTCODE).equals(p2.get(ADDR_POSTCODE))) { 219 // address including postcode identical 220 severityLevel = Severity.WARNING; 221 } else { 222 // city/postcode unclear - warn if very close, otherwise only notify 223 // TODO: get city from surrounding boundaries? 224 if (distance < maxDistance) { 225 severityLevel = Severity.WARNING; 226 } else { 227 severityLevel = Severity.OTHER; 228 } 229 } 230 } 231 result.add(TestError.builder(this, severityLevel, DUPLICATE_HOUSE_NUMBER) 232 .message(tr("Duplicate house numbers"), marktr("''{0}'' ({1}m)"), simplifiedAddress, (int) distance) 233 .primitives(Arrays.asList(p, p2)).build()); 234 } 235 knownAddresses.get(simplifiedAddress).remove(p); // otherwise we would get every warning two times 236 result.add(TestError.builder(this, severityLevel, DUPLICATE_HOUSE_NUMBER) 237 .message(tr("Duplicate house numbers"), marktr("''{0}'' ({1}m)"), simplifiedAddress, (int) distance) 238 .primitives(Arrays.asList(p, p2)).build()); 239 } 240 knownAddresses.get(simplifiedAddress).remove(p); // otherwise we would get every warning two times 241 } 236 242 } 237 243 errors.addAll(result); … … 241 247 } 242 248 243 static StringgetSimplifiedAddress(OsmPrimitive p) {249 static List<String> getSimplifiedAddresses(OsmPrimitive p) { 244 250 String simplifiedStreetName = p.hasKey(ADDR_STREET) ? p.get(ADDR_STREET) : p.get(ADDR_PLACE); 245 251 // ignore whitespaces and dashes in street name, so that "Mozart-Gasse", "Mozart Gasse" and "Mozartgasse" are all seen as equal 246 return Utils.strip(Stream.of( 252 return expandHouseNumber(p.get(ADDR_HOUSE_NUMBER)).stream().map(addrHouseNumber -> Utils.strip(Stream.of( 247 253 simplifiedStreetName.replaceAll("[ -]", ""), 248 p.get(ADDR_HOUSE_NUMBER),254 addrHouseNumber, 249 255 p.get(ADDR_HOUSE_NAME), 250 256 p.get(ADDR_UNIT), … … 252 258 .filter(Objects::nonNull) 253 259 .collect(Collectors.joining(" "))) 254 .toUpperCase(Locale.ENGLISH); 260 .toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()); 261 } 262 263 /** 264 * Split addr:housenumber on , and ; (common separators) 265 * 266 * @param houseNumber The housenumber to be split 267 * @return A list of addr:housenumber equivalents 268 */ 269 static List<String> expandHouseNumber(String houseNumber) { 270 return Arrays.asList(houseNumber.split(",|;")); 255 271 } 256 272 -
trunk/test/unit/org/openstreetmap/josm/data/validation/tests/AddressesTest.java
r15043 r15745 58 58 @Test 59 59 public void testHouseNumberWithoutStreet() { 60 assertNull(doTestHouseNumberWithoutStreet( 61 "", null, null)); 62 assertNotNull(doTestHouseNumberWithoutStreet( 63 "addr:housenumber=1", null, null)); 64 assertNull(doTestHouseNumberWithoutStreet( 65 "addr:housenumber=1 addr:street=Foo", null, null)); 66 assertNull(doTestHouseNumberWithoutStreet( 67 "addr:housenumber=1 addr:place=Foo", null, null)); 68 assertNull(doTestHouseNumberWithoutStreet( 69 "addr:housenumber=1 addr:neighbourhood=Foo", null, null)); 70 assertNotNull(doTestHouseNumberWithoutStreet( 71 "addr:housenumber=1", null, "type=enforcement")); 72 assertNull(doTestHouseNumberWithoutStreet( 73 "addr:housenumber=1", null, "type=associatedStreet")); 74 assertNotNull(doTestHouseNumberWithoutStreet( 75 "addr:housenumber=1", "building=yes", null)); 76 assertNull(doTestHouseNumberWithoutStreet( 77 "addr:housenumber=1", "addr:interpolation=odd addr:street=Foo", null)); 60 assertNull(doTestHouseNumberWithoutStreet("", null, null)); 61 assertNotNull(doTestHouseNumberWithoutStreet("addr:housenumber=1", null, null)); 62 assertNull(doTestHouseNumberWithoutStreet("addr:housenumber=1 addr:street=Foo", null, null)); 63 assertNull(doTestHouseNumberWithoutStreet("addr:housenumber=1 addr:place=Foo", null, null)); 64 assertNull(doTestHouseNumberWithoutStreet("addr:housenumber=1 addr:neighbourhood=Foo", null, null)); 65 assertNotNull(doTestHouseNumberWithoutStreet("addr:housenumber=1", null, "type=enforcement")); 66 assertNull(doTestHouseNumberWithoutStreet("addr:housenumber=1", null, "type=associatedStreet")); 67 assertNotNull(doTestHouseNumberWithoutStreet("addr:housenumber=1", "building=yes", null)); 68 assertNull( 69 doTestHouseNumberWithoutStreet("addr:housenumber=1", "addr:interpolation=odd addr:street=Foo", null)); 78 70 } 79 71 80 private static void doTestDuplicateHouseNumber( 81 S tring tags1, LatLon ll1, String tags2, LatLon ll2, Severity expected) {72 private static void doTestDuplicateHouseNumber(String tags1, LatLon ll1, String tags2, LatLon ll2, 73 Severity expected) { 82 74 DataSet ds = new DataSet(); 83 Node n1 = TestUtils.newNode(tags1); n1.setCoor(ll1); ds.addPrimitive(n1); 84 Node n2 = TestUtils.newNode(tags2); n2.setCoor(ll2); ds.addPrimitive(n2); 75 Node n1 = TestUtils.newNode(tags1); 76 n1.setCoor(ll1); 77 ds.addPrimitive(n1); 78 Node n2 = TestUtils.newNode(tags2); 79 n2.setCoor(ll2); 80 ds.addPrimitive(n2); 85 81 List<TestError> errors = new Addresses().checkForDuplicate(n2); 86 82 assertEquals(expected != null ? 1 : 0, errors.size()); … … 108 104 doTestDuplicateHouseNumber(num1, ZERO, num2, ZERO, null); 109 105 // Info for same address in different cities, warning if same city 110 doTestDuplicateHouseNumber(num1+city1, ZERO, num1+city2, ZERO, Severity.OTHER); 111 doTestDuplicateHouseNumber(num1+city1, ZERO, num1+city1, ZERO, Severity.WARNING); 112 // Info for same address in same city but different suburbs, warning if same suburb 113 doTestDuplicateHouseNumber(num1+city1+suburb1, ZERO, num1+city1+suburb2, ZERO, Severity.OTHER); 114 doTestDuplicateHouseNumber(num1+city1+suburb1, ZERO, num1+city1+suburb1, ZERO, Severity.WARNING); 106 doTestDuplicateHouseNumber(num1 + city1, ZERO, num1 + city2, ZERO, Severity.OTHER); 107 doTestDuplicateHouseNumber(num1 + city1, ZERO, num1 + city1, ZERO, Severity.WARNING); 108 // Info for same address in same city but different suburbs, warning if same 109 // suburb 110 doTestDuplicateHouseNumber(num1 + city1 + suburb1, ZERO, num1 + city1 + suburb2, ZERO, Severity.OTHER); 111 doTestDuplicateHouseNumber(num1 + city1 + suburb1, ZERO, num1 + city1 + suburb1, ZERO, Severity.WARNING); 112 } 113 114 /** 115 * Unit test of {@link Addresses#expandHouseNumber} 116 */ 117 @Test 118 public void testMultiAddressDuplicates() { 119 String num1 = "addr:housenumber=1,3 addr:street=Foo"; 120 String num2 = "addr:housenumber=1 addr:street=Foo"; 121 String num3 = "addr:housenumber=3 addr:street=Foo"; 122 String num4 = "addr:housenumber=4 addr:street=Foo"; 123 124 doTestDuplicateHouseNumber(num1, ZERO, num2, ZERO, Severity.WARNING); 125 doTestDuplicateHouseNumber(num1, ZERO, num3, ZERO, Severity.WARNING); 126 doTestDuplicateHouseNumber(num1, ZERO, num4, ZERO, null); 127 128 num1 = num1.replace(",", ";"); 129 130 doTestDuplicateHouseNumber(num1, ZERO, num2, ZERO, Severity.WARNING); 131 doTestDuplicateHouseNumber(num1, ZERO, num3, ZERO, Severity.WARNING); 132 doTestDuplicateHouseNumber(num1, ZERO, num4, ZERO, null); 115 133 } 116 134 }
Note:
See TracChangeset
for help on using the changeset viewer.