001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.Arrays; 007import java.util.List; 008 009import org.openstreetmap.josm.data.osm.Node; 010import org.openstreetmap.josm.data.osm.OsmPrimitive; 011import org.openstreetmap.josm.data.osm.Relation; 012import org.openstreetmap.josm.data.osm.Way; 013import org.openstreetmap.josm.data.validation.Severity; 014import org.openstreetmap.josm.data.validation.Test; 015import org.openstreetmap.josm.data.validation.TestError; 016import org.openstreetmap.josm.gui.mappaint.ElemStyles; 017 018/** 019 * Checks for ways connected to areas. 020 * @since 4682 021 */ 022public class WayConnectedToArea extends Test { 023 024 /** 025 * Constructs a new {@code WayConnectedToArea} test. 026 */ 027 public WayConnectedToArea() { 028 super(tr("Way connected to Area"), tr("Checks for ways connected to areas.")); 029 } 030 031 @Override 032 public void visit(Way w) { 033 if (!w.isUsable() || w.isClosed() || !w.hasKey("highway")) { 034 return; 035 } 036 037 boolean hasway = false; 038 List<OsmPrimitive> r = w.firstNode().getReferrers(); 039 for (OsmPrimitive p : r) { 040 if(p != w && p.hasKey("highway")) { 041 hasway = true; 042 break; 043 } 044 } 045 if (!hasway) { 046 for (OsmPrimitive p : r) { 047 testForError(w, w.firstNode(), p); 048 } 049 } 050 hasway = false; 051 r = w.lastNode().getReferrers(); 052 for (OsmPrimitive p : r) { 053 if(p != w && p.hasKey("highway")) { 054 hasway = true; 055 break; 056 } 057 } 058 if (!hasway) { 059 for (OsmPrimitive p : r) { 060 testForError(w, w.lastNode(), p); 061 } 062 } 063 } 064 065 private void testForError(Way w, Node wayNode, OsmPrimitive p) { 066 if (isArea(p)) { 067 addError(w, wayNode, p); 068 } else { 069 for (OsmPrimitive r : p.getReferrers()) { 070 if (r instanceof Relation 071 && r.hasTag("type", "multipolygon") 072 && isArea(r)) { 073 addError(w, wayNode, p); 074 break; 075 } 076 } 077 } 078 } 079 080 private boolean isArea(OsmPrimitive p) { 081 return (p.hasKey("landuse") || p.hasKey("natural")) 082 && ElemStyles.hasAreaElemStyle(p, false); 083 } 084 085 private void addError(Way w, Node wayNode, OsmPrimitive p) { 086 errors.add(new TestError(this, Severity.WARNING, 087 tr("Way terminates on Area"), 2301, 088 Arrays.asList(w, p), 089 Arrays.asList(wayNode))); 090 } 091}