Changeset 33417 in osm
- Timestamp:
- 2017-06-28T18:00:52+02:00 (8 years ago)
- Location:
- applications/editors/josm/plugins/pt_assistant
- Files:
-
- 15 edited
-
src/org/openstreetmap/josm/plugins/pt_assistant/PTAssistantPlugin.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/AddStopPositionAction.java (modified) (5 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/EdgeSelectionAction.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/EditHighlightedRelationsAction.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/SplitRoundaboutAction.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteSegment.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayer.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayerManager.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPaintVisitor.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/utils/RouteUtils.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/NodeChecker.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java (modified) (1 diff)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/RouteChecker.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java (modified) (1 diff)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/actions/SplitRoundaboutTest.java (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/PTAssistantPlugin.java
r33399 r33417 105 105 lastFix = segment; 106 106 SwingUtilities.invokeLater(() -> 107 repeatLastFixMenu.setEnabled(segment != null));107 repeatLastFixMenu.setEnabled(segment != null)); 108 108 } 109 109 … … 117 117 } 118 118 119 public static List<Relation> getHighlightedRelations() {120 return new ArrayList<>(highlightedRelations);121 }119 public static List<Relation> getHighlightedRelations() { 120 return new ArrayList<>(highlightedRelations); 121 } 122 122 123 public static void addHighlightedRelation(Relation highlightedRelation) {124 highlightedRelations.add(highlightedRelation);125 if(!editHighlightedRelationsMenu.isEnabled()) {126 SwingUtilities.invokeLater(() ->127 editHighlightedRelationsMenu.setEnabled(true));128 }129 }123 public static void addHighlightedRelation(Relation highlightedRelation) { 124 highlightedRelations.add(highlightedRelation); 125 if(!editHighlightedRelationsMenu.isEnabled()) { 126 SwingUtilities.invokeLater(() -> 127 editHighlightedRelationsMenu.setEnabled(true)); 128 } 129 } 130 130 131 public static void clearHighlightedRelations() {132 highlightedRelations.clear();133 SwingUtilities.invokeLater(() ->134 editHighlightedRelationsMenu.setEnabled(false));135 }131 public static void clearHighlightedRelations() { 132 highlightedRelations.clear(); 133 SwingUtilities.invokeLater(() -> 134 editHighlightedRelationsMenu.setEnabled(false)); 135 } 136 136 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/AddStopPositionAction.java
r33409 r33417 33 33 public class AddStopPositionAction extends MapMode { 34 34 35 private static final String mapModeName = "Add stop position";35 private static final String mapModeName = "Add stop position"; 36 36 37 private transient Set<OsmPrimitive> newHighlights = new HashSet<>();38 private transient Set<OsmPrimitive> oldHighlights = new HashSet<>();37 private transient Set<OsmPrimitive> newHighlights = new HashSet<>(); 38 private transient Set<OsmPrimitive> oldHighlights = new HashSet<>(); 39 39 40 40 private final Cursor cursorJoinNode; … … 44 44 * Creates a new AddStopPositionAction 45 45 */ 46 public AddStopPositionAction() {47 super(tr(mapModeName), "bus", tr(mapModeName),48 Shortcut.registerShortcut("mapmode:stop_position",46 public AddStopPositionAction() { 47 super(tr(mapModeName), "bus", tr(mapModeName), 48 Shortcut.registerShortcut("mapmode:stop_position", 49 49 tr("Mode: {0}", tr(mapModeName)), 50 50 KeyEvent.VK_K, Shortcut.CTRL_SHIFT), 51 getCursor());51 getCursor()); 52 52 53 cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");53 cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode"); 54 54 cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway"); 55 }55 } 56 56 57 57 private static Cursor getCursor() { 58 Cursor cursor = ImageProvider.getCursor("crosshair", "bus");59 if(cursor == null)60 cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);61 return cursor;58 Cursor cursor = ImageProvider.getCursor("crosshair", "bus"); 59 if(cursor == null) 60 cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); 61 return cursor; 62 62 } 63 63 … … 79 79 public void mouseMoved(MouseEvent e) { 80 80 81 //while the mouse is moving, surroundings are checked82 //if anything is found, it will be highlighted.83 //priority is given to nodes84 Cursor newCurs = getCursor();81 //while the mouse is moving, surroundings are checked 82 //if anything is found, it will be highlighted. 83 //priority is given to nodes 84 Cursor newCurs = getCursor(); 85 85 86 Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);87 if(n != null) {88 newHighlights.add(n);89 newCurs = cursorJoinNode;90 } else {91 List<WaySegment> wss =92 Main.map.mapView.getNearestWaySegments(e.getPoint(), OsmPrimitive::isSelectable);86 Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable); 87 if(n != null) { 88 newHighlights.add(n); 89 newCurs = cursorJoinNode; 90 } else { 91 List<WaySegment> wss = 92 Main.map.mapView.getNearestWaySegments(e.getPoint(), OsmPrimitive::isSelectable); 93 93 94 if(!wss.isEmpty()) {95 for(WaySegment ws : wss) {96 newHighlights.add(ws.way);97 }98 newCurs = cursorJoinWay;99 }100 }94 if(!wss.isEmpty()) { 95 for(WaySegment ws : wss) { 96 newHighlights.add(ws.way); 97 } 98 newCurs = cursorJoinWay; 99 } 100 } 101 101 102 Main.map.mapView.setCursor(newCurs);103 updateHighlights();102 Main.map.mapView.setCursor(newCurs); 103 updateHighlights(); 104 104 } 105 105 … … 107 107 public void mouseClicked(MouseEvent e) { 108 108 109 Boolean newNode = false;110 Node newStopPos;109 Boolean newNode = false; 110 Node newStopPos; 111 111 112 //check if the user as selected an existing node, or a new one113 Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);112 //check if the user as selected an existing node, or a new one 113 Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable); 114 114 if (n == null) { 115 newNode = true;116 newStopPos = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));115 newNode = true; 116 newStopPos = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY())); 117 117 } else { 118 newStopPos = new Node(n);118 newStopPos = new Node(n); 119 119 clearNodeTags(newStopPos); 120 120 } 121 121 122 122 //add the tags of the stop position 123 newStopPos.put("bus", "yes");124 newStopPos.put("public_transport", "stop_position");123 newStopPos.put("bus", "yes"); 124 newStopPos.put("public_transport", "stop_position"); 125 125 126 if(newNode) {127 Main.main.undoRedo.add(new AddCommand(newStopPos));128 } else {129 Main.main.undoRedo.add(new ChangeCommand(n, newStopPos));130 }126 if(newNode) { 127 Main.main.undoRedo.add(new AddCommand(newStopPos)); 128 } else { 129 Main.main.undoRedo.add(new ChangeCommand(n, newStopPos)); 130 } 131 131 132 DataSet ds = Main.getLayerManager().getEditLayer().data;133 ds.setSelected(newStopPos);132 DataSet ds = Main.getLayerManager().getEditLayer().data; 133 ds.setSelected(newStopPos); 134 134 135 //join the node to the way only if the node is new136 if(newNode) {137 JoinNodeWayAction joinNodeWayAction = JoinNodeWayAction.createJoinNodeToWayAction();138 joinNodeWayAction.actionPerformed(null);139 }135 //join the node to the way only if the node is new 136 if(newNode) { 137 JoinNodeWayAction joinNodeWayAction = JoinNodeWayAction.createJoinNodeToWayAction(); 138 joinNodeWayAction.actionPerformed(null); 139 } 140 140 141 141 // split the way in any case … … 145 145 146 146 private void clearNodeTags(Node newStopPos) { 147 for(String key : newStopPos.keySet()) {148 newStopPos.put(key, null);149 }147 for(String key : newStopPos.keySet()) { 148 newStopPos.put(key, null); 149 } 150 150 151 }151 } 152 152 153 //turn off what has been highlighted on last mouse move and highlight what has to be highlighted now153 //turn off what has been highlighted on last mouse move and highlight what has to be highlighted now 154 154 private void updateHighlights() 155 155 { 156 if(oldHighlights.isEmpty() && newHighlights.isEmpty()) {157 return;158 }156 if(oldHighlights.isEmpty() && newHighlights.isEmpty()) { 157 return; 158 } 159 159 160 for(OsmPrimitive osm : oldHighlights) {161 osm.setHighlighted(false);162 }160 for(OsmPrimitive osm : oldHighlights) { 161 osm.setHighlighted(false); 162 } 163 163 164 for(OsmPrimitive osm : newHighlights) {165 osm.setHighlighted(true);166 }164 for(OsmPrimitive osm : newHighlights) { 165 osm.setHighlighted(true); 166 } 167 167 168 Main.getLayerManager().getEditLayer().invalidate();168 Main.getLayerManager().getEditLayer().invalidate(); 169 169 170 oldHighlights.clear();171 oldHighlights.addAll(newHighlights);172 newHighlights.clear();170 oldHighlights.clear(); 171 oldHighlights.addAll(newHighlights); 172 newHighlights.clear(); 173 173 } 174 174 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/EdgeSelectionAction.java
r33409 r33417 30 30 public class EdgeSelectionAction extends MapMode { 31 31 32 private static final String mapModeName = "Edge Selection";33 private static final long serialVersionUID = 2414977774504904238L;32 private static final String mapModeName = "Edge Selection"; 33 private static final long serialVersionUID = 2414977774504904238L; 34 34 35 private transient Set<Way> highlighted;35 private transient Set<Way> highlighted; 36 36 37 private Cursor selectionCursor;38 private Cursor waySelectCursor;37 private Cursor selectionCursor; 38 private Cursor waySelectCursor; 39 39 40 public EdgeSelectionAction() {41 super(tr(mapModeName), "edgeSelection", tr(mapModeName),42 Shortcut.registerShortcut("mapmode:edge_selection",40 public EdgeSelectionAction() { 41 super(tr(mapModeName), "edgeSelection", tr(mapModeName), 42 Shortcut.registerShortcut("mapmode:edge_selection", 43 43 tr("Mode: {0}", tr(mapModeName)), 44 44 KeyEvent.VK_K, Shortcut.CTRL), 45 ImageProvider.getCursor("normal", "selection"));46 highlighted = new HashSet<>();45 ImageProvider.getCursor("normal", "selection")); 46 highlighted = new HashSet<>(); 47 47 48 selectionCursor = ImageProvider.getCursor("normal", "selection");49 waySelectCursor = ImageProvider.getCursor("normal", "select_way");50 }48 selectionCursor = ImageProvider.getCursor("normal", "selection"); 49 waySelectCursor = ImageProvider.getCursor("normal", "select_way"); 50 } 51 51 52 52 /* … … 55 55 */ 56 56 private List<Way> getEdgeFromWay(Way initial, String modeOfTravel) { 57 List<Way> edge = new ArrayList<>();58 if(!isWaySuitableForMode(initial, modeOfTravel))59 return edge;57 List<Way> edge = new ArrayList<>(); 58 if(!isWaySuitableForMode(initial, modeOfTravel)) 59 return edge; 60 60 61 Way curr = initial;62 while(true) {63 List<Way> options = curr.firstNode(true).getParentWays();64 options.remove(curr);65 curr = chooseBestWay(options, modeOfTravel);66 if(curr == null || edge.contains(curr))67 break;68 edge.add(curr);69 }61 Way curr = initial; 62 while(true) { 63 List<Way> options = curr.firstNode(true).getParentWays(); 64 options.remove(curr); 65 curr = chooseBestWay(options, modeOfTravel); 66 if(curr == null || edge.contains(curr)) 67 break; 68 edge.add(curr); 69 } 70 70 71 curr = initial;72 while(true) {73 List<Way> options = curr.lastNode(true).getParentWays();74 options.remove(curr);75 curr = chooseBestWay(options, modeOfTravel);76 if(curr == null || edge.contains(curr))77 break;78 edge.add(curr);79 }71 curr = initial; 72 while(true) { 73 List<Way> options = curr.lastNode(true).getParentWays(); 74 options.remove(curr); 75 curr = chooseBestWay(options, modeOfTravel); 76 if(curr == null || edge.contains(curr)) 77 break; 78 edge.add(curr); 79 } 80 80 81 edge.add(initial);82 return edge;81 edge.add(initial); 82 return edge; 83 83 } 84 84 85 85 private Boolean isWaySuitableForMode(Way toCheck, String modeOfTravel) { 86 if("bus".equals(modeOfTravel))87 return RouteUtils.isWaySuitableForBuses(toCheck);86 if("bus".equals(modeOfTravel)) 87 return RouteUtils.isWaySuitableForBuses(toCheck); 88 88 89 return RouteUtils.isWaySuitableForPublicTransport(toCheck);89 return RouteUtils.isWaySuitableForPublicTransport(toCheck); 90 90 } 91 91 … … 94 94 */ 95 95 private Way chooseBestWay(List<Way> ways, String modeOfTravel) { 96 ways.removeIf(w -> !isWaySuitableForMode(w, modeOfTravel));97 if(ways.isEmpty())98 return null;99 if(ways.size() == 1)100 return ways.get(0);96 ways.removeIf(w -> !isWaySuitableForMode(w, modeOfTravel)); 97 if(ways.isEmpty()) 98 return null; 99 if(ways.size() == 1) 100 return ways.get(0); 101 101 102 Way theChoosenOne = null;102 Way theChoosenOne = null; 103 103 104 if("bus".equals(modeOfTravel))105 {104 if("bus".equals(modeOfTravel)) 105 { 106 106 107 }108 if("tram".equals(modeOfTravel))109 {107 } 108 if("tram".equals(modeOfTravel)) 109 { 110 110 111 }111 } 112 112 113 return theChoosenOne;113 return theChoosenOne; 114 114 } 115 115 116 116 private String getModeOfTravel() { 117 //find a way to get the currently opened relation editor and get the118 //from there the current type of route119 return "bus";120 }117 //find a way to get the currently opened relation editor and get the 118 //from there the current type of route 119 return "bus"; 120 } 121 121 122 @Override122 @Override 123 123 public void mouseClicked(MouseEvent e) { 124 124 125 DataSet ds = Main.getLayerManager().getEditLayer().data;126 Way initial = Main.map.mapView.getNearestWay(e.getPoint(), OsmPrimitive::isUsable);127 if(initial != null){128 ds.setSelected(getEdgeFromWay(initial, getModeOfTravel()));129 }130 else131 ds.clearSelection();125 DataSet ds = Main.getLayerManager().getEditLayer().data; 126 Way initial = Main.map.mapView.getNearestWay(e.getPoint(), OsmPrimitive::isUsable); 127 if(initial != null){ 128 ds.setSelected(getEdgeFromWay(initial, getModeOfTravel())); 129 } 130 else 131 ds.clearSelection(); 132 132 } 133 133 134 134 @Override 135 135 public void mouseMoved(MouseEvent e) { 136 super.mouseMoved(e);136 super.mouseMoved(e); 137 137 138 for(Way way : highlighted)139 way.setHighlighted(false);140 highlighted.clear();138 for(Way way : highlighted) 139 way.setHighlighted(false); 140 highlighted.clear(); 141 141 142 Way initial = Main.map.mapView.getNearestWay(e.getPoint(), OsmPrimitive::isUsable);143 if(initial == null) {144 Main.map.mapView.setCursor(selectionCursor);145 }146 else {147 Main.map.mapView.setCursor(waySelectCursor);148 highlighted.addAll(getEdgeFromWay(initial, getModeOfTravel()));149 }142 Way initial = Main.map.mapView.getNearestWay(e.getPoint(), OsmPrimitive::isUsable); 143 if(initial == null) { 144 Main.map.mapView.setCursor(selectionCursor); 145 } 146 else { 147 Main.map.mapView.setCursor(waySelectCursor); 148 highlighted.addAll(getEdgeFromWay(initial, getModeOfTravel())); 149 } 150 150 151 for(Way way : highlighted)152 way.setHighlighted(true);151 for(Way way : highlighted) 152 way.setHighlighted(true); 153 153 } 154 154 -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/EditHighlightedRelationsAction.java
r33409 r33417 33 33 super(tr(actionName), new ImageProvider("dialogs", "edit"), tr(actionName), 34 34 Shortcut.registerShortcut("Edit Highlighted Relation", tr(actionName), 35 KeyEvent.VK_K, Shortcut.ALT),35 KeyEvent.VK_K, Shortcut.ALT), 36 36 false, "editHighlightedRelations", false); 37 37 } … … 39 39 @Override 40 40 public void actionPerformed(ActionEvent e) { 41 for(Relation relation : PTAssistantPlugin.getHighlightedRelations()) {42 RelationEditor editor = RelationEditor.getEditor(43 Main.getLayerManager().getEditLayer(), relation, null);41 for(Relation relation : PTAssistantPlugin.getHighlightedRelations()) { 42 RelationEditor editor = RelationEditor.getEditor( 43 Main.getLayerManager().getEditLayer(), relation, null); 44 44 editor.setVisible(true); 45 }45 } 46 46 } 47 47 -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/SplitRoundaboutAction.java
r33416 r33417 111 111 List<Node> splitNodes = getSplitNodes(roundabout); 112 112 SplitWayResult result = SplitWayAction.split(getLayerManager().getEditLayer(), 113 roundabout, splitNodes, Collections.emptyList());113 roundabout, splitNodes, Collections.emptyList()); 114 114 Main.main.undoRedo.add(result.getCommand()); 115 115 Collection<Way> splitWays = result.getNewWays(); -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteSegment.java
r33387 r33417 187 187 public boolean equalsRouteSegment(PTRouteSegment other) { 188 188 189 // if(!firstStop.equalsStop(firstStop) || !lastStop.equalsStop(other.lastStop))190 // return false;189 // if(!firstStop.equalsStop(firstStop) || !lastStop.equalsStop(other.lastStop)) 190 // return false; 191 191 192 192 List<Way> thisWays = new ArrayList<>(); -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayer.java
r33414 r33417 128 128 public void setPrimitives(List<OsmPrimitive> primitives) 129 129 { 130 this.primitives.clear();131 this.primitives.addAll(primitives);130 this.primitives.clear(); 131 this.primitives.addAll(primitives); 132 132 } 133 133 … … 267 267 268 268 if(event.getRemovedLayer() == this) { 269 PTAssistantLayerManager.PTLM.resetLayer();270 PTAssistantPlugin.clearHighlightedRelations();269 PTAssistantLayerManager.PTLM.resetLayer(); 270 PTAssistantPlugin.clearHighlightedRelations(); 271 271 } 272 272 } … … 274 274 @Override 275 275 public synchronized void destroy() { 276 KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener(this);276 KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener(this); 277 277 Main.getLayerManager().removeLayerChangeListener(this); 278 super.destroy();278 super.destroy(); 279 279 } 280 280 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayerManager.java
r33414 r33417 14 14 public class PTAssistantLayerManager implements SelectionChangedListener { 15 15 16 public final static PTAssistantLayerManager PTLM = new PTAssistantLayerManager();17 private PTAssistantLayer layer;16 public final static PTAssistantLayerManager PTLM = new PTAssistantLayerManager(); 17 private PTAssistantLayer layer; 18 18 19 19 public PTAssistantLayer getLayer() { … … 25 25 26 26 public void resetLayer() { 27 layer = null;27 layer = null; 28 28 } 29 29 … … 38 38 for (OsmPrimitive primitive : newSelection) { 39 39 if (primitive.getType().equals(OsmPrimitiveType.RELATION) 40 && RouteUtils.isVersionTwoPTRoute((Relation) primitive)) {41 routes.add(primitive);40 && RouteUtils.isVersionTwoPTRoute((Relation) primitive)) { 41 routes.add(primitive); 42 42 } 43 43 } 44 44 45 45 if (!routes.isEmpty()) { 46 getLayer().setPrimitives(routes);47 PTAssistantPlugin.clearHighlightedRelations();48 for(OsmPrimitive primitive : routes)49 PTAssistantPlugin.addHighlightedRelation((Relation) primitive);46 getLayer().setPrimitives(routes); 47 PTAssistantPlugin.clearHighlightedRelations(); 48 for(OsmPrimitive primitive : routes) 49 PTAssistantPlugin.addHighlightedRelation((Relation) primitive); 50 50 } 51 51 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPaintVisitor.java
r33414 r33417 286 286 @Override 287 287 protected void drawNode(Node n, Color color) { 288 if (mv == null || g == null) {289 return;290 }288 if (mv == null || g == null) { 289 ; 290 } 291 291 Point p = mv.getPoint(n); 292 if (p == null) {293 return;294 }292 if (p == null) { 293 return; 294 } 295 295 g.setColor(color); 296 296 g.drawOval(p.x - 5, p.y - 5, 10, 10); -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/utils/RouteUtils.java
r33414 r33417 19 19 public final class RouteUtils { 20 20 21 private final static String ptVersionTag = "public_transport:version";21 private final static String ptVersionTag = "public_transport:version"; 22 22 private RouteUtils() { 23 23 // private constructor for util classes -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/NodeChecker.java
r33082 r33417 28 28 public class NodeChecker extends Checker { 29 29 30 protected NodeChecker(Node node, Test test) {31 super(node, test);30 protected NodeChecker(Node node, Test test) { 31 super(node, test); 32 32 33 }33 } 34 34 35 /**36 * Checks if the given stop_position node belongs to any way37 */38 protected void performSolitaryStopPositionTest() {35 /** 36 * Checks if the given stop_position node belongs to any way 37 */ 38 protected void performSolitaryStopPositionTest() { 39 39 40 List<OsmPrimitive> referrers = node.getReferrers();40 List<OsmPrimitive> referrers = node.getReferrers(); 41 41 42 for (OsmPrimitive referrer : referrers) {43 if (referrer.getType().equals(OsmPrimitiveType.WAY)) {44 Way referrerWay = (Way) referrer;45 if (RouteUtils.isWaySuitableForPublicTransport(referrerWay)) {46 return;47 }42 for (OsmPrimitive referrer : referrers) { 43 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 44 Way referrerWay = (Way) referrer; 45 if (RouteUtils.isWaySuitableForPublicTransport(referrerWay)) { 46 return; 47 } 48 48 49 }50 }49 } 50 } 51 51 52 List<OsmPrimitive> primitives = new ArrayList<>(1);53 primitives.add(node);54 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION);55 builder.message(tr("PT: Stop_position is not part of a way"));56 builder.primitives(primitives);57 TestError e = builder.build();58 errors.add(e);52 List<OsmPrimitive> primitives = new ArrayList<>(1); 53 primitives.add(node); 54 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION); 55 builder.message(tr("PT: Stop_position is not part of a way")); 56 builder.primitives(primitives); 57 TestError e = builder.build(); 58 errors.add(e); 59 59 60 }60 } 61 61 62 /**63 * Checks if the given platform node belongs to any way64 */65 protected void performPlatformPartOfWayTest() {62 /** 63 * Checks if the given platform node belongs to any way 64 */ 65 protected void performPlatformPartOfWayTest() { 66 66 67 List<OsmPrimitive> referrers = node.getReferrers();67 List<OsmPrimitive> referrers = node.getReferrers(); 68 68 69 for (OsmPrimitive referrer : referrers) {70 List<Node> primitives = new ArrayList<>(1);71 primitives.add(node);72 if (referrer.getType().equals(OsmPrimitiveType.WAY)) {73 Way referringWay = (Way) referrer;74 if (RouteUtils.isWaySuitableForPublicTransport(referringWay)) {75 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY);76 builder.message(tr("PT: Platform should not be part of a way"));77 builder.primitives(primitives);78 TestError e = builder.build();79 errors.add(e);80 return;81 }82 }83 }84 }69 for (OsmPrimitive referrer : referrers) { 70 List<Node> primitives = new ArrayList<>(1); 71 primitives.add(node); 72 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 73 Way referringWay = (Way) referrer; 74 if (RouteUtils.isWaySuitableForPublicTransport(referringWay)) { 75 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY); 76 builder.message(tr("PT: Platform should not be part of a way")); 77 builder.primitives(primitives); 78 TestError e = builder.build(); 79 errors.add(e); 80 return; 81 } 82 } 83 } 84 } 85 85 86 /**87 * Checks if the given stop_position node belongs to any stop_area relation88 * 89 * @author xamanu90 */91 protected void performNodePartOfStopAreaTest() {86 /** 87 * Checks if the given stop_position node belongs to any stop_area relation 88 * 89 * @author xamanu 90 */ 91 protected void performNodePartOfStopAreaTest() { 92 92 93 if (!StopUtils.verifyIfMemberOfStopArea(node)) {93 if (!StopUtils.verifyIfMemberOfStopArea(node)) { 94 94 95 List<OsmPrimitive> primitives = new ArrayList<>(1);96 primitives.add(node);97 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA);98 builder.message(tr("PT: Stop position or platform is not part of a stop area relation"));99 builder.primitives(primitives);100 TestError e = builder.build();101 errors.add(e);102 }103 }95 List<OsmPrimitive> primitives = new ArrayList<>(1); 96 primitives.add(node); 97 Builder builder = TestError.builder(this.test, Severity.WARNING, PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA); 98 builder.message(tr("PT: Stop position or platform is not part of a stop area relation")); 99 builder.primitives(primitives); 100 TestError e = builder.build(); 101 errors.add(e); 102 } 103 } 104 104 105 /**106 * Fixes errors: solitary stop position and platform which is part of a way.107 * Asks the user first.108 *109 * @param testError110 * test error111 * @return fix command112 */113 protected static Command fixError(TestError testError) {105 /** 106 * Fixes errors: solitary stop position and platform which is part of a way. 107 * Asks the user first. 108 * 109 * @param testError 110 * test error 111 * @return fix command 112 */ 113 protected static Command fixError(TestError testError) { 114 114 115 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION116 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {117 return null;118 }115 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 116 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 117 return null; 118 } 119 119 120 Node problematicNode = (Node) testError.getPrimitives().iterator().next();120 Node problematicNode = (Node) testError.getPrimitives().iterator().next(); 121 121 122 final int[] userSelection = { JOptionPane.YES_OPTION };123 final TestError errorParameter = testError;124 if (SwingUtilities.isEventDispatchThread()) {122 final int[] userSelection = { JOptionPane.YES_OPTION }; 123 final TestError errorParameter = testError; 124 if (SwingUtilities.isEventDispatchThread()) { 125 125 126 userSelection[0] = showFixNodeTagDialog(errorParameter);126 userSelection[0] = showFixNodeTagDialog(errorParameter); 127 127 128 } else {128 } else { 129 129 130 try {131 SwingUtilities.invokeAndWait(new Runnable() {132 @Override133 public void run() {134 userSelection[0] = showFixNodeTagDialog(errorParameter);135 }136 });137 } catch (InvocationTargetException | InterruptedException e) {138 e.printStackTrace();139 return null;140 }141 }130 try { 131 SwingUtilities.invokeAndWait(new Runnable() { 132 @Override 133 public void run() { 134 userSelection[0] = showFixNodeTagDialog(errorParameter); 135 } 136 }); 137 } catch (InvocationTargetException | InterruptedException e) { 138 e.printStackTrace(); 139 return null; 140 } 141 } 142 142 143 if (userSelection[0] == JOptionPane.YES_OPTION) {143 if (userSelection[0] == JOptionPane.YES_OPTION) { 144 144 145 Node modifiedNode = new Node(problematicNode);146 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) {147 modifiedNode.put("public_transport", "platform");148 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode);149 return command;150 } else {151 modifiedNode.put("public_transport", "stop_position");152 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode);153 return command;154 }155 }145 Node modifiedNode = new Node(problematicNode); 146 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) { 147 modifiedNode.put("public_transport", "platform"); 148 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode); 149 return command; 150 } else { 151 modifiedNode.put("public_transport", "stop_position"); 152 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode); 153 return command; 154 } 155 } 156 156 157 return null;157 return null; 158 158 159 }159 } 160 160 161 private static int showFixNodeTagDialog(TestError e) {162 Node problematicNode = (Node) e.getPrimitives().iterator().next();163 // Main.map.mapView.zoomTo(problematicNode.getCoor());164 // zoom to problem:165 Collection<OsmPrimitive> primitives = new ArrayList<>(1);166 primitives.add(problematicNode);167 AutoScaleAction.zoomTo(primitives);161 private static int showFixNodeTagDialog(TestError e) { 162 Node problematicNode = (Node) e.getPrimitives().iterator().next(); 163 // Main.map.mapView.zoomTo(problematicNode.getCoor()); 164 // zoom to problem: 165 Collection<OsmPrimitive> primitives = new ArrayList<>(1); 166 primitives.add(problematicNode); 167 AutoScaleAction.zoomTo(primitives); 168 168 169 String[] options = { tr("Yes"), tr("No") };170 String message;171 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) {172 message = "Do you want to change the tag public_transport=stop_position to public_transport=platform?";173 } else {174 message = "Do you want to change the tag public_transport=platform to public_transport=stop_position?";175 }176 return JOptionPane.showOptionDialog(null, message, tr("PT_Assistant Message"), JOptionPane.YES_NO_OPTION,177 JOptionPane.QUESTION_MESSAGE, null, options, 0);178 }169 String[] options = { tr("Yes"), tr("No") }; 170 String message; 171 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) { 172 message = "Do you want to change the tag public_transport=stop_position to public_transport=platform?"; 173 } else { 174 message = "Do you want to change the tag public_transport=platform to public_transport=stop_position?"; 175 } 176 return JOptionPane.showOptionDialog(null, message, tr("PT_Assistant Message"), JOptionPane.YES_NO_OPTION, 177 JOptionPane.QUESTION_MESSAGE, null, options, 0); 178 } 179 179 180 180 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java
r33414 r33417 44 44 public class PTAssistantValidatorTest extends Test { 45 45 46 public static final int ERROR_CODE_SORTING = 3711;47 public static final int ERROR_CODE_PARTIAL_SORTING = 3712;48 public static final int ERROR_CODE_ROAD_TYPE = 3721;49 public static final int ERROR_CODE_CONSTRUCTION = 3722;50 public static final int ERROR_CODE_DIRECTION = 3731;51 public static final int ERROR_CODE_END_STOP = 3741;52 public static final int ERROR_CODE_SPLIT_WAY = 3742;53 public static final int ERROR_CODE_RELATION_MEMBER_ROLES = 3743;54 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751;55 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752;56 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753;57 public static final int ERROR_CODE_STOP_BY_STOP = 3754;58 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761;59 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762;60 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763;61 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764;62 63 public PTAssistantValidatorTest() {64 super(tr("Public Transport Assistant tests"),65 tr("Check if route relations are compatible with public transport version 2"));66 67 DataSet.addSelectionListener(PTAssistantLayerManager.PTLM);68 69 }70 71 @Override72 public void visit(Node n) {73 74 if (n.isIncomplete()) {75 return;76 }77 78 NodeChecker nodeChecker = new NodeChecker(n, this);79 80 // select only stop_positions81 if (n.hasTag("public_transport", "stop_position")) {82 83 // check if stop positions are on a way:84 nodeChecker.performSolitaryStopPositionTest();85 86 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true) {87 // check if stop positions are in any stop_area relation:88 nodeChecker.performNodePartOfStopAreaTest();89 }90 91 }92 93 // select only platforms94 if (n.hasTag("public_transport", "platform")) {95 96 // check that platforms are not part of any way:97 nodeChecker.performPlatformPartOfWayTest();98 99 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true) {100 // check if platforms are in any stop_area relation:101 nodeChecker.performNodePartOfStopAreaTest();102 }103 104 }105 106 this.errors.addAll(nodeChecker.getErrors());107 108 }109 110 @Override111 public void visit(Relation r) {112 113 // Download incomplete members. If the download does not work, return114 // and do not do any testing.115 if (r.hasIncompleteMembers()) {116 117 boolean downloadSuccessful = this.downloadIncompleteMembers();118 if (!downloadSuccessful) {119 return;120 }121 }122 123 if (r.hasIncompleteMembers()) {124 return;125 }126 127 // Do some testing on stop area relations128 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true && StopUtils.isStopArea(r)) {129 130 StopChecker stopChecker = new StopChecker(r, this);131 132 // Check if stop area relation has one stop position.133 stopChecker.performStopAreaStopPositionTest();134 135 // Check if stop area relation has one platform.136 stopChecker.performStopAreaPlatformTest();137 138 // Check if stop position(s) belong the same route relation as139 // related platform(s)140 stopChecker.performStopAreaRelationsTest();141 142 // Attach thrown errors143 this.errors.addAll(stopChecker.getErrors());144 }145 146 if (!RouteUtils.isVersionTwoPTRoute(r)) {147 return;148 }149 150 // Check individual ways using the oneway direction test and the road151 // type test:152 WayChecker wayChecker = new WayChecker(r, this);153 wayChecker.performDirectionTest();154 wayChecker.performRoadTypeTest();155 this.errors.addAll(wayChecker.getErrors());156 157 proceedWithSorting(r);158 159 // This allows to modify the route before the sorting and160 // SegmentChecker are carried out:161 // if (this.errors.isEmpty()) {162 // proceedWithSorting(r);163 // } else {164 // this.proceedAfterWayCheckerErrors(r);165 // }166 167 }168 169 /**170 * Downloads incomplete relation members in an extra thread (user input171 * required)172 *173 * @return true if successful, false if not successful174 */175 private boolean downloadIncompleteMembers() {176 177 final int[] userSelection = { 0 };178 179 try {180 181 if (SwingUtilities.isEventDispatchThread()) {182 183 userSelection[0] = showIncompleteMembersDownloadDialog();184 185 } else {186 187 SwingUtilities.invokeAndWait(new Runnable() {188 @Override189 public void run() {190 try {191 userSelection[0] = showIncompleteMembersDownloadDialog();192 } catch (InterruptedException e) {193 e.printStackTrace();194 }195 196 }197 });198 199 }200 201 } catch (InterruptedException | InvocationTargetException e) {202 return false;203 }204 205 if (userSelection[0] == JOptionPane.YES_OPTION) {206 207 Thread t = new IncompleteMembersDownloadThread();208 t.start();209 synchronized (t) {210 try {211 t.wait();212 } catch (InterruptedException e) {213 return false;214 }215 }216 217 }218 219 return true;220 221 }222 223 /**224 * Shows the dialog asking the user about an incomplete member download225 *226 * @return user's selection227 * @throws InterruptedException228 * if interrupted229 */230 private int showIncompleteMembersDownloadDialog() throws InterruptedException {231 232 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) {233 return JOptionPane.YES_OPTION;234 }235 236 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) {237 return JOptionPane.NO_OPTION;238 }239 240 IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog();241 return incompleteMembersDownloadDialog.getUserSelection();242 243 }244 245 /**246 * Gets user input after errors were detected by WayChecker. Although this247 * method is not used in the current implementation, it can be used to fix248 * errors from the previous testing stage and modify the route before the249 * second stage of testing is carried out.250 */251 @SuppressWarnings("unused")252 private void proceedAfterWayCheckerErrors(Relation r) {253 254 // count errors of each type:255 int numberOfDirectionErrors = 0;256 int numberOfRoadTypeErrors = 0;257 for (TestError e : this.errors) {258 if (e.getCode() == ERROR_CODE_DIRECTION) {259 numberOfDirectionErrors++;260 }261 if (e.getCode() == ERROR_CODE_ROAD_TYPE) {262 numberOfRoadTypeErrors++;263 }264 }265 266 final int[] userInput = { 0 };267 final long idParameter = r.getId();268 final int directionErrorParameter = numberOfDirectionErrors;269 final int roadTypeErrorParameter = numberOfRoadTypeErrors;270 271 if (SwingUtilities.isEventDispatchThread()) {272 273 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);274 275 } else {276 277 try {278 SwingUtilities.invokeAndWait(new Runnable() {279 @Override280 public void run() {281 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);282 283 }284 });285 } catch (InvocationTargetException | InterruptedException e1) {286 e1.printStackTrace();287 }288 289 }290 291 if (userInput[0] == 0) {292 this.fixErrorFromPlugin(this.errors);293 proceedWithSorting(r);294 return;295 }296 297 if (userInput[0] == 1) {298 JOptionPane.showMessageDialog(null, "This is not implemented yet!");299 return;300 }301 302 if (userInput[0] == 2) {303 proceedWithSorting(r);304 }305 306 // if userInput==-1 (i.e. no input), do nothing and stop testing of the307 // route.308 309 }310 311 private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {312 313 if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) {314 return 2;315 }316 317 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) {318 return 0;319 }320 321 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) {322 return 2;323 }324 325 ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors);326 return proceedDialog.getUserSelection();327 328 }329 330 /**331 * Carries out the second stage of the testing: sorting332 *333 * @param r334 * relation335 */336 private void proceedWithSorting(Relation r) {337 338 // Check if the relation is correct, or only has a wrong sorting order:339 RouteChecker routeChecker = new RouteChecker(r, this);340 routeChecker.performSortingTest();341 List<TestError> routeCheckerErrors = routeChecker.getErrors();342 343 /*- At this point, there are 3 variants:344 *345 * 1) There are no errors => route is correct346 * 2) There is only a sorting error (can only be 1), but otherwise347 * correct.348 * 3) There are some other errors/gaps that cannot be fixed by349 * sorting => start further test (stop-by-stop)350 *351 * */352 353 if (!routeCheckerErrors.isEmpty()) {354 // Variant 2355 // If there is only the sorting error, add it356 this.errors.addAll(routeChecker.getErrors());357 }358 359 // if (!routeChecker.getHasGap()) {360 // // Variant 1361 // storeCorrectRouteSegments(r);362 // }363 364 // Variant 3:365 proceedAfterSorting(r);366 367 }368 369 /**370 * Carries out the stop-by-stop testing which includes building the route371 * data model.372 *373 * @param r374 * route relation375 */376 private void proceedAfterSorting(Relation r) {377 378 SegmentChecker segmentChecker = new SegmentChecker(r, this);379 380 // Check if the creation of the route data model in the segment checker381 // worked. If it did not, it means the roles in the route relation do382 // not match the tags of the route members.383 if (!segmentChecker.getErrors().isEmpty()) {384 this.errors.addAll(segmentChecker.getErrors());385 }386 387 segmentChecker.performFirstStopTest();388 segmentChecker.performLastStopTest();389 segmentChecker.performStopNotServedTest();390 391 boolean sortingErrorFound = false;392 for (TestError error : this.errors) {393 if (error.getCode() == ERROR_CODE_SORTING394 || error.getCode() == ERROR_CODE_PARTIAL_SORTING) {395 sortingErrorFound = true;396 break;397 }398 }399 if (!sortingErrorFound) {400 segmentChecker.performStopByStopTest();401 segmentChecker.findFixes();402 }403 404 for (TestError error : segmentChecker.getErrors()) {405 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELATION_MEMBER_ROLES) {406 this.errors.add(error);407 }408 }409 }410 411 @Override412 public void startTest(ProgressMonitor progressMonitor) {413 super.startTest(progressMonitor);414 415 // reset the static collections in SegmentChecker:416 SegmentChecker.reset();417 }418 419 /**420 * Method is called after all primitives has been visited, overrides the421 * method of the superclass.422 */423 @Override424 public void endTest() {425 426 // modify the error messages for the stop-by-stop test:427 SegmentChecker.modifyStopByStopErrorMessages();428 429 // add the stop-by-stop errors with modified messages:430 for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) {431 TestError error = entry.getKey().build();432 SegmentChecker.wrongSegments.put(error, entry.getValue());433 this.errors.add(error);434 }435 436 super.endTest();437 438 }439 440 /**441 * Creates the PTRouteSegments of a route that has been found correct and442 * stores them in the list of correct route segments443 *444 * @param r445 * route relation446 */447 @SuppressWarnings("unused")448 private void storeCorrectRouteSegments(Relation r) {449 PTRouteDataManager manager = new PTRouteDataManager(r);450 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays());451 if (manager.getPTStops().size() > 1) {452 for (int i = 1; i < manager.getPTStops().size(); i++) {453 PTStop segmentStartStop = manager.getPTStops().get(i - 1);454 PTStop segmentEndStop = manager.getPTStops().get(i);455 Way segmentStartWay = assigner.get(segmentStartStop);456 Way segmentEndWay = assigner.get(segmentEndStop);457 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay);458 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r);459 SegmentChecker.addCorrectSegment(routeSegment);460 }461 }462 }463 464 /**465 * Checks if the test error is fixable466 */467 @Override468 public boolean isFixable(TestError testError) {469 if (testError.getCode() == ERROR_CODE_DIRECTION470 || testError.getCode() == ERROR_CODE_ROAD_TYPE471 || testError.getCode() == ERROR_CODE_CONSTRUCTION472 || testError.getCode() == ERROR_CODE_SORTING473 || testError.getCode() == ERROR_CODE_PARTIAL_SORTING474 || testError.getCode() == ERROR_CODE_END_STOP475 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {476 return true;477 }478 479 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) {480 return true;481 }482 483 return false;484 }485 486 /**487 * Fixes the given error488 */489 @Override490 public Command fixError(TestError testError) {491 492 // repaint the relation in the pt_assistant layer:493 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) {494 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next();495 PTAssistantLayerManager.PTLM.getLayer().repaint(relationToBeFixed);496 }497 498 // reset the last fix:499 PTAssistantPlugin.setLastFix(null);500 501 List<Command> commands = new ArrayList<>();502 503 if (testError.getCode() == ERROR_CODE_ROAD_TYPE504 || testError.getCode() == ERROR_CODE_CONSTRUCTION505 || testError.getCode() == ERROR_CODE_DIRECTION506 || testError.getCode() == ERROR_CODE_END_STOP) {507 commands.add(WayChecker.fixErrorByZooming(testError));508 }509 510 if (testError.getCode() == ERROR_CODE_SORTING511 || testError.getCode() == ERROR_CODE_PARTIAL_SORTING) {512 commands.add(RouteChecker.fixSortingError(testError));513 }514 515 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION516 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {517 commands.add(NodeChecker.fixError(testError));518 }519 520 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) {521 commands.add(SegmentChecker.fixError(testError));522 // make sure the primitives of this testError are selected:523 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>();524 for (Object obj : testError.getPrimitives()) {525 primitivesToSelect.add((OsmPrimitive) obj);526 }527 SelectCommand selectCommand = new SelectCommand(primitivesToSelect);528 SwingUtilities.invokeLater(new Runnable() {529 @Override530 public void run() {531 selectCommand.executeCommand();532 }533 });534 }535 536 if (commands.isEmpty()) {537 return null;538 }539 540 if (commands.size() == 1) {541 return commands.get(0);542 }543 544 return new SequenceCommand(tr("Fix error"), commands);545 }546 547 /**548 * This method is the counterpart of the fixError(TestError testError)549 * method. The fixError method is invoked from the core validator (e.g. when550 * user presses the "Fix" button in the validator). This method is invoken551 * when the fix is initiated from within the plugin (e.g. automated fixes).552 */553 private void fixErrorFromPlugin(List<TestError> testErrors) {554 555 // run fix task asynchronously556 FixTask fixTask = new FixTask(testErrors);557 558 Thread t = new Thread(fixTask);559 t.start();560 try {561 t.join();562 errors.removeAll(testErrors);563 564 } catch (InterruptedException e) {565 JOptionPane.showMessageDialog(null, "Error occurred during fixing");566 }567 568 }569 570 public void addFixVariants(List<List<PTWay>> fixVariants) {571 PTAssistantLayerManager.PTLM.getLayer().addFixVariants(fixVariants);572 }573 574 public void clearFixVariants() {575 PTAssistantLayerManager.PTLM.getLayer().clearFixVariants();576 }577 578 public List<PTWay> getFixVariant(Character c) {579 return PTAssistantLayerManager.PTLM.getLayer().getFixVariant(c);580 }581 582 @SuppressWarnings("unused")583 private void performDummyTest(Relation r) {584 List<Relation> primitives = new ArrayList<>(1);585 primitives.add(r);586 Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION);587 builder.message(tr("PT: dummy test warning"));588 builder.primitives(primitives);589 errors.add(builder.build());590 }46 public static final int ERROR_CODE_SORTING = 3711; 47 public static final int ERROR_CODE_PARTIAL_SORTING = 3712; 48 public static final int ERROR_CODE_ROAD_TYPE = 3721; 49 public static final int ERROR_CODE_CONSTRUCTION = 3722; 50 public static final int ERROR_CODE_DIRECTION = 3731; 51 public static final int ERROR_CODE_END_STOP = 3741; 52 public static final int ERROR_CODE_SPLIT_WAY = 3742; 53 public static final int ERROR_CODE_RELATION_MEMBER_ROLES = 3743; 54 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751; 55 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752; 56 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753; 57 public static final int ERROR_CODE_STOP_BY_STOP = 3754; 58 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761; 59 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762; 60 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763; 61 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764; 62 63 public PTAssistantValidatorTest() { 64 super(tr("Public Transport Assistant tests"), 65 tr("Check if route relations are compatible with public transport version 2")); 66 67 DataSet.addSelectionListener(PTAssistantLayerManager.PTLM); 68 69 } 70 71 @Override 72 public void visit(Node n) { 73 74 if (n.isIncomplete()) { 75 return; 76 } 77 78 NodeChecker nodeChecker = new NodeChecker(n, this); 79 80 // select only stop_positions 81 if (n.hasTag("public_transport", "stop_position")) { 82 83 // check if stop positions are on a way: 84 nodeChecker.performSolitaryStopPositionTest(); 85 86 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true) { 87 // check if stop positions are in any stop_area relation: 88 nodeChecker.performNodePartOfStopAreaTest(); 89 } 90 91 } 92 93 // select only platforms 94 if (n.hasTag("public_transport", "platform")) { 95 96 // check that platforms are not part of any way: 97 nodeChecker.performPlatformPartOfWayTest(); 98 99 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true) { 100 // check if platforms are in any stop_area relation: 101 nodeChecker.performNodePartOfStopAreaTest(); 102 } 103 104 } 105 106 this.errors.addAll(nodeChecker.getErrors()); 107 108 } 109 110 @Override 111 public void visit(Relation r) { 112 113 // Download incomplete members. If the download does not work, return 114 // and do not do any testing. 115 if (r.hasIncompleteMembers()) { 116 117 boolean downloadSuccessful = this.downloadIncompleteMembers(); 118 if (!downloadSuccessful) { 119 return; 120 } 121 } 122 123 if (r.hasIncompleteMembers()) { 124 return; 125 } 126 127 // Do some testing on stop area relations 128 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", false) == true && StopUtils.isStopArea(r)) { 129 130 StopChecker stopChecker = new StopChecker(r, this); 131 132 // Check if stop area relation has one stop position. 133 stopChecker.performStopAreaStopPositionTest(); 134 135 // Check if stop area relation has one platform. 136 stopChecker.performStopAreaPlatformTest(); 137 138 // Check if stop position(s) belong the same route relation as 139 // related platform(s) 140 stopChecker.performStopAreaRelationsTest(); 141 142 // Attach thrown errors 143 this.errors.addAll(stopChecker.getErrors()); 144 } 145 146 if (!RouteUtils.isVersionTwoPTRoute(r)) { 147 return; 148 } 149 150 // Check individual ways using the oneway direction test and the road 151 // type test: 152 WayChecker wayChecker = new WayChecker(r, this); 153 wayChecker.performDirectionTest(); 154 wayChecker.performRoadTypeTest(); 155 this.errors.addAll(wayChecker.getErrors()); 156 157 proceedWithSorting(r); 158 159 // This allows to modify the route before the sorting and 160 // SegmentChecker are carried out: 161 // if (this.errors.isEmpty()) { 162 // proceedWithSorting(r); 163 // } else { 164 // this.proceedAfterWayCheckerErrors(r); 165 // } 166 167 } 168 169 /** 170 * Downloads incomplete relation members in an extra thread (user input 171 * required) 172 * 173 * @return true if successful, false if not successful 174 */ 175 private boolean downloadIncompleteMembers() { 176 177 final int[] userSelection = { 0 }; 178 179 try { 180 181 if (SwingUtilities.isEventDispatchThread()) { 182 183 userSelection[0] = showIncompleteMembersDownloadDialog(); 184 185 } else { 186 187 SwingUtilities.invokeAndWait(new Runnable() { 188 @Override 189 public void run() { 190 try { 191 userSelection[0] = showIncompleteMembersDownloadDialog(); 192 } catch (InterruptedException e) { 193 e.printStackTrace(); 194 } 195 196 } 197 }); 198 199 } 200 201 } catch (InterruptedException | InvocationTargetException e) { 202 return false; 203 } 204 205 if (userSelection[0] == JOptionPane.YES_OPTION) { 206 207 Thread t = new IncompleteMembersDownloadThread(); 208 t.start(); 209 synchronized (t) { 210 try { 211 t.wait(); 212 } catch (InterruptedException e) { 213 return false; 214 } 215 } 216 217 } 218 219 return true; 220 221 } 222 223 /** 224 * Shows the dialog asking the user about an incomplete member download 225 * 226 * @return user's selection 227 * @throws InterruptedException 228 * if interrupted 229 */ 230 private int showIncompleteMembersDownloadDialog() throws InterruptedException { 231 232 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) { 233 return JOptionPane.YES_OPTION; 234 } 235 236 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) { 237 return JOptionPane.NO_OPTION; 238 } 239 240 IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog(); 241 return incompleteMembersDownloadDialog.getUserSelection(); 242 243 } 244 245 /** 246 * Gets user input after errors were detected by WayChecker. Although this 247 * method is not used in the current implementation, it can be used to fix 248 * errors from the previous testing stage and modify the route before the 249 * second stage of testing is carried out. 250 */ 251 @SuppressWarnings("unused") 252 private void proceedAfterWayCheckerErrors(Relation r) { 253 254 // count errors of each type: 255 int numberOfDirectionErrors = 0; 256 int numberOfRoadTypeErrors = 0; 257 for (TestError e : this.errors) { 258 if (e.getCode() == ERROR_CODE_DIRECTION) { 259 numberOfDirectionErrors++; 260 } 261 if (e.getCode() == ERROR_CODE_ROAD_TYPE) { 262 numberOfRoadTypeErrors++; 263 } 264 } 265 266 final int[] userInput = { 0 }; 267 final long idParameter = r.getId(); 268 final int directionErrorParameter = numberOfDirectionErrors; 269 final int roadTypeErrorParameter = numberOfRoadTypeErrors; 270 271 if (SwingUtilities.isEventDispatchThread()) { 272 273 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 274 275 } else { 276 277 try { 278 SwingUtilities.invokeAndWait(new Runnable() { 279 @Override 280 public void run() { 281 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 282 283 } 284 }); 285 } catch (InvocationTargetException | InterruptedException e1) { 286 e1.printStackTrace(); 287 } 288 289 } 290 291 if (userInput[0] == 0) { 292 this.fixErrorFromPlugin(this.errors); 293 proceedWithSorting(r); 294 return; 295 } 296 297 if (userInput[0] == 1) { 298 JOptionPane.showMessageDialog(null, "This is not implemented yet!"); 299 return; 300 } 301 302 if (userInput[0] == 2) { 303 proceedWithSorting(r); 304 } 305 306 // if userInput==-1 (i.e. no input), do nothing and stop testing of the 307 // route. 308 309 } 310 311 private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 312 313 if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) { 314 return 2; 315 } 316 317 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) { 318 return 0; 319 } 320 321 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) { 322 return 2; 323 } 324 325 ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors); 326 return proceedDialog.getUserSelection(); 327 328 } 329 330 /** 331 * Carries out the second stage of the testing: sorting 332 * 333 * @param r 334 * relation 335 */ 336 private void proceedWithSorting(Relation r) { 337 338 // Check if the relation is correct, or only has a wrong sorting order: 339 RouteChecker routeChecker = new RouteChecker(r, this); 340 routeChecker.performSortingTest(); 341 List<TestError> routeCheckerErrors = routeChecker.getErrors(); 342 343 /*- At this point, there are 3 variants: 344 * 345 * 1) There are no errors => route is correct 346 * 2) There is only a sorting error (can only be 1), but otherwise 347 * correct. 348 * 3) There are some other errors/gaps that cannot be fixed by 349 * sorting => start further test (stop-by-stop) 350 * 351 * */ 352 353 if (!routeCheckerErrors.isEmpty()) { 354 // Variant 2 355 // If there is only the sorting error, add it 356 this.errors.addAll(routeChecker.getErrors()); 357 } 358 359 // if (!routeChecker.getHasGap()) { 360 // // Variant 1 361 // storeCorrectRouteSegments(r); 362 // } 363 364 // Variant 3: 365 proceedAfterSorting(r); 366 367 } 368 369 /** 370 * Carries out the stop-by-stop testing which includes building the route 371 * data model. 372 * 373 * @param r 374 * route relation 375 */ 376 private void proceedAfterSorting(Relation r) { 377 378 SegmentChecker segmentChecker = new SegmentChecker(r, this); 379 380 // Check if the creation of the route data model in the segment checker 381 // worked. If it did not, it means the roles in the route relation do 382 // not match the tags of the route members. 383 if (!segmentChecker.getErrors().isEmpty()) { 384 this.errors.addAll(segmentChecker.getErrors()); 385 } 386 387 segmentChecker.performFirstStopTest(); 388 segmentChecker.performLastStopTest(); 389 segmentChecker.performStopNotServedTest(); 390 391 boolean sortingErrorFound = false; 392 for (TestError error : this.errors) { 393 if (error.getCode() == ERROR_CODE_SORTING 394 || error.getCode() == ERROR_CODE_PARTIAL_SORTING) { 395 sortingErrorFound = true; 396 break; 397 } 398 } 399 if (!sortingErrorFound) { 400 segmentChecker.performStopByStopTest(); 401 segmentChecker.findFixes(); 402 } 403 404 for (TestError error : segmentChecker.getErrors()) { 405 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELATION_MEMBER_ROLES) { 406 this.errors.add(error); 407 } 408 } 409 } 410 411 @Override 412 public void startTest(ProgressMonitor progressMonitor) { 413 super.startTest(progressMonitor); 414 415 // reset the static collections in SegmentChecker: 416 SegmentChecker.reset(); 417 } 418 419 /** 420 * Method is called after all primitives has been visited, overrides the 421 * method of the superclass. 422 */ 423 @Override 424 public void endTest() { 425 426 // modify the error messages for the stop-by-stop test: 427 SegmentChecker.modifyStopByStopErrorMessages(); 428 429 // add the stop-by-stop errors with modified messages: 430 for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) { 431 TestError error = entry.getKey().build(); 432 SegmentChecker.wrongSegments.put(error, entry.getValue()); 433 this.errors.add(error); 434 } 435 436 super.endTest(); 437 438 } 439 440 /** 441 * Creates the PTRouteSegments of a route that has been found correct and 442 * stores them in the list of correct route segments 443 * 444 * @param r 445 * route relation 446 */ 447 @SuppressWarnings("unused") 448 private void storeCorrectRouteSegments(Relation r) { 449 PTRouteDataManager manager = new PTRouteDataManager(r); 450 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 451 if (manager.getPTStops().size() > 1) { 452 for (int i = 1; i < manager.getPTStops().size(); i++) { 453 PTStop segmentStartStop = manager.getPTStops().get(i - 1); 454 PTStop segmentEndStop = manager.getPTStops().get(i); 455 Way segmentStartWay = assigner.get(segmentStartStop); 456 Way segmentEndWay = assigner.get(segmentEndStop); 457 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay); 458 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r); 459 SegmentChecker.addCorrectSegment(routeSegment); 460 } 461 } 462 } 463 464 /** 465 * Checks if the test error is fixable 466 */ 467 @Override 468 public boolean isFixable(TestError testError) { 469 if (testError.getCode() == ERROR_CODE_DIRECTION 470 || testError.getCode() == ERROR_CODE_ROAD_TYPE 471 || testError.getCode() == ERROR_CODE_CONSTRUCTION 472 || testError.getCode() == ERROR_CODE_SORTING 473 || testError.getCode() == ERROR_CODE_PARTIAL_SORTING 474 || testError.getCode() == ERROR_CODE_END_STOP 475 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 476 return true; 477 } 478 479 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) { 480 return true; 481 } 482 483 return false; 484 } 485 486 /** 487 * Fixes the given error 488 */ 489 @Override 490 public Command fixError(TestError testError) { 491 492 // repaint the relation in the pt_assistant layer: 493 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) { 494 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next(); 495 PTAssistantLayerManager.PTLM.getLayer().repaint(relationToBeFixed); 496 } 497 498 // reset the last fix: 499 PTAssistantPlugin.setLastFix(null); 500 501 List<Command> commands = new ArrayList<>(); 502 503 if (testError.getCode() == ERROR_CODE_ROAD_TYPE 504 || testError.getCode() == ERROR_CODE_CONSTRUCTION 505 || testError.getCode() == ERROR_CODE_DIRECTION 506 || testError.getCode() == ERROR_CODE_END_STOP) { 507 commands.add(WayChecker.fixErrorByZooming(testError)); 508 } 509 510 if (testError.getCode() == ERROR_CODE_SORTING 511 || testError.getCode() == ERROR_CODE_PARTIAL_SORTING) { 512 commands.add(RouteChecker.fixSortingError(testError)); 513 } 514 515 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION 516 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 517 commands.add(NodeChecker.fixError(testError)); 518 } 519 520 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) { 521 commands.add(SegmentChecker.fixError(testError)); 522 // make sure the primitives of this testError are selected: 523 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>(); 524 for (Object obj : testError.getPrimitives()) { 525 primitivesToSelect.add((OsmPrimitive) obj); 526 } 527 SelectCommand selectCommand = new SelectCommand(primitivesToSelect); 528 SwingUtilities.invokeLater(new Runnable() { 529 @Override 530 public void run() { 531 selectCommand.executeCommand(); 532 } 533 }); 534 } 535 536 if (commands.isEmpty()) { 537 return null; 538 } 539 540 if (commands.size() == 1) { 541 return commands.get(0); 542 } 543 544 return new SequenceCommand(tr("Fix error"), commands); 545 } 546 547 /** 548 * This method is the counterpart of the fixError(TestError testError) 549 * method. The fixError method is invoked from the core validator (e.g. when 550 * user presses the "Fix" button in the validator). This method is invoken 551 * when the fix is initiated from within the plugin (e.g. automated fixes). 552 */ 553 private void fixErrorFromPlugin(List<TestError> testErrors) { 554 555 // run fix task asynchronously 556 FixTask fixTask = new FixTask(testErrors); 557 558 Thread t = new Thread(fixTask); 559 t.start(); 560 try { 561 t.join(); 562 errors.removeAll(testErrors); 563 564 } catch (InterruptedException e) { 565 JOptionPane.showMessageDialog(null, "Error occurred during fixing"); 566 } 567 568 } 569 570 public void addFixVariants(List<List<PTWay>> fixVariants) { 571 PTAssistantLayerManager.PTLM.getLayer().addFixVariants(fixVariants); 572 } 573 574 public void clearFixVariants() { 575 PTAssistantLayerManager.PTLM.getLayer().clearFixVariants(); 576 } 577 578 public List<PTWay> getFixVariant(Character c) { 579 return PTAssistantLayerManager.PTLM.getLayer().getFixVariant(c); 580 } 581 582 @SuppressWarnings("unused") 583 private void performDummyTest(Relation r) { 584 List<Relation> primitives = new ArrayList<>(1); 585 primitives.add(r); 586 Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION); 587 builder.message(tr("PT: dummy test warning")); 588 builder.primitives(primitives); 589 errors.add(builder.build()); 590 } 591 591 592 592 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/RouteChecker.java
r33405 r33417 94 94 */ 95 95 private int countGaps(List<RelationMember> waysToCheck) { 96 int numberOfGaps = 0;96 int numberOfGaps = 0; 97 97 98 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator();98 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator(); 99 99 final List<WayConnectionType> links = connectionTypeCalculator.updateLinks(waysToCheck); 100 100 for (int i = 0; i < links.size(); i++) { … … 102 102 if(!(i == 0 || link.linkPrev) || !(i == links.size() - 1 || link.linkNext) 103 103 || link.direction == null || WayConnectionType.Direction.NONE.equals(link.direction)) { 104 numberOfGaps++;105 i++;104 numberOfGaps++; 105 i++; 106 106 } 107 107 } … … 124 124 protected static Command fixSortingError(TestError testError) { 125 125 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SORTING 126 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PARTIAL_SORTING) {126 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PARTIAL_SORTING) { 127 127 return null; 128 128 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java
r33387 r33417 49 49 public class SegmentChecker extends Checker { 50 50 51 /* PTRouteSegments that have been validated and are correct */52 private static List<PTRouteSegment> correctSegments = new ArrayList<>();53 54 /* PTRouteSegments that are wrong, stored in case the user calls the fix */55 protected static HashMap<TestError, PTRouteSegment> wrongSegments = new HashMap<>();56 protected static HashMap<Builder, PTRouteSegment> wrongSegmentBuilders = new HashMap<>();57 58 /* Manager of the PTStops and PTWays of the current route */59 private PTRouteDataManager manager;60 61 /* Assigns PTStops to nearest PTWays and stores that correspondence */62 private StopToWayAssigner assigner;63 64 public SegmentChecker(Relation relation, Test test) {65 66 super(relation, test);67 68 this.manager = new PTRouteDataManager(relation);69 70 for (RelationMember rm : manager.getFailedMembers()) {71 List<Relation> primitives = new ArrayList<>(1);72 primitives.add(relation);73 List<OsmPrimitive> highlighted = new ArrayList<>(1);74 highlighted.add(rm.getMember());75 Builder builder = TestError.builder(this.test, Severity.WARNING,76 PTAssistantValidatorTest.ERROR_CODE_RELATION_MEMBER_ROLES);77 builder.message(tr("PT: Relation member roles do not match tags"));78 builder.primitives(primitives);79 builder.highlight(highlighted);80 TestError e = builder.build();81 this.errors.add(e);82 }83 84 this.assigner = new StopToWayAssigner(manager.getPTWays());85 86 }87 88 /**89 * Returns the number of route segments that have been already successfully90 * verified91 *92 * @return the number of route segments93 */94 public static int getCorrectSegmentCount() {95 return correctSegments.size();96 }97 98 /**99 * Adds the given correct segment to the list of correct segments without100 * checking its correctness101 *102 * @param segment103 * to add to the list of correct segments104 */105 public static synchronized void addCorrectSegment(PTRouteSegment segment) {106 for (PTRouteSegment correctSegment : correctSegments) {107 if (correctSegment.equalsRouteSegment(segment)) {108 return;109 }110 }111 correctSegments.add(segment);112 }113 114 /**115 * Used for unit tests116 *117 * @param error118 * test error119 * @return wrong route segment120 */121 protected static PTRouteSegment getWrongSegment(TestError error) {122 return wrongSegments.get(error);123 }124 125 public void performFirstStopTest() {126 127 performEndStopTest(manager.getFirstStop());128 129 }130 131 public void performLastStopTest() {132 133 performEndStopTest(manager.getLastStop());134 135 }136 137 private void performEndStopTest(PTStop endStop) {138 139 if (endStop == null) {140 return;141 }142 143 /*144 * This test checks: (1) that a stop position exists; (2) that it is the145 * first or last node of its parent ways which belong to this route.146 */147 148 if (endStop.getStopPosition() == null) {149 150 List<Node> potentialStopPositionList = endStop.findPotentialStopPositions();151 List<Node> stopPositionsOfThisRoute = new ArrayList<>();152 boolean containsAtLeastOneStopPositionAsFirstOrLastNode = false;153 154 for (Node potentialStopPosition : potentialStopPositionList) {155 156 int belongsToWay = belongsToAWayOfThisRoute(potentialStopPosition);157 158 if (belongsToWay == 0) {159 stopPositionsOfThisRoute.add(potentialStopPosition);160 containsAtLeastOneStopPositionAsFirstOrLastNode = true;161 }162 163 if (belongsToWay == 1) {164 stopPositionsOfThisRoute.add(potentialStopPosition);165 }166 }167 168 if (stopPositionsOfThisRoute.isEmpty()) {169 List<Relation> primitives = new ArrayList<>(1);170 primitives.add(relation);171 List<OsmPrimitive> highlighted = new ArrayList<>(1);172 highlighted.add(endStop.getPlatform());173 Builder builder = TestError.builder(this.test, Severity.WARNING,174 PTAssistantValidatorTest.ERROR_CODE_END_STOP);175 builder.message(tr("PT: Route should start and end with a stop_position"));176 builder.primitives(primitives);177 builder.highlight(highlighted);178 TestError e = builder.build();179 this.errors.add(e);180 return;181 }182 183 if (stopPositionsOfThisRoute.size() == 1) {184 endStop.setStopPosition(stopPositionsOfThisRoute.get(0));185 }186 187 // At this point, there is at least one stop_position for this188 // endStop:189 if (!containsAtLeastOneStopPositionAsFirstOrLastNode) {190 List<Relation> primitives = new ArrayList<>(1);191 primitives.add(relation);192 List<OsmPrimitive> highlighted = new ArrayList<>();193 highlighted.addAll(stopPositionsOfThisRoute);194 195 Builder builder = TestError.builder(this.test, Severity.WARNING,196 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY);197 builder.message(tr("PT: First or last way needs to be split"));198 builder.primitives(primitives);199 builder.highlight(highlighted);200 TestError e = builder.build();201 this.errors.add(e);202 }203 204 } else {205 206 // if the stop_position is known:207 int belongsToWay = this.belongsToAWayOfThisRoute(endStop.getStopPosition());208 209 if (belongsToWay == 1) {210 211 List<Relation> primitives = new ArrayList<>(1);212 primitives.add(relation);213 List<OsmPrimitive> highlighted = new ArrayList<>();214 highlighted.add(endStop.getStopPosition());215 Builder builder = TestError.builder(this.test, Severity.WARNING,216 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY);217 builder.message(tr("PT: First or last way needs to be split"));218 builder.primitives(primitives);219 builder.highlight(highlighted);220 TestError e = builder.build();221 this.errors.add(e);222 }223 }224 225 }226 227 /**228 * Checks if the given node belongs to the ways of this route.229 *230 * @param node231 * Node to be checked232 * @return 1 if belongs only as an inner node, 0 if belongs as a first or233 * last node for at least one way, -1 if does not belong to any way.234 */235 private int belongsToAWayOfThisRoute(Node node) {236 237 boolean contains = false;238 239 List<PTWay> ptways = manager.getPTWays();240 for (PTWay ptway : ptways) {241 List<Way> ways = ptway.getWays();242 for (Way way : ways) {243 if (way.containsNode(node)) {244 245 if (way.firstNode().equals(node) || way.lastNode().equals(node)) {246 return 0;247 }248 249 contains = true;250 }251 }252 }253 254 if (contains) {255 return 1;256 }257 258 return -1;259 }260 261 public void performStopNotServedTest() {262 for (PTStop stop : manager.getPTStops()) {263 Way way = assigner.get(stop);264 if (way == null) {265 createStopError(stop);266 }267 }268 }269 270 /**271 * Performs the stop-by-stop test by visiting each segment between two272 * consecutive stops and checking if the ways between them are correct273 */274 public void performStopByStopTest() {275 276 if (manager.getPTStopCount() < 2) {277 return;278 }279 280 List<OsmPrimitive> lastCreatedBuilderHighlighted = null;281 282 // Check each route segment:283 for (int i = 1; i < manager.getPTStopCount(); i++) {284 285 PTStop startStop = manager.getPTStops().get(i - 1);286 PTStop endStop = manager.getPTStops().get(i);287 288 Way startWay = assigner.get(startStop);289 Way endWay = assigner.get(endStop);290 if (startWay == null || endWay == null || (startWay == endWay && startWay == manager.getLastWay())) {291 continue;292 }293 294 List<PTWay> segmentWays = manager.getPTWaysBetween(startWay, endWay);295 296 Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0));297 298 if (firstNode == null) {299 // check if this error has just been reported:300 if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted != null && lastCreatedBuilderHighlighted.size() == 1301 && lastCreatedBuilderHighlighted.get(0) == startWay) {302 // do nothing, this error has already been reported in303 // the previous route segment304 } else {305 List<Relation> primitives = new ArrayList<>(1);306 primitives.add(relation);307 List<OsmPrimitive> highlighted = new ArrayList<>();308 highlighted.add(startWay);309 Builder builder = TestError.builder(this.test, Severity.WARNING,310 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP);311 builder.primitives(primitives);312 builder.highlight(highlighted);313 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation);314 wrongSegmentBuilders.put(builder, routeSegment);315 }316 continue;317 }318 319 PTWay wronglySortedPtway = existingWaySortingIsWrong(segmentWays.get(0), firstNode,320 segmentWays.get(segmentWays.size() - 1));321 if (wronglySortedPtway == null) { // i.e. if the sorting is correct:322 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation);323 addCorrectSegment(routeSegment);324 } else { // i.e. if the sorting is wrong:325 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation);326 // TestError error = this.errors.get(this.errors.size() - 1);327 // wrongSegments.put(error, routeSegment);328 329 List<Relation> primitives = new ArrayList<>(1);330 primitives.add(relation);331 List<OsmPrimitive> highlighted = new ArrayList<>();332 highlighted.add(startStop.getStopPosition());333 highlighted.add(endStop.getStopPosition());334 Builder builder = TestError.builder(this.test, Severity.WARNING,335 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP);336 builder.primitives(primitives);337 builder.highlight(highlighted);338 lastCreatedBuilderHighlighted = highlighted;339 wrongSegmentBuilders.put(builder, routeSegment);340 }341 }342 }343 344 /**345 * Creates a TestError and adds it to the list of errors for a stop that is346 * not served.347 *348 * @param stop349 * stop350 */351 private void createStopError(PTStop stop) {352 List<Relation> primitives = new ArrayList<>(1);353 primitives.add(relation);354 List<OsmPrimitive> highlighted = new ArrayList<>();355 OsmPrimitive stopPrimitive = stop.getPlatform();356 if (stopPrimitive == null) {357 stopPrimitive = stop.getStopPosition();358 }359 highlighted.add(stopPrimitive);360 Builder builder = TestError.builder(this.test, Severity.WARNING,361 PTAssistantValidatorTest.ERROR_CODE_STOP_NOT_SERVED);362 builder.message(tr("PT: Stop not served"));363 builder.primitives(primitives);364 builder.highlight(highlighted);365 TestError e = builder.build();366 this.errors.add(e);367 }368 369 private Node findFirstNodeOfRouteSegmentInDirectionOfTravel(PTWay startWay) {370 371 // 1) at first check if one of the first or last node of the first ptway372 // is a deadend node:373 Node[] startWayEndnodes = startWay.getEndNodes();374 if (isDeadendNode(startWayEndnodes[0])) {375 return startWayEndnodes[0];376 }377 if (isDeadendNode(startWayEndnodes[1])) {378 return startWayEndnodes[1];379 }380 381 // 2) failing that, check which node this startWay shares with the382 // following way:383 PTWay nextWay = manager.getNextPTWay(startWay);384 if (nextWay == null) {385 return null;386 }387 PTWay wayAfterNext = manager.getNextPTWay(nextWay);388 Node[] nextWayEndnodes = nextWay.getEndNodes();389 if ((startWayEndnodes[0] == nextWayEndnodes[0] && startWayEndnodes[1] == nextWayEndnodes[1])390 || (startWayEndnodes[0] == nextWayEndnodes[1] && startWayEndnodes[1] == nextWayEndnodes[0])) {391 // if this is a split roundabout:392 Node[] wayAfterNextEndnodes = wayAfterNext.getEndNodes();393 if (startWayEndnodes[0] == wayAfterNextEndnodes[0] || startWayEndnodes[0] == wayAfterNextEndnodes[1]) {394 return startWayEndnodes[0];395 }396 if (startWayEndnodes[1] == wayAfterNextEndnodes[0] || startWayEndnodes[1] == wayAfterNextEndnodes[1]) {397 return startWayEndnodes[1];398 }399 }400 401 if (startWayEndnodes[0] == nextWayEndnodes[0] || startWayEndnodes[0] == nextWayEndnodes[1]) {402 return startWayEndnodes[1];403 }404 if (startWayEndnodes[1] == nextWayEndnodes[0] || startWayEndnodes[1] == nextWayEndnodes[1]) {405 return startWayEndnodes[0];406 }407 408 return null;409 410 }411 412 private boolean isDeadendNode(Node node) {413 int count = 0;414 for (PTWay ptway : manager.getPTWays()) {415 List<Way> ways = ptway.getWays();416 for (Way way : ways) {417 if (way.firstNode() == node || way.lastNode() == node) {418 count++;419 }420 }421 }422 return count == 1;423 }424 425 /**426 * Finds the deadend node closest to the given node represented by its427 * coordinates428 *429 * @param coord430 * coordinates of the givenn node431 * @param deadendNodes432 * dead end nodes433 * @return the closest deadend node434 */435 @SuppressWarnings("unused")436 private Node findClosestDeadendNode(LatLon coord, List<Node> deadendNodes) {437 438 Node closestDeadendNode = null;439 double minSqDistance = Double.MAX_VALUE;440 for (Node deadendNode : deadendNodes) {441 double distanceSq = coord.distanceSq(deadendNode.getCoor());442 if (distanceSq < minSqDistance) {443 minSqDistance = distanceSq;444 closestDeadendNode = deadendNode;445 }446 }447 return closestDeadendNode;448 449 }450 451 /**452 * Checks if the existing sorting of the given route segment is correct453 *454 * @param start455 * PTWay assigned to the first stop of the segment456 * @param startWayPreviousNodeInDirectionOfTravel457 * Node if the start way which is furthest away from the rest of458 * the route459 * @param end460 * PTWay assigned to the end stop of the segment461 * @return null if the sorting is correct, or the wrongly sorted PTWay462 * otherwise.463 */464 private PTWay existingWaySortingIsWrong(PTWay start, Node startWayPreviousNodeInDirectionOfTravel, PTWay end) {465 466 if (start == end) {467 // if both PTStops are on the same PTWay468 // return true;469 return null;470 }471 472 PTWay current = start;473 Node currentNode = startWayPreviousNodeInDirectionOfTravel;474 475 while (!current.equals(end)) {476 // "equals" is used here instead of "==" because when the same way477 // is passed multiple times by the bus, the algorithm should stop no478 // matter which of the geometrically equal PTWays it finds479 480 PTWay nextPTWayAccortingToExistingSorting = manager.getNextPTWay(current);481 482 // if current contains an unsplit roundabout:483 if (current.containsUnsplitRoundabout()) {484 currentNode = manager.getCommonNode(current, nextPTWayAccortingToExistingSorting);485 if (currentNode == null) {486 487 return current;488 489 }490 } else {491 // if this is a regular way, not an unsplit roundabout492 493 // find the next node in direction of travel (which is part of494 // the PTWay start):495 currentNode = getOppositeEndNode(current, currentNode);496 497 List<PTWay> nextWaysInDirectionOfTravel = this.findNextPTWaysInDirectionOfTravel(current, currentNode);498 499 if (!nextWaysInDirectionOfTravel.contains(nextPTWayAccortingToExistingSorting)) {500 return current;501 502 }503 }504 505 current = nextPTWayAccortingToExistingSorting;506 507 }508 509 return null;510 }511 512 /**513 * Will return the same node if the way is an unsplit roundabout514 *515 * @param way516 * way517 * @param node518 * node519 * @return the same node if the way is an unsplit roundabout520 */521 private Node getOppositeEndNode(Way way, Node node) {522 523 if (node == way.firstNode()) {524 return way.lastNode();525 }526 527 if (node == way.lastNode()) {528 return way.firstNode();529 }530 531 return null;532 }533 534 /**535 * Does not work correctly for unsplit roundabouts536 *537 * @param ptway538 * way539 * @param node540 * node541 * @return node542 */543 private Node getOppositeEndNode(PTWay ptway, Node node) {544 if (ptway.isWay()) {545 return getOppositeEndNode(ptway.getWays().get(0), node);546 }547 548 Way firstWay = ptway.getWays().get(0);549 Way lastWay = ptway.getWays().get(ptway.getWays().size() - 1);550 Node oppositeNode = node;551 if (firstWay.firstNode() == node || firstWay.lastNode() == node) {552 for (int i = 0; i < ptway.getWays().size(); i++) {553 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode);554 }555 return oppositeNode;556 } else if (lastWay.firstNode() == node || lastWay.lastNode() == node) {557 for (int i = ptway.getWays().size() - 1; i >= 0; i--) {558 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode);559 }560 return oppositeNode;561 }562 563 return null;564 565 }566 567 /**568 * Finds the next ways for the route stop-by-stop parsing procedure569 *570 * @param currentWay571 * current way572 * @param nextNodeInDirectionOfTravel573 * next node in direction of travel574 * @return the next ways for the route stop-by-stop parsing procedure575 */576 private List<PTWay> findNextPTWaysInDirectionOfTravel(PTWay currentWay, Node nextNodeInDirectionOfTravel) {577 578 List<PTWay> nextPtways = new ArrayList<>();579 580 List<PTWay> ptways = manager.getPTWays();581 582 for (PTWay ptway : ptways) {583 584 if (ptway != currentWay) {585 for (Way way : ptway.getWays()) {586 if (way.containsNode(nextNodeInDirectionOfTravel)) {587 nextPtways.add(ptway);588 }589 }590 }591 }592 593 return nextPtways;594 595 }596 597 protected static boolean isFixable(TestError testError) {598 599 /*-600 * When is an error fixable (outdated)?601 * - if there is a correct segment602 * - if it can be fixed by sorting603 * - if the route is compete even without some ways604 * - if simple routing closes the gap605 */606 607 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP) {608 return true;609 }610 611 return false;612 613 }614 615 @SuppressWarnings("unused")616 private static boolean isFixableByUsingCorrectSegment(TestError testError) {617 PTRouteSegment wrongSegment = wrongSegments.get(testError);618 PTRouteSegment correctSegment = null;619 for (PTRouteSegment segment : correctSegments) {620 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop())621 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) {622 correctSegment = segment;623 break;624 }625 }626 return correctSegment != null;627 }628 629 @SuppressWarnings("unused")630 private static boolean isFixableBySortingAndRemoval(TestError testError) {631 PTRouteSegment wrongSegment = wrongSegments.get(testError);632 List<List<PTWay>> fixVariants = wrongSegment.getFixVariants();633 if (!fixVariants.isEmpty()) {634 return true;635 }636 return false;637 }638 639 /**640 * Finds fixes using sorting and removal.641 */642 protected void findFixes() {643 644 for (Builder builder : wrongSegmentBuilders.keySet()) {645 646 if (wrongSegmentBuilders.get(builder).getRelation() == this.relation) {647 648 findFix(builder);649 650 }651 }652 653 }654 655 /**656 * Modifies the error messages of the stop-by-stop test errors depending on how many fixes each of them has.657 */658 protected static void modifyStopByStopErrorMessages() {659 660 for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) {661 662 // change the error code based on the availability of fixes:663 Builder builder = entry.getKey();664 PTRouteSegment wrongSegment = entry.getValue();665 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>();666 for (PTRouteSegment segment : correctSegments) {667 if (wrongSegment.getFirstWay().getUniqueId() == segment.getFirstWay().getUniqueId()668 && wrongSegment.getLastWay().getUniqueId() == segment.getLastWay().getUniqueId()) {669 correctSegmentsForThisError.add(segment);670 }671 }672 673 int numberOfFixes = correctSegmentsForThisError.size();674 675 if (numberOfFixes == 0) {676 numberOfFixes = wrongSegment.getFixVariants().size();677 }678 if (numberOfFixes == 0) {679 for (PTRouteSegment segment : correctSegments) {680 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop())681 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) {682 correctSegmentsForThisError.add(segment);683 }684 }685 numberOfFixes = correctSegmentsForThisError.size();686 }687 688 // change the error message:689 if (numberOfFixes == 0) {690 builder.message(tr("PT: Problem in the route segment with no automatic fix"));691 } else if (numberOfFixes == 1) {692 builder.message(tr("PT: Problem in the route segment with one automatic fix"));693 } else {694 builder.message("PT: Problem in the route segment with several automatic fixes");695 }696 697 }698 699 }700 701 /**702 * This method assumes that the first and the second ways of the route703 * segment are correctly connected. If they are not, the error will be704 * marked as not fixable.705 *706 * @param testError707 * test error708 */709 private void findFix(Builder builder) {710 711 PTRouteSegment wrongSegment = wrongSegmentBuilders.get(builder);712 PTWay startPTWay = wrongSegment.getFirstPTWay();713 PTWay endPTWay = wrongSegment.getLastPTWay();714 715 Node previousNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(startPTWay);716 if (previousNode == null) {717 return;718 }719 720 List<List<PTWay>> initialFixes = new ArrayList<>();721 List<PTWay> initialFix = new ArrayList<>();722 initialFix.add(startPTWay);723 initialFixes.add(initialFix);724 725 List<List<PTWay>> allFixes = findWaysForFix(initialFixes, initialFix, previousNode, endPTWay);726 for (List<PTWay> fix : allFixes) {727 if (!fix.isEmpty() && fix.get(fix.size() - 1).equals(endPTWay)) {728 wrongSegment.addFixVariant(fix);729 }730 }731 732 }733 734 /**735 * Recursive method to parse the route segment736 *737 * @param allFixes738 * all fixes739 * @param currentFix740 * current fix741 * @param previousNode742 * previous node743 * @param endWay744 * end way745 * @return list of list of ways746 */747 private List<List<PTWay>> findWaysForFix(List<List<PTWay>> allFixes, List<PTWay> currentFix, Node previousNode,748 PTWay endWay) {749 750 PTWay currentWay = currentFix.get(currentFix.size() - 1);751 Node nextNode = getOppositeEndNode(currentWay, previousNode);752 753 List<PTWay> nextWays = this.findNextPTWaysInDirectionOfTravel(currentWay, nextNode);754 755 if (nextWays.size() > 1) {756 for (int i = 1; i < nextWays.size(); i++) {757 List<PTWay> newFix = new ArrayList<>();758 newFix.addAll(currentFix);759 newFix.add(nextWays.get(i));760 allFixes.add(newFix);761 if (!nextWays.get(i).equals(endWay) && !currentFix.contains(nextWays.get(i))) {762 allFixes = findWaysForFix(allFixes, newFix, nextNode, endWay);763 }764 }765 }766 767 if (!nextWays.isEmpty()) {768 boolean contains = currentFix.contains(nextWays.get(0));769 currentFix.add(nextWays.get(0));770 if (!nextWays.get(0).equals(endWay) && !contains) {771 allFixes = findWaysForFix(allFixes, currentFix, nextNode, endWay);772 }773 }774 775 return allFixes;776 }777 778 /**779 * Fixes the error by first searching in the list of correct segments and780 * then trying to sort and remove existing route relation members781 *782 * @param testError783 * test error784 * @return fix command785 */786 protected static Command fixError(TestError testError) {787 788 // if fix options for another route are displayed in the pt_assistant789 // layer, clear them:790 ((PTAssistantValidatorTest) testError.getTester()).clearFixVariants();791 792 PTRouteSegment wrongSegment = wrongSegments.get(testError);793 794 // 1) try to fix by using the correct segment:795 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>();796 for (PTRouteSegment segment : correctSegments) {797 if (wrongSegment.getFirstWay().getUniqueId() == segment.getFirstWay().getUniqueId()798 && wrongSegment.getLastWay().getUniqueId() == segment.getLastWay().getUniqueId()) {799 correctSegmentsForThisError.add(segment);800 }801 }802 803 // if no correct segment found, apply less strict criteria to look for804 // one:805 if (correctSegmentsForThisError.isEmpty() && wrongSegment.getFixVariants().isEmpty()) {806 for (PTRouteSegment segment : correctSegments) {807 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop())808 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) {809 correctSegmentsForThisError.add(segment);810 }811 }812 if (!correctSegmentsForThisError.isEmpty()) {813 // display the notification:814 if (SwingUtilities.isEventDispatchThread()) {815 Notification notification = new Notification(816 tr("Warning: the diplayed fix variants are based on less strict criteria"));817 notification.show();818 } else {819 SwingUtilities.invokeLater(new Runnable() {820 @Override821 public void run() {822 Notification notification = new Notification(823 tr("Warning: the diplayed fix variants are based on less strict criteria"));824 notification.show();825 }826 });827 }828 }829 }830 831 if (!correctSegmentsForThisError.isEmpty()) {832 833 if (correctSegmentsForThisError.size() > 1) {834 List<List<PTWay>> fixVariants = new ArrayList<>();835 for (PTRouteSegment segment : correctSegmentsForThisError) {836 fixVariants.add(segment.getPTWays());837 }838 displayFixVariants(fixVariants, testError);839 return null;840 }841 842 PTAssistantPlugin.setLastFix(correctSegmentsForThisError.get(0));843 return carryOutSingleFix(testError, correctSegmentsForThisError.get(0).getPTWays());844 845 } else if (!wrongSegment.getFixVariants().isEmpty()) {846 // 2) try to fix using the sorting and removal of existing ways847 // of the wrong segment:848 if (wrongSegment.getFixVariants().size() > 1) {849 displayFixVariants(wrongSegment.getFixVariants(), testError);850 return null;851 }852 853 PTAssistantPlugin.setLastFix(new PTRouteSegment(wrongSegment.getFirstStop(), wrongSegment.getLastStop(),854 wrongSegment.getFixVariants().get(0), (Relation) testError.getPrimitives().iterator().next()));855 return carryOutSingleFix(testError, wrongSegment.getFixVariants().get(0));856 }857 858 // if there is no fix:859 return fixErrorByZooming(testError);860 861 }862 863 /**864 * This is largely a copy of the displayFixVariants() method, adapted for865 * use with the key listener866 *867 * @param fixVariants868 * fix variants869 * @param testError870 * test error871 */872 private static void displayFixVariants(List<List<PTWay>> fixVariants, TestError testError) {873 // find the letters of the fix variants:874 char alphabet = 'A';875 final List<Character> allowedCharacters = new ArrayList<>();876 for (int i = 0; i < fixVariants.size(); i++) {877 allowedCharacters.add(alphabet);878 alphabet++;879 }880 881 // zoom to problem:882 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>();883 884 for (List<PTWay> variants : fixVariants)885 for(PTWay variant : variants)886 waysToZoom.add(variant.getWay());887 888 if (SwingUtilities.isEventDispatchThread()) {889 AutoScaleAction.zoomTo(waysToZoom);890 } else {891 SwingUtilities.invokeLater(new Runnable() {892 @Override893 public void run() {894 AutoScaleAction.zoomTo(waysToZoom);895 }896 });897 }898 899 // display the fix variants:900 final PTAssistantValidatorTest test = (PTAssistantValidatorTest) testError.getTester();901 test.addFixVariants(fixVariants);902 PTAssistantLayerManager.PTLM.getLayer().repaint((Relation) testError.getPrimitives().iterator().next());903 904 // prepare the variables for the key listener:905 final TestError testErrorParameter = testError;906 907 // // add the key listener:908 Main.map.mapView.requestFocus();909 Main.map.mapView.addKeyListener(new KeyListener() {910 911 @Override912 public void keyTyped(KeyEvent e) {913 // TODO Auto-generated method stub914 }915 916 @Override917 public void keyPressed(KeyEvent e) {918 Character typedKey = e.getKeyChar();919 Character typedKeyUpperCase = typedKey.toString().toUpperCase().toCharArray()[0];920 if (allowedCharacters.contains(typedKeyUpperCase)) {921 Main.map.mapView.removeKeyListener(this);922 List<PTWay> selectedFix = test.getFixVariant(typedKeyUpperCase);923 test.clearFixVariants();924 carryOutSelectedFix(testErrorParameter, selectedFix);925 }926 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {927 Main.map.mapView.removeKeyListener(this);928 test.clearFixVariants();929 }930 }931 932 @Override933 public void keyReleased(KeyEvent e) {934 // TODO Auto-generated method stub935 }936 });937 938 // display the notification:939 if (SwingUtilities.isEventDispatchThread()) {940 Notification notification = new Notification(941 tr("Type letter to select the fix variant or press Escape for no fix"));942 notification.show();943 } else {944 SwingUtilities.invokeLater(new Runnable() {945 @Override946 public void run() {947 Notification notification = new Notification(948 tr("Type letter to select the fix variant or press Escape for no fix"));949 notification.show();950 }951 });952 }953 }954 955 /**956 * Carries out the fix (i.e. modifies the route) after the user has picked957 * the fix from several fix variants.958 *959 * @param testError960 * test error to be fixed961 * @param fix962 * the fix variant to be adopted963 */964 private static void carryOutSelectedFix(TestError testError, List<PTWay> fix) {965 // modify the route:966 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next();967 Relation modifiedRelation = new Relation(originalRelation);968 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix));969 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation);970 Main.main.undoRedo.addNoRedraw(changeCommand);971 Main.main.undoRedo.afterAdd();972 PTRouteSegment wrongSegment = wrongSegments.get(testError);973 wrongSegments.remove(testError);974 wrongSegment.setPTWays(fix);975 addCorrectSegment(wrongSegment);976 PTAssistantPlugin.setLastFixNoGui(wrongSegment);977 978 // get ways for the fix:979 List<Way> primitives = new ArrayList<>();980 for (PTWay ptway : fix) {981 primitives.addAll(ptway.getWays());982 }983 984 // get layer:985 OsmDataLayer layer = null;986 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class);987 for (OsmDataLayer osmDataLayer : listOfLayers) {988 if (osmDataLayer.data == originalRelation.getDataSet()) {989 layer = osmDataLayer;990 break;991 }992 }993 994 // create editor:995 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, originalRelation,996 originalRelation.getMembersFor(primitives));997 998 // open editor:999 editor.setVisible(true);1000 1001 }1002 1003 /**1004 * Carries out the fix (i.e. modifies the route) when there is only one fix1005 * variant.1006 *1007 * @param testError1008 * test error1009 * @param fix1010 * fix1011 */1012 private static Command carryOutSingleFix(TestError testError, List<PTWay> fix) {1013 1014 // wait:1015 synchronized (SegmentChecker.class) {1016 try {1017 SegmentChecker.class.wait(1500);1018 } catch (InterruptedException e) {1019 e.printStackTrace();1020 }1021 }1022 1023 // Zoom to the problematic ways:1024 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>();1025 for (Object highlightedPrimitive : testError.getHighlighted()) {1026 waysToZoom.add((OsmPrimitive) highlightedPrimitive);1027 }1028 if (SwingUtilities.isEventDispatchThread()) {1029 AutoScaleAction.zoomTo(waysToZoom);1030 } else {1031 SwingUtilities.invokeLater(new Runnable() {1032 @Override1033 public void run() {1034 AutoScaleAction.zoomTo(waysToZoom);1035 }1036 });1037 }1038 1039 // wait:1040 synchronized (SegmentChecker.class) {1041 try {1042 SegmentChecker.class.wait(1500);1043 } catch (InterruptedException e) {1044 e.printStackTrace();1045 }1046 }1047 1048 // modify the route:1049 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next();1050 Relation modifiedRelation = new Relation(originalRelation);1051 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix));1052 wrongSegments.remove(testError);1053 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation);1054 return changeCommand;1055 }1056 1057 /**1058 * Returns a list of the modified relation members. This list can be used by1059 * the calling method (relation.setMemers()) to modify the modify the route1060 * relation. The route relation is not modified by this method. The lists of1061 * wrong and correct segments are not updated.1062 *1063 * @param testError1064 * test error to be fixed1065 * @param fix1066 * the fix variant to be adopted1067 * @return List of modified relation members to be applied to the route1068 * relation1069 */1070 private static List<RelationMember> getModifiedRelationMembers(TestError testError, List<PTWay> fix) {1071 PTRouteSegment wrongSegment = wrongSegments.get(testError);1072 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next();1073 1074 // copy stops first:1075 List<RelationMember> modifiedRelationMembers = listStopMembers(originalRelation);1076 1077 // copy PTWays last:1078 List<RelationMember> waysOfOriginalRelation = listNotStopMembers(originalRelation);1079 for (int i = 0; i < waysOfOriginalRelation.size(); i++) {1080 if (waysOfOriginalRelation.get(i).getWay() == wrongSegment.getPTWays().get(0).getWays().get(0)) {1081 modifiedRelationMembers.addAll(fix);1082 i = i + wrongSegment.getPTWays().size() - 1;1083 } else {1084 modifiedRelationMembers.add(waysOfOriginalRelation.get(i));1085 }1086 }1087 1088 return modifiedRelationMembers;1089 }1090 1091 public static void carryOutRepeatLastFix(PTRouteSegment segment) {1092 1093 List<TestError> wrongSegmentsToRemove = new ArrayList<>();1094 1095 // find all wrong ways that have the same segment:1096 for (TestError testError : wrongSegments.keySet()) {1097 PTRouteSegment wrongSegment = wrongSegments.get(testError);1098 if (wrongSegment.getFirstWay() == segment.getFirstWay()1099 && wrongSegment.getLastWay() == segment.getLastWay()) {1100 // modify the route:1101 Relation originalRelation = wrongSegment.getRelation();1102 Relation modifiedRelation = new Relation(originalRelation);1103 modifiedRelation.setMembers(getModifiedRelationMembers(testError, segment.getPTWays()));1104 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation);1105 Main.main.undoRedo.addNoRedraw(changeCommand);1106 Main.main.undoRedo.afterAdd();1107 wrongSegmentsToRemove.add(testError);1108 }1109 }1110 1111 // update the errors displayed in the validator dialog:1112 List<TestError> modifiedValidatorTestErrors = new ArrayList<>();1113 for (TestError validatorTestError : Main.map.validatorDialog.tree.getErrors()) {1114 if (!wrongSegmentsToRemove.contains(validatorTestError)) {1115 modifiedValidatorTestErrors.add(validatorTestError);1116 }1117 }1118 Main.map.validatorDialog.tree.setErrors(modifiedValidatorTestErrors);1119 1120 // update wrong segments:1121 for (TestError testError : wrongSegmentsToRemove) {1122 wrongSegments.remove(testError);1123 }1124 1125 }1126 1127 /**1128 * Resets the static list variables (used for unit tests and in Test.startTest() method)1129 */1130 protected static void reset() {1131 correctSegments.clear();1132 wrongSegments.clear();1133 wrongSegmentBuilders.clear();1134 }51 /* PTRouteSegments that have been validated and are correct */ 52 private static List<PTRouteSegment> correctSegments = new ArrayList<>(); 53 54 /* PTRouteSegments that are wrong, stored in case the user calls the fix */ 55 protected static HashMap<TestError, PTRouteSegment> wrongSegments = new HashMap<>(); 56 protected static HashMap<Builder, PTRouteSegment> wrongSegmentBuilders = new HashMap<>(); 57 58 /* Manager of the PTStops and PTWays of the current route */ 59 private PTRouteDataManager manager; 60 61 /* Assigns PTStops to nearest PTWays and stores that correspondence */ 62 private StopToWayAssigner assigner; 63 64 public SegmentChecker(Relation relation, Test test) { 65 66 super(relation, test); 67 68 this.manager = new PTRouteDataManager(relation); 69 70 for (RelationMember rm : manager.getFailedMembers()) { 71 List<Relation> primitives = new ArrayList<>(1); 72 primitives.add(relation); 73 List<OsmPrimitive> highlighted = new ArrayList<>(1); 74 highlighted.add(rm.getMember()); 75 Builder builder = TestError.builder(this.test, Severity.WARNING, 76 PTAssistantValidatorTest.ERROR_CODE_RELATION_MEMBER_ROLES); 77 builder.message(tr("PT: Relation member roles do not match tags")); 78 builder.primitives(primitives); 79 builder.highlight(highlighted); 80 TestError e = builder.build(); 81 this.errors.add(e); 82 } 83 84 this.assigner = new StopToWayAssigner(manager.getPTWays()); 85 86 } 87 88 /** 89 * Returns the number of route segments that have been already successfully 90 * verified 91 * 92 * @return the number of route segments 93 */ 94 public static int getCorrectSegmentCount() { 95 return correctSegments.size(); 96 } 97 98 /** 99 * Adds the given correct segment to the list of correct segments without 100 * checking its correctness 101 * 102 * @param segment 103 * to add to the list of correct segments 104 */ 105 public static synchronized void addCorrectSegment(PTRouteSegment segment) { 106 for (PTRouteSegment correctSegment : correctSegments) { 107 if (correctSegment.equalsRouteSegment(segment)) { 108 return; 109 } 110 } 111 correctSegments.add(segment); 112 } 113 114 /** 115 * Used for unit tests 116 * 117 * @param error 118 * test error 119 * @return wrong route segment 120 */ 121 protected static PTRouteSegment getWrongSegment(TestError error) { 122 return wrongSegments.get(error); 123 } 124 125 public void performFirstStopTest() { 126 127 performEndStopTest(manager.getFirstStop()); 128 129 } 130 131 public void performLastStopTest() { 132 133 performEndStopTest(manager.getLastStop()); 134 135 } 136 137 private void performEndStopTest(PTStop endStop) { 138 139 if (endStop == null) { 140 return; 141 } 142 143 /* 144 * This test checks: (1) that a stop position exists; (2) that it is the 145 * first or last node of its parent ways which belong to this route. 146 */ 147 148 if (endStop.getStopPosition() == null) { 149 150 List<Node> potentialStopPositionList = endStop.findPotentialStopPositions(); 151 List<Node> stopPositionsOfThisRoute = new ArrayList<>(); 152 boolean containsAtLeastOneStopPositionAsFirstOrLastNode = false; 153 154 for (Node potentialStopPosition : potentialStopPositionList) { 155 156 int belongsToWay = belongsToAWayOfThisRoute(potentialStopPosition); 157 158 if (belongsToWay == 0) { 159 stopPositionsOfThisRoute.add(potentialStopPosition); 160 containsAtLeastOneStopPositionAsFirstOrLastNode = true; 161 } 162 163 if (belongsToWay == 1) { 164 stopPositionsOfThisRoute.add(potentialStopPosition); 165 } 166 } 167 168 if (stopPositionsOfThisRoute.isEmpty()) { 169 List<Relation> primitives = new ArrayList<>(1); 170 primitives.add(relation); 171 List<OsmPrimitive> highlighted = new ArrayList<>(1); 172 highlighted.add(endStop.getPlatform()); 173 Builder builder = TestError.builder(this.test, Severity.WARNING, 174 PTAssistantValidatorTest.ERROR_CODE_END_STOP); 175 builder.message(tr("PT: Route should start and end with a stop_position")); 176 builder.primitives(primitives); 177 builder.highlight(highlighted); 178 TestError e = builder.build(); 179 this.errors.add(e); 180 return; 181 } 182 183 if (stopPositionsOfThisRoute.size() == 1) { 184 endStop.setStopPosition(stopPositionsOfThisRoute.get(0)); 185 } 186 187 // At this point, there is at least one stop_position for this 188 // endStop: 189 if (!containsAtLeastOneStopPositionAsFirstOrLastNode) { 190 List<Relation> primitives = new ArrayList<>(1); 191 primitives.add(relation); 192 List<OsmPrimitive> highlighted = new ArrayList<>(); 193 highlighted.addAll(stopPositionsOfThisRoute); 194 195 Builder builder = TestError.builder(this.test, Severity.WARNING, 196 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY); 197 builder.message(tr("PT: First or last way needs to be split")); 198 builder.primitives(primitives); 199 builder.highlight(highlighted); 200 TestError e = builder.build(); 201 this.errors.add(e); 202 } 203 204 } else { 205 206 // if the stop_position is known: 207 int belongsToWay = this.belongsToAWayOfThisRoute(endStop.getStopPosition()); 208 209 if (belongsToWay == 1) { 210 211 List<Relation> primitives = new ArrayList<>(1); 212 primitives.add(relation); 213 List<OsmPrimitive> highlighted = new ArrayList<>(); 214 highlighted.add(endStop.getStopPosition()); 215 Builder builder = TestError.builder(this.test, Severity.WARNING, 216 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY); 217 builder.message(tr("PT: First or last way needs to be split")); 218 builder.primitives(primitives); 219 builder.highlight(highlighted); 220 TestError e = builder.build(); 221 this.errors.add(e); 222 } 223 } 224 225 } 226 227 /** 228 * Checks if the given node belongs to the ways of this route. 229 * 230 * @param node 231 * Node to be checked 232 * @return 1 if belongs only as an inner node, 0 if belongs as a first or 233 * last node for at least one way, -1 if does not belong to any way. 234 */ 235 private int belongsToAWayOfThisRoute(Node node) { 236 237 boolean contains = false; 238 239 List<PTWay> ptways = manager.getPTWays(); 240 for (PTWay ptway : ptways) { 241 List<Way> ways = ptway.getWays(); 242 for (Way way : ways) { 243 if (way.containsNode(node)) { 244 245 if (way.firstNode().equals(node) || way.lastNode().equals(node)) { 246 return 0; 247 } 248 249 contains = true; 250 } 251 } 252 } 253 254 if (contains) { 255 return 1; 256 } 257 258 return -1; 259 } 260 261 public void performStopNotServedTest() { 262 for (PTStop stop : manager.getPTStops()) { 263 Way way = assigner.get(stop); 264 if (way == null) { 265 createStopError(stop); 266 } 267 } 268 } 269 270 /** 271 * Performs the stop-by-stop test by visiting each segment between two 272 * consecutive stops and checking if the ways between them are correct 273 */ 274 public void performStopByStopTest() { 275 276 if (manager.getPTStopCount() < 2) { 277 return; 278 } 279 280 List<OsmPrimitive> lastCreatedBuilderHighlighted = null; 281 282 // Check each route segment: 283 for (int i = 1; i < manager.getPTStopCount(); i++) { 284 285 PTStop startStop = manager.getPTStops().get(i - 1); 286 PTStop endStop = manager.getPTStops().get(i); 287 288 Way startWay = assigner.get(startStop); 289 Way endWay = assigner.get(endStop); 290 if (startWay == null || endWay == null || (startWay == endWay && startWay == manager.getLastWay())) { 291 continue; 292 } 293 294 List<PTWay> segmentWays = manager.getPTWaysBetween(startWay, endWay); 295 296 Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0)); 297 298 if (firstNode == null) { 299 // check if this error has just been reported: 300 if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted != null && lastCreatedBuilderHighlighted.size() == 1 301 && lastCreatedBuilderHighlighted.get(0) == startWay) { 302 // do nothing, this error has already been reported in 303 // the previous route segment 304 } else { 305 List<Relation> primitives = new ArrayList<>(1); 306 primitives.add(relation); 307 List<OsmPrimitive> highlighted = new ArrayList<>(); 308 highlighted.add(startWay); 309 Builder builder = TestError.builder(this.test, Severity.WARNING, 310 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP); 311 builder.primitives(primitives); 312 builder.highlight(highlighted); 313 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 314 wrongSegmentBuilders.put(builder, routeSegment); 315 } 316 continue; 317 } 318 319 PTWay wronglySortedPtway = existingWaySortingIsWrong(segmentWays.get(0), firstNode, 320 segmentWays.get(segmentWays.size() - 1)); 321 if (wronglySortedPtway == null) { // i.e. if the sorting is correct: 322 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 323 addCorrectSegment(routeSegment); 324 } else { // i.e. if the sorting is wrong: 325 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 326 // TestError error = this.errors.get(this.errors.size() - 1); 327 // wrongSegments.put(error, routeSegment); 328 329 List<Relation> primitives = new ArrayList<>(1); 330 primitives.add(relation); 331 List<OsmPrimitive> highlighted = new ArrayList<>(); 332 highlighted.add(startStop.getStopPosition()); 333 highlighted.add(endStop.getStopPosition()); 334 Builder builder = TestError.builder(this.test, Severity.WARNING, 335 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP); 336 builder.primitives(primitives); 337 builder.highlight(highlighted); 338 lastCreatedBuilderHighlighted = highlighted; 339 wrongSegmentBuilders.put(builder, routeSegment); 340 } 341 } 342 } 343 344 /** 345 * Creates a TestError and adds it to the list of errors for a stop that is 346 * not served. 347 * 348 * @param stop 349 * stop 350 */ 351 private void createStopError(PTStop stop) { 352 List<Relation> primitives = new ArrayList<>(1); 353 primitives.add(relation); 354 List<OsmPrimitive> highlighted = new ArrayList<>(); 355 OsmPrimitive stopPrimitive = stop.getPlatform(); 356 if (stopPrimitive == null) { 357 stopPrimitive = stop.getStopPosition(); 358 } 359 highlighted.add(stopPrimitive); 360 Builder builder = TestError.builder(this.test, Severity.WARNING, 361 PTAssistantValidatorTest.ERROR_CODE_STOP_NOT_SERVED); 362 builder.message(tr("PT: Stop not served")); 363 builder.primitives(primitives); 364 builder.highlight(highlighted); 365 TestError e = builder.build(); 366 this.errors.add(e); 367 } 368 369 private Node findFirstNodeOfRouteSegmentInDirectionOfTravel(PTWay startWay) { 370 371 // 1) at first check if one of the first or last node of the first ptway 372 // is a deadend node: 373 Node[] startWayEndnodes = startWay.getEndNodes(); 374 if (isDeadendNode(startWayEndnodes[0])) { 375 return startWayEndnodes[0]; 376 } 377 if (isDeadendNode(startWayEndnodes[1])) { 378 return startWayEndnodes[1]; 379 } 380 381 // 2) failing that, check which node this startWay shares with the 382 // following way: 383 PTWay nextWay = manager.getNextPTWay(startWay); 384 if (nextWay == null) { 385 return null; 386 } 387 PTWay wayAfterNext = manager.getNextPTWay(nextWay); 388 Node[] nextWayEndnodes = nextWay.getEndNodes(); 389 if ((startWayEndnodes[0] == nextWayEndnodes[0] && startWayEndnodes[1] == nextWayEndnodes[1]) 390 || (startWayEndnodes[0] == nextWayEndnodes[1] && startWayEndnodes[1] == nextWayEndnodes[0])) { 391 // if this is a split roundabout: 392 Node[] wayAfterNextEndnodes = wayAfterNext.getEndNodes(); 393 if (startWayEndnodes[0] == wayAfterNextEndnodes[0] || startWayEndnodes[0] == wayAfterNextEndnodes[1]) { 394 return startWayEndnodes[0]; 395 } 396 if (startWayEndnodes[1] == wayAfterNextEndnodes[0] || startWayEndnodes[1] == wayAfterNextEndnodes[1]) { 397 return startWayEndnodes[1]; 398 } 399 } 400 401 if (startWayEndnodes[0] == nextWayEndnodes[0] || startWayEndnodes[0] == nextWayEndnodes[1]) { 402 return startWayEndnodes[1]; 403 } 404 if (startWayEndnodes[1] == nextWayEndnodes[0] || startWayEndnodes[1] == nextWayEndnodes[1]) { 405 return startWayEndnodes[0]; 406 } 407 408 return null; 409 410 } 411 412 private boolean isDeadendNode(Node node) { 413 int count = 0; 414 for (PTWay ptway : manager.getPTWays()) { 415 List<Way> ways = ptway.getWays(); 416 for (Way way : ways) { 417 if (way.firstNode() == node || way.lastNode() == node) { 418 count++; 419 } 420 } 421 } 422 return count == 1; 423 } 424 425 /** 426 * Finds the deadend node closest to the given node represented by its 427 * coordinates 428 * 429 * @param coord 430 * coordinates of the givenn node 431 * @param deadendNodes 432 * dead end nodes 433 * @return the closest deadend node 434 */ 435 @SuppressWarnings("unused") 436 private Node findClosestDeadendNode(LatLon coord, List<Node> deadendNodes) { 437 438 Node closestDeadendNode = null; 439 double minSqDistance = Double.MAX_VALUE; 440 for (Node deadendNode : deadendNodes) { 441 double distanceSq = coord.distanceSq(deadendNode.getCoor()); 442 if (distanceSq < minSqDistance) { 443 minSqDistance = distanceSq; 444 closestDeadendNode = deadendNode; 445 } 446 } 447 return closestDeadendNode; 448 449 } 450 451 /** 452 * Checks if the existing sorting of the given route segment is correct 453 * 454 * @param start 455 * PTWay assigned to the first stop of the segment 456 * @param startWayPreviousNodeInDirectionOfTravel 457 * Node if the start way which is furthest away from the rest of 458 * the route 459 * @param end 460 * PTWay assigned to the end stop of the segment 461 * @return null if the sorting is correct, or the wrongly sorted PTWay 462 * otherwise. 463 */ 464 private PTWay existingWaySortingIsWrong(PTWay start, Node startWayPreviousNodeInDirectionOfTravel, PTWay end) { 465 466 if (start == end) { 467 // if both PTStops are on the same PTWay 468 // return true; 469 return null; 470 } 471 472 PTWay current = start; 473 Node currentNode = startWayPreviousNodeInDirectionOfTravel; 474 475 while (!current.equals(end)) { 476 // "equals" is used here instead of "==" because when the same way 477 // is passed multiple times by the bus, the algorithm should stop no 478 // matter which of the geometrically equal PTWays it finds 479 480 PTWay nextPTWayAccortingToExistingSorting = manager.getNextPTWay(current); 481 482 // if current contains an unsplit roundabout: 483 if (current.containsUnsplitRoundabout()) { 484 currentNode = manager.getCommonNode(current, nextPTWayAccortingToExistingSorting); 485 if (currentNode == null) { 486 487 return current; 488 489 } 490 } else { 491 // if this is a regular way, not an unsplit roundabout 492 493 // find the next node in direction of travel (which is part of 494 // the PTWay start): 495 currentNode = getOppositeEndNode(current, currentNode); 496 497 List<PTWay> nextWaysInDirectionOfTravel = this.findNextPTWaysInDirectionOfTravel(current, currentNode); 498 499 if (!nextWaysInDirectionOfTravel.contains(nextPTWayAccortingToExistingSorting)) { 500 return current; 501 502 } 503 } 504 505 current = nextPTWayAccortingToExistingSorting; 506 507 } 508 509 return null; 510 } 511 512 /** 513 * Will return the same node if the way is an unsplit roundabout 514 * 515 * @param way 516 * way 517 * @param node 518 * node 519 * @return the same node if the way is an unsplit roundabout 520 */ 521 private Node getOppositeEndNode(Way way, Node node) { 522 523 if (node == way.firstNode()) { 524 return way.lastNode(); 525 } 526 527 if (node == way.lastNode()) { 528 return way.firstNode(); 529 } 530 531 return null; 532 } 533 534 /** 535 * Does not work correctly for unsplit roundabouts 536 * 537 * @param ptway 538 * way 539 * @param node 540 * node 541 * @return node 542 */ 543 private Node getOppositeEndNode(PTWay ptway, Node node) { 544 if (ptway.isWay()) { 545 return getOppositeEndNode(ptway.getWays().get(0), node); 546 } 547 548 Way firstWay = ptway.getWays().get(0); 549 Way lastWay = ptway.getWays().get(ptway.getWays().size() - 1); 550 Node oppositeNode = node; 551 if (firstWay.firstNode() == node || firstWay.lastNode() == node) { 552 for (int i = 0; i < ptway.getWays().size(); i++) { 553 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 554 } 555 return oppositeNode; 556 } else if (lastWay.firstNode() == node || lastWay.lastNode() == node) { 557 for (int i = ptway.getWays().size() - 1; i >= 0; i--) { 558 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 559 } 560 return oppositeNode; 561 } 562 563 return null; 564 565 } 566 567 /** 568 * Finds the next ways for the route stop-by-stop parsing procedure 569 * 570 * @param currentWay 571 * current way 572 * @param nextNodeInDirectionOfTravel 573 * next node in direction of travel 574 * @return the next ways for the route stop-by-stop parsing procedure 575 */ 576 private List<PTWay> findNextPTWaysInDirectionOfTravel(PTWay currentWay, Node nextNodeInDirectionOfTravel) { 577 578 List<PTWay> nextPtways = new ArrayList<>(); 579 580 List<PTWay> ptways = manager.getPTWays(); 581 582 for (PTWay ptway : ptways) { 583 584 if (ptway != currentWay) { 585 for (Way way : ptway.getWays()) { 586 if (way.containsNode(nextNodeInDirectionOfTravel)) { 587 nextPtways.add(ptway); 588 } 589 } 590 } 591 } 592 593 return nextPtways; 594 595 } 596 597 protected static boolean isFixable(TestError testError) { 598 599 /*- 600 * When is an error fixable (outdated)? 601 * - if there is a correct segment 602 * - if it can be fixed by sorting 603 * - if the route is compete even without some ways 604 * - if simple routing closes the gap 605 */ 606 607 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP) { 608 return true; 609 } 610 611 return false; 612 613 } 614 615 @SuppressWarnings("unused") 616 private static boolean isFixableByUsingCorrectSegment(TestError testError) { 617 PTRouteSegment wrongSegment = wrongSegments.get(testError); 618 PTRouteSegment correctSegment = null; 619 for (PTRouteSegment segment : correctSegments) { 620 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 621 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 622 correctSegment = segment; 623 break; 624 } 625 } 626 return correctSegment != null; 627 } 628 629 @SuppressWarnings("unused") 630 private static boolean isFixableBySortingAndRemoval(TestError testError) { 631 PTRouteSegment wrongSegment = wrongSegments.get(testError); 632 List<List<PTWay>> fixVariants = wrongSegment.getFixVariants(); 633 if (!fixVariants.isEmpty()) { 634 return true; 635 } 636 return false; 637 } 638 639 /** 640 * Finds fixes using sorting and removal. 641 */ 642 protected void findFixes() { 643 644 for (Builder builder : wrongSegmentBuilders.keySet()) { 645 646 if (wrongSegmentBuilders.get(builder).getRelation() == this.relation) { 647 648 findFix(builder); 649 650 } 651 } 652 653 } 654 655 /** 656 * Modifies the error messages of the stop-by-stop test errors depending on how many fixes each of them has. 657 */ 658 protected static void modifyStopByStopErrorMessages() { 659 660 for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) { 661 662 // change the error code based on the availability of fixes: 663 Builder builder = entry.getKey(); 664 PTRouteSegment wrongSegment = entry.getValue(); 665 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 666 for (PTRouteSegment segment : correctSegments) { 667 if (wrongSegment.getFirstWay().getUniqueId() == segment.getFirstWay().getUniqueId() 668 && wrongSegment.getLastWay().getUniqueId() == segment.getLastWay().getUniqueId()) { 669 correctSegmentsForThisError.add(segment); 670 } 671 } 672 673 int numberOfFixes = correctSegmentsForThisError.size(); 674 675 if (numberOfFixes == 0) { 676 numberOfFixes = wrongSegment.getFixVariants().size(); 677 } 678 if (numberOfFixes == 0) { 679 for (PTRouteSegment segment : correctSegments) { 680 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 681 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 682 correctSegmentsForThisError.add(segment); 683 } 684 } 685 numberOfFixes = correctSegmentsForThisError.size(); 686 } 687 688 // change the error message: 689 if (numberOfFixes == 0) { 690 builder.message(tr("PT: Problem in the route segment with no automatic fix")); 691 } else if (numberOfFixes == 1) { 692 builder.message(tr("PT: Problem in the route segment with one automatic fix")); 693 } else { 694 builder.message("PT: Problem in the route segment with several automatic fixes"); 695 } 696 697 } 698 699 } 700 701 /** 702 * This method assumes that the first and the second ways of the route 703 * segment are correctly connected. If they are not, the error will be 704 * marked as not fixable. 705 * 706 * @param testError 707 * test error 708 */ 709 private void findFix(Builder builder) { 710 711 PTRouteSegment wrongSegment = wrongSegmentBuilders.get(builder); 712 PTWay startPTWay = wrongSegment.getFirstPTWay(); 713 PTWay endPTWay = wrongSegment.getLastPTWay(); 714 715 Node previousNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(startPTWay); 716 if (previousNode == null) { 717 return; 718 } 719 720 List<List<PTWay>> initialFixes = new ArrayList<>(); 721 List<PTWay> initialFix = new ArrayList<>(); 722 initialFix.add(startPTWay); 723 initialFixes.add(initialFix); 724 725 List<List<PTWay>> allFixes = findWaysForFix(initialFixes, initialFix, previousNode, endPTWay); 726 for (List<PTWay> fix : allFixes) { 727 if (!fix.isEmpty() && fix.get(fix.size() - 1).equals(endPTWay)) { 728 wrongSegment.addFixVariant(fix); 729 } 730 } 731 732 } 733 734 /** 735 * Recursive method to parse the route segment 736 * 737 * @param allFixes 738 * all fixes 739 * @param currentFix 740 * current fix 741 * @param previousNode 742 * previous node 743 * @param endWay 744 * end way 745 * @return list of list of ways 746 */ 747 private List<List<PTWay>> findWaysForFix(List<List<PTWay>> allFixes, List<PTWay> currentFix, Node previousNode, 748 PTWay endWay) { 749 750 PTWay currentWay = currentFix.get(currentFix.size() - 1); 751 Node nextNode = getOppositeEndNode(currentWay, previousNode); 752 753 List<PTWay> nextWays = this.findNextPTWaysInDirectionOfTravel(currentWay, nextNode); 754 755 if (nextWays.size() > 1) { 756 for (int i = 1; i < nextWays.size(); i++) { 757 List<PTWay> newFix = new ArrayList<>(); 758 newFix.addAll(currentFix); 759 newFix.add(nextWays.get(i)); 760 allFixes.add(newFix); 761 if (!nextWays.get(i).equals(endWay) && !currentFix.contains(nextWays.get(i))) { 762 allFixes = findWaysForFix(allFixes, newFix, nextNode, endWay); 763 } 764 } 765 } 766 767 if (!nextWays.isEmpty()) { 768 boolean contains = currentFix.contains(nextWays.get(0)); 769 currentFix.add(nextWays.get(0)); 770 if (!nextWays.get(0).equals(endWay) && !contains) { 771 allFixes = findWaysForFix(allFixes, currentFix, nextNode, endWay); 772 } 773 } 774 775 return allFixes; 776 } 777 778 /** 779 * Fixes the error by first searching in the list of correct segments and 780 * then trying to sort and remove existing route relation members 781 * 782 * @param testError 783 * test error 784 * @return fix command 785 */ 786 protected static Command fixError(TestError testError) { 787 788 // if fix options for another route are displayed in the pt_assistant 789 // layer, clear them: 790 ((PTAssistantValidatorTest) testError.getTester()).clearFixVariants(); 791 792 PTRouteSegment wrongSegment = wrongSegments.get(testError); 793 794 // 1) try to fix by using the correct segment: 795 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 796 for (PTRouteSegment segment : correctSegments) { 797 if (wrongSegment.getFirstWay().getUniqueId() == segment.getFirstWay().getUniqueId() 798 && wrongSegment.getLastWay().getUniqueId() == segment.getLastWay().getUniqueId()) { 799 correctSegmentsForThisError.add(segment); 800 } 801 } 802 803 // if no correct segment found, apply less strict criteria to look for 804 // one: 805 if (correctSegmentsForThisError.isEmpty() && wrongSegment.getFixVariants().isEmpty()) { 806 for (PTRouteSegment segment : correctSegments) { 807 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 808 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 809 correctSegmentsForThisError.add(segment); 810 } 811 } 812 if (!correctSegmentsForThisError.isEmpty()) { 813 // display the notification: 814 if (SwingUtilities.isEventDispatchThread()) { 815 Notification notification = new Notification( 816 tr("Warning: the diplayed fix variants are based on less strict criteria")); 817 notification.show(); 818 } else { 819 SwingUtilities.invokeLater(new Runnable() { 820 @Override 821 public void run() { 822 Notification notification = new Notification( 823 tr("Warning: the diplayed fix variants are based on less strict criteria")); 824 notification.show(); 825 } 826 }); 827 } 828 } 829 } 830 831 if (!correctSegmentsForThisError.isEmpty()) { 832 833 if (correctSegmentsForThisError.size() > 1) { 834 List<List<PTWay>> fixVariants = new ArrayList<>(); 835 for (PTRouteSegment segment : correctSegmentsForThisError) { 836 fixVariants.add(segment.getPTWays()); 837 } 838 displayFixVariants(fixVariants, testError); 839 return null; 840 } 841 842 PTAssistantPlugin.setLastFix(correctSegmentsForThisError.get(0)); 843 return carryOutSingleFix(testError, correctSegmentsForThisError.get(0).getPTWays()); 844 845 } else if (!wrongSegment.getFixVariants().isEmpty()) { 846 // 2) try to fix using the sorting and removal of existing ways 847 // of the wrong segment: 848 if (wrongSegment.getFixVariants().size() > 1) { 849 displayFixVariants(wrongSegment.getFixVariants(), testError); 850 return null; 851 } 852 853 PTAssistantPlugin.setLastFix(new PTRouteSegment(wrongSegment.getFirstStop(), wrongSegment.getLastStop(), 854 wrongSegment.getFixVariants().get(0), (Relation) testError.getPrimitives().iterator().next())); 855 return carryOutSingleFix(testError, wrongSegment.getFixVariants().get(0)); 856 } 857 858 // if there is no fix: 859 return fixErrorByZooming(testError); 860 861 } 862 863 /** 864 * This is largely a copy of the displayFixVariants() method, adapted for 865 * use with the key listener 866 * 867 * @param fixVariants 868 * fix variants 869 * @param testError 870 * test error 871 */ 872 private static void displayFixVariants(List<List<PTWay>> fixVariants, TestError testError) { 873 // find the letters of the fix variants: 874 char alphabet = 'A'; 875 final List<Character> allowedCharacters = new ArrayList<>(); 876 for (int i = 0; i < fixVariants.size(); i++) { 877 allowedCharacters.add(alphabet); 878 alphabet++; 879 } 880 881 // zoom to problem: 882 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 883 884 for (List<PTWay> variants : fixVariants) 885 for(PTWay variant : variants) 886 waysToZoom.add(variant.getWay()); 887 888 if (SwingUtilities.isEventDispatchThread()) { 889 AutoScaleAction.zoomTo(waysToZoom); 890 } else { 891 SwingUtilities.invokeLater(new Runnable() { 892 @Override 893 public void run() { 894 AutoScaleAction.zoomTo(waysToZoom); 895 } 896 }); 897 } 898 899 // display the fix variants: 900 final PTAssistantValidatorTest test = (PTAssistantValidatorTest) testError.getTester(); 901 test.addFixVariants(fixVariants); 902 PTAssistantLayerManager.PTLM.getLayer().repaint((Relation) testError.getPrimitives().iterator().next()); 903 904 // prepare the variables for the key listener: 905 final TestError testErrorParameter = testError; 906 907 // // add the key listener: 908 Main.map.mapView.requestFocus(); 909 Main.map.mapView.addKeyListener(new KeyListener() { 910 911 @Override 912 public void keyTyped(KeyEvent e) { 913 // TODO Auto-generated method stub 914 } 915 916 @Override 917 public void keyPressed(KeyEvent e) { 918 Character typedKey = e.getKeyChar(); 919 Character typedKeyUpperCase = typedKey.toString().toUpperCase().toCharArray()[0]; 920 if (allowedCharacters.contains(typedKeyUpperCase)) { 921 Main.map.mapView.removeKeyListener(this); 922 List<PTWay> selectedFix = test.getFixVariant(typedKeyUpperCase); 923 test.clearFixVariants(); 924 carryOutSelectedFix(testErrorParameter, selectedFix); 925 } 926 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 927 Main.map.mapView.removeKeyListener(this); 928 test.clearFixVariants(); 929 } 930 } 931 932 @Override 933 public void keyReleased(KeyEvent e) { 934 // TODO Auto-generated method stub 935 } 936 }); 937 938 // display the notification: 939 if (SwingUtilities.isEventDispatchThread()) { 940 Notification notification = new Notification( 941 tr("Type letter to select the fix variant or press Escape for no fix")); 942 notification.show(); 943 } else { 944 SwingUtilities.invokeLater(new Runnable() { 945 @Override 946 public void run() { 947 Notification notification = new Notification( 948 tr("Type letter to select the fix variant or press Escape for no fix")); 949 notification.show(); 950 } 951 }); 952 } 953 } 954 955 /** 956 * Carries out the fix (i.e. modifies the route) after the user has picked 957 * the fix from several fix variants. 958 * 959 * @param testError 960 * test error to be fixed 961 * @param fix 962 * the fix variant to be adopted 963 */ 964 private static void carryOutSelectedFix(TestError testError, List<PTWay> fix) { 965 // modify the route: 966 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 967 Relation modifiedRelation = new Relation(originalRelation); 968 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 969 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 970 Main.main.undoRedo.addNoRedraw(changeCommand); 971 Main.main.undoRedo.afterAdd(); 972 PTRouteSegment wrongSegment = wrongSegments.get(testError); 973 wrongSegments.remove(testError); 974 wrongSegment.setPTWays(fix); 975 addCorrectSegment(wrongSegment); 976 PTAssistantPlugin.setLastFixNoGui(wrongSegment); 977 978 // get ways for the fix: 979 List<Way> primitives = new ArrayList<>(); 980 for (PTWay ptway : fix) { 981 primitives.addAll(ptway.getWays()); 982 } 983 984 // get layer: 985 OsmDataLayer layer = null; 986 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class); 987 for (OsmDataLayer osmDataLayer : listOfLayers) { 988 if (osmDataLayer.data == originalRelation.getDataSet()) { 989 layer = osmDataLayer; 990 break; 991 } 992 } 993 994 // create editor: 995 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, originalRelation, 996 originalRelation.getMembersFor(primitives)); 997 998 // open editor: 999 editor.setVisible(true); 1000 1001 } 1002 1003 /** 1004 * Carries out the fix (i.e. modifies the route) when there is only one fix 1005 * variant. 1006 * 1007 * @param testError 1008 * test error 1009 * @param fix 1010 * fix 1011 */ 1012 private static Command carryOutSingleFix(TestError testError, List<PTWay> fix) { 1013 1014 // wait: 1015 synchronized (SegmentChecker.class) { 1016 try { 1017 SegmentChecker.class.wait(1500); 1018 } catch (InterruptedException e) { 1019 e.printStackTrace(); 1020 } 1021 } 1022 1023 // Zoom to the problematic ways: 1024 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 1025 for (Object highlightedPrimitive : testError.getHighlighted()) { 1026 waysToZoom.add((OsmPrimitive) highlightedPrimitive); 1027 } 1028 if (SwingUtilities.isEventDispatchThread()) { 1029 AutoScaleAction.zoomTo(waysToZoom); 1030 } else { 1031 SwingUtilities.invokeLater(new Runnable() { 1032 @Override 1033 public void run() { 1034 AutoScaleAction.zoomTo(waysToZoom); 1035 } 1036 }); 1037 } 1038 1039 // wait: 1040 synchronized (SegmentChecker.class) { 1041 try { 1042 SegmentChecker.class.wait(1500); 1043 } catch (InterruptedException e) { 1044 e.printStackTrace(); 1045 } 1046 } 1047 1048 // modify the route: 1049 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 1050 Relation modifiedRelation = new Relation(originalRelation); 1051 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 1052 wrongSegments.remove(testError); 1053 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 1054 return changeCommand; 1055 } 1056 1057 /** 1058 * Returns a list of the modified relation members. This list can be used by 1059 * the calling method (relation.setMemers()) to modify the modify the route 1060 * relation. The route relation is not modified by this method. The lists of 1061 * wrong and correct segments are not updated. 1062 * 1063 * @param testError 1064 * test error to be fixed 1065 * @param fix 1066 * the fix variant to be adopted 1067 * @return List of modified relation members to be applied to the route 1068 * relation 1069 */ 1070 private static List<RelationMember> getModifiedRelationMembers(TestError testError, List<PTWay> fix) { 1071 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1072 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 1073 1074 // copy stops first: 1075 List<RelationMember> modifiedRelationMembers = listStopMembers(originalRelation); 1076 1077 // copy PTWays last: 1078 List<RelationMember> waysOfOriginalRelation = listNotStopMembers(originalRelation); 1079 for (int i = 0; i < waysOfOriginalRelation.size(); i++) { 1080 if (waysOfOriginalRelation.get(i).getWay() == wrongSegment.getPTWays().get(0).getWays().get(0)) { 1081 modifiedRelationMembers.addAll(fix); 1082 i = i + wrongSegment.getPTWays().size() - 1; 1083 } else { 1084 modifiedRelationMembers.add(waysOfOriginalRelation.get(i)); 1085 } 1086 } 1087 1088 return modifiedRelationMembers; 1089 } 1090 1091 public static void carryOutRepeatLastFix(PTRouteSegment segment) { 1092 1093 List<TestError> wrongSegmentsToRemove = new ArrayList<>(); 1094 1095 // find all wrong ways that have the same segment: 1096 for (TestError testError : wrongSegments.keySet()) { 1097 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1098 if (wrongSegment.getFirstWay() == segment.getFirstWay() 1099 && wrongSegment.getLastWay() == segment.getLastWay()) { 1100 // modify the route: 1101 Relation originalRelation = wrongSegment.getRelation(); 1102 Relation modifiedRelation = new Relation(originalRelation); 1103 modifiedRelation.setMembers(getModifiedRelationMembers(testError, segment.getPTWays())); 1104 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 1105 Main.main.undoRedo.addNoRedraw(changeCommand); 1106 Main.main.undoRedo.afterAdd(); 1107 wrongSegmentsToRemove.add(testError); 1108 } 1109 } 1110 1111 // update the errors displayed in the validator dialog: 1112 List<TestError> modifiedValidatorTestErrors = new ArrayList<>(); 1113 for (TestError validatorTestError : Main.map.validatorDialog.tree.getErrors()) { 1114 if (!wrongSegmentsToRemove.contains(validatorTestError)) { 1115 modifiedValidatorTestErrors.add(validatorTestError); 1116 } 1117 } 1118 Main.map.validatorDialog.tree.setErrors(modifiedValidatorTestErrors); 1119 1120 // update wrong segments: 1121 for (TestError testError : wrongSegmentsToRemove) { 1122 wrongSegments.remove(testError); 1123 } 1124 1125 } 1126 1127 /** 1128 * Resets the static list variables (used for unit tests and in Test.startTest() method) 1129 */ 1130 protected static void reset() { 1131 correctSegments.clear(); 1132 wrongSegments.clear(); 1133 wrongSegmentBuilders.clear(); 1134 } 1135 1135 1136 1136 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/actions/SplitRoundaboutTest.java
r33415 r33417 71 71 @Test 72 72 public void test1() { 73 Collection<Way> sw1 = splitWay(r1);74 assertEquals(4, sw1.size());73 Collection<Way> sw1 = splitWay(r1); 74 assertEquals(4, sw1.size()); 75 75 sw1.forEach(w -> { 76 76 if (w.firstNode().getUniqueId() == 267843779L && w.lastNode().getUniqueId() == 2968718407L) … … 89 89 @Test 90 90 public void test2() { 91 Collection<Way> sw2 = splitWay(r2);92 assertEquals(4, sw2.size());91 Collection<Way> sw2 = splitWay(r2); 92 assertEquals(4, sw2.size()); 93 93 sw2.forEach(w -> { 94 94 if(w.firstNode().getUniqueId() == 2158181809L && w.lastNode().getUniqueId() == 2158181798L) … … 107 107 @Test 108 108 public void test3() { 109 Collection<Way> sw3 = splitWay(r3);110 assertEquals(4, sw3.size());109 Collection<Way> sw3 = splitWay(r3); 110 assertEquals(4, sw3.size()); 111 111 sw3.forEach(w -> { 112 112 if(w.firstNode().getUniqueId() == 280697532L && w.lastNode().getUniqueId() == 280697452L) … … 125 125 @Test 126 126 public void test4() { 127 Collection<Way> sw4 = splitWay(r4);128 assertEquals(10, sw4.size());129 Node entry11 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry1-1")).iterator().next();130 Node exit11 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit1-1")).iterator().next();131 Node entry12 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry1-2")).iterator().next();132 Node exit12 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit1-2")).iterator().next();133 Node entry21 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry2-1")).iterator().next();134 Node exit21 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit2-1")).iterator().next();135 Node entry22 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry2-2")).iterator().next();136 Node exit22 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit2-2")).iterator().next();137 Node entry3 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry3")).iterator().next();138 Node exit3 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit3")).iterator().next();127 Collection<Way> sw4 = splitWay(r4); 128 assertEquals(10, sw4.size()); 129 Node entry11 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry1-1")).iterator().next(); 130 Node exit11 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit1-1")).iterator().next(); 131 Node entry12 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry1-2")).iterator().next(); 132 Node exit12 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit1-2")).iterator().next(); 133 Node entry21 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry2-1")).iterator().next(); 134 Node exit21 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit2-1")).iterator().next(); 135 Node entry22 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry2-2")).iterator().next(); 136 Node exit22 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit2-2")).iterator().next(); 137 Node entry3 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nentry3")).iterator().next(); 138 Node exit3 = (Node) ds.getPrimitives(p -> p.hasTag("name", "nexit3")).iterator().next(); 139 139 140 140 sw4.forEach(w -> {
Note:
See TracChangeset
for help on using the changeset viewer.
