001 // License: GPL. See LICENSE file for details. 002 package org.openstreetmap.josm.data.validation.tests; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.util.ArrayList; 007 import java.util.Collection; 008 import java.util.HashMap; 009 import java.util.LinkedHashSet; 010 import java.util.List; 011 import java.util.Map; 012 013 import org.openstreetmap.josm.data.osm.Node; 014 import org.openstreetmap.josm.data.osm.OsmPrimitive; 015 import org.openstreetmap.josm.data.osm.OsmUtils; 016 import org.openstreetmap.josm.data.osm.Way; 017 import org.openstreetmap.josm.data.osm.WaySegment; 018 import org.openstreetmap.josm.data.validation.Severity; 019 import org.openstreetmap.josm.data.validation.Test; 020 import org.openstreetmap.josm.data.validation.TestError; 021 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 022 import org.openstreetmap.josm.tools.MultiMap; 023 import org.openstreetmap.josm.tools.Pair; 024 025 /** 026 * Tests if there are overlapping ways 027 * 028 * @author frsantos 029 */ 030 public class OverlappingWays extends Test { 031 032 /** Bag of all way segments */ 033 MultiMap<Pair<Node,Node>, WaySegment> nodePairs; 034 035 protected static final int OVERLAPPING_HIGHWAY = 101; 036 protected static final int OVERLAPPING_RAILWAY = 102; 037 protected static final int OVERLAPPING_WAY = 103; 038 protected static final int OVERLAPPING_HIGHWAY_AREA = 111; 039 protected static final int OVERLAPPING_RAILWAY_AREA = 112; 040 protected static final int OVERLAPPING_WAY_AREA = 113; 041 protected static final int OVERLAPPING_AREA = 120; 042 043 /** Constructor */ 044 public OverlappingWays() { 045 super(tr("Overlapping ways"), 046 tr("This test checks that a connection between two nodes " 047 + "is not used by more than one way.")); 048 } 049 050 @Override 051 public void startTest(ProgressMonitor monitor) { 052 super.startTest(monitor); 053 nodePairs = new MultiMap<Pair<Node,Node>, WaySegment>(1000); 054 } 055 056 @Override 057 public void endTest() { 058 Map<List<Way>, LinkedHashSet<WaySegment>> ways_seen = new HashMap<List<Way>, LinkedHashSet<WaySegment>>(500); 059 060 for (LinkedHashSet<WaySegment> duplicated : nodePairs.values()) { 061 int ways = duplicated.size(); 062 063 if (ways > 1) { 064 List<OsmPrimitive> prims = new ArrayList<OsmPrimitive>(); 065 List<Way> current_ways = new ArrayList<Way>(); 066 Collection<WaySegment> highlight; 067 int highway = 0; 068 int railway = 0; 069 int area = 0; 070 071 for (WaySegment ws : duplicated) { 072 if (ws.way.get("highway") != null) { 073 highway++; 074 } else if (ws.way.get("railway") != null) { 075 railway++; 076 } 077 Boolean ar = OsmUtils.getOsmBoolean(ws.way.get("area")); 078 if (ar != null && ar) { 079 area++; 080 } 081 if (ws.way.get("landuse") != null 082 || ws.way.get("natural") != null 083 || ws.way.get("amenity") != null 084 || ws.way.get("leisure") != null 085 || ws.way.get("building") != null) { 086 area++; 087 ways--; 088 } 089 090 prims.add(ws.way); 091 current_ways.add(ws.way); 092 } 093 /* These ways not seen before 094 * If two or more of the overlapping ways are 095 * highways or railways mark a separate error 096 */ 097 if ((highlight = ways_seen.get(current_ways)) == null) { 098 String errortype; 099 int type; 100 101 if (area > 0) { 102 if (ways == 0 || duplicated.size() == area) { 103 errortype = tr("Areas share segment"); 104 type = OVERLAPPING_AREA; 105 } else if (highway == ways) { 106 errortype = tr("Highways share segment with area"); 107 type = OVERLAPPING_HIGHWAY_AREA; 108 } else if (railway == ways) { 109 errortype = tr("Railways share segment with area"); 110 type = OVERLAPPING_RAILWAY_AREA; 111 } else { 112 errortype = tr("Ways share segment with area"); 113 type = OVERLAPPING_WAY_AREA; 114 } 115 } 116 else if (highway == ways) { 117 errortype = tr("Overlapping highways"); 118 type = OVERLAPPING_HIGHWAY; 119 } else if (railway == ways) { 120 errortype = tr("Overlapping railways"); 121 type = OVERLAPPING_RAILWAY; 122 } else { 123 errortype = tr("Overlapping ways"); 124 type = OVERLAPPING_WAY; 125 } 126 127 errors.add(new TestError(this, 128 type < OVERLAPPING_HIGHWAY_AREA ? Severity.WARNING : Severity.OTHER, 129 errortype, type, prims, duplicated)); 130 ways_seen.put(current_ways, duplicated); 131 } else { /* way seen, mark highlight layer only */ 132 for (WaySegment ws : duplicated) { 133 highlight.add(ws); 134 } 135 } 136 } 137 } 138 super.endTest(); 139 nodePairs = null; 140 } 141 142 @Override 143 public void visit(Way w) { 144 Node lastN = null; 145 int i = -2; 146 for (Node n : w.getNodes()) { 147 i++; 148 if (lastN == null) { 149 lastN = n; 150 continue; 151 } 152 nodePairs.put(Pair.sort(new Pair<Node,Node>(lastN, n)), 153 new WaySegment(w, i)); 154 lastN = n; 155 } 156 } 157 }