- Timestamp:
- 2016-01-23T14:47:56+01:00 (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
r9553 r9582 156 156 if (r.isMultipolygon()) { 157 157 checkMembersAndRoles(r); 158 159 Multipolygon polygon = MultipolygonCache.getInstance().get(Main.map.mapView, r); 160 161 boolean hasOuterWay = false; 162 for (RelationMember m : r.getMembers()) { 163 if ("outer".equals(m.getRole())) { 164 hasOuterWay = true; 165 break; 166 } 167 } 168 if (!hasOuterWay) { 169 addError(r, new TestError(this, Severity.WARNING, tr("No outer way for multipolygon"), MISSING_OUTER_WAY, r)); 170 } 171 172 if (r.hasIncompleteMembers()) { 173 return; // Rest of checks is only for complete multipolygons 174 } 175 176 // Create new multipolygon using the logics from CreateMultipolygonAction and see if roles match. 177 final Pair<Relation, Relation> newMP = CreateMultipolygonAction.createMultipolygonRelation(r.getMemberPrimitives(Way.class), false); 178 if (newMP != null) { 179 for (RelationMember member : r.getMembers()) { 180 final Collection<RelationMember> memberInNewMP = newMP.b.getMembersFor(Collections.singleton(member.getMember())); 181 if (memberInNewMP != null && !memberInNewMP.isEmpty()) { 182 final String roleInNewMP = memberInNewMP.iterator().next().getRole(); 183 if (!member.getRole().equals(roleInNewMP)) { 184 List<OsmPrimitive> l = new ArrayList<>(); 185 l.add(r); 186 l.add(member.getMember()); 187 addError(r, new TestError(this, Severity.WARNING, RelationChecker.ROLE_VERIF_PROBLEM_MSG, 188 tr("Role for ''{0}'' should be ''{1}''", 189 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 190 MessageFormat.format("Role for ''{0}'' should be ''{1}''", 191 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 192 WRONG_MEMBER_ROLE, l, Collections.singleton(member.getMember()))); 158 checkOuterWay(r); 159 160 // Rest of checks is only for complete multipolygons 161 if (!r.hasIncompleteMembers()) { 162 Multipolygon polygon = MultipolygonCache.getInstance().get(Main.map.mapView, r); 163 164 // Create new multipolygon using the logics from CreateMultipolygonAction and see if roles match. 165 checkMemberRoleCorrectness(r); 166 checkStyleConsistency(r, polygon); 167 checkGeometry(r, polygon); 168 } 169 } 170 } 171 172 /** 173 * Checks that multipolygon has at least an outer way:<ul> 174 * <li>{@link #MISSING_OUTER_WAY}: No outer way for multipolygon</li> 175 * </ul> 176 * @param r relation 177 */ 178 private void checkOuterWay(Relation r) { 179 boolean hasOuterWay = false; 180 for (RelationMember m : r.getMembers()) { 181 if ("outer".equals(m.getRole())) { 182 hasOuterWay = true; 183 break; 184 } 185 } 186 if (!hasOuterWay) { 187 addError(r, new TestError(this, Severity.WARNING, tr("No outer way for multipolygon"), MISSING_OUTER_WAY, r)); 188 } 189 } 190 191 /** 192 * Create new multipolygon using the logics from CreateMultipolygonAction and see if roles match:<ul> 193 * <li>{@link #WRONG_MEMBER_ROLE}: Role for ''{0}'' should be ''{1}''</li> 194 * </ul> 195 * @param r relation 196 */ 197 private void checkMemberRoleCorrectness(Relation r) { 198 final Pair<Relation, Relation> newMP = CreateMultipolygonAction.createMultipolygonRelation(r.getMemberPrimitives(Way.class), false); 199 if (newMP != null) { 200 for (RelationMember member : r.getMembers()) { 201 final Collection<RelationMember> memberInNewMP = newMP.b.getMembersFor(Collections.singleton(member.getMember())); 202 if (memberInNewMP != null && !memberInNewMP.isEmpty()) { 203 final String roleInNewMP = memberInNewMP.iterator().next().getRole(); 204 if (!member.getRole().equals(roleInNewMP)) { 205 List<OsmPrimitive> l = new ArrayList<>(); 206 l.add(r); 207 l.add(member.getMember()); 208 addError(r, new TestError(this, Severity.WARNING, RelationChecker.ROLE_VERIF_PROBLEM_MSG, 209 tr("Role for ''{0}'' should be ''{1}''", 210 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 211 MessageFormat.format("Role for ''{0}'' should be ''{1}''", 212 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 213 WRONG_MEMBER_ROLE, l, Collections.singleton(member.getMember()))); 214 } 215 } 216 } 217 } 218 } 219 220 /** 221 * Various style-related checks:<ul> 222 * <li>{@link #NO_STYLE_POLYGON}: Multipolygon relation should be tagged with area tags and not the outer way</li> 223 * <li>{@link #INNER_STYLE_MISMATCH}: With the currently used mappaint style the style for inner way equals the multipolygon style</li> 224 * <li>{@link #OUTER_STYLE_MISMATCH}: Style for outer way mismatches</li> 225 * <li>{@link #OUTER_STYLE}: Area style on outer way</li> 226 * </ul> 227 * @param r relation 228 * @param polygon multipolygon 229 */ 230 private void checkStyleConsistency(Relation r, Multipolygon polygon) { 231 if (styles != null && !"boundary".equals(r.get("type"))) { 232 AreaElement area = ElemStyles.getAreaElemStyle(r, false); 233 boolean areaStyle = area != null; 234 // If area style was not found for relation then use style of ways 235 if (area == null) { 236 for (Way w : polygon.getOuterWays()) { 237 area = ElemStyles.getAreaElemStyle(w, true); 238 if (area != null) { 239 break; 240 } 241 } 242 if (area == null) { 243 addError(r, new TestError(this, Severity.OTHER, tr("No area style for multipolygon"), NO_STYLE, r)); 244 } else { 245 /* old style multipolygon - solve: copy tags from outer way to multipolygon */ 246 addError(r, new TestError(this, Severity.WARNING, 247 trn("Multipolygon relation should be tagged with area tags and not the outer way", 248 "Multipolygon relation should be tagged with area tags and not the outer ways", 249 polygon.getOuterWays().size()), 250 NO_STYLE_POLYGON, r)); 251 } 252 } 253 254 if (area != null) { 255 for (Way wInner : polygon.getInnerWays()) { 256 AreaElement areaInner = ElemStyles.getAreaElemStyle(wInner, false); 257 258 if (areaInner != null && area.equals(areaInner)) { 259 List<OsmPrimitive> l = new ArrayList<>(); 260 l.add(r); 261 l.add(wInner); 262 addError(r, new TestError(this, Severity.OTHER, 263 tr("With the currently used mappaint style the style for inner way equals the multipolygon style"), 264 INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner))); 265 } 266 } 267 for (Way wOuter : polygon.getOuterWays()) { 268 AreaElement areaOuter = ElemStyles.getAreaElemStyle(wOuter, false); 269 if (areaOuter != null) { 270 List<OsmPrimitive> l = new ArrayList<>(); 271 l.add(r); 272 l.add(wOuter); 273 if (!area.equals(areaOuter)) { 274 addError(r, new TestError(this, Severity.WARNING, !areaStyle ? tr("Style for outer way mismatches") 275 : tr("With the currently used mappaint style(s) the style for outer way mismatches polygon"), 276 OUTER_STYLE_MISMATCH, l, Collections.singletonList(wOuter))); 277 } else if (areaStyle) { /* style on outer way of multipolygon, but equal to polygon */ 278 addError(r, new TestError(this, Severity.WARNING, tr("Area style on outer way"), OUTER_STYLE, 279 l, Collections.singletonList(wOuter))); 193 280 } 194 281 } 195 282 } 196 283 } 197 198 if (styles != null && !"boundary".equals(r.get("type"))) { 199 AreaElement area = ElemStyles.getAreaElemStyle(r, false); 200 boolean areaStyle = area != null; 201 // If area style was not found for relation then use style of ways 202 if (area == null) { 203 for (Way w : polygon.getOuterWays()) { 204 area = ElemStyles.getAreaElemStyle(w, true); 205 if (area != null) { 206 break; 207 } 208 } 209 if (area == null) { 210 addError(r, new TestError(this, Severity.OTHER, tr("No area style for multipolygon"), NO_STYLE, r)); 211 } else { 212 /* old style multipolygon - solve: copy tags from outer way to multipolygon */ 213 addError(r, new TestError(this, Severity.WARNING, 214 trn("Multipolygon relation should be tagged with area tags and not the outer way", 215 "Multipolygon relation should be tagged with area tags and not the outer ways", 216 polygon.getOuterWays().size()), 217 NO_STYLE_POLYGON, r)); 218 } 219 } 220 221 if (area != null) { 222 for (Way wInner : polygon.getInnerWays()) { 223 AreaElement areaInner = ElemStyles.getAreaElemStyle(wInner, false); 224 225 if (areaInner != null && area.equals(areaInner)) { 226 List<OsmPrimitive> l = new ArrayList<>(); 227 l.add(r); 228 l.add(wInner); 229 addError(r, new TestError(this, Severity.OTHER, 230 tr("With the currently used mappaint style the style for inner way equals the multipolygon style"), 231 INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner))); 232 } 233 } 234 for (Way wOuter : polygon.getOuterWays()) { 235 AreaElement areaOuter = ElemStyles.getAreaElemStyle(wOuter, false); 236 if (areaOuter != null) { 237 List<OsmPrimitive> l = new ArrayList<>(); 238 l.add(r); 239 l.add(wOuter); 240 if (!area.equals(areaOuter)) { 241 addError(r, new TestError(this, Severity.WARNING, !areaStyle ? tr("Style for outer way mismatches") 242 : tr("With the currently used mappaint style(s) the style for outer way mismatches polygon"), 243 OUTER_STYLE_MISMATCH, l, Collections.singletonList(wOuter))); 244 } else if (areaStyle) { /* style on outer way of multipolygon, but equal to polygon */ 245 addError(r, new TestError(this, Severity.WARNING, tr("Area style on outer way"), OUTER_STYLE, 246 l, Collections.singletonList(wOuter))); 247 } 248 } 249 } 250 } 251 } 252 253 List<Node> openNodes = polygon.getOpenEnds(); 254 if (!openNodes.isEmpty()) { 255 List<OsmPrimitive> primitives = new LinkedList<>(); 256 primitives.add(r); 257 primitives.addAll(openNodes); 258 Arrays.asList(openNodes, r); 259 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon is not closed"), NON_CLOSED_WAY, 260 primitives, openNodes)); 261 } 262 263 // For painting is used Polygon class which works with ints only. For validation we need more precision 264 List<GeneralPath> outerPolygons = createPolygons(polygon.getOuterPolygons()); 265 for (Multipolygon.PolyData pdInner : polygon.getInnerPolygons()) { 266 boolean outside = true; 267 boolean crossing = false; 268 Multipolygon.PolyData outerWay = null; 269 for (int i = 0; i < polygon.getOuterPolygons().size(); i++) { 270 GeneralPath outer = outerPolygons.get(i); 271 Intersection intersection = getPolygonIntersection(outer, pdInner.getNodes()); 272 outside = outside & intersection == Intersection.OUTSIDE; 273 if (intersection == Intersection.CROSSING) { 274 crossing = true; 275 outerWay = polygon.getOuterPolygons().get(i); 276 } 277 } 278 if (outside || crossing) { 279 List<List<Node>> highlights = new ArrayList<>(); 280 highlights.add(pdInner.getNodes()); 281 if (outside) { 282 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside"), 283 INNER_WAY_OUTSIDE, Collections.singletonList(r), highlights)); 284 } else if (outerWay != null) { 285 highlights.add(outerWay.getNodes()); 286 addError(r, new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), 287 CROSSING_WAYS, Collections.singletonList(r), highlights)); 288 } 289 } 290 } 291 } 292 } 293 284 } 285 } 286 287 /** 288 * Various geometry-related checks:<ul> 289 * <li>{@link #NON_CLOSED_WAY}: Multipolygon is not closed</li> 290 * <li>{@link #INNER_WAY_OUTSIDE}: Multipolygon inner way is outside</li> 291 * <li>{@link #CROSSING_WAYS}: Intersection between multipolygon ways</li> 292 * </ul> 293 * @param r relation 294 * @param polygon multipolygon 295 */ 296 private void checkGeometry(Relation r, Multipolygon polygon) { 297 List<Node> openNodes = polygon.getOpenEnds(); 298 if (!openNodes.isEmpty()) { 299 List<OsmPrimitive> primitives = new LinkedList<>(); 300 primitives.add(r); 301 primitives.addAll(openNodes); 302 Arrays.asList(openNodes, r); 303 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon is not closed"), NON_CLOSED_WAY, 304 primitives, openNodes)); 305 } 306 307 // For painting is used Polygon class which works with ints only. For validation we need more precision 308 List<GeneralPath> outerPolygons = createPolygons(polygon.getOuterPolygons()); 309 for (Multipolygon.PolyData pdInner : polygon.getInnerPolygons()) { 310 boolean outside = true; 311 boolean crossing = false; 312 Multipolygon.PolyData outerWay = null; 313 for (int i = 0; i < polygon.getOuterPolygons().size(); i++) { 314 GeneralPath outer = outerPolygons.get(i); 315 Intersection intersection = getPolygonIntersection(outer, pdInner.getNodes()); 316 outside = outside & intersection == Intersection.OUTSIDE; 317 if (intersection == Intersection.CROSSING) { 318 crossing = true; 319 outerWay = polygon.getOuterPolygons().get(i); 320 } 321 } 322 if (outside || crossing) { 323 List<List<Node>> highlights = new ArrayList<>(); 324 highlights.add(pdInner.getNodes()); 325 if (outside) { 326 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside"), 327 INNER_WAY_OUTSIDE, Collections.singletonList(r), highlights)); 328 } else if (outerWay != null) { 329 highlights.add(outerWay.getNodes()); 330 addError(r, new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), 331 CROSSING_WAYS, Collections.singletonList(r), highlights)); 332 } 333 } 334 } 335 } 336 337 /** 338 * Check for:<ul> 339 * <li>{@link #WRONG_MEMBER_ROLE}: No useful role for multipolygon member</li> 340 * <li>{@link #WRONG_MEMBER_TYPE}: Non-Way in multipolygon</li> 341 * </ul> 342 * @param r relation 343 */ 294 344 private void checkMembersAndRoles(Relation r) { 295 345 for (RelationMember rm : r.getMembers()) {
Note:
See TracChangeset
for help on using the changeset viewer.