Changeset 33055 in osm
- Timestamp:
- 2016-11-12T20:44:31+01:00 (8 years ago)
- Location:
- applications/editors/josm/plugins/pt_assistant
- Files:
-
- 2 added
- 40 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/pt_assistant/.project
r32261 r33055 16 16 </arguments> 17 17 </buildCommand> 18 <buildCommand> 19 <name>net.sf.eclipsecs.core.CheckstyleBuilder</name> 20 <arguments> 21 </arguments> 22 </buildCommand> 18 23 </buildSpec> 19 24 <natures> 20 25 <nature>org.eclipse.jdt.core.javanature</nature> 26 <nature>net.sf.eclipsecs.core.CheckstyleNature</nature> 21 27 </natures> 22 28 </projectDescription> -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/PTAssistantPlugin.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file.1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.plugins.pt_assistant; 3 3 … … 22 22 * 23 23 * @author darya / Darya Golovko 24 * 24 * 25 25 */ 26 26 public class PTAssistantPlugin extends Plugin { 27 27 28 29 30 31 32 28 /* 29 * last fix that was can be re-applied to all similar route segments, can be 30 * null if unavailable 31 */ 32 private static PTRouteSegment lastFix; 33 33 34 /* item of the Tools menu for adding stop_positions */ 35 private JMenuItem addStopPositionMenu; 36 37 /* item of the Tools menu for repeating the last fix */ 38 private static JMenuItem repeatLastFixMenu; 34 /* item of the Tools menu for adding stop_positions */ 35 private JMenuItem addStopPositionMenu; 39 36 40 /** 41 * Main constructor. 42 * 43 * @param info 44 * Required information of the plugin. Obtained from the jar 45 * file. 46 */ 47 public PTAssistantPlugin(PluginInformation info) { 48 super(info); 37 /* item of the Tools menu for repeating the last fix */ 38 private static JMenuItem repeatLastFixMenu; 49 39 50 OsmValidator.addTest(PTAssistantValidatorTest.class); 40 /** 41 * Main constructor. 42 * 43 * @param info 44 * Required information of the plugin. Obtained from the jar 45 * file. 46 */ 47 public PTAssistantPlugin(PluginInformation info) { 48 super(info); 51 49 52 AddStopPositionAction addStopPositionAction = new AddStopPositionAction(); 53 addStopPositionMenu = MainMenu.add(Main.main.menu.toolsMenu, addStopPositionAction, false); 54 RepeatLastFixAction repeatLastFixAction = new RepeatLastFixAction(); 55 repeatLastFixMenu = MainMenu.add(Main.main.menu.toolsMenu, repeatLastFixAction, false); 50 OsmValidator.addTest(PTAssistantValidatorTest.class); 56 51 57 } 52 AddStopPositionAction addStopPositionAction = new AddStopPositionAction(); 53 addStopPositionMenu = MainMenu.add(Main.main.menu.toolsMenu, addStopPositionAction, false); 54 RepeatLastFixAction repeatLastFixAction = new RepeatLastFixAction(); 55 repeatLastFixMenu = MainMenu.add(Main.main.menu.toolsMenu, repeatLastFixAction, false); 58 56 59 /** 60 * Called when the JOSM map frame is created or destroyed. 61 */ 62 @Override 63 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 64 if (oldFrame == null && newFrame != null) { 65 addStopPositionMenu.setEnabled(true); 66 repeatLastFixMenu.setEnabled(false); 67 } else if (oldFrame != null && newFrame == null) { 68 addStopPositionMenu.setEnabled(false); 69 repeatLastFixMenu.setEnabled(false); 70 } 71 } 57 } 72 58 73 /** 74 * Sets up the pt_assistant tab in JOSM Preferences 75 */ 76 @Override 77 public PreferenceSetting getPreferenceSetting() { 78 return new PTAssistantPreferenceSetting(); 79 } 59 /** 60 * Called when the JOSM map frame is created or destroyed. 61 */ 62 @Override 63 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 64 if (oldFrame == null && newFrame != null) { 65 addStopPositionMenu.setEnabled(true); 66 repeatLastFixMenu.setEnabled(false); 67 } else if (oldFrame != null && newFrame == null) { 68 addStopPositionMenu.setEnabled(false); 69 repeatLastFixMenu.setEnabled(false); 70 } 71 } 80 72 81 public static PTRouteSegment getLastFix() { 82 return lastFix; 83 } 73 /** 74 * Sets up the pt_assistant tab in JOSM Preferences 75 */ 76 @Override 77 public PreferenceSetting getPreferenceSetting() { 78 return new PTAssistantPreferenceSetting(); 79 } 84 80 85 /** 86 * Remembers the last fix and enables/disables the Repeat last fix menu 87 * 88 * @param segment 89 * The last fix, call be null to disable the Repeat last fix menu 90 */ 91 public static void setLastFix(PTRouteSegment segment) { 92 lastFix = segment; 81 public static PTRouteSegment getLastFix() { 82 return lastFix; 83 } 93 84 94 SwingUtilities.invokeLater(new Runnable() { 95 @Override 96 public void run() { 97 repeatLastFixMenu.setEnabled(segment != null); 98 } 99 }); 100 } 85 /** 86 * Remembers the last fix and enables/disables the Repeat last fix menu 87 * 88 * @param segment 89 * The last fix, call be null to disable the Repeat last fix menu 90 */ 91 public static void setLastFix(PTRouteSegment segment) { 92 lastFix = segment; 101 93 102 /** 103 * Used in unit tests 104 * 105 * @param segment 106 */ 107 public static void setLastFixNoGui(PTRouteSegment segment) { 108 lastFix = segment; 109 } 94 SwingUtilities.invokeLater(new Runnable() { 95 @Override 96 public void run() { 97 repeatLastFixMenu.setEnabled(segment != null); 98 } 99 }); 100 } 101 102 /** 103 * Used in unit tests 104 * 105 * @param segment route segment 106 */ 107 public static void setLastFixNoGui(PTRouteSegment segment) { 108 lastFix = segment; 109 } 110 110 111 111 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/AddStopPositionAction.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.actions; 2 3 … … 21 22 /** 22 23 * Action to add stop position and split the relevant way 23 * 24 * 24 25 * @author darya 25 26 * … … 27 28 public class AddStopPositionAction extends JosmAction { 28 29 29 30 * 31 32 30 /** 31 * 32 */ 33 private static final long serialVersionUID = -5140181388906670207L; 33 34 34 35 36 37 35 public AddStopPositionAction() { 36 super(tr("Add stop position"), new ImageProvider("presets/transport", "bus.svg"), tr("Add stop position"), 37 Shortcut.registerShortcut("Add stop position", tr("Add stop position"), KeyEvent.VK_T, Shortcut.NONE), 38 false, "addStopPosition", false); 38 39 39 40 } 40 41 41 42 43 44 45 42 /** 43 * Actions that add the new node, set tags and update the map frame. 44 */ 45 @Override 46 public void actionPerformed(ActionEvent e) { 46 47 47 if (!isEnabled() || !Main.isDisplayingMapView()) { 48 return; 49 } 50 51 final ActionEvent actionEventParameter = e; 48 if (!isEnabled() || !Main.isDisplayingMapView()) { 49 return; 50 } 52 51 53 Main.map.mapView.addMouseListener(new MouseAdapter() { 52 final ActionEvent actionEventParameter = e; 54 53 55 LatLon clickPosition; 54 Main.map.mapView.addMouseListener(new MouseAdapter() { 56 55 56 LatLon clickPosition; 57 57 58 @Override 59 public void mouseClicked(MouseEvent e) { 60 61 if (clickPosition == null) { 62 clickPosition = Main.map.mapView.getLatLon(e.getX(), e.getY()); 58 @Override 59 public void mouseClicked(MouseEvent e) { 63 60 64 Layer activeLayer = Main.getLayerManager().getActiveLayer(); 61 if (clickPosition == null) { 62 clickPosition = Main.map.mapView.getLatLon(e.getX(), e.getY()); 65 63 66 if (activeLayer instanceof OsmDataLayer) { 67 OsmDataLayer osmDataLayer = (OsmDataLayer) activeLayer; 68 Node newNode = new Node(clickPosition); 69 newNode.put("bus", "yes"); 70 newNode.put("public_transport", "stop_position"); 71 osmDataLayer.data.addPrimitive(newNode); 72 osmDataLayer.data.setSelected(newNode); 73 Main.map.mapView.repaint(); 74 75 // make the stop position node part of the way: 76 JoinNodeWayAction joinNodeWayAction = JoinNodeWayAction.createJoinNodeToWayAction(); 77 joinNodeWayAction.actionPerformed(actionEventParameter); 78 79 // split the way: 80 SplitWayAction splitWayAction = new SplitWayAction(); 81 splitWayAction.actionPerformed(actionEventParameter); 64 Layer activeLayer = Main.getLayerManager().getActiveLayer(); 82 65 83 } 66 if (activeLayer instanceof OsmDataLayer) { 67 OsmDataLayer osmDataLayer = (OsmDataLayer) activeLayer; 68 Node newNode = new Node(clickPosition); 69 newNode.put("bus", "yes"); 70 newNode.put("public_transport", "stop_position"); 71 osmDataLayer.data.addPrimitive(newNode); 72 osmDataLayer.data.setSelected(newNode); 73 Main.map.mapView.repaint(); 84 74 85 Main.map.mapView.removeMouseListener(this); 86 Main.map.mapView.removeMouseMotionListener(this); 75 // make the stop position node part of the way: 76 JoinNodeWayAction joinNodeWayAction = JoinNodeWayAction.createJoinNodeToWayAction(); 77 joinNodeWayAction.actionPerformed(actionEventParameter); 87 78 88 } 89 } 90 });79 // split the way: 80 SplitWayAction splitWayAction = new SplitWayAction(); 81 splitWayAction.actionPerformed(actionEventParameter); 91 82 92 } 83 } 84 85 Main.map.mapView.removeMouseListener(this); 86 Main.map.mapView.removeMouseMotionListener(this); 87 88 } 89 } 90 }); 91 92 } 93 93 94 94 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/DownloadReferrersThread.java
r32616 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.actions; 2 3 … … 11 12 public class DownloadReferrersThread extends Thread { 12 13 13 14 private Node node; 14 15 15 16 17 16 public DownloadReferrersThread(Node node) { 17 super(); 18 this.node = node; 18 19 19 20 } 20 21 21 22 22 @Override 23 public void run() { 23 24 24 25 synchronized (this) { 25 26 26 Collection<Node> allNodes = node.getDataSet().getNodes(); 27 List<PrimitiveId> nodesToBeDownloaded = new ArrayList<PrimitiveId>(); 28 for (Node currNode : allNodes) { 29 if (currNode.hasTag("public_transport", "stop_position") || currNode.hasTag("highway", "bus_stop") 30 || currNode.hasTag("public_transport", "platform") || currNode.hasTag("highway", "platform") 31 || currNode.hasTag("railway", "platform")) { 32 nodesToBeDownloaded.add(currNode); 33 } 34 } 35 36 DownloadPrimitivesWithReferrersTask task = new DownloadPrimitivesWithReferrersTask(false, nodesToBeDownloaded, false, true, 37 null, null); 38 Thread t = new Thread(task); 39 t.start(); 40 try { 41 t.join(); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 } 27 Collection<Node> allNodes = node.getDataSet().getNodes(); 28 List<PrimitiveId> nodesToBeDownloaded = new ArrayList<>(); 29 for (Node currNode : allNodes) { 30 if (currNode.hasTag("public_transport", "stop_position") || currNode.hasTag("highway", "bus_stop") 31 || currNode.hasTag("public_transport", "platform") || currNode.hasTag("highway", "platform") 32 || currNode.hasTag("railway", "platform")) { 33 nodesToBeDownloaded.add(currNode); 34 } 35 } 45 36 46 } 37 DownloadPrimitivesWithReferrersTask task = new DownloadPrimitivesWithReferrersTask(false, nodesToBeDownloaded, false, true, 38 null, null); 39 Thread t = new Thread(task); 40 t.start(); 41 try { 42 t.join(); 43 } catch (InterruptedException e) { 44 e.printStackTrace(); 45 } 46 47 } 47 48 48 49 49 50 } 50 51 51 52 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/FixTask.java
r32435 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.actions; 2 3 … … 20 21 /** 21 22 * This class was copied with minor changes from ValidatorDialog.FixTask 22 * 23 * 23 24 * @author darya 24 25 * 25 26 */ 26 public class FixTask extends PleaseWaitRunnable { 27 28 private final Collection<TestError> testErrors; 29 private boolean canceled; 27 public class FixTask extends PleaseWaitRunnable { 30 28 31 public FixTask(Collection<TestError> testErrors) { 32 super(tr("Fixing errors ..."), false /* don't ignore exceptions */); 33 this.testErrors = testErrors == null ? new ArrayList<TestError>() : testErrors; 34 } 29 private final Collection<TestError> testErrors; 30 private boolean canceled; 35 31 36 @Override 37 protected void cancel() { 38 this.canceled = true;39 32 public FixTask(Collection<TestError> testErrors) { 33 super(tr("Fixing errors ..."), false /* don't ignore exceptions */); 34 this.testErrors = testErrors == null ? new ArrayList<>() : testErrors; 35 } 40 36 41 42 protected void finish() {43 // do nothing 44 37 @Override 38 protected void cancel() { 39 this.canceled = true; 40 } 45 41 46 protected void fixError(TestError error) throws InterruptedException, InvocationTargetException { 47 if (error.isFixable()) { 48 final Command fixCommand = error.getFix(); 49 if (fixCommand != null) { 50 SwingUtilities.invokeAndWait(new Runnable() { 51 @Override 52 public void run() { 53 Main.main.undoRedo.addNoRedraw(fixCommand); 54 } 55 }); 56 } 57 // It is wanted to ignore an error if it said fixable, even if 58 // fixCommand was null 59 // This is to fix #5764 and #5773: 60 // a delete command, for example, may be null if all concerned 61 // primitives have already been deleted 62 error.setIgnored(true); 63 } 64 } 42 @Override 43 protected void finish() { 44 // do nothing 45 } 65 46 66 @Override 67 protected void realRun() throws SAXException, IOException, OsmTransferException { 68 ProgressMonitor monitor = getProgressMonitor(); 69 try { 70 monitor.setTicksCount(testErrors.size()); 71 int i = 0; 72 SwingUtilities.invokeAndWait(new Runnable() { 73 @Override 74 public void run() { 75 Main.getLayerManager().getEditDataSet().beginUpdate(); 76 } 77 }); 78 try { 79 for (TestError error : testErrors) { 80 i++; 81 monitor.subTask(tr("Fixing ({0}/{1}): ''{2}''", i, testErrors.size(), error.getMessage())); 82 if (this.canceled) 83 return; 84 fixError(error); 85 monitor.worked(1); 86 } 87 } finally { 88 SwingUtilities.invokeAndWait(new Runnable() { 89 @Override 90 public void run() { 91 Main.getLayerManager().getEditDataSet().endUpdate(); 92 } 93 }); 94 } 95 monitor.subTask(tr("Updating map ...")); 96 SwingUtilities.invokeAndWait(new Runnable() { 97 @Override 98 public void run() { 99 Main.main.undoRedo.afterAdd(); 100 Main.map.repaint(); 101 // tree.resetErrors(); 102 Main.getLayerManager().getEditDataSet().fireSelectionChanged(); 103 } 104 }); 105 } catch (InterruptedException | InvocationTargetException e) { 106 // FIXME: signature of realRun should have a generic checked 107 // exception we 108 // could throw here 109 throw new RuntimeException(e); 110 } finally { 111 monitor.finishTask(); 112 } 113 114 } 47 protected void fixError(TestError error) throws InterruptedException, InvocationTargetException { 48 if (error.isFixable()) { 49 final Command fixCommand = error.getFix(); 50 if (fixCommand != null) { 51 SwingUtilities.invokeAndWait(new Runnable() { 52 @Override 53 public void run() { 54 Main.main.undoRedo.addNoRedraw(fixCommand); 55 } 56 }); 57 } 58 // It is wanted to ignore an error if it said fixable, even if 59 // fixCommand was null 60 // This is to fix #5764 and #5773: 61 // a delete command, for example, may be null if all concerned 62 // primitives have already been deleted 63 error.setIgnored(true); 64 } 65 } 66 67 @Override 68 protected void realRun() throws SAXException, IOException, OsmTransferException { 69 ProgressMonitor monitor = getProgressMonitor(); 70 try { 71 monitor.setTicksCount(testErrors.size()); 72 int i = 0; 73 SwingUtilities.invokeAndWait(new Runnable() { 74 @Override 75 public void run() { 76 Main.getLayerManager().getEditDataSet().beginUpdate(); 77 } 78 }); 79 try { 80 for (TestError error : testErrors) { 81 i++; 82 monitor.subTask(tr("Fixing ({0}/{1}): ''{2}''", i, testErrors.size(), error.getMessage())); 83 if (this.canceled) 84 return; 85 fixError(error); 86 monitor.worked(1); 87 } 88 } finally { 89 SwingUtilities.invokeAndWait(new Runnable() { 90 @Override 91 public void run() { 92 Main.getLayerManager().getEditDataSet().endUpdate(); 93 } 94 }); 95 } 96 monitor.subTask(tr("Updating map ...")); 97 SwingUtilities.invokeAndWait(new Runnable() { 98 @Override 99 public void run() { 100 Main.main.undoRedo.afterAdd(); 101 Main.map.repaint(); 102 // tree.resetErrors(); 103 Main.getLayerManager().getEditDataSet().fireSelectionChanged(); 104 } 105 }); 106 } catch (InterruptedException | InvocationTargetException e) { 107 // FIXME: signature of realRun should have a generic checked 108 // exception we 109 // could throw here 110 throw new RuntimeException(e); 111 } finally { 112 monitor.finishTask(); 113 } 114 115 } 115 116 116 117 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/IncompleteMembersDownloadThread.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.actions; 2 3 … … 21 22 public class IncompleteMembersDownloadThread extends Thread { 22 23 23 24 25 26 27 24 /** 25 * Default constructor 26 */ 27 public IncompleteMembersDownloadThread() { 28 super(); 28 29 29 30 } 30 31 31 32 32 @Override 33 public void run() { 33 34 34 35 35 try { 36 synchronized (this) { 36 37 37 38 ArrayList<PrimitiveId> list = new ArrayList<>(); 38 39 39 40 41 42 43 44 45 40 // if there are selected routes, try adding them first: 41 for (Relation currentSelectedRelation : Main.getLayerManager().getEditDataSet() 42 .getSelectedRelations()) { 43 if (RouteUtils.isTwoDirectionRoute(currentSelectedRelation)) { 44 list.add(currentSelectedRelation); 45 } 46 } 46 47 47 48 49 50 51 52 53 54 55 56 48 if (list.isEmpty()) { 49 // add all route relations that are of public_transport 50 // version 2: 51 Collection<Relation> allRelations = Main.getLayerManager().getEditDataSet().getRelations(); 52 for (Relation currentRelation : allRelations) { 53 if (RouteUtils.isTwoDirectionRoute(currentRelation)) { 54 list.add(currentRelation); 55 } 56 } 57 } 57 58 58 59 60 61 62 63 64 65 66 67 68 69 70 71 59 // add all stop_positions: 60 Collection<Node> allNodes = Main.getLayerManager().getEditDataSet().getNodes(); 61 for (Node currentNode : allNodes) { 62 if (currentNode.hasTag("public_transport", "stop_position")) { 63 List<OsmPrimitive> referrers = currentNode.getReferrers(); 64 boolean parentWayExists = false; 65 for (OsmPrimitive referrer : referrers) { 66 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 67 parentWayExists = true; 68 break; 69 } 70 } 71 if (!parentWayExists) { 72 list.add(currentNode); 72 73 73 74 } 74 75 75 76 76 } 77 } 77 78 78 79 80 81 82 79 DownloadPrimitivesWithReferrersTask task = new DownloadPrimitivesWithReferrersTask(false, list, false, 80 true, null, null); 81 Thread t = new Thread(task); 82 t.start(); 83 t.join(); 83 84 84 85 } 85 86 86 } catch (InterruptedException e) { 87 // do nothing in case the download was interrupted 88 } 87 } catch (InterruptedException e) { 88 // do nothing in case the download was interrupted 89 Main.trace(e); 90 } 89 91 90 92 } 91 93 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/actions/RepeatLastFixAction.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.actions; 2 3 … … 15 16 /** 16 17 * Carries out the changes after the Repeat last fix button has been pressed 17 * 18 * 18 19 * @author darya 19 20 * … … 21 22 public class RepeatLastFixAction extends JosmAction { 22 23 23 24 private static final long serialVersionUID = 2681464946469047054L; 24 25 25 26 27 28 29 30 31 26 /** 27 * Default constructor 28 */ 29 public RepeatLastFixAction() { 30 super(tr("Repeat last fix"), new ImageProvider("presets/transport", "bus.svg"), tr("Repeat last fix"), 31 Shortcut.registerShortcut("Repeat last fix", tr("Repeat last fix"), KeyEvent.VK_E, Shortcut.NONE), 32 false, "repeatLastFix", false); 32 33 33 34 } 34 35 35 36 37 38 39 36 /** 37 * Applies the fixes, resets the last fix attribute 38 */ 39 @Override 40 public void actionPerformed(ActionEvent e) { 40 41 41 42 43 42 if (!isEnabled() || !Main.isDisplayingMapView()) { 43 return; 44 } 44 45 45 46 SegmentChecker.carryOutRepeatLastFix(PTAssistantPlugin.getLastFix()); 46 47 47 48 PTAssistantPlugin.setLastFix(null); 48 49 49 50 } 50 51 51 52 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteDataManager.java
r32895 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 16 17 * Creates a representation of a route relation in the pt_assistant data model, 17 18 * then maintains a list of PTStops and PTWays of a route. 18 * 19 * 19 20 * @author darya 20 21 * … … 22 23 public class PTRouteDataManager { 23 24 24 /* The route relation */ 25 Relation relation; 26 27 /* Stores all relation members that are PTStops */ 28 private List<PTStop> ptstops = new ArrayList<>(); 29 30 /* Stores all relation members that are PTWays */ 31 private List<PTWay> ptways = new ArrayList<>(); 32 33 /* 34 * Stores relation members that could not be created because they are not 35 * expected in the model for public_transport version 2 36 */ 37 private Set<RelationMember> failedMembers = new HashSet<>(); 38 39 public PTRouteDataManager(Relation relation) throws IllegalArgumentException { 40 41 // It is assumed that the relation is a route. Build in a check here 42 // (e.g. from class RouteUtils) if you want to invoke this constructor 43 // from outside the pt_assitant SegmentChecker) 44 45 this.relation = relation; 46 47 PTStop prev = null; // stores the last created PTStop 48 49 for (RelationMember member : this.relation.getMembers()) { 50 51 if (RouteUtils.isPTStop(member)) { 52 53 // First, check if the stop already exists (i.e. there are 54 // consecutive elements that belong to the same stop: 55 boolean stopExists = false; 56 57 if (prev != null) { 58 if (prev.getName() == null || prev.getName().equals("") || member.getMember().get("name") == null 59 || member.getMember().get("name").equals("")) { 60 61 // if there is no name, check by proximity: 62 // Squared distance of 0.000004 corresponds to 63 // around 100 m 64 if (this.calculateDistanceSq(member, prev) < 0.000001) { 65 stopExists = true; 66 } 67 68 } else { 69 70 // if there is a name, check by name comparison: 71 if (prev.getName().equalsIgnoreCase(member.getMember().get("name"))) { 72 73 stopExists = true; 74 } 75 } 76 } 77 78 // check if there are consecutive elements that belong to 79 // the same stop: 80 if (stopExists) { 81 // this PTStop already exists, so just add a new 82 // element: 83 prev.addStopElement(member); 84 // TODO: something may need to be done if adding the 85 // element 86 // did not succeed. The failure is a result of the same 87 // stop 88 // having >1 stop_position, platform or stop_area. 89 } else { 90 // this PTStop does not exist yet, so create it: 91 92 try { 93 PTStop ptstop = new PTStop(member); 94 ptstops.add(ptstop); 95 prev = ptstop; 96 } catch (IllegalArgumentException ex) { 97 if (ex.getMessage().equals( 98 "The RelationMember type does not match its role " + member.getMember().getName())) { 99 if (!failedMembers.contains(member)) { 100 failedMembers.add(member); 101 } 102 } else { 103 throw ex; 104 } 105 } 106 107 } 108 109 } else if (RouteUtils.isPTWay(member)) { 110 111 PTWay ptway = new PTWay(member); 112 ptways.add(ptway); 113 114 } else { 115 if (!failedMembers.contains(member)) { 116 failedMembers.add(member); 117 } 118 119 } 120 121 } 122 } 123 124 /** 125 * Calculates the squared distance between the centers of bounding boxes of 126 * two relation members (which are supposed to be platforms or 127 * stop_positions) 128 * 129 * @param member1 130 * @param member2 131 * @return Squared distance between the centers of the bounding boxes of the 132 * given relation members 133 */ 134 private double calculateDistanceSq(RelationMember member1, RelationMember member2) { 135 LatLon coord1 = member1.getMember().getBBox().getCenter(); 136 LatLon coord2 = member2.getMember().getBBox().getCenter(); 137 return coord1.distanceSq(coord2); 138 } 139 140 /** 141 * Assigns the given way to a PTWay of this route relation. If multiple 142 * PTWays contain the same inputWay, the first found PTWay is returned. 143 * 144 * @param inputWay 145 * Way to be assigned to a PTWAy of this route relation 146 * @return PTWay that contains the geometry of the inputWay, null if not 147 * found 148 */ 149 public PTWay getPTWay(Way inputWay) { 150 151 for (PTWay curr : ptways) { 152 153 if (curr.isWay() && curr.getWays().get(0) == inputWay) { 154 return curr; 155 } 156 157 if (curr.isRelation()) { 158 for (RelationMember rm : curr.getRelation().getMembers()) { 159 Way wayInNestedRelation = rm.getWay(); 160 if (wayInNestedRelation == inputWay) { 161 return curr; 162 } 163 } 164 } 165 } 166 167 return null; // if not found 168 } 169 170 public List<PTStop> getPTStops() { 171 return this.ptstops; 172 } 173 174 public List<PTWay> getPTWays() { 175 return this.ptways; 176 } 177 178 public int getPTStopCount() { 179 return ptstops.size(); 180 } 181 182 public int getPTWayCount() { 183 return this.ptways.size(); 184 } 185 186 public PTStop getFirstStop() { 187 if (this.ptstops.isEmpty()) { 188 return null; 189 } 190 return this.ptstops.get(0); 191 } 192 193 public PTStop getLastStop() { 194 if (this.ptstops.isEmpty()) { 195 return null; 196 } 197 return this.ptstops.get(ptstops.size() - 1); 198 } 199 200 public Set<RelationMember> getFailedMembers() { 201 return this.failedMembers; 202 } 203 204 /** 205 * Returns the route relation for which this manager was created: 206 * 207 * @return 208 */ 209 public Relation getRelation() { 210 return this.relation; 211 } 212 213 /** 214 * Returns a PTStop that matches the given id. Returns null if not found 215 * 216 * @param id 217 * @return 218 */ 219 public PTStop getPTStop(long id) { 220 for (PTStop stop : this.ptstops) { 221 if (stop.getStopPosition() != null && stop.getStopPosition().getId() == id) { 222 return stop; 223 } 224 225 if (stop.getPlatform() != null && stop.getPlatform().getId() == id) { 226 return stop; 227 } 228 } 229 230 return null; 231 } 232 233 /** 234 * Returns a PTWay that matches the given id. Returns null if not found 235 * 236 * @param id 237 * @return 238 */ 239 public PTWay getPTWay(long id) { 240 for (PTWay ptway : this.ptways) { 241 for (Way way : ptway.getWays()) { 242 if (way.getId() == id) { 243 return ptway; 244 } 245 } 246 } 247 return null; 248 } 249 250 /** 251 * Returns all PTWays of this route that contain the given way. 252 * 253 * @param way 254 * @return 255 */ 256 public List<PTWay> findPTWaysThatContain(Way way) { 257 258 List<PTWay> ptwaysThatContain = new ArrayList<>(); 259 for (PTWay ptway : ptways) { 260 if (ptway.getWays().contains(way)) { 261 ptwaysThatContain.add(ptway); 262 } 263 } 264 return ptwaysThatContain; 265 } 266 267 /** 268 * Returns all PTWays of this route that contain the given node as their 269 * first or last node. 270 * 271 * @return 272 */ 273 public List<PTWay> findPTWaysThatContainAsEndNode(Node node) { 274 275 List<PTWay> ptwaysThatContain = new ArrayList<>(); 276 for (PTWay ptway : ptways) { 277 List<Way> ways = ptway.getWays(); 278 if (ways.get(0).firstNode() == node || ways.get(0).lastNode() == node 279 || ways.get(ways.size() - 1).firstNode() == node || ways.get(ways.size() - 1).lastNode() == node) { 280 ptwaysThatContain.add(ptway); 281 } 282 } 283 return ptwaysThatContain; 284 285 } 286 287 /** 288 * Checks if at most one PTWay of this route refers to the given node 289 * 290 * @param node 291 * @return 292 */ 293 public boolean isDeadendNode(Node node) { 294 295 List<PTWay> referringPtways = this.findPTWaysThatContainAsEndNode(node); 296 if (referringPtways.size() <= 1) { 297 return true; 298 } 299 return false; 300 } 301 302 /** 303 * Returns the PTWay which comes directly after the given ptway according to 304 * the existing route member sorting 305 * 306 * @param ptway 307 * @return 308 */ 309 public PTWay getNextPTWay(PTWay ptway) { 310 311 for (int i = 0; i < ptways.size() - 1; i++) { 312 if (ptways.get(i) == ptway) { 313 return ptways.get(i + 1); 314 } 315 } 316 return null; 317 318 } 319 320 /** 321 * Returns the PTWay which comes directly before the given ptway according 322 * to the existing route member sorting 323 * 324 * @param ptway 325 * @return 326 */ 327 public PTWay getPreviousPTWay(PTWay ptway) { 328 329 for (int i = 1; i < ptways.size(); i++) { 330 if (ptways.get(i) == ptway) { 331 return ptways.get(i - 1); 332 } 333 } 334 return null; 335 } 336 337 /** 338 * Returns a sequence of PTWays that are between the start way and the end 339 * way. The resulting list includes the start and end PTWays. 340 * 341 * @param start 342 * @param end 343 * @return 344 */ 345 public List<PTWay> getPTWaysBetween(Way start, Way end) { 346 347 List<Integer> potentialStartIndices = new ArrayList<>(); 348 List<Integer> potentialEndIndices = new ArrayList<>(); 349 350 for (int i = 0; i < ptways.size(); i++) { 351 if (ptways.get(i).getWays().contains(start)) { 352 potentialStartIndices.add(i); 353 } 354 if (ptways.get(i).getWays().contains(end)) { 355 potentialEndIndices.add(i); 356 } 357 } 358 359 List<int[]> pairList = new ArrayList<>(); 360 for (Integer potentialStartIndex : potentialStartIndices) { 361 for (Integer potentialEndIndex : potentialEndIndices) { 362 if (potentialStartIndex <= potentialEndIndex) { 363 int[] pair = { potentialStartIndex, potentialEndIndex }; 364 pairList.add(pair); 365 } 366 } 367 } 368 369 int minDifference = Integer.MAX_VALUE; 370 int[] mostSuitablePair = { 0, 0 }; 371 for (int[] pair : pairList) { 372 int diff = pair[1] - pair[0]; 373 if (diff < minDifference) { 374 minDifference = diff; 375 mostSuitablePair = pair; 376 } 377 } 378 379 List<PTWay> result = new ArrayList<>(); 380 for (int i = mostSuitablePair[0]; i <= mostSuitablePair[1]; i++) { 381 result.add(ptways.get(i)); 382 } 383 return result; 384 } 385 386 /** 387 * Returns the common Node of two PTWays or null if there is no common Node. 388 * If there is more than one common Node, only the first found is returned. 389 * 390 * @param way1 391 * @param way2 392 * @return 393 */ 394 public Node getCommonNode(PTWay way1, PTWay way2) { 395 396 List<Way> wayList1 = way1.getWays(); 397 List<Way> wayList2 = way2.getWays(); 398 399 HashSet<Node> nodeSet1 = new HashSet<>(); 400 for (Way w : wayList1) { 401 nodeSet1.addAll(w.getNodes()); 402 } 403 HashSet<Node> nodeSet2 = new HashSet<>(); 404 for (Way w : wayList2) { 405 nodeSet2.addAll(w.getNodes()); 406 } 407 408 for (Node n : nodeSet1) { 409 if (nodeSet2.contains(n)) { 410 return n; 411 } 412 } 413 414 return null; 415 } 416 417 /** 418 * Returns the last way of this route 419 * 420 * @return 421 */ 422 public Way getLastWay() { 423 PTWay lastPTWay = this.ptways.get(ptways.size() - 1); 424 if (lastPTWay == null) { 425 return null; 426 } 427 return lastPTWay.getWays().get(lastPTWay.getWays().size() - 1); 428 } 25 /* The route relation */ 26 Relation relation; 27 28 /* Stores all relation members that are PTStops */ 29 private List<PTStop> ptstops = new ArrayList<>(); 30 31 /* Stores all relation members that are PTWays */ 32 private List<PTWay> ptways = new ArrayList<>(); 33 34 /* 35 * Stores relation members that could not be created because they are not 36 * expected in the model for public_transport version 2 37 */ 38 private Set<RelationMember> failedMembers = new HashSet<>(); 39 40 public PTRouteDataManager(Relation relation) throws IllegalArgumentException { 41 42 // It is assumed that the relation is a route. Build in a check here 43 // (e.g. from class RouteUtils) if you want to invoke this constructor 44 // from outside the pt_assitant SegmentChecker) 45 46 this.relation = relation; 47 48 PTStop prev = null; // stores the last created PTStop 49 50 for (RelationMember member : this.relation.getMembers()) { 51 52 if (RouteUtils.isPTStop(member)) { 53 54 // First, check if the stop already exists (i.e. there are 55 // consecutive elements that belong to the same stop: 56 boolean stopExists = false; 57 58 if (prev != null) { 59 if (prev.getName() == null || prev.getName().equals("") || member.getMember().get("name") == null 60 || member.getMember().get("name").equals("")) { 61 62 // if there is no name, check by proximity: 63 // Squared distance of 0.000004 corresponds to 64 // around 100 m 65 if (this.calculateDistanceSq(member, prev) < 0.000001) { 66 stopExists = true; 67 } 68 69 } else { 70 71 // if there is a name, check by name comparison: 72 if (prev.getName().equalsIgnoreCase(member.getMember().get("name"))) { 73 74 stopExists = true; 75 } 76 } 77 } 78 79 // check if there are consecutive elements that belong to 80 // the same stop: 81 if (stopExists) { 82 // this PTStop already exists, so just add a new 83 // element: 84 prev.addStopElement(member); 85 // TODO: something may need to be done if adding the 86 // element 87 // did not succeed. The failure is a result of the same 88 // stop 89 // having >1 stop_position, platform or stop_area. 90 } else { 91 // this PTStop does not exist yet, so create it: 92 93 try { 94 PTStop ptstop = new PTStop(member); 95 ptstops.add(ptstop); 96 prev = ptstop; 97 } catch (IllegalArgumentException ex) { 98 if (ex.getMessage().equals( 99 "The RelationMember type does not match its role " + member.getMember().getName())) { 100 if (!failedMembers.contains(member)) { 101 failedMembers.add(member); 102 } 103 } else { 104 throw ex; 105 } 106 } 107 108 } 109 110 } else if (RouteUtils.isPTWay(member)) { 111 112 PTWay ptway = new PTWay(member); 113 ptways.add(ptway); 114 115 } else { 116 if (!failedMembers.contains(member)) { 117 failedMembers.add(member); 118 } 119 120 } 121 122 } 123 } 124 125 /** 126 * Calculates the squared distance between the centers of bounding boxes of 127 * two relation members (which are supposed to be platforms or 128 * stop_positions) 129 * 130 * @param member1 first member 131 * @param member2 second member 132 * @return Squared distance between the centers of the bounding boxes of the 133 * given relation members 134 */ 135 private double calculateDistanceSq(RelationMember member1, RelationMember member2) { 136 LatLon coord1 = member1.getMember().getBBox().getCenter(); 137 LatLon coord2 = member2.getMember().getBBox().getCenter(); 138 return coord1.distanceSq(coord2); 139 } 140 141 /** 142 * Assigns the given way to a PTWay of this route relation. If multiple 143 * PTWays contain the same inputWay, the first found PTWay is returned. 144 * 145 * @param inputWay 146 * Way to be assigned to a PTWAy of this route relation 147 * @return PTWay that contains the geometry of the inputWay, null if not 148 * found 149 */ 150 public PTWay getPTWay(Way inputWay) { 151 152 for (PTWay curr : ptways) { 153 154 if (curr.isWay() && curr.getWays().get(0) == inputWay) { 155 return curr; 156 } 157 158 if (curr.isRelation()) { 159 for (RelationMember rm : curr.getRelation().getMembers()) { 160 Way wayInNestedRelation = rm.getWay(); 161 if (wayInNestedRelation == inputWay) { 162 return curr; 163 } 164 } 165 } 166 } 167 168 return null; // if not found 169 } 170 171 public List<PTStop> getPTStops() { 172 return this.ptstops; 173 } 174 175 public List<PTWay> getPTWays() { 176 return this.ptways; 177 } 178 179 public int getPTStopCount() { 180 return ptstops.size(); 181 } 182 183 public int getPTWayCount() { 184 return this.ptways.size(); 185 } 186 187 public PTStop getFirstStop() { 188 if (this.ptstops.isEmpty()) { 189 return null; 190 } 191 return this.ptstops.get(0); 192 } 193 194 public PTStop getLastStop() { 195 if (this.ptstops.isEmpty()) { 196 return null; 197 } 198 return this.ptstops.get(ptstops.size() - 1); 199 } 200 201 public Set<RelationMember> getFailedMembers() { 202 return this.failedMembers; 203 } 204 205 /** 206 * Returns the route relation for which this manager was created: 207 * 208 * @return the route relation for which this manager was created 209 */ 210 public Relation getRelation() { 211 return this.relation; 212 } 213 214 /** 215 * Returns a PTStop that matches the given id. Returns null if not found 216 * 217 * @param id identifier 218 * @return a PTStop that matches the given id. Returns null if not found 219 */ 220 public PTStop getPTStop(long id) { 221 for (PTStop stop : this.ptstops) { 222 if (stop.getStopPosition() != null && stop.getStopPosition().getId() == id) { 223 return stop; 224 } 225 226 if (stop.getPlatform() != null && stop.getPlatform().getId() == id) { 227 return stop; 228 } 229 } 230 231 return null; 232 } 233 234 /** 235 * Returns a PTWay that matches the given id. Returns null if not found 236 * 237 * @param id identifier 238 * @return a PTWay that matches the given id. Returns null if not found 239 */ 240 public PTWay getPTWay(long id) { 241 for (PTWay ptway : this.ptways) { 242 for (Way way : ptway.getWays()) { 243 if (way.getId() == id) { 244 return ptway; 245 } 246 } 247 } 248 return null; 249 } 250 251 /** 252 * Returns all PTWays of this route that contain the given way. 253 * 254 * @param way way 255 * @return all PTWays of this route that contain the given way 256 */ 257 public List<PTWay> findPTWaysThatContain(Way way) { 258 259 List<PTWay> ptwaysThatContain = new ArrayList<>(); 260 for (PTWay ptway : ptways) { 261 if (ptway.getWays().contains(way)) { 262 ptwaysThatContain.add(ptway); 263 } 264 } 265 return ptwaysThatContain; 266 } 267 268 /** 269 * Returns all PTWays of this route that contain the given node as their 270 * first or last node. 271 * 272 * @return all PTWays of this route that contain the given node as their 273 * first or last node 274 */ 275 public List<PTWay> findPTWaysThatContainAsEndNode(Node node) { 276 277 List<PTWay> ptwaysThatContain = new ArrayList<>(); 278 for (PTWay ptway : ptways) { 279 List<Way> ways = ptway.getWays(); 280 if (ways.get(0).firstNode() == node || ways.get(0).lastNode() == node 281 || ways.get(ways.size() - 1).firstNode() == node || ways.get(ways.size() - 1).lastNode() == node) { 282 ptwaysThatContain.add(ptway); 283 } 284 } 285 return ptwaysThatContain; 286 287 } 288 289 /** 290 * Checks if at most one PTWay of this route refers to the given node 291 * 292 * @param node node 293 * @return {@code true} if at most one PTWay of this route refers to the given node 294 */ 295 public boolean isDeadendNode(Node node) { 296 297 List<PTWay> referringPtways = this.findPTWaysThatContainAsEndNode(node); 298 if (referringPtways.size() <= 1) { 299 return true; 300 } 301 return false; 302 } 303 304 /** 305 * Returns the PTWay which comes directly after the given ptway according to 306 * the existing route member sorting 307 * 308 * @param ptway way 309 * @return the PTWay which comes directly after the given ptway according to 310 * the existing route member sorting 311 */ 312 public PTWay getNextPTWay(PTWay ptway) { 313 314 for (int i = 0; i < ptways.size() - 1; i++) { 315 if (ptways.get(i) == ptway) { 316 return ptways.get(i + 1); 317 } 318 } 319 return null; 320 321 } 322 323 /** 324 * Returns the PTWay which comes directly before the given ptway according 325 * to the existing route member sorting 326 * 327 * @param ptway way 328 * @return the PTWay which comes directly before the given ptway according 329 * to the existing route member sorting 330 */ 331 public PTWay getPreviousPTWay(PTWay ptway) { 332 333 for (int i = 1; i < ptways.size(); i++) { 334 if (ptways.get(i) == ptway) { 335 return ptways.get(i - 1); 336 } 337 } 338 return null; 339 } 340 341 /** 342 * Returns a sequence of PTWays that are between the start way and the end 343 * way. The resulting list includes the start and end PTWays. 344 * 345 * @param start start way 346 * @param end end way 347 * @return a sequence of PTWays that are between the start way and the end way 348 */ 349 public List<PTWay> getPTWaysBetween(Way start, Way end) { 350 351 List<Integer> potentialStartIndices = new ArrayList<>(); 352 List<Integer> potentialEndIndices = new ArrayList<>(); 353 354 for (int i = 0; i < ptways.size(); i++) { 355 if (ptways.get(i).getWays().contains(start)) { 356 potentialStartIndices.add(i); 357 } 358 if (ptways.get(i).getWays().contains(end)) { 359 potentialEndIndices.add(i); 360 } 361 } 362 363 List<int[]> pairList = new ArrayList<>(); 364 for (Integer potentialStartIndex : potentialStartIndices) { 365 for (Integer potentialEndIndex : potentialEndIndices) { 366 if (potentialStartIndex <= potentialEndIndex) { 367 int[] pair = {potentialStartIndex, potentialEndIndex}; 368 pairList.add(pair); 369 } 370 } 371 } 372 373 int minDifference = Integer.MAX_VALUE; 374 int[] mostSuitablePair = {0, 0}; 375 for (int[] pair : pairList) { 376 int diff = pair[1] - pair[0]; 377 if (diff < minDifference) { 378 minDifference = diff; 379 mostSuitablePair = pair; 380 } 381 } 382 383 List<PTWay> result = new ArrayList<>(); 384 for (int i = mostSuitablePair[0]; i <= mostSuitablePair[1]; i++) { 385 result.add(ptways.get(i)); 386 } 387 return result; 388 } 389 390 /** 391 * Returns the common Node of two PTWays or null if there is no common Node. 392 * If there is more than one common Node, only the first found is returned. 393 * 394 * @param way1 first way 395 * @param way2 second way 396 * @return the common Node of two PTWays or null if there is no common Node 397 */ 398 public Node getCommonNode(PTWay way1, PTWay way2) { 399 400 List<Way> wayList1 = way1.getWays(); 401 List<Way> wayList2 = way2.getWays(); 402 403 HashSet<Node> nodeSet1 = new HashSet<>(); 404 for (Way w : wayList1) { 405 nodeSet1.addAll(w.getNodes()); 406 } 407 HashSet<Node> nodeSet2 = new HashSet<>(); 408 for (Way w : wayList2) { 409 nodeSet2.addAll(w.getNodes()); 410 } 411 412 for (Node n : nodeSet1) { 413 if (nodeSet2.contains(n)) { 414 return n; 415 } 416 } 417 418 return null; 419 } 420 421 /** 422 * Returns the last way of this route 423 * 424 * @return the last way of this route 425 */ 426 public Way getLastWay() { 427 PTWay lastPTWay = this.ptways.get(ptways.size() - 1); 428 if (lastPTWay == null) { 429 return null; 430 } 431 return lastPTWay.getWays().get(lastPTWay.getWays().size() - 1); 432 } 429 433 430 434 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteSegment.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 12 13 * will be two route segments between each pair of consecutive stops, one in 13 14 * each direction. 14 * 15 * 15 16 * @author darya 16 17 * … … 19 20 public class PTRouteSegment { 20 21 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 * @return 55 56 57 58 59 60 61 62 * @param ptwayList 63 64 65 66 67 68 69 70 71 * @return 72 73 74 75 76 77 78 79 * @return 80 81 82 83 84 85 86 87 * @return 88 89 90 91 92 93 94 95 96 97 98 * @return 99 100 101 102 103 104 105 106 107 108 109 * @return 110 111 112 113 114 115 116 117 118 119 120 * @return 121 122 123 124 125 126 127 128 129 130 131 132 133 * 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 * @return 167 168 169 170 171 172 173 174 * @return 175 176 177 178 179 180 181 182 * 183 * @param other 184 * @return 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 22 /* first stop of the route segment */ 23 private PTStop firstStop; 24 25 /* last stop of the route segment */ 26 private PTStop lastStop; 27 28 /* ptways that belong to this route segment */ 29 private List<PTWay> ptways; 30 31 /* fix variants available for this route segment */ 32 private List<List<PTWay>> fixVariants; 33 34 /* route relation for which this route segment was created */ 35 private Relation relation; 36 37 /** 38 * Constructor 39 * @param firstStop first stop of the route segment 40 * @param lastStop last stop of the route segment 41 * @param ways ways PTWays that belong to this route segment 42 * @param relation the route relation for which this route segment is created 43 */ 44 public PTRouteSegment(PTStop firstStop, PTStop lastStop, List<PTWay> ways, Relation relation) { 45 this.firstStop = firstStop; 46 this.lastStop = lastStop; 47 this.ptways = new ArrayList<>(ways.size()); 48 ptways.addAll(ways); 49 fixVariants = new ArrayList<>(); 50 this.relation = relation; 51 } 52 53 /** 54 * Returns the PTWays of this route segment 55 * @return the PTWays of this route segment 56 */ 57 public List<PTWay> getPTWays() { 58 return this.ptways; 59 } 60 61 /** 62 * Sets the PTWays of this route segment to the given list 63 * @param ptwayList list of ways 64 */ 65 public void setPTWays(List<PTWay> ptwayList) { 66 this.ptways = ptwayList; 67 this.fixVariants.clear(); 68 } 69 70 /** 71 * Returns the first stop of this route segment 72 * @return the first stop of this route segment 73 */ 74 public PTStop getFirstStop() { 75 return this.firstStop; 76 } 77 78 /** 79 * Returns the last stop of this route segment 80 * @return the last stop of this route segment 81 */ 82 public PTStop getLastStop() { 83 return this.lastStop; 84 } 85 86 /** 87 * Returns the first PTWay of this route segment 88 * @return the first PTWay of this route segment 89 */ 90 public PTWay getFirstPTWay() { 91 if (ptways.isEmpty()) { 92 return null; 93 } 94 return ptways.get(0); 95 } 96 97 /** 98 * Returns the last PTWay of this route segment 99 * @return the last PTWay of this route segment 100 */ 101 public PTWay getLastPTWay() { 102 if (ptways.isEmpty()) { 103 return null; 104 } 105 return ptways.get(ptways.size() - 1); 106 } 107 108 /** 109 * Returns the first way of this route segment 110 * @return the first way of this route segment 111 */ 112 public Way getFirstWay() { 113 if (ptways.isEmpty()) { 114 return null; 115 } 116 return ptways.get(0).getWays().get(0); 117 } 118 119 /** 120 * Returns the last way of this route segment 121 * @return the last way of this route segment 122 */ 123 public Way getLastWay() { 124 if (ptways.isEmpty()) { 125 return null; 126 } 127 List<Way> waysOfLast = ptways.get(ptways.size() - 1).getWays(); 128 return waysOfLast.get(waysOfLast.size() - 1); 129 } 130 131 /** 132 * Adds the new fix variant if an identical fix variant (i.e. same ways) is 133 * not already contained in the list of the fix variants of this. 134 * 135 * @param list the PTWays of the new fix variant 136 */ 137 public synchronized void addFixVariant(List<PTWay> list) { 138 List<Way> otherWays = new ArrayList<>(); 139 for (PTWay ptway : list) { 140 otherWays.addAll(ptway.getWays()); 141 } 142 143 for (List<PTWay> fixVariant : this.fixVariants) { 144 List<Way> thisWays = new ArrayList<>(); 145 for (PTWay ptway : fixVariant) { 146 thisWays.addAll(ptway.getWays()); 147 } 148 boolean listsEqual = (thisWays.size() == otherWays.size()); 149 if (listsEqual) { 150 for (int i = 0; i < thisWays.size(); i++) { 151 if (thisWays.get(i).getId() != otherWays.get(i).getId()) { 152 listsEqual = false; 153 break; 154 } 155 } 156 } 157 if (listsEqual) { 158 return; 159 } 160 } 161 162 this.fixVariants.add(list); 163 } 164 165 /** 166 * Returns the fix variants stored for this route segment 167 * @return the fix variants stored for this route segment 168 */ 169 public List<List<PTWay>> getFixVariants() { 170 return this.fixVariants; 171 } 172 173 /** 174 * Returns the route relation for which this route segment was created 175 * @return the route relation for which this route segment was created 176 */ 177 public Relation getRelation() { 178 return this.relation; 179 } 180 181 /** 182 * Checks if this and the other route segments are equal 183 * 184 * @param other other route segment 185 * @return {@code true} if this and the other route segments are equal 186 */ 187 public boolean equalsRouteSegment(PTRouteSegment other) { 188 189 List<Way> thisWays = new ArrayList<>(); 190 for (PTWay ptway : this.ptways) { 191 thisWays.addAll(ptway.getWays()); 192 } 193 List<Way> otherWays = new ArrayList<>(); 194 for (PTWay ptway : other.getPTWays()) { 195 otherWays.addAll(ptway.getWays()); 196 } 197 198 if (thisWays.size() != otherWays.size()) { 199 return false; 200 } 201 202 for (int i = 0; i < thisWays.size(); i++) { 203 if (thisWays.get(i).getId() != otherWays.get(i).getId()) { 204 return false; 205 } 206 } 207 208 return true; 209 } 209 210 210 211 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/data/PTStop.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 14 15 /** 15 16 * Model a stop with one or two elements (platform and/or stop_position) 16 * 17 * 17 18 * @author darya 18 19 * … … 20 21 public class PTStop extends RelationMember { 21 22 22 23 24 25 26 27 28 29 30 31 32 33 * 34 * @param other35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 * 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 * 115 * @return 116 117 118 119 120 121 122 123 124 * 125 * @return 126 127 128 129 130 131 132 133 * @return 134 135 136 137 138 139 140 141 * @param newStopPosition 142 143 144 145 146 147 148 149 150 151 152 153 154 * 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 * 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 23 /* stop_position element of this stop */ 24 private Node stopPosition = null; 25 26 /* platform element of this stop */ 27 private OsmPrimitive platform = null; 28 29 /* the name of this stop */ 30 private String name = ""; 31 32 /** 33 * Constructor 34 * 35 * @param other other relation member 36 * @throws IllegalArgumentException 37 * if the given relation member does not fit to the data model 38 * used in the plugin 39 */ 40 public PTStop(RelationMember other) throws IllegalArgumentException { 41 42 super(other); 43 44 // if ((other.hasRole("stop") || other.hasRole("stop_entry_only") || 45 // other.hasRole("stop_exit_only")) 46 // && other.getType().equals(OsmPrimitiveType.NODE)) { 47 48 if (other.getMember().hasTag("public_transport", "stop_position")) { 49 50 this.stopPosition = other.getNode(); 51 this.name = stopPosition.get("name"); 52 53 // } else if (other.getRole().equals("platform") || 54 // other.getRole().equals("platform_entry_only") 55 // || other.getRole().equals("platform_exit_only")) { 56 } else if (other.getMember().hasTag("highway", "bus_stop") 57 || other.getMember().hasTag("public_transport", "platform") 58 || other.getMember().hasTag("highway", "platform") || other.getMember().hasTag("railway", "platform")) { 59 60 this.platform = other.getMember(); 61 this.name = platform.get("name"); 62 63 } else { 64 throw new IllegalArgumentException( 65 "The RelationMember type does not match its role " + other.getMember().getName()); 66 } 67 68 } 69 70 /** 71 * Adds the given element to the stop after a check 72 * 73 * @param member 74 * Element to add 75 * @return true if added successfully, false otherwise. A false value 76 * indicates either that the OsmPrimitiveType of the given 77 * RelationMember does not match its role or that this PTStop 78 * already has an attribute with that role. 79 */ 80 protected boolean addStopElement(RelationMember member) { 81 82 // each element is only allowed once per stop 83 84 // add stop position: 85 // if (member.hasRole("stop") || member.hasRole("stop_entry_only") || 86 // member.hasRole("stop_exit_only")) { 87 if (member.getMember().hasTag("public_transport", "stop_position")) { 88 if (member.getType().equals(OsmPrimitiveType.NODE) && stopPosition == null) { 89 this.stopPosition = member.getNode(); 90 return true; 91 } 92 } 93 94 // add platform: 95 // if (member.getRole().equals("platform") || 96 // member.getRole().equals("platform_entry_only") 97 // || member.getRole().equals("platform_exit_only")) { 98 if (member.getMember().hasTag("highway", "bus_stop") 99 || member.getMember().hasTag("public_transport", "platform") 100 || member.getMember().hasTag("highway", "platform") 101 || member.getMember().hasTag("railway", "platform")) { 102 if (platform == null) { 103 platform = member.getMember(); 104 return true; 105 } 106 } 107 108 return false; 109 110 } 111 112 /** 113 * Returns the stop_position for this PTstop. If the stop_position is not 114 * available directly, the method searches for a stop_area relation 115 * 116 * @return the stop_position for this PTstop 117 */ 118 public Node getStopPosition() { 119 120 return this.stopPosition; 121 } 122 123 /** 124 * Returns platform (including platform_entry_only and platform_exit_only) 125 * 126 * @return platform (including platform_entry_only and platform_exit_only) 127 */ 128 public OsmPrimitive getPlatform() { 129 return this.platform; 130 } 131 132 /** 133 * Returns the name of this stop 134 * @return the name of this stop 135 */ 136 protected String getName() { 137 return this.name; 138 } 139 140 /** 141 * Sets the stop_position for this stop to the given node 142 * @param newStopPosition the stop_position for this stop to the given node 143 */ 144 public void setStopPosition(Node newStopPosition) { 145 146 this.stopPosition = newStopPosition; 147 148 } 149 150 /** 151 * Finds potential stop_positions of the platform of this PTStop. It only 152 * makes sense to call this method if the stop_position attribute is null. 153 * The stop_positions are potential because they may refer to a different 154 * route, which this method does not check. 155 * 156 * @return List of potential stop_positions for this PTStop 157 */ 158 public List<Node> findPotentialStopPositions() { 159 160 ArrayList<Node> potentialStopPositions = new ArrayList<>(); 161 162 if (platform == null) { 163 return potentialStopPositions; 164 } 165 166 // Look for a stop position within 0.002 degrees (around 100 m) of this 167 // platform: 168 169 LatLon platformCenter = platform.getBBox().getCenter(); 170 Double ax = platformCenter.getX() - 0.002; 171 Double bx = platformCenter.getX() + 0.002; 172 Double ay = platformCenter.getY() - 0.002; 173 Double by = platformCenter.getY() + 0.002; 174 BBox platformBBox = new BBox(ax, ay, bx, by); 175 176 Collection<Node> allNodes = platform.getDataSet().getNodes(); 177 for (Node currentNode : allNodes) { 178 if (platformBBox.bounds(currentNode.getBBox()) && currentNode.hasTag("public_transport", "stop_position")) { 179 potentialStopPositions.add(currentNode); 180 } 181 } 182 183 return potentialStopPositions; 184 } 185 186 /** 187 * Checks if this stop equals to other by comparing if they have the same 188 * stop_position or a platform 189 * 190 * @param other 191 * PTStop to be compared 192 * @return true if equal, false otherwise 193 */ 194 public boolean equalsStop(PTStop other) { 195 196 if (other == null) { 197 return false; 198 } 199 200 if (this.stopPosition != null 201 && (this.stopPosition == other.getStopPosition() || this.stopPosition == other.getPlatform())) { 202 return true; 203 } 204 205 if (this.platform != null 206 && (this.platform == other.getPlatform() || this.platform == other.getStopPosition())) { 207 return true; 208 } 209 210 return false; 211 } 211 212 212 213 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/data/PTWay.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 11 12 /** 12 13 * Representation of PTWays, which can be of OsmPrimitiveType Way or Relation 13 * 14 * 14 15 * @author darya 15 16 * … … 17 18 public class PTWay extends RelationMember { 18 19 19 20 21 22 23 24 private List<Way> ways = new ArrayList<Way>();20 /* 21 * Ways that belong to this PTWay. If the corresponding relation member is 22 * OsmPrimitiveType.WAY, this list size is 1. If the corresponding relation 23 * member is a nested relation, the list size is >= 1. 24 */ 25 private List<Way> ways = new ArrayList<>(); 25 26 26 27 * 28 29 30 31 32 33 34 27 /** 28 * 29 * @param other 30 * the corresponding RelationMember 31 * @throws IllegalArgumentException 32 * if the given relation member cannot be a PTWay due to its 33 * OsmPrimitiveType and/or role. 34 */ 35 public PTWay(RelationMember other) throws IllegalArgumentException { 35 36 36 37 super(other); 37 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 39 if (other.getType().equals(OsmPrimitiveType.WAY)) { 40 ways.add(other.getWay()); 41 } else if (other.getType().equals(OsmPrimitiveType.RELATION)) { 42 for (RelationMember rm : other.getRelation().getMembers()) { 43 if (rm.getType().equals(OsmPrimitiveType.WAY)) { 44 ways.add(rm.getWay()); 45 } else { 46 throw new IllegalArgumentException( 47 "A route relation member of OsmPrimitiveType.RELATION can only have ways as members"); 48 } 49 } 50 } else { 51 // the RelationMember other cannot be a OsmPrimitiveType.NODE 52 throw new IllegalArgumentException("A node cannot be used to model a public transport way"); 53 } 53 54 54 55 } 55 56 56 57 58 59 60 * 61 * @return 62 63 64 65 57 /** 58 * Returns the course of this PTWay. In most cases, this list only has 1 59 * element. In the case of nested relations in a route, the list can have 60 * multiple elements. 61 * 62 * @return the course of this PTWay 63 */ 64 public List<Way> getWays() { 65 return this.ways; 66 } 66 67 67 /** 68 * Determines if this PTWay is modeled by an OsmPrimitiveType.WAY 69 */ 70 public boolean isWay() { 71 if (this.getType().equals(OsmPrimitiveType.WAY)) { 72 return true; 73 } 74 return false; 75 } 68 /** 69 * Determines if this PTWay is modeled by an OsmPrimitiveType.WAY 70 */ 71 @Override 72 public boolean isWay() { 73 if (this.getType().equals(OsmPrimitiveType.WAY)) { 74 return true; 75 } 76 return false; 77 } 76 78 77 /** 78 * Determines if this PTWay is modeled by an OsmPrimitieType.RELATION (i.e. 79 * this is a nested relation) 80 */ 81 public boolean isRelation() { 82 if (this.getType().equals(OsmPrimitiveType.RELATION)) { 83 return true; 84 } 85 return false; 86 } 79 /** 80 * Determines if this PTWay is modeled by an OsmPrimitieType.RELATION (i.e. 81 * this is a nested relation) 82 */ 83 @Override 84 public boolean isRelation() { 85 if (this.getType().equals(OsmPrimitiveType.RELATION)) { 86 return true; 87 } 88 return false; 89 } 87 90 88 89 90 91 * 92 * @return 93 94 95 91 /** 92 * Returns the end nodes of this PTWay. If this PTWay is a nested relation, 93 * the order of the composing ways is assumed to be correct 94 * 95 * @return the end nodes of this PTWay 96 */ 97 public Node[] getEndNodes() { 98 Node[] endNodes = new Node[2]; 96 99 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 100 if (this.isWay()) { 101 endNodes[0] = this.getWay().firstNode(); 102 endNodes[1] = this.getWay().lastNode(); 103 // TODO: if this is a roundabout 104 } else { // nested relation: 105 Way firstWay = this.getWays().get(0); 106 Way secondWay = this.getWays().get(1); 107 Way prelastWay = this.getWays().get(this.getWays().size() - 2); 108 Way lastWay = this.getWays().get(this.getWays().size() - 1); 109 if (firstWay.firstNode() == secondWay.firstNode() || firstWay.firstNode() == secondWay.lastNode()) { 110 endNodes[0] = firstWay.lastNode(); 111 } else { 112 endNodes[0] = firstWay.firstNode(); 113 } 114 if (lastWay.firstNode() == prelastWay.firstNode() || lastWay.firstNode() == prelastWay.lastNode()) { 115 endNodes[1] = lastWay.lastNode(); 116 } else { 117 endNodes[1] = lastWay.firstNode(); 118 } 119 } 117 120 118 119 121 return endNodes; 122 } 120 123 121 122 123 124 * 125 * @return 126 127 124 /** 125 * Checks if this PTWay contains an unsplit roundabout (i.e. a way that 126 * touches itself) among its ways 127 * 128 * @return {@code true} if this PTWay contains an unsplit roundabout 129 */ 130 public boolean containsUnsplitRoundabout() { 128 131 129 130 131 132 133 134 135 136 132 List<Way> ways = this.getWays(); 133 for (Way way : ways) { 134 if (way.firstNode() == way.lastNode()) { 135 return true; 136 } 137 } 138 return false; 139 } 137 140 138 139 140 141 * 142 * @return 143 144 145 146 147 148 149 141 /** 142 * Checks if the first Way of this PTWay is an unsplit roundabout (i.e. a 143 * way that touches itself) 144 * 145 * @return {@code true} if the first Way of this PTWay is an unsplit roundabout 146 */ 147 public boolean startsWithUnsplitRoundabout() { 148 if (this.ways.get(0).firstNode() == this.ways.get(0).lastNode()) { 149 return true; 150 } 151 return false; 152 } 150 153 151 152 153 154 * 155 * @return 156 157 158 159 160 161 162 154 /** 155 * Checks if the last Way of this PTWay is an unsplit roundabout (i.e. a way 156 * that touches itself) 157 * 158 * @return {@code true} if the last Way of this PTWay is an unsplit roundabout 159 */ 160 public boolean endsWithUnsplitRoundabout() { 161 if (this.ways.get(this.ways.size() - 1).firstNode() == this.ways.get(this.ways.size() - 1).lastNode()) { 162 return true; 163 } 164 return false; 165 } 163 166 164 167 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/DownloadReferrersDialog.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 14 15 public class DownloadReferrersDialog extends JPanel { 15 16 16 private static final long serialVersionUID = 6112230984193215297L; 17 18 // indicates if the user needs to be asked before fetching incomplete 19 // members of a relation. 20 private enum ASK_TO_FETCH { 21 DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH 22 }; 17 private static final long serialVersionUID = 6112230984193215297L; 23 18 24 // by default, the user should be asked 25 private static ASK_TO_FETCH askToFetch = ASK_TO_FETCH.DO_ASK; 19 // indicates if the user needs to be asked before fetching incomplete 20 // members of a relation. 21 private enum ASK_TO_FETCH { 22 DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH 23 } 26 24 27 String message; 28 private JCheckBox checkbox; 29 private String[] options; 30 private int selectedOption; 25 // by default, the user should be asked 26 private static ASK_TO_FETCH askToFetch = ASK_TO_FETCH.DO_ASK; 31 27 32 public DownloadReferrersDialog() { 33 34 selectedOption = Integer.MIN_VALUE; 35 message = tr("Do you want to download referrers of platforms and stop positions?"); 36 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session")); 37 options = new String[2]; 38 options[0] = tr("Yes"); 39 options[1] = tr("No"); 28 String message; 29 private JCheckBox checkbox; 30 private String[] options; 31 private int selectedOption; 40 32 41 } 33 public DownloadReferrersDialog() { 42 34 43 /** 44 * Finds out whether the user wants to download referrers. In the 45 * default case, creates a JOptionPane to ask. 46 * 47 * @return JOptionPane.YES_OPTION if the referrers should be 48 * downloaded, JOptionPane.NO_OPTION otherwise. 49 */ 50 public int getUserSelection() { 35 selectedOption = Integer.MIN_VALUE; 36 message = tr("Do you want to download referrers of platforms and stop positions?"); 37 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session")); 38 options = new String[2]; 39 options[0] = tr("Yes"); 40 options[1] = tr("No"); 51 41 52 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) { 53 return JOptionPane.YES_OPTION; 54 } 42 } 55 43 56 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH) { 57 return JOptionPane.NO_OPTION; 58 } 44 /** 45 * Finds out whether the user wants to download referrers. In the 46 * default case, creates a JOptionPane to ask. 47 * 48 * @return JOptionPane.YES_OPTION if the referrers should be 49 * downloaded, JOptionPane.NO_OPTION otherwise. 50 */ 51 public int getUserSelection() { 59 52 60 61 Object[] params = {message, checkbox}; 62 selectedOption = JOptionPane.showOptionDialog(this, params, tr("PT_Assistant Fetch Request"), JOptionPane.YES_NO_OPTION, 63 JOptionPane.QUESTION_MESSAGE, null, options, 0); 64 65 if (checkbox.isSelected()) { 66 if (selectedOption == JOptionPane.YES_OPTION) { 67 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_FETCH; 68 } else { 69 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH; 70 } 71 } 53 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) { 54 return JOptionPane.YES_OPTION; 55 } 72 56 73 return selectedOption; 74 } 57 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH) { 58 return JOptionPane.NO_OPTION; 59 } 75 60 76 61 62 Object[] params = {message, checkbox}; 63 selectedOption = JOptionPane.showOptionDialog(this, params, tr("PT_Assistant Fetch Request"), JOptionPane.YES_NO_OPTION, 64 JOptionPane.QUESTION_MESSAGE, null, options, 0); 65 66 if (checkbox.isSelected()) { 67 if (selectedOption == JOptionPane.YES_OPTION) { 68 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_FETCH; 69 } else { 70 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH; 71 } 72 } 73 74 return selectedOption; 75 } 77 76 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/IncompleteMembersDownloadDialog.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 10 11 * Dialog that asks the user whether the incomplete relation members should be 11 12 * downloaded. 12 * 13 * 13 14 * @author darya 14 15 * … … 16 17 public class IncompleteMembersDownloadDialog extends JPanel { 17 18 18 19 private static final long serialVersionUID = -4275151182361040329L; 19 20 20 21 22 23 24 }; 21 // indicates if the user needs to be asked before fetching incomplete 22 // members of a relation. 23 public enum ASK_TO_FETCH { 24 DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH 25 } 25 26 26 27 27 // by default, the user should be asked 28 public static ASK_TO_FETCH askToFetch; 28 29 29 30 31 32 30 String message; 31 private JCheckBox checkbox; 32 private String[] options; 33 private int selectedOption; 33 34 34 35 public IncompleteMembersDownloadDialog() { 35 36 36 37 38 39 40 41 42 37 selectedOption = Integer.MIN_VALUE; 38 message = tr( 39 "Route relations have incomplete members.\nThey need to be downloaded to proceed with validation.\nDo you want to download them?"); 40 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session")); 41 options = new String[2]; 42 options[0] = tr("Yes"); 43 options[1] = tr("No"); 43 44 44 45 } 45 46 46 47 48 49 * 50 51 52 53 47 /** 48 * Finds out whether the user wants to download incomplete members. In the 49 * default case, creates a JOptionPane to ask. 50 * 51 * @return JOptionPane.YES_OPTION if the incomplete members should be 52 * downloaded, JOptionPane.NO_OPTION otherwise. 53 */ 54 public int getUserSelection() { 54 55 55 56 57 56 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) { 57 return JOptionPane.YES_OPTION; 58 } 58 59 59 60 61 60 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH) { 61 return JOptionPane.NO_OPTION; 62 } 62 63 63 Object[] params = { message, checkbox};64 65 64 Object[] params = {message, checkbox}; 65 selectedOption = JOptionPane.showOptionDialog(this, params, tr("PT_Assistant Fetch Request"), 66 JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0); 66 67 67 68 69 70 71 72 73 68 if (checkbox.isSelected()) { 69 if (selectedOption == JOptionPane.YES_OPTION) { 70 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_FETCH; 71 } else { 72 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH; 73 } 74 } 74 75 75 76 76 return selectedOption; 77 } 77 78 78 79 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayer.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 40 41 /** 41 42 * Layer that visualizes the routes in a more convenient way 42 * 43 * 43 44 * @author darya 44 45 * 45 46 */ 46 public class PTAssistantLayer extends Layer47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 * 72 * @param primitive 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 * 94 * @param fixVariants95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 * 129 * @param c 130 * @return 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 return new Action[] {LayerListDialog.getInstance().createShowHideLayerAction(),162 163 new RenameLayerAction(null, this), SeparatorLayerAction.INSTANCE, new LayerListPopup.InfoAction(this)};164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 * 252 * @paramrelation253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 47 public final class PTAssistantLayer extends Layer 48 implements SelectionChangedListener, PropertyChangeListener, LayerChangeListener { 49 50 private static PTAssistantLayer layer; 51 private List<OsmPrimitive> primitives = new ArrayList<>(); 52 private PTAssistantPaintVisitor paintVisitor; 53 private HashMap<Character, List<PTWay>> fixVariants = new HashMap<>(); 54 private HashMap<Way, List<Character>> wayColoring = new HashMap<>(); 55 56 private PTAssistantLayer() { 57 super("pt_assistant layer"); 58 KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(this); 59 Main.getLayerManager().addLayerChangeListener(this); 60 layer = this; 61 } 62 63 public static PTAssistantLayer getLayer() { 64 if (layer == null) { 65 new PTAssistantLayer(); 66 } 67 return layer; 68 } 69 70 /** 71 * Adds a primitive (route) to be displayed in this layer 72 * 73 * @param primitive primitive (route) 74 */ 75 public void addPrimitive(OsmPrimitive primitive) { 76 this.primitives.add(primitive); 77 } 78 79 /** 80 * Clears all primitives (routes) from being displayed. 81 */ 82 public void clear() { 83 this.primitives.clear(); 84 } 85 86 public void clearFixVariants() { 87 fixVariants.clear(); 88 wayColoring.clear(); 89 Main.map.mapView.repaint(); 90 } 91 92 /** 93 * Adds the first 5 fix variants to be displayed in the pt_assistant layer 94 * 95 * @param fixVariants fix variants 96 */ 97 public void addFixVariants(List<List<PTWay>> fixVariants) { 98 HashMap<List<PTWay>, Character> fixVariantLetterMap = new HashMap<>(); 99 100 char alphabet = 'A'; 101 for (int i = 0; i < 5 && i < fixVariants.size(); i++) { 102 List<PTWay> fixVariant = fixVariants.get(i); 103 this.fixVariants.put(alphabet, fixVariant); 104 fixVariantLetterMap.put(fixVariant, alphabet); 105 alphabet++; 106 } 107 108 for (Character currentFixVariantLetter : this.fixVariants.keySet()) { 109 List<PTWay> fixVariant = this.fixVariants.get(currentFixVariantLetter); 110 for (PTWay ptway : fixVariant) { 111 for (Way way : ptway.getWays()) { 112 if (wayColoring.containsKey(way)) { 113 if (!wayColoring.get(way).contains(currentFixVariantLetter)) { 114 wayColoring.get(way).add(currentFixVariantLetter); 115 } 116 } else { 117 List<Character> letterList = new ArrayList<>(); 118 letterList.add(currentFixVariantLetter); 119 wayColoring.put(way, letterList); 120 } 121 } 122 } 123 } 124 } 125 126 /** 127 * Returns fix variant (represented by a list of PTWays) that corresponds to 128 * the given character. 129 * 130 * @param c character 131 * @return fix variant 132 */ 133 public List<PTWay> getFixVariant(char c) { 134 return this.fixVariants.get(Character.toUpperCase(c)); 135 } 136 137 @Override 138 public void paint(final Graphics2D g, final MapView mv, Bounds bounds) { 139 140 paintVisitor = new PTAssistantPaintVisitor(g, mv); 141 142 for (OsmPrimitive primitive : primitives) { 143 paintVisitor.visit(primitive); 144 } 145 146 paintVisitor.visitFixVariants(this.fixVariants, this.wayColoring); 147 148 } 149 150 @Override 151 public Icon getIcon() { 152 return ImageProvider.get("layer", "osmdata_small"); 153 } 154 155 @Override 156 public Object getInfoComponent() { 157 return getToolTipText(); 158 } 159 160 @Override 161 public Action[] getMenuEntries() { 162 return new Action[] {LayerListDialog.getInstance().createShowHideLayerAction(), 163 LayerListDialog.getInstance().createDeleteLayerAction(), SeparatorLayerAction.INSTANCE, 164 new RenameLayerAction(null, this), SeparatorLayerAction.INSTANCE, new LayerListPopup.InfoAction(this)}; 165 } 166 167 @Override 168 public String getToolTipText() { 169 return "pt_assistant layer"; 170 } 171 172 @Override 173 public boolean isMergable(Layer arg0) { 174 return false; 175 } 176 177 @Override 178 public void mergeFrom(Layer arg0) { 179 // do nothing 180 181 } 182 183 @Override 184 public void visitBoundingBox(BoundingXYVisitor arg0) { 185 // do nothing 186 187 } 188 189 @Override 190 public LayerPositionStrategy getDefaultLayerPosition() { 191 return LayerPositionStrategy.IN_FRONT; 192 } 193 194 /** 195 * Listens to a selection change 196 */ 197 @Override 198 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 199 200 ArrayList<Relation> routes = new ArrayList<>(); 201 202 for (OsmPrimitive primitive : newSelection) { 203 if (primitive.getType().equals(OsmPrimitiveType.RELATION)) { 204 Relation relation = (Relation) primitive; 205 if (RouteUtils.isTwoDirectionRoute(relation)) { 206 routes.add(relation); 207 } 208 209 } 210 } 211 212 if (!routes.isEmpty()) { 213 this.primitives.clear(); 214 this.primitives.addAll(routes); 215 if (!Main.getLayerManager().containsLayer(this)) { 216 Main.getLayerManager().addLayer(this); 217 } 218 } 219 220 } 221 222 /** 223 * Listens to a focus change, sets the primitives attribute to the route 224 * relation in the top Relation Editor and repaints the map 225 */ 226 @Override 227 public void propertyChange(PropertyChangeEvent evt) { 228 229 if ("focusedWindow".equals(evt.getPropertyName())) { 230 231 if (evt.getNewValue() == null) { 232 return; 233 } 234 235 if (evt.getNewValue().getClass().equals(GenericRelationEditor.class)) { 236 237 GenericRelationEditor editor = (GenericRelationEditor) evt.getNewValue(); 238 Relation relation = editor.getRelation(); 239 240 if (RouteUtils.isTwoDirectionRoute(relation)) { 241 242 this.repaint(relation); 243 244 } 245 246 } 247 } 248 } 249 250 /** 251 * Repaints the layer in cases when there was no selection change 252 * 253 * @param relation relation 254 */ 255 public void repaint(Relation relation) { 256 this.primitives.clear(); 257 this.primitives.add(relation); 258 if (!Main.getLayerManager().containsLayer(this)) { 259 Main.getLayerManager().addLayer(this); 260 } 261 262 if (paintVisitor == null) { 263 Graphics g = Main.map.mapView.getGraphics(); 264 MapView mv = Main.map.mapView; 265 paintVisitor = new PTAssistantPaintVisitor(g, mv); 266 } 267 268 for (OsmPrimitive primitive : primitives) { 269 paintVisitor.visit(primitive); 270 } 271 272 paintVisitor.visitFixVariants(this.fixVariants, this.wayColoring); 273 274 Main.map.mapView.repaint(); 275 } 276 277 @Override 278 public void layerAdded(LayerAddEvent arg0) { 279 // do nothing 280 } 281 282 @Override 283 public void layerOrderChanged(LayerOrderChangeEvent arg0) { 284 // do nothing 285 286 } 287 288 @Override 289 public void layerRemoving(LayerRemoveEvent event) { 290 291 if (event.getRemovedLayer() instanceof OsmDataLayer) { 292 this.primitives.clear(); 293 this.fixVariants.clear(); 294 this.wayColoring.clear(); 295 Main.map.mapView.repaint(); 296 } 297 298 } 298 299 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPaintVisitor.java
r32895 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 27 28 /** 28 29 * Visits the primitives to be visualized in the pt_assistant layer 29 * 30 * 30 31 * @author darya 31 32 * … … 33 34 public class PTAssistantPaintVisitor extends PaintVisitor { 34 35 35 /** The graphics */ 36 private final Graphics g; 37 /** The MapView */ 38 private final MapView mv; 39 40 /** 41 * Constructor 42 * 43 * @param g 44 * @param mv 45 */ 46 public PTAssistantPaintVisitor(Graphics g, MapView mv) { 47 super(g, mv); 48 this.g = g; 49 this.mv = mv; 50 } 51 52 @Override 53 public void visit(Relation r) { 54 55 // first, draw primitives: 56 for (RelationMember rm : r.getMembers()) { 57 58 if (RouteUtils.isPTStop(rm)) { 59 60 drawStop(rm.getMember()); 61 62 } else if (RouteUtils.isPTWay(rm)) { 63 if (rm.isWay()) { 64 visit(rm.getWay()); 65 } else if (rm.isRelation()) { 66 visit(rm.getRelation()); 67 } else { 68 // if the relation has members that do not fit with the 69 // PT_Assistant data model, do nothing 70 } 71 } else { 72 // if the relation has members that do not fit with the 73 // PT_Assistant data model, do nothing 74 } 75 } 76 77 // in the end, draw labels: 78 HashMap<Long, String> stopOrderMap = new HashMap<>(); 79 int stopCount = 1; 80 81 for (RelationMember rm : r.getMembers()) { 82 if (RouteUtils.isPTStop(rm) || (rm.getMember().isIncomplete() && (rm.isNode() || rm.hasRole("stop") 83 || rm.hasRole("stop_entry_only") || rm.hasRole("stop_exit_only") || rm.hasRole("platform") 84 || rm.hasRole("platform_entry_only") || rm.hasRole("platform_exit_only")))) { 85 86 String label = ""; 87 88 if (stopOrderMap.containsKey(rm.getUniqueId())) { 89 label = stopOrderMap.get(rm.getUniqueId()); 90 label = label + ";" + stopCount; 91 } else { 92 if (r.hasKey("ref")) { 93 label = label + r.get("ref"); 94 } else if (r.hasKey("name")) { 95 label = label + r.get("name"); 96 } else { 97 label = "NA"; 98 } 99 label = label + " - " + stopCount; 100 } 101 102 stopOrderMap.put(rm.getUniqueId(), label); 103 try { 104 drawStopLabel(rm.getMember(), label); 105 } catch (NullPointerException ex) { 106 // do nothing 107 } 108 stopCount++; 109 } 110 } 111 112 } 113 114 @Override 115 public void visit(Way w) { 116 117 if (w == null) { 118 return; 119 } 120 121 /*- 122 * oneway values: 123 * 0 two-way street 124 * 1 oneway street in the way's direction 125 * 2 oneway street in ways's direction but public transport allowed 126 * -1 oneway street in reverse direction 127 * -2 oneway street in reverse direction but public transport allowed 128 */ 129 int oneway = 0; 130 131 if (w.hasTag("junction", "roundabout") || w.hasTag("highway", "motorway")) { 132 oneway = 1; 133 } else if (w.hasTag("oneway", "1") || w.hasTag("oneway", "yes") || w.hasTag("oneway", "true")) { 134 if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane") 135 || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane") 136 || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) { 137 oneway = 2; 138 } else { 139 oneway = 1; 140 } 141 } else if (w.hasTag("oneway", "-1") || w.hasTag("oneway", "reverse")) { 142 if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane") 143 || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane") 144 || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) { 145 oneway = -2; 146 } else { 147 oneway = -1; 148 } 149 } 150 151 visit(w.getNodes(), oneway); 152 153 } 154 155 /** 156 * Variation of the visit method that allows a special visualization of 157 * oneway roads 158 * 159 * @param nodes 160 * @param oneway 161 */ 162 public void visit(List<Node> nodes, int oneway) { 163 Node lastN = null; 164 for (Node n : nodes) { 165 if (lastN == null) { 166 lastN = n; 167 continue; 168 } 169 this.drawSegment(lastN, n, new Color(128, 0, 128, 100), oneway); 170 lastN = n; 171 } 172 } 173 174 /** 175 * Draw a small rectangle. White if selected (as always) or red otherwise. 176 * 177 * @param n 178 * The node to draw. 179 */ 180 @Override 181 public void visit(Node n) { 182 if (n.isDrawable() && isNodeVisible(n)) { 183 drawNode(n, Color.BLUE); 184 } 185 } 186 187 /** 188 * Draws a line around the segment 189 * 190 * @param n1 191 * The first node of segment 192 * @param n2 193 * The second node of segment 194 * @param color 195 * The color 196 */ 197 protected void drawSegment(Node n1, Node n2, Color color, int oneway) { 198 if (n1.isDrawable() && n2.isDrawable() && isSegmentVisible(n1, n2)) { 199 try { 200 drawSegment(mv.getPoint(n1), mv.getPoint(n2), color, oneway); 201 } catch (NullPointerException ex) { 202 // do nothing 203 } 204 205 } 206 } 207 208 /** 209 * Draws a line around the segment 210 * 211 * @param p1 212 * The first point of segment 213 * @param p2 214 * The second point of segment 215 * @param color 216 * The color 217 */ 218 protected void drawSegment(Point p1, Point p2, Color color, int oneway) { 219 220 double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y); 221 double cosT = 9 * Math.cos(t); 222 double sinT = 9 * Math.sin(t); 223 224 int[] xPoints = { (int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT) }; 225 int[] yPoints = { (int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT) }; 226 g.setColor(color); 227 g.fillPolygon(xPoints, yPoints, 4); 228 g.fillOval((int) (p1.x - 9), (int) (p1.y - 9), 18, 18); 229 g.fillOval((int) (p2.x - 9), (int) (p2.y - 9), 18, 18); 230 231 if (oneway != 0) { 232 double middleX = (double) (p1.x + p2.x) / 2.0; 233 double middleY = (double) (p1.y + p2.y) / 2.0; 234 double cosTriangle = 6 * Math.cos(t); 235 double sinTriangle = 6 * Math.sin(t); 236 g.setColor(Color.WHITE); 237 238 if (oneway > 0) { 239 int[] xFillTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 240 (int) (middleX + 2 * sinTriangle) }; 241 int[] yFillTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 242 (int) (middleY + 2 * cosTriangle) }; 243 g.fillPolygon(xFillTriangle, yFillTriangle, 3); 244 245 if (oneway == 2) { 246 int[] xDrawTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 247 (int) (middleX - 2 * sinTriangle) }; 248 int[] yDrawTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 249 (int) (middleY - 2 * cosTriangle) }; 250 g.drawPolygon(xDrawTriangle, yDrawTriangle, 3); 251 } 252 } 253 254 if (oneway < 0) { 255 int[] xFillTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 256 (int) (middleX - 2 * sinTriangle) }; 257 int[] yFillTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 258 (int) (middleY - 2 * cosTriangle) }; 259 g.fillPolygon(xFillTriangle, yFillTriangle, 3); 260 261 if (oneway == -2) { 262 int[] xDrawTriangle = { (int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 263 (int) (middleX + 2 * sinTriangle) }; 264 int[] yDrawTriangle = { (int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 265 (int) (middleY + 2 * cosTriangle) }; 266 g.drawPolygon(xDrawTriangle, yDrawTriangle, 3); 267 } 268 } 269 270 } 271 272 } 273 274 /** 275 * Draws a circle around the node 276 * 277 * @param n 278 * The node 279 * @param color 280 * The circle color 281 */ 282 protected void drawNode(Node n, Color color) { 283 284 Point p = mv.getPoint(n); 285 286 g.setColor(color); 287 g.drawOval(p.x - 5, p.y - 5, 10, 10); 288 289 } 290 291 /** 292 * Draws s stop_position as a blue circle; draws a platform as a blue square 293 * 294 * @param primitive 295 */ 296 protected void drawStop(OsmPrimitive primitive) { 297 298 // find the point to which the stop visualization will be linked: 299 Node n = new Node(primitive.getBBox().getCenter()); 300 301 Point p = mv.getPoint(n); 302 303 g.setColor(Color.BLUE); 304 305 if (primitive.hasTag("public_transport", "stop_position") && p != null) { 306 g.fillOval(p.x - 8, p.y - 8, 16, 16); 307 } else { 308 g.fillRect(p.x - 8, p.y - 8, 16, 16); 309 } 310 311 } 312 313 /** 314 * Draws the labels for the stops, which include the ordered position of the 315 * stop in the route and the ref numbers of other routes that use this stop 316 * 317 * @param primitive 318 * @param label 319 */ 320 protected void drawStopLabel(OsmPrimitive primitive, String label) { 321 322 // find the point to which the stop visualization will be linked: 323 Node n = new Node(primitive.getBBox().getCenter()); 324 325 Point p = mv.getPoint(n); 326 327 if (label != null && !label.equals("")) { 328 g.setColor(Color.WHITE); 329 Font stringFont = new Font("SansSerif", Font.PLAIN, 24); 330 g.setFont(stringFont); 331 g.drawString(label, p.x + 20, p.y - 20); 332 } 333 334 // draw the ref values of all parent routes: 335 List<String> parentsLabelList = new ArrayList<>(); 336 for (OsmPrimitive parent : primitive.getReferrers()) { 337 if (parent.getType().equals(OsmPrimitiveType.RELATION)) { 338 Relation relation = (Relation) parent; 339 if (RouteUtils.isTwoDirectionRoute(relation) && relation.get("ref") != null 340 && !relation.get("ref").equals("")) { 341 342 boolean stringFound = false; 343 for (String s : parentsLabelList) { 344 if (s.equals(relation.get("ref"))) { 345 stringFound = true; 346 } 347 } 348 if (!stringFound) { 349 parentsLabelList.add(relation.get("ref")); 350 } 351 352 } 353 } 354 } 355 356 Collections.sort(parentsLabelList, new RefTagComparator()); 357 358 String parentsLabel = ""; 359 for (String s : parentsLabelList) { 360 parentsLabel = parentsLabel + s + ";"; 361 } 362 363 if (!parentsLabel.equals("")) { 364 // remove the last semicolon: 365 parentsLabel = parentsLabel.substring(0, parentsLabel.length() - 1); 366 367 g.setColor(new Color(255, 20, 147)); 368 Font parentLabelFont = new Font("SansSerif", Font.ITALIC, 20); 369 g.setFont(parentLabelFont); 370 g.drawString(parentsLabel, p.x + 20, p.y + 20); 371 } 372 373 } 374 375 /** 376 * Compares route ref numbers 377 * @author darya 378 * 379 */ 380 private class RefTagComparator implements Comparator<String> { 381 382 @Override 383 public int compare(String s1, String s2) { 384 385 if (s1 == null || s1.equals("") || s2 == null || s2.equals("")) { 386 // if at least one of the strings is null or empty, there is no 387 // point in comparing: 388 return 0; 389 } 390 391 String[] splitString1 = s1.split("\\D"); 392 String[] splitString2 = s2.split("\\D"); 393 394 if (splitString1.length == 0 && splitString2.length != 0) { 395 // if the first ref does not start a digit and the second ref 396 // starts with a digit: 397 return 1; 398 } 399 400 if (splitString1.length != 0 && splitString2.length == 0) { 401 // if the first ref starts a digit and the second ref does not 402 // start with a digit: 403 return -1; 404 } 405 406 if (splitString1.length == 0 && splitString2.length == 0) { 407 // if both ref values do not start with a digit: 408 return s1.compareTo(s2); 409 } 410 411 String firstNumberString1 = splitString1[0]; 412 String firstNumberString2 = splitString2[0]; 413 414 try { 415 int firstNumber1 = Integer.valueOf(firstNumberString1); 416 int firstNumber2 = Integer.valueOf(firstNumberString2); 417 if (firstNumber1 > firstNumber2) { 418 return 1; 419 } else if (firstNumber1 < firstNumber2) { 420 return -1; 421 } else { 422 // if the first number is the same: 423 424 return s1.compareTo(s2); 425 426 } 427 } catch (NumberFormatException ex) { 428 return s1.compareTo(s2); 429 } 430 431 } 432 433 } 434 435 /** 436 * Visualizes the fix variants, assigns colors to them based on their order 437 * @param fixVariants 438 */ 439 protected void visitFixVariants(HashMap<Character, List<PTWay>> fixVariants, 440 HashMap<Way, List<Character>> wayColoring) { 441 442 drawFixVariantsWithParallelLines(wayColoring, fixVariants.size()); 443 444 Color[] colors = { new Color(255, 0, 0, 150), new Color(0, 255, 0, 150), new Color(0, 0, 255, 150), 445 new Color(255, 255, 0, 150), new Color(0, 255, 255, 150) }; 446 447 int colorIndex = 0; 448 449 double letterX = Main.map.mapView.getBounds().getMinX() + 20; 450 double letterY = Main.map.mapView.getBounds().getMinY() + 100; 451 452 for (Character c : fixVariants.keySet()) { 453 if (fixVariants.get(c) != null) { 454 // drawFixVariant(fixVariants.get(c), colors[colorIndex % 5]); 455 drawFixVariantLetter(c.toString(), colors[colorIndex % 5], letterX, letterY); 456 colorIndex++; 457 letterY = letterY + 60; 458 } 459 } 460 461 // display the "Esc" label: 462 if (!fixVariants.isEmpty()) { 463 drawFixVariantLetter("Esc", Color.WHITE, letterX, letterY); 464 } 465 } 466 467 /** 468 * 469 * @param fixVariant 470 * @param color 471 */ 472 @SuppressWarnings("unused") 473 private void drawFixVariant(List<PTWay> fixVariant, Color color) { 474 for (PTWay ptway : fixVariant) { 475 for (Way way : ptway.getWays()) { 476 for (Pair<Node, Node> nodePair : way.getNodePairs(false)) { 477 drawSegment(nodePair.a, nodePair.b, color, 0); 478 } 479 } 480 } 481 } 482 483 /** 484 * 485 * @param wayColoring 486 */ 487 protected void drawFixVariantsWithParallelLines(Map<Way, List<Character>> wayColoring, int numberOfFixVariants) { 488 489 HashMap<Character, Color> colors = new HashMap<>(); 490 colors.put('A', new Color(255, 0, 0, 200)); 491 colors.put('B', new Color(0, 255, 0, 200)); 492 colors.put('C', new Color(0, 0, 255, 200)); 493 colors.put('D', new Color(255, 255, 0, 200)); 494 colors.put('E', new Color(0, 255, 255, 200)); 495 496 for (Way way : wayColoring.keySet()) { 497 List<Character> letterList = wayColoring.get(way); 498 List<Color> wayColors = new ArrayList<>(); 499 for (Character letter : letterList) { 500 wayColors.add(colors.get(letter)); 501 } 502 for (Pair<Node, Node> nodePair : way.getNodePairs(false)) { 503 drawSegmentWithParallelLines(nodePair.a, nodePair.b, wayColors); 504 } 505 } 506 } 507 508 /** 509 * 510 * @param n1 511 * @param n2 512 * @param color 513 */ 514 protected void drawSegmentWithParallelLines(Node n1, Node n2, List<Color> colors) { 515 if (!n1.isDrawable() || !n2.isDrawable() || !isSegmentVisible(n1, n2)) { 516 return; 517 } 518 519 Point p1 = mv.getPoint(n1); 520 Point p2 = mv.getPoint(n2); 521 double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y); 522 double cosT = 9 * Math.cos(t); 523 double sinT = 9 * Math.sin(t); 524 double heightCosT = 9 * Math.cos(t); 525 double heightSinT = 9 * Math.sin(t); 526 527 double prevPointX = p1.x; 528 double prevPointY = p1.y; 529 double nextPointX = p1.x + heightSinT; 530 double nextPointY = p1.y + heightCosT; 531 532 Color currentColor = colors.get(0); 533 int i = 0; 534 g.setColor(currentColor); 535 g.fillOval((int) (p1.x - 9), (int) (p1.y - 9), 18, 18); 536 537 if (colors.size() == 1) { 538 int[] xPoints = { (int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT) }; 539 int[] yPoints = { (int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT) }; 540 g.setColor(currentColor); 541 g.fillPolygon(xPoints, yPoints, 4); 542 } else { 543 boolean iterate = true; 544 while (iterate) { 545 currentColor = colors.get(i % colors.size()); 546 547 int[] xPoints = { (int) (prevPointX + cosT), (int) (nextPointX + cosT), (int) (nextPointX - cosT), 548 (int) (prevPointX - cosT) }; 549 int[] yPoints = { (int) (prevPointY - sinT), (int) (nextPointY - sinT), (int) (nextPointY + sinT), 550 (int) (prevPointY + sinT) }; 551 g.setColor(currentColor); 552 g.fillPolygon(xPoints, yPoints, 4); 553 554 prevPointX = prevPointX + heightSinT; 555 prevPointY = prevPointY + heightCosT; 556 nextPointX = nextPointX + heightSinT; 557 nextPointY = nextPointY + heightCosT; 558 i++; 559 if ((p1.x < p2.x && nextPointX >= p2.x) || (p1.x >= p2.x && nextPointX <= p2.x)) { 560 iterate = false; 561 } 562 } 563 564 int[] lastXPoints = { (int) (prevPointX + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), 565 (int) (prevPointX - cosT) }; 566 int[] lastYPoints = { (int) (prevPointY - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), 567 (int) (prevPointY + sinT) }; 568 g.setColor(currentColor); 569 g.fillPolygon(lastXPoints, lastYPoints, 4); 570 } 571 572 g.setColor(currentColor); 573 g.fillOval((int) (p2.x - 9), (int) (p2.y - 9), 18, 18); 574 } 575 576 /** 577 * Visuallizes the letters for each fix variant 578 * @param letter 579 * @param color 580 * @param letterX 581 * @param letterY 582 */ 583 private void drawFixVariantLetter(String letter, Color color, double letterX, double letterY) { 584 g.setColor(color); 585 Font stringFont = new Font("SansSerif", Font.PLAIN, 50); 586 g.setFont(stringFont); 587 try { 588 g.drawString(letter, (int) letterX, (int) letterY); 589 g.drawString(letter, (int) letterX, (int) letterY); 590 } catch (NullPointerException ex) { 591 // do nothing 592 } 593 594 } 36 /** The graphics */ 37 private final Graphics g; 38 /** The MapView */ 39 private final MapView mv; 40 41 /** 42 * Constructor 43 * 44 * @param g graphics 45 * @param mv map view 46 */ 47 public PTAssistantPaintVisitor(Graphics g, MapView mv) { 48 super(g, mv); 49 this.g = g; 50 this.mv = mv; 51 } 52 53 @Override 54 public void visit(Relation r) { 55 56 // first, draw primitives: 57 for (RelationMember rm : r.getMembers()) { 58 59 if (RouteUtils.isPTStop(rm)) { 60 61 drawStop(rm.getMember()); 62 63 } else if (RouteUtils.isPTWay(rm)) { 64 if (rm.isWay()) { 65 visit(rm.getWay()); 66 } else if (rm.isRelation()) { 67 visit(rm.getRelation()); 68 } //else { 69 // if the relation has members that do not fit with the 70 // PT_Assistant data model, do nothing 71 //} 72 } //else { 73 // if the relation has members that do not fit with the 74 // PT_Assistant data model, do nothing 75 //} 76 } 77 78 // in the end, draw labels: 79 HashMap<Long, String> stopOrderMap = new HashMap<>(); 80 int stopCount = 1; 81 82 for (RelationMember rm : r.getMembers()) { 83 if (RouteUtils.isPTStop(rm) || (rm.getMember().isIncomplete() && (rm.isNode() || rm.hasRole("stop") 84 || rm.hasRole("stop_entry_only") || rm.hasRole("stop_exit_only") || rm.hasRole("platform") 85 || rm.hasRole("platform_entry_only") || rm.hasRole("platform_exit_only")))) { 86 87 String label = ""; 88 89 if (stopOrderMap.containsKey(rm.getUniqueId())) { 90 label = stopOrderMap.get(rm.getUniqueId()); 91 label = label + ";" + stopCount; 92 } else { 93 if (r.hasKey("ref")) { 94 label = label + r.get("ref"); 95 } else if (r.hasKey("name")) { 96 label = label + r.get("name"); 97 } else { 98 label = "NA"; 99 } 100 label = label + " - " + stopCount; 101 } 102 103 stopOrderMap.put(rm.getUniqueId(), label); 104 try { 105 drawStopLabel(rm.getMember(), label); 106 } catch (NullPointerException ex) { 107 // do nothing 108 Main.trace(ex); 109 } 110 stopCount++; 111 } 112 } 113 114 } 115 116 @Override 117 public void visit(Way w) { 118 119 if (w == null) { 120 return; 121 } 122 123 /*- 124 * oneway values: 125 * 0 two-way street 126 * 1 oneway street in the way's direction 127 * 2 oneway street in ways's direction but public transport allowed 128 * -1 oneway street in reverse direction 129 * -2 oneway street in reverse direction but public transport allowed 130 */ 131 int oneway = 0; 132 133 if (w.hasTag("junction", "roundabout") || w.hasTag("highway", "motorway")) { 134 oneway = 1; 135 } else if (w.hasTag("oneway", "1") || w.hasTag("oneway", "yes") || w.hasTag("oneway", "true")) { 136 if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane") 137 || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane") 138 || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) { 139 oneway = 2; 140 } else { 141 oneway = 1; 142 } 143 } else if (w.hasTag("oneway", "-1") || w.hasTag("oneway", "reverse")) { 144 if (w.hasTag("busway", "lane") || w.hasTag("busway:left", "lane") || w.hasTag("busway:right", "lane") 145 || w.hasTag("oneway:bus", "no") || w.hasTag("busway", "opposite_lane") 146 || w.hasTag("oneway:psv", "no") || w.hasTag("trolley_wire", "backward")) { 147 oneway = -2; 148 } else { 149 oneway = -1; 150 } 151 } 152 153 visit(w.getNodes(), oneway); 154 155 } 156 157 /** 158 * Variation of the visit method that allows a special visualization of 159 * oneway roads 160 * 161 * @param nodes nodes 162 * @param oneway oneway 163 */ 164 public void visit(List<Node> nodes, int oneway) { 165 Node lastN = null; 166 for (Node n : nodes) { 167 if (lastN == null) { 168 lastN = n; 169 continue; 170 } 171 this.drawSegment(lastN, n, new Color(128, 0, 128, 100), oneway); 172 lastN = n; 173 } 174 } 175 176 /** 177 * Draw a small rectangle. White if selected (as always) or red otherwise. 178 * 179 * @param n 180 * The node to draw. 181 */ 182 @Override 183 public void visit(Node n) { 184 if (n.isDrawable() && isNodeVisible(n)) { 185 drawNode(n, Color.BLUE); 186 } 187 } 188 189 /** 190 * Draws a line around the segment 191 * 192 * @param n1 193 * The first node of segment 194 * @param n2 195 * The second node of segment 196 * @param color 197 * The color 198 */ 199 protected void drawSegment(Node n1, Node n2, Color color, int oneway) { 200 if (n1.isDrawable() && n2.isDrawable() && isSegmentVisible(n1, n2)) { 201 try { 202 drawSegment(mv.getPoint(n1), mv.getPoint(n2), color, oneway); 203 } catch (NullPointerException ex) { 204 // do nothing 205 Main.trace(ex); 206 } 207 208 } 209 } 210 211 /** 212 * Draws a line around the segment 213 * 214 * @param p1 215 * The first point of segment 216 * @param p2 217 * The second point of segment 218 * @param color 219 * The color 220 */ 221 protected void drawSegment(Point p1, Point p2, Color color, int oneway) { 222 223 double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y); 224 double cosT = 9 * Math.cos(t); 225 double sinT = 9 * Math.sin(t); 226 227 int[] xPoints = {(int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT)}; 228 int[] yPoints = {(int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT)}; 229 g.setColor(color); 230 g.fillPolygon(xPoints, yPoints, 4); 231 g.fillOval(p1.x - 9, p1.y - 9, 18, 18); 232 g.fillOval(p2.x - 9, p2.y - 9, 18, 18); 233 234 if (oneway != 0) { 235 double middleX = (p1.x + p2.x) / 2.0; 236 double middleY = (p1.y + p2.y) / 2.0; 237 double cosTriangle = 6 * Math.cos(t); 238 double sinTriangle = 6 * Math.sin(t); 239 g.setColor(Color.WHITE); 240 241 if (oneway > 0) { 242 int[] xFillTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 243 (int) (middleX + 2 * sinTriangle)}; 244 int[] yFillTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 245 (int) (middleY + 2 * cosTriangle)}; 246 g.fillPolygon(xFillTriangle, yFillTriangle, 3); 247 248 if (oneway == 2) { 249 int[] xDrawTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 250 (int) (middleX - 2 * sinTriangle)}; 251 int[] yDrawTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 252 (int) (middleY - 2 * cosTriangle)}; 253 g.drawPolygon(xDrawTriangle, yDrawTriangle, 3); 254 } 255 } 256 257 if (oneway < 0) { 258 int[] xFillTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 259 (int) (middleX - 2 * sinTriangle)}; 260 int[] yFillTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 261 (int) (middleY - 2 * cosTriangle)}; 262 g.fillPolygon(xFillTriangle, yFillTriangle, 3); 263 264 if (oneway == -2) { 265 int[] xDrawTriangle = {(int) (middleX + cosTriangle), (int) (middleX - cosTriangle), 266 (int) (middleX + 2 * sinTriangle)}; 267 int[] yDrawTriangle = {(int) (middleY - sinTriangle), (int) (middleY + sinTriangle), 268 (int) (middleY + 2 * cosTriangle)}; 269 g.drawPolygon(xDrawTriangle, yDrawTriangle, 3); 270 } 271 } 272 273 } 274 275 } 276 277 /** 278 * Draws a circle around the node 279 * 280 * @param n 281 * The node 282 * @param color 283 * The circle color 284 */ 285 @Override 286 protected void drawNode(Node n, Color color) { 287 288 Point p = mv.getPoint(n); 289 290 g.setColor(color); 291 g.drawOval(p.x - 5, p.y - 5, 10, 10); 292 293 } 294 295 /** 296 * Draws s stop_position as a blue circle; draws a platform as a blue square 297 * 298 * @param primitive primitive 299 */ 300 protected void drawStop(OsmPrimitive primitive) { 301 302 // find the point to which the stop visualization will be linked: 303 Node n = new Node(primitive.getBBox().getCenter()); 304 305 Point p = mv.getPoint(n); 306 307 g.setColor(Color.BLUE); 308 309 if (primitive.hasTag("public_transport", "stop_position") && p != null) { 310 g.fillOval(p.x - 8, p.y - 8, 16, 16); 311 } else { 312 g.fillRect(p.x - 8, p.y - 8, 16, 16); 313 } 314 315 } 316 317 /** 318 * Draws the labels for the stops, which include the ordered position of the 319 * stop in the route and the ref numbers of other routes that use this stop 320 * 321 * @param primitive primitive 322 * @param label label 323 */ 324 protected void drawStopLabel(OsmPrimitive primitive, String label) { 325 326 // find the point to which the stop visualization will be linked: 327 Node n = new Node(primitive.getBBox().getCenter()); 328 329 Point p = mv.getPoint(n); 330 331 if (label != null && !label.equals("")) { 332 g.setColor(Color.WHITE); 333 Font stringFont = new Font("SansSerif", Font.PLAIN, 24); 334 g.setFont(stringFont); 335 g.drawString(label, p.x + 20, p.y - 20); 336 } 337 338 // draw the ref values of all parent routes: 339 List<String> parentsLabelList = new ArrayList<>(); 340 for (OsmPrimitive parent : primitive.getReferrers()) { 341 if (parent.getType().equals(OsmPrimitiveType.RELATION)) { 342 Relation relation = (Relation) parent; 343 if (RouteUtils.isTwoDirectionRoute(relation) && relation.get("ref") != null 344 && !relation.get("ref").equals("")) { 345 346 boolean stringFound = false; 347 for (String s : parentsLabelList) { 348 if (s.equals(relation.get("ref"))) { 349 stringFound = true; 350 } 351 } 352 if (!stringFound) { 353 parentsLabelList.add(relation.get("ref")); 354 } 355 356 } 357 } 358 } 359 360 Collections.sort(parentsLabelList, new RefTagComparator()); 361 362 String parentsLabel = ""; 363 for (String s : parentsLabelList) { 364 parentsLabel = parentsLabel + s + ";"; 365 } 366 367 if (!parentsLabel.equals("")) { 368 // remove the last semicolon: 369 parentsLabel = parentsLabel.substring(0, parentsLabel.length() - 1); 370 371 g.setColor(new Color(255, 20, 147)); 372 Font parentLabelFont = new Font("SansSerif", Font.ITALIC, 20); 373 g.setFont(parentLabelFont); 374 g.drawString(parentsLabel, p.x + 20, p.y + 20); 375 } 376 377 } 378 379 /** 380 * Compares route ref numbers 381 * @author darya 382 * 383 */ 384 private class RefTagComparator implements Comparator<String> { 385 386 @Override 387 public int compare(String s1, String s2) { 388 389 if (s1 == null || s1.equals("") || s2 == null || s2.equals("")) { 390 // if at least one of the strings is null or empty, there is no 391 // point in comparing: 392 return 0; 393 } 394 395 String[] splitString1 = s1.split("\\D"); 396 String[] splitString2 = s2.split("\\D"); 397 398 if (splitString1.length == 0 && splitString2.length != 0) { 399 // if the first ref does not start a digit and the second ref 400 // starts with a digit: 401 return 1; 402 } 403 404 if (splitString1.length != 0 && splitString2.length == 0) { 405 // if the first ref starts a digit and the second ref does not 406 // start with a digit: 407 return -1; 408 } 409 410 if (splitString1.length == 0 && splitString2.length == 0) { 411 // if both ref values do not start with a digit: 412 return s1.compareTo(s2); 413 } 414 415 String firstNumberString1 = splitString1[0]; 416 String firstNumberString2 = splitString2[0]; 417 418 try { 419 int firstNumber1 = Integer.valueOf(firstNumberString1); 420 int firstNumber2 = Integer.valueOf(firstNumberString2); 421 if (firstNumber1 > firstNumber2) { 422 return 1; 423 } else if (firstNumber1 < firstNumber2) { 424 return -1; 425 } else { 426 // if the first number is the same: 427 428 return s1.compareTo(s2); 429 430 } 431 } catch (NumberFormatException ex) { 432 return s1.compareTo(s2); 433 } 434 435 } 436 437 } 438 439 /** 440 * Visualizes the fix variants, assigns colors to them based on their order 441 * @param fixVariants fix variants 442 */ 443 protected void visitFixVariants(HashMap<Character, List<PTWay>> fixVariants, 444 HashMap<Way, List<Character>> wayColoring) { 445 446 drawFixVariantsWithParallelLines(wayColoring, fixVariants.size()); 447 448 Color[] colors = { 449 new Color(255, 0, 0, 150), 450 new Color(0, 255, 0, 150), 451 new Color(0, 0, 255, 150), 452 new Color(255, 255, 0, 150), 453 new Color(0, 255, 255, 150)}; 454 455 int colorIndex = 0; 456 457 double letterX = Main.map.mapView.getBounds().getMinX() + 20; 458 double letterY = Main.map.mapView.getBounds().getMinY() + 100; 459 460 for (Character c : fixVariants.keySet()) { 461 if (fixVariants.get(c) != null) { 462 // drawFixVariant(fixVariants.get(c), colors[colorIndex % 5]); 463 drawFixVariantLetter(c.toString(), colors[colorIndex % 5], letterX, letterY); 464 colorIndex++; 465 letterY = letterY + 60; 466 } 467 } 468 469 // display the "Esc" label: 470 if (!fixVariants.isEmpty()) { 471 drawFixVariantLetter("Esc", Color.WHITE, letterX, letterY); 472 } 473 } 474 475 @SuppressWarnings("unused") 476 private void drawFixVariant(List<PTWay> fixVariant, Color color) { 477 for (PTWay ptway : fixVariant) { 478 for (Way way : ptway.getWays()) { 479 for (Pair<Node, Node> nodePair : way.getNodePairs(false)) { 480 drawSegment(nodePair.a, nodePair.b, color, 0); 481 } 482 } 483 } 484 } 485 486 protected void drawFixVariantsWithParallelLines(Map<Way, List<Character>> wayColoring, int numberOfFixVariants) { 487 488 HashMap<Character, Color> colors = new HashMap<>(); 489 colors.put('A', new Color(255, 0, 0, 200)); 490 colors.put('B', new Color(0, 255, 0, 200)); 491 colors.put('C', new Color(0, 0, 255, 200)); 492 colors.put('D', new Color(255, 255, 0, 200)); 493 colors.put('E', new Color(0, 255, 255, 200)); 494 495 for (Way way : wayColoring.keySet()) { 496 List<Character> letterList = wayColoring.get(way); 497 List<Color> wayColors = new ArrayList<>(); 498 for (Character letter : letterList) { 499 wayColors.add(colors.get(letter)); 500 } 501 for (Pair<Node, Node> nodePair : way.getNodePairs(false)) { 502 drawSegmentWithParallelLines(nodePair.a, nodePair.b, wayColors); 503 } 504 } 505 } 506 507 protected void drawSegmentWithParallelLines(Node n1, Node n2, List<Color> colors) { 508 if (!n1.isDrawable() || !n2.isDrawable() || !isSegmentVisible(n1, n2)) { 509 return; 510 } 511 512 Point p1 = mv.getPoint(n1); 513 Point p2 = mv.getPoint(n2); 514 double t = Math.atan2((double) p2.x - p1.x, (double) p2.y - p1.y); 515 double cosT = 9 * Math.cos(t); 516 double sinT = 9 * Math.sin(t); 517 double heightCosT = 9 * Math.cos(t); 518 double heightSinT = 9 * Math.sin(t); 519 520 double prevPointX = p1.x; 521 double prevPointY = p1.y; 522 double nextPointX = p1.x + heightSinT; 523 double nextPointY = p1.y + heightCosT; 524 525 Color currentColor = colors.get(0); 526 int i = 0; 527 g.setColor(currentColor); 528 g.fillOval(p1.x - 9, p1.y - 9, 18, 18); 529 530 if (colors.size() == 1) { 531 int[] xPoints = {(int) (p1.x + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), (int) (p1.x - cosT)}; 532 int[] yPoints = {(int) (p1.y - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), (int) (p1.y + sinT)}; 533 g.setColor(currentColor); 534 g.fillPolygon(xPoints, yPoints, 4); 535 } else { 536 boolean iterate = true; 537 while (iterate) { 538 currentColor = colors.get(i % colors.size()); 539 540 int[] xPoints = {(int) (prevPointX + cosT), (int) (nextPointX + cosT), (int) (nextPointX - cosT), 541 (int) (prevPointX - cosT)}; 542 int[] yPoints = {(int) (prevPointY - sinT), (int) (nextPointY - sinT), (int) (nextPointY + sinT), 543 (int) (prevPointY + sinT)}; 544 g.setColor(currentColor); 545 g.fillPolygon(xPoints, yPoints, 4); 546 547 prevPointX = prevPointX + heightSinT; 548 prevPointY = prevPointY + heightCosT; 549 nextPointX = nextPointX + heightSinT; 550 nextPointY = nextPointY + heightCosT; 551 i++; 552 if ((p1.x < p2.x && nextPointX >= p2.x) || (p1.x >= p2.x && nextPointX <= p2.x)) { 553 iterate = false; 554 } 555 } 556 557 int[] lastXPoints = {(int) (prevPointX + cosT), (int) (p2.x + cosT), (int) (p2.x - cosT), 558 (int) (prevPointX - cosT)}; 559 int[] lastYPoints = {(int) (prevPointY - sinT), (int) (p2.y - sinT), (int) (p2.y + sinT), 560 (int) (prevPointY + sinT)}; 561 g.setColor(currentColor); 562 g.fillPolygon(lastXPoints, lastYPoints, 4); 563 } 564 565 g.setColor(currentColor); 566 g.fillOval(p2.x - 9, p2.y - 9, 18, 18); 567 } 568 569 /** 570 * Visuallizes the letters for each fix variant 571 * @param letter letter 572 * @param color color 573 * @param letterX letter X 574 * @param letterY letter Y 575 */ 576 private void drawFixVariantLetter(String letter, Color color, double letterX, double letterY) { 577 g.setColor(color); 578 Font stringFont = new Font("SansSerif", Font.PLAIN, 50); 579 g.setFont(stringFont); 580 try { 581 g.drawString(letter, (int) letterX, (int) letterY); 582 g.drawString(letter, (int) letterX, (int) letterY); 583 } catch (NullPointerException ex) { 584 // do nothing 585 Main.trace(ex); 586 } 587 588 } 595 589 596 590 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPreferenceSetting.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 21 22 public class PTAssistantPreferenceSetting implements SubPreferenceSetting { 22 23 23 private final JCheckBox downloadIncompleteMembers = new JCheckBox(I18n.tr("Download incomplete route relation members")); 24 private final JCheckBox stopArea = new JCheckBox(I18n.tr("Include stop_area tests")); 25 26 /** 27 * Setting up the pt_assistant preference tab 28 */ 29 @Override 30 public void addGui(PreferenceTabbedPane gui) { 24 private final JCheckBox downloadIncompleteMembers = new JCheckBox(I18n.tr("Download incomplete route relation members")); 25 private final JCheckBox stopArea = new JCheckBox(I18n.tr("Include stop_area tests")); 31 26 32 JPanel mainPanel = new JPanel(); 33 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 34 mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 20, 5, 5)); 35 36 mainPanel.add(downloadIncompleteMembers); 37 mainPanel.add(stopArea); 38 39 downloadIncompleteMembers.setSelected(Main.pref.getBoolean("pt_assistant.download-incomplete", false)); 40 stopArea.setSelected(Main.pref.getBoolean("pt_assistant.stop-area-tests", true)); 27 /** 28 * Setting up the pt_assistant preference tab 29 */ 30 @Override 31 public void addGui(PreferenceTabbedPane gui) { 41 32 42 synchronized (gui.getDisplayPreference().getTabPane()) { 43 gui.getValidatorPreference().addSubTab(this, "PT_Assistant", new JScrollPane(mainPanel)); 44 gui.getValidatorPreference().getTabPane().setIconAt(gui.getValidatorPreference().getTabPane().getTabCount() - 1, 45 new ImageProvider("presets/transport", "bus.svg").get()); 33 JPanel mainPanel = new JPanel(); 34 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 35 mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 20, 5, 5)); 46 36 47 } 37 mainPanel.add(downloadIncompleteMembers); 38 mainPanel.add(stopArea); 48 39 49 } 40 downloadIncompleteMembers.setSelected(Main.pref.getBoolean("pt_assistant.download-incomplete", false)); 41 stopArea.setSelected(Main.pref.getBoolean("pt_assistant.stop-area-tests", true)); 50 42 51 @Override 52 public boolean isExpert() { 53 return false; 54 } 43 synchronized (gui.getDisplayPreference().getTabPane()) { 44 gui.getValidatorPreference().addSubTab(this, "PT_Assistant", new JScrollPane(mainPanel)); 45 gui.getValidatorPreference().getTabPane().setIconAt(gui.getValidatorPreference().getTabPane().getTabCount() - 1, 46 new ImageProvider("presets/transport", "bus.svg").get()); 55 47 56 /** 57 * Action to be performed when the OK button is pressed 58 */ 59 @Override 60 public boolean ok() { 61 Main.pref.put("pt_assistant.download-incomplete", this.downloadIncompleteMembers.isSelected()); 62 Main.pref.put("pt_assistant.stop-area-tests", this.stopArea.isSelected()); 63 return false; 64 } 48 } 65 49 66 @Override 67 public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) { 68 return gui.getDisplayPreference(); 69 } 50 } 51 52 @Override 53 public boolean isExpert() { 54 return false; 55 } 56 57 /** 58 * Action to be performed when the OK button is pressed 59 */ 60 @Override 61 public boolean ok() { 62 Main.pref.put("pt_assistant.download-incomplete", this.downloadIncompleteMembers.isSelected()); 63 Main.pref.put("pt_assistant.stop-area-tests", this.stopArea.isSelected()); 64 return false; 65 } 66 67 @Override 68 public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) { 69 return gui.getDisplayPreference(); 70 } 70 71 71 72 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/gui/ProceedDialog.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.gui; 2 3 … … 19 20 * (i.e. if the errors found in the first stage of testing should be fixed 20 21 * before continuing with the testing). 21 * 22 * 22 23 * @author darya 23 24 * … … 25 26 public class ProceedDialog extends JPanel { 26 27 27 28 private static final long serialVersionUID = 2986537034076698693L; 28 29 29 30 31 }; 30 public enum ASK_TO_PROCEED { 31 DO_ASK, DONT_ASK_AND_FIX_AUTOMATICALLY, DONT_ASK_AND_FIX_MANUALLY, DONT_ASK_AND_DONT_FIX 32 } 32 33 33 34 34 // by default, the user should be asked 35 public static ASK_TO_PROCEED askToProceed; 35 36 36 37 38 39 40 41 42 37 private JRadioButton radioButtonFixAutomatically; 38 private JRadioButton radioButtonFixManually; 39 private JRadioButton radioButtonDontFix; 40 private JCheckBox checkbox; 41 private String[] options; 42 private JPanel panel; 43 private int selectedOption; 43 44 44 45 public ProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 45 46 46 47 47 panel = new JPanel(); 48 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 48 49 49 50 51 50 JLabel label1 = new JLabel(tr("PT_Assistant plugin found that this relation (id={0}) has errors:", id)); 51 panel.add(label1); 52 label1.setAlignmentX(Component.LEFT_ALIGNMENT); 52 53 53 54 55 56 57 58 54 if (true) { 55 JLabel label2 = new JLabel(" " + trn("{0} direction error", "{0} direction errors", 56 numberOfDirectionErrors, numberOfDirectionErrors)); 57 panel.add(label2); 58 label2.setAlignmentX(Component.LEFT_ALIGNMENT); 59 } 59 60 60 61 62 63 64 65 61 if (numberOfRoadTypeErrors != 0) { 62 JLabel label3 = new JLabel(" " + trn("{0} road type error", "{0} road type errors", 63 numberOfRoadTypeErrors, numberOfRoadTypeErrors)); 64 panel.add(label3); 65 label3.setAlignmentX(Component.LEFT_ALIGNMENT); 66 } 66 67 67 68 69 68 JLabel label4 = new JLabel(tr("How do you want to proceed?")); 69 panel.add(label4); 70 label4.setAlignmentX(Component.LEFT_ALIGNMENT); 70 71 71 72 73 74 75 76 77 78 79 80 81 82 83 72 radioButtonFixAutomatically = new JRadioButton("Fix all errors automatically and proceed"); 73 radioButtonFixManually = new JRadioButton("I will fix the errors manually and click the button to proceed"); 74 radioButtonDontFix = new JRadioButton("Do not fix anything and proceed with further tests", true); 75 ButtonGroup fixOptionButtonGroup = new ButtonGroup(); 76 fixOptionButtonGroup.add(radioButtonFixAutomatically); 77 fixOptionButtonGroup.add(radioButtonFixManually); 78 fixOptionButtonGroup.add(radioButtonDontFix); 79 panel.add(radioButtonFixAutomatically); 80 // panel.add(radioButtonFixManually); 81 panel.add(radioButtonDontFix); 82 radioButtonFixAutomatically.setAlignmentX(Component.LEFT_ALIGNMENT); 83 radioButtonFixManually.setAlignmentX(Component.LEFT_ALIGNMENT); 84 radioButtonDontFix.setAlignmentX(Component.LEFT_ALIGNMENT); 84 85 85 86 87 86 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session")); 87 panel.add(checkbox); 88 checkbox.setAlignmentX(Component.LEFT_ALIGNMENT); 88 89 89 90 91 90 options = new String[2]; 91 options[0] = "OK"; 92 options[1] = "Cancel & stop testing"; 92 93 93 94 selectedOption = Integer.MIN_VALUE; 94 95 95 96 } 96 97 97 98 99 100 * 101 102 103 * 104 105 98 /** 99 * Finds out whether the user wants to download incomplete members. In the 100 * default case, creates a JOptionPane to ask. 101 * 102 * @return 0 to fix automatically, 1 to fix manually, 2 to proceed without 103 * fixing, -1 to stop testing or if dialog is closed without answer 104 * 105 */ 106 public int getUserSelection() { 106 107 107 108 109 110 111 112 113 114 115 108 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_FIX_AUTOMATICALLY) { 109 return 0; 110 } 111 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_FIX_MANUALLY) { 112 return 1; 113 } 114 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_DONT_FIX) { 115 return 2; 116 } 116 117 117 118 119 118 // showDialog(); FIXME 119 selectedOption = JOptionPane.showOptionDialog(this, panel, tr("PT_Assistant Proceed Request"), 120 JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0); 120 121 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 122 if (selectedOption == 0) { 123 if (radioButtonFixAutomatically.isSelected()) { 124 if (checkbox.isSelected()) { 125 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_FIX_AUTOMATICALLY; 126 } 127 return 0; 128 } 129 if (radioButtonFixManually.isSelected()) { 130 if (checkbox.isSelected()) { 131 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_FIX_MANUALLY; 132 } 133 return 1; 134 } 135 if (radioButtonDontFix.isSelected()) { 136 if (checkbox.isSelected()) { 137 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_DONT_FIX; 138 } 139 return 2; 140 } 141 } 141 142 142 143 143 return -1; 144 } 144 145 145 146 * 147 148 149 146 /** 147 * 148 */ 149 @SuppressWarnings("unused") 150 private void showDialog() { 150 151 151 152 153 154 152 if (!SwingUtilities.isEventDispatchThread()) { 153 selectedOption = JOptionPane.showOptionDialog(this, panel, tr("PT_Assistant Proceed Request"), 154 JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0); 155 } else { 155 156 156 157 158 159 160 161 157 SwingUtilities.invokeLater(new Runnable() { 158 @Override 159 public void run() { 160 showDialog(); 161 } 162 }); 162 163 163 164 } 164 165 165 166 } 166 167 167 168 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/utils/RouteUtils.java
r32895 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.utils; 2 3 … … 12 13 /** 13 14 * Utils class for routes 14 * 15 * 15 16 * @author darya 16 17 * 17 18 */ 18 public class RouteUtils {19 20 21 22 23 24 25 26 27 * 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 * 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 * 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 * 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 * 150 * @param w1 151 * @param w2 152 * @return 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 * 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 * 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 * @paramway230 * @return 231 232 233 234 235 236 237 238 239 240 241 242 19 public final class RouteUtils { 20 21 private RouteUtils() { 22 // private constructor for util classes 23 } 24 25 /** 26 * Checks if the relation is a route of one of the following categories: 27 * bus, trolleybus, share_taxi, tram, light_rail, subway, train. 28 * 29 * @param r 30 * Relation to be checked 31 * @return true if the route belongs to the categories that can be validated 32 * with the pt_assistant plugin, false otherwise. 33 */ 34 public static boolean isTwoDirectionRoute(Relation r) { 35 36 if (r == null) { 37 return false; 38 } 39 40 if (!r.hasKey("route") || !r.hasTag("public_transport:version", "2")) { 41 return false; 42 } 43 if (r.hasTag("route", "bus") || r.hasTag("route", "trolleybus") || r.hasTag("route", "share_taxi") 44 || r.hasTag("route", "tram") || r.hasTag("route", "light_rail") || r.hasTag("route", "subway") 45 || r.hasTag("route", "train")) { 46 47 if (!r.hasTag("bus", "on_demand")) { 48 return true; 49 } 50 51 } 52 return false; 53 } 54 55 /** 56 * Checks if the relation member refers to a stop in a public transport 57 * route. Some stops can be modeled with ways. 58 * 59 * @param rm 60 * relation member to be checked 61 * @return true if the relation member refers to a stop, false otherwise 62 */ 63 public static boolean isPTStop(RelationMember rm) { 64 65 66 if (rm.getType().equals(OsmPrimitiveType.NODE)) { 67 return true; 68 } 69 70 if (rm.getType().equals(OsmPrimitiveType.WAY)) { 71 if (rm.getWay().hasTag("public_transport", "platform") || rm.getWay().hasTag("highway", "platform") 72 || rm.getWay().hasTag("railway", "platform")) { 73 return true; 74 } 75 } 76 77 return false; 78 79 } 80 81 /** 82 * Checks if the relation member refers to a way in a public transport 83 * route. Some OsmPrimitiveType.WAY have to be excluded because platforms 84 * can be modeled with ways. 85 * 86 * @param rm 87 * relation member to be checked 88 * @return true if the relation member refers to a way in a public transport 89 * route, false otherwise. 90 */ 91 public static boolean isPTWay(RelationMember rm) { 92 93 if (rm.getType().equals(OsmPrimitiveType.NODE)) { 94 return false; 95 } 96 97 if (rm.getType().equals(OsmPrimitiveType.WAY)) { 98 if (rm.getWay().hasTag("public_transport", "platform") || rm.getWay().hasTag("highway", "platform") 99 || rm.getWay().hasTag("railway", "platform")) { 100 return false; 101 } 102 return true; 103 } 104 105 Relation nestedRelation = rm.getRelation(); 106 107 for (RelationMember nestedRelationMember : nestedRelation.getMembers()) { 108 if (!nestedRelationMember.getType().equals(OsmPrimitiveType.WAY)) { 109 return false; 110 } 111 } 112 113 return true; 114 } 115 116 /** 117 * Checks if the given way has tags that make it oneway for public 118 * transport. The test does not check whether the way violates those 119 * restrictions. 120 * 121 * @return 0 if the way is not oneway for public transport, 1 if the way is 122 * oneway for public transport, -1 if the way is reversely oneway 123 * for public transport 124 */ 125 public static int isOnewayForPublicTransport(Way way) { 126 127 if (OsmUtils.isTrue(way.get("oneway")) || OsmUtils.isReversed(way.get("oneway")) 128 || way.hasTag("junction", "roundabout") || way.hasTag("highway", "motorway")) { 129 130 if (!way.hasTag("busway", "lane") && !way.hasTag("busway:left", "lane") 131 && !way.hasTag("busway:right", "lane") && !way.hasTag("oneway:bus", "no") 132 && !way.hasTag("busway", "opposite_lane") && !way.hasTag("oneway:psv", "no") 133 && !way.hasTag("trolley_wire", "backward")) { 134 135 if (OsmUtils.isReversed(way.get("oneway"))) { 136 return -1; 137 } 138 139 return 1; 140 141 } 142 143 } 144 145 return 0; 146 } 147 148 /** 149 * Checks if the ways have a common node 150 * 151 * @param w1 first way 152 * @param w2 second way 153 * @return {@code true} if the ways have a common node 154 */ 155 public static boolean waysTouch(Way w1, Way w2) { 156 157 if (w1 == null || w2 == null) { 158 return false; 159 } 160 161 Node w1FirstNode = w1.firstNode(); 162 Node w1LastNode = w1.lastNode(); 163 Node w2FirstNode = w2.firstNode(); 164 Node w2LastNode = w2.lastNode(); 165 166 if (w1FirstNode == w2FirstNode || w1FirstNode == w2LastNode || w1LastNode == w2FirstNode 167 || w1LastNode == w2LastNode) { 168 return true; 169 } 170 171 return false; 172 } 173 174 /** 175 * Checks if any way from the first collection touches any way from the 176 * second collection 177 * 178 * @param c1 first collection 179 * @param c2 second collection 180 * @return true if ways touch, false otherwise 181 */ 182 public static boolean waysTouch(Collection<Way> c1, Collection<Way> c2) { 183 184 if (c1 == null || c2 == null) { 185 return false; 186 } 187 188 for (Way w1 : c1) { 189 for (Way w2 : c2) { 190 if (waysTouch(w1, w2)) { 191 return true; 192 } 193 } 194 } 195 196 return false; 197 } 198 199 /** 200 * Checks if the type of the way is suitable for buses to go on it. The 201 * direction of the way (i.e. one-way roads) is irrelevant for this test. 202 * 203 * @param way 204 * to be checked 205 * @return true if the way is suitable for buses, false otherwise. 206 */ 207 public static boolean isWaySuitableForBuses(Way way) { 208 if (way.hasTag("highway", "motorway") || way.hasTag("highway", "trunk") || way.hasTag("highway", "primary") 209 || way.hasTag("highway", "secondary") || way.hasTag("highway", "tertiary") 210 || way.hasTag("highway", "unclassified") || way.hasTag("highway", "road") 211 || way.hasTag("highway", "residential") || way.hasTag("highway", "service") 212 || way.hasTag("highway", "motorway_link") || way.hasTag("highway", "trunk_link") 213 || way.hasTag("highway", "primary_link") || way.hasTag("highway", "secondary_link") 214 || way.hasTag("highway", "tertiary_link") || way.hasTag("highway", "living_street") 215 || way.hasTag("highway", "bus_guideway") || way.hasTag("highway", "road") 216 || way.hasTag("cycleway", "share_busway") || way.hasTag("cycleway", "shared_lane")) { 217 return true; 218 } 219 220 if (way.hasTag("highway", "pedestrian") && (way.hasTag("bus", "yes") || way.hasTag("psv", "yes") 221 || way.hasTag("bus", "designated") || way.hasTag("psv", "designated"))) { 222 return true; 223 } 224 225 return false; 226 } 227 228 /** 229 * Checks if this way is suitable for public transport (not only for buses) 230 * @param way way 231 * @return {@code true} if this way is suitable for public transport 232 */ 233 public static boolean isWaySuitableForPublicTransport(Way way) { 234 235 if (isWaySuitableForBuses(way) || way.hasTag("railway", "tram") || way.hasTag("railway", "subway") 236 || way.hasTag("railway", "subway") || way.hasTag("railway", "light_rail") 237 || way.hasTag("railway", "rail")) { 238 return true; 239 } 240 241 return false; 242 243 } 243 244 244 245 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/utils/StopToWayAssigner.java
r32793 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.utils; 2 3 … … 24 25 * list of already assigned stops, (2) checks if the stop has a stop position, 25 26 * (3) calculates it using proximity / growing bounding boxes 26 * 27 * 27 28 * @author darya 28 29 * … … 30 31 public class StopToWayAssigner { 31 32 32 /* contains assigned stops */ 33 public static HashMap<PTStop, List<Way>> stopToWay = new HashMap<>(); 34 35 /* 36 * contains all PTWays of the route relation for which this assigner was 37 * created 38 */ 39 private HashSet<Way> ways; 40 41 /* route relation for which this StopToWayAssigner was created */ 42 43 public StopToWayAssigner(List<PTWay> ptways) { 44 ways = new HashSet<Way>(); 45 for (PTWay ptway : ptways) { 46 ways.addAll(ptway.getWays()); 47 } 48 } 49 50 /** 51 * Returns the PTWay for the given PTStop 52 * 53 * @param stop 54 * @return 55 */ 56 public Way get(PTStop stop) { 57 58 // 1) Search if this stop has already been assigned: 59 if (stopToWay.containsKey(stop)) { 60 List<Way> assignedWays = stopToWay.get(stop); 61 for (Way assignedWay : assignedWays) { 62 if (this.ways.contains(assignedWay)) { 63 return assignedWay; 64 } 65 } 66 } 67 68 // 2) Search if the stop has a stop position: 69 Way wayOfStopPosition = findWayForNode(stop.getStopPosition()); 70 if (wayOfStopPosition != null) { 71 addAssignedWayToMap(stop, wayOfStopPosition); 72 return wayOfStopPosition; 73 } 74 75 // 3) Search if the stop has a stop_area: 76 List<OsmPrimitive> stopElements = new ArrayList<>(2); 77 if (stop.getStopPosition() != null) { 78 stopElements.add(stop.getStopPosition()); 79 } 80 if (stop.getPlatform() != null) { 81 stopElements.add(stop.getPlatform()); 82 } 83 Set<Relation> parents = Node.getParentRelations(stopElements); 84 for (Relation parentRelation : parents) { 85 if (parentRelation.hasTag("public_transport", "stop_area")) { 86 for (RelationMember rm : parentRelation.getMembers()) { 87 if (rm.getMember().hasTag("public_transport", "stop_position")) { 88 Way rmWay = this.findWayForNode(rm.getNode()); 89 if (rmWay != null) { 90 addAssignedWayToMap(stop, rmWay); 91 return rmWay; 92 } 93 } 94 } 95 } 96 } 97 98 // 4) Search if a stop position is in the vicinity of a platform: 99 if (stop.getPlatform() != null) { 100 List<Node> potentialStopPositionList = stop.findPotentialStopPositions(); 101 Node closestStopPosition = null; 102 double minDistanceSq = Double.MAX_VALUE; 103 for (Node potentialStopPosition : potentialStopPositionList) { 104 double distanceSq = potentialStopPosition.getCoor() 105 .distanceSq(stop.getPlatform().getBBox().getCenter()); 106 if (distanceSq < minDistanceSq) { 107 closestStopPosition = potentialStopPosition; 108 minDistanceSq = distanceSq; 109 } 110 } 111 if (closestStopPosition != null) { 112 Way closestWay = null; 113 double minDistanceSqToWay = Double.MAX_VALUE; 114 for (Way way: this.ways) { 115 if (way.containsNode(closestStopPosition)) { 116 double distanceSq = calculateMinDistanceToSegment(new Node(stop.getPlatform().getBBox().getCenter()), way); 117 if (distanceSq < minDistanceSqToWay) { 118 closestWay = way; 119 minDistanceSqToWay = distanceSq; 120 } 121 } 122 } 123 if (closestWay != null) { 124 addAssignedWayToMap(stop, closestWay); 125 return closestWay; 126 } 127 } 128 } 129 130 // 5) Run the growing-bounding-boxes algorithm: 131 double searchRadius = 0.001; 132 while (searchRadius < 0.005) { 133 134 Way foundWay = this.findNearestWayInRadius(stop.getPlatform(), searchRadius); 135 if (foundWay != null) { 136 addAssignedWayToMap(stop, foundWay); 137 return foundWay; 138 } 139 140 foundWay = this.findNearestWayInRadius(stop.getStopPosition(), searchRadius); 141 if (foundWay != null) { 142 addAssignedWayToMap(stop, foundWay); 143 return foundWay; 144 } 145 146 searchRadius = searchRadius + 0.001; 147 } 148 149 return null; 150 } 151 152 /** 153 * Finds the PTWay of the given stop_position by looking at its referrers 154 * 155 * @param stopPosition 156 * @return 157 */ 158 private Way findWayForNode(Node stopPosition) { 159 160 if (stopPosition == null) { 161 return null; 162 } 163 164 // search in the referrers: 165 List<OsmPrimitive> referrers = stopPosition.getReferrers(); 166 for (OsmPrimitive referredPrimitive : referrers) { 167 if (referredPrimitive.getType().equals(OsmPrimitiveType.WAY)) { 168 Way referredWay = (Way) referredPrimitive; 169 if (this.ways.contains(referredWay)) { 170 return referredWay; 171 } 172 } 173 } 174 175 return null; 176 } 177 178 /** 179 * Finds the PTWay in the given radius of the OsmPrimitive. The PTWay has to 180 * belong to the route relation for which this StopToWayAssigner was 181 * created. If multiple PTWays were found, the closest one is chosen. 182 * 183 * @param platform 184 * @param searchRadius 185 * @return 186 */ 187 private Way findNearestWayInRadius(OsmPrimitive platform, double searchRadius) { 188 189 if (platform == null) { 190 return null; 191 } 192 193 LatLon platformCenter = platform.getBBox().getCenter(); 194 Double ax = platformCenter.getX() - searchRadius; 195 Double bx = platformCenter.getX() + searchRadius; 196 Double ay = platformCenter.getY() - searchRadius; 197 Double by = platformCenter.getY() + searchRadius; 198 BBox platformBBox = new BBox(ax, ay, bx, by); 199 200 Set<Way> potentialWays = new HashSet<>(); 201 202 Collection<Node> allNodes = platform.getDataSet().getNodes(); 203 for (Node currentNode : allNodes) { 204 if (platformBBox.bounds(currentNode.getBBox())) { 205 List<OsmPrimitive> referrers = currentNode.getReferrers(); 206 for (OsmPrimitive referrer : referrers) { 207 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 208 Way referrerWay = (Way) referrer; 209 if (this.ways.contains(referrerWay)) { 210 potentialWays.add(referrerWay); 211 } 212 } 213 } 214 215 } 216 } 217 218 Node platformNode = null; 219 if (platform.getType().equals(OsmPrimitiveType.NODE)) { 220 platformNode = (Node) platform; 221 } else { 222 platformNode = new Node(platform.getBBox().getCenter()); 223 } 224 Way nearestWay = null; 225 Double minDistance = Double.MAX_VALUE; 226 for (Way potentialWay : potentialWays) { 227 double distance = this.calculateMinDistanceToSegment(platformNode, potentialWay); 228 if (distance < minDistance) { 229 minDistance = distance; 230 nearestWay = potentialWay; 231 } 232 } 233 234 return nearestWay; 235 } 236 237 /** 238 * Calculates the minimum distance between a node and a way 239 * 240 * @param node 241 * @param way 242 * @return 243 */ 244 private double calculateMinDistanceToSegment(Node node, Way way) { 245 246 double minDistance = Double.MAX_VALUE; 247 248 List<Pair<Node, Node>> waySegments = way.getNodePairs(false); 249 250 for (Pair<Node, Node> waySegment : waySegments) { 251 if (waySegment.a != node && waySegment.b != node) { 252 double distanceToLine = this.calculateDistanceToSegment(node, waySegment); 253 if (distanceToLine < minDistance) { 254 minDistance = distanceToLine; 255 } 256 } 257 } 258 259 return minDistance; 260 261 } 262 263 /** 264 * Calculates the distance from point to segment and differentiates between 265 * acute, right and obtuse triangles. If a triangle is acute or right, the 266 * distance to segment is calculated as distance from point to line. If the 267 * triangle is obtuse, the distance is calculated as the distance to the 268 * nearest vertex of the segment. 269 * 270 * @param node 271 * @param segment 272 * @return 273 */ 274 private double calculateDistanceToSegment(Node node, Pair<Node, Node> segment) { 275 276 if (node == segment.a || node == segment.b) { 277 return 0.0; 278 } 279 280 double lengthA = node.getCoor().distance(segment.a.getCoor()); 281 double lengthB = node.getCoor().distance(segment.b.getCoor()); 282 double lengthC = segment.a.getCoor().distance(segment.b.getCoor()); 283 284 if (isObtuse(lengthC, lengthB, lengthA)) { 285 return lengthB; 286 } 287 288 if (isObtuse(lengthA, lengthC, lengthB)) { 289 return lengthA; 290 } 291 292 return calculateDistanceToLine(node, segment); 293 } 294 295 /** 296 * Calculates the distance from point to line using formulas for triangle 297 * area. Does not differentiate between acute, right and obtuse triangles 298 * 299 * @param node 300 * @param waySegment 301 * @return 302 */ 303 private double calculateDistanceToLine(Node node, Pair<Node, Node> segment) { 304 305 /* 306 * Let a be the triangle edge between the point and the first node of 307 * the segment. Let b be the triangle edge between the point and the 308 * second node of the segment. Let c be the triangle edge which is the 309 * segment. 310 */ 311 312 double lengthA = node.getCoor().distance(segment.a.getCoor()); 313 double lengthB = node.getCoor().distance(segment.b.getCoor()); 314 double lengthC = segment.a.getCoor().distance(segment.b.getCoor()); 315 316 // calculate triangle area using Heron's formula: 317 double p = (lengthA + lengthB + lengthC) / 2.0; 318 double triangleArea = Math.sqrt(p * (p - lengthA) * (p - lengthB) * (p - lengthC)); 319 320 // calculate the distance from point to segment using the 0.5*c*h 321 // formula for triangle area: 322 return triangleArea * 2.0 / lengthC; 323 } 324 325 /** 326 * Checks if the angle opposite of the edge c is obtuse. Uses the cosine 327 * theorem 328 * 329 * @param lengthA 330 * @param lengthB 331 * @param lengthC 332 * the triangle edge which is testes 333 * @return true if the angle opposite of te edge c is obtuse 334 */ 335 private boolean isObtuse(double lengthA, double lengthB, double lengthC) { 336 337 /*- 338 * Law of cosines: 339 * c^2 = a^2 + b^2 - 2abcos 340 * if c^2 = a^2 + b^2, it is a right triangle 341 * if c^2 < a^2 + b^2, it is an acute triangle 342 * if c^2 > a^2 + b^2, it is an obtuse triangle 343 */ 344 345 if (lengthC * lengthC > lengthA * lengthA + lengthB * lengthB) { 346 return true; 347 } 348 349 return false; 350 } 351 352 /** 353 * Adds the given way to the map of assigned ways. Assumes that the given 354 * way is not contained in the map. 355 * 356 * @param stop 357 * @param way 358 */ 359 private void addAssignedWayToMap(PTStop stop, Way way) { 360 if (stopToWay.containsKey(stop)) { 361 List<Way> assignedWays = stopToWay.get(stop); 362 assignedWays.add(way); 363 } else { 364 List<Way> assignedWays = new ArrayList<Way>(); 365 assignedWays.add(way); 366 stopToWay.put(stop, assignedWays); 367 } 368 } 369 370 /** 371 * May be needed if the correspondence between stops and ways has changed 372 * significantly 373 */ 374 public static void reinitiate() { 375 stopToWay = new HashMap<>(); 376 } 33 /* contains assigned stops */ 34 public static HashMap<PTStop, List<Way>> stopToWay = new HashMap<>(); 35 36 /* 37 * contains all PTWays of the route relation for which this assigner was 38 * created 39 */ 40 private HashSet<Way> ways; 41 42 /* route relation for which this StopToWayAssigner was created */ 43 44 public StopToWayAssigner(List<PTWay> ptways) { 45 ways = new HashSet<>(); 46 for (PTWay ptway : ptways) { 47 ways.addAll(ptway.getWays()); 48 } 49 } 50 51 /** 52 * Returns the PTWay for the given PTStop 53 * 54 * @param stop stop 55 * @return the PTWay for the given PTStop 56 */ 57 public Way get(PTStop stop) { 58 59 // 1) Search if this stop has already been assigned: 60 if (stopToWay.containsKey(stop)) { 61 List<Way> assignedWays = stopToWay.get(stop); 62 for (Way assignedWay : assignedWays) { 63 if (this.ways.contains(assignedWay)) { 64 return assignedWay; 65 } 66 } 67 } 68 69 // 2) Search if the stop has a stop position: 70 Way wayOfStopPosition = findWayForNode(stop.getStopPosition()); 71 if (wayOfStopPosition != null) { 72 addAssignedWayToMap(stop, wayOfStopPosition); 73 return wayOfStopPosition; 74 } 75 76 // 3) Search if the stop has a stop_area: 77 List<OsmPrimitive> stopElements = new ArrayList<>(2); 78 if (stop.getStopPosition() != null) { 79 stopElements.add(stop.getStopPosition()); 80 } 81 if (stop.getPlatform() != null) { 82 stopElements.add(stop.getPlatform()); 83 } 84 Set<Relation> parents = Node.getParentRelations(stopElements); 85 for (Relation parentRelation : parents) { 86 if (parentRelation.hasTag("public_transport", "stop_area")) { 87 for (RelationMember rm : parentRelation.getMembers()) { 88 if (rm.getMember().hasTag("public_transport", "stop_position")) { 89 Way rmWay = this.findWayForNode(rm.getNode()); 90 if (rmWay != null) { 91 addAssignedWayToMap(stop, rmWay); 92 return rmWay; 93 } 94 } 95 } 96 } 97 } 98 99 // 4) Search if a stop position is in the vicinity of a platform: 100 if (stop.getPlatform() != null) { 101 List<Node> potentialStopPositionList = stop.findPotentialStopPositions(); 102 Node closestStopPosition = null; 103 double minDistanceSq = Double.MAX_VALUE; 104 for (Node potentialStopPosition : potentialStopPositionList) { 105 double distanceSq = potentialStopPosition.getCoor() 106 .distanceSq(stop.getPlatform().getBBox().getCenter()); 107 if (distanceSq < minDistanceSq) { 108 closestStopPosition = potentialStopPosition; 109 minDistanceSq = distanceSq; 110 } 111 } 112 if (closestStopPosition != null) { 113 Way closestWay = null; 114 double minDistanceSqToWay = Double.MAX_VALUE; 115 for (Way way: this.ways) { 116 if (way.containsNode(closestStopPosition)) { 117 double distanceSq = calculateMinDistanceToSegment(new Node(stop.getPlatform().getBBox().getCenter()), way); 118 if (distanceSq < minDistanceSqToWay) { 119 closestWay = way; 120 minDistanceSqToWay = distanceSq; 121 } 122 } 123 } 124 if (closestWay != null) { 125 addAssignedWayToMap(stop, closestWay); 126 return closestWay; 127 } 128 } 129 } 130 131 // 5) Run the growing-bounding-boxes algorithm: 132 double searchRadius = 0.001; 133 while (searchRadius < 0.005) { 134 135 Way foundWay = this.findNearestWayInRadius(stop.getPlatform(), searchRadius); 136 if (foundWay != null) { 137 addAssignedWayToMap(stop, foundWay); 138 return foundWay; 139 } 140 141 foundWay = this.findNearestWayInRadius(stop.getStopPosition(), searchRadius); 142 if (foundWay != null) { 143 addAssignedWayToMap(stop, foundWay); 144 return foundWay; 145 } 146 147 searchRadius = searchRadius + 0.001; 148 } 149 150 return null; 151 } 152 153 /** 154 * Finds the PTWay of the given stop_position by looking at its referrers 155 * 156 * @param stopPosition stop position 157 * @return the PTWay of the given stop_position by looking at its referrers 158 */ 159 private Way findWayForNode(Node stopPosition) { 160 161 if (stopPosition == null) { 162 return null; 163 } 164 165 // search in the referrers: 166 List<OsmPrimitive> referrers = stopPosition.getReferrers(); 167 for (OsmPrimitive referredPrimitive : referrers) { 168 if (referredPrimitive.getType().equals(OsmPrimitiveType.WAY)) { 169 Way referredWay = (Way) referredPrimitive; 170 if (this.ways.contains(referredWay)) { 171 return referredWay; 172 } 173 } 174 } 175 176 return null; 177 } 178 179 /** 180 * Finds the PTWay in the given radius of the OsmPrimitive. The PTWay has to 181 * belong to the route relation for which this StopToWayAssigner was 182 * created. If multiple PTWays were found, the closest one is chosen. 183 * 184 * @param platform platform 185 * @param searchRadius search radius 186 * @return the PTWay in the given radius of the OsmPrimitive 187 */ 188 private Way findNearestWayInRadius(OsmPrimitive platform, double searchRadius) { 189 190 if (platform == null) { 191 return null; 192 } 193 194 LatLon platformCenter = platform.getBBox().getCenter(); 195 Double ax = platformCenter.getX() - searchRadius; 196 Double bx = platformCenter.getX() + searchRadius; 197 Double ay = platformCenter.getY() - searchRadius; 198 Double by = platformCenter.getY() + searchRadius; 199 BBox platformBBox = new BBox(ax, ay, bx, by); 200 201 Set<Way> potentialWays = new HashSet<>(); 202 203 Collection<Node> allNodes = platform.getDataSet().getNodes(); 204 for (Node currentNode : allNodes) { 205 if (platformBBox.bounds(currentNode.getBBox())) { 206 List<OsmPrimitive> referrers = currentNode.getReferrers(); 207 for (OsmPrimitive referrer : referrers) { 208 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 209 Way referrerWay = (Way) referrer; 210 if (this.ways.contains(referrerWay)) { 211 potentialWays.add(referrerWay); 212 } 213 } 214 } 215 216 } 217 } 218 219 Node platformNode = null; 220 if (platform.getType().equals(OsmPrimitiveType.NODE)) { 221 platformNode = (Node) platform; 222 } else { 223 platformNode = new Node(platform.getBBox().getCenter()); 224 } 225 Way nearestWay = null; 226 Double minDistance = Double.MAX_VALUE; 227 for (Way potentialWay : potentialWays) { 228 double distance = this.calculateMinDistanceToSegment(platformNode, potentialWay); 229 if (distance < minDistance) { 230 minDistance = distance; 231 nearestWay = potentialWay; 232 } 233 } 234 235 return nearestWay; 236 } 237 238 /** 239 * Calculates the minimum distance between a node and a way 240 * 241 * @param node node 242 * @param way way 243 * @return the minimum distance between a node and a way 244 */ 245 private double calculateMinDistanceToSegment(Node node, Way way) { 246 247 double minDistance = Double.MAX_VALUE; 248 249 List<Pair<Node, Node>> waySegments = way.getNodePairs(false); 250 251 for (Pair<Node, Node> waySegment : waySegments) { 252 if (waySegment.a != node && waySegment.b != node) { 253 double distanceToLine = this.calculateDistanceToSegment(node, waySegment); 254 if (distanceToLine < minDistance) { 255 minDistance = distanceToLine; 256 } 257 } 258 } 259 260 return minDistance; 261 262 } 263 264 /** 265 * Calculates the distance from point to segment and differentiates between 266 * acute, right and obtuse triangles. If a triangle is acute or right, the 267 * distance to segment is calculated as distance from point to line. If the 268 * triangle is obtuse, the distance is calculated as the distance to the 269 * nearest vertex of the segment. 270 * 271 * @param node node 272 * @param segment segment 273 * @return the distance from point to segment 274 */ 275 private double calculateDistanceToSegment(Node node, Pair<Node, Node> segment) { 276 277 if (node == segment.a || node == segment.b) { 278 return 0.0; 279 } 280 281 double lengthA = node.getCoor().distance(segment.a.getCoor()); 282 double lengthB = node.getCoor().distance(segment.b.getCoor()); 283 double lengthC = segment.a.getCoor().distance(segment.b.getCoor()); 284 285 if (isObtuse(lengthC, lengthB, lengthA)) { 286 return lengthB; 287 } 288 289 if (isObtuse(lengthA, lengthC, lengthB)) { 290 return lengthA; 291 } 292 293 return calculateDistanceToLine(node, segment); 294 } 295 296 /** 297 * Calculates the distance from point to line using formulas for triangle 298 * area. Does not differentiate between acute, right and obtuse triangles 299 * 300 * @param node node 301 * @param waySegment way segment 302 * @return the distance from point to line 303 */ 304 private double calculateDistanceToLine(Node node, Pair<Node, Node> segment) { 305 306 /* 307 * Let a be the triangle edge between the point and the first node of 308 * the segment. Let b be the triangle edge between the point and the 309 * second node of the segment. Let c be the triangle edge which is the 310 * segment. 311 */ 312 313 double lengthA = node.getCoor().distance(segment.a.getCoor()); 314 double lengthB = node.getCoor().distance(segment.b.getCoor()); 315 double lengthC = segment.a.getCoor().distance(segment.b.getCoor()); 316 317 // calculate triangle area using Heron's formula: 318 double p = (lengthA + lengthB + lengthC) / 2.0; 319 double triangleArea = Math.sqrt(p * (p - lengthA) * (p - lengthB) * (p - lengthC)); 320 321 // calculate the distance from point to segment using the 0.5*c*h 322 // formula for triangle area: 323 return triangleArea * 2.0 / lengthC; 324 } 325 326 /** 327 * Checks if the angle opposite of the edge c is obtuse. Uses the cosine 328 * theorem 329 * 330 * @param lengthA length A 331 * @param lengthB length B 332 * @param lengthC length C 333 * @return true if the angle opposite of the edge c is obtuse 334 */ 335 private boolean isObtuse(double lengthA, double lengthB, double lengthC) { 336 337 /*- 338 * Law of cosines: 339 * c^2 = a^2 + b^2 - 2abcos 340 * if c^2 = a^2 + b^2, it is a right triangle 341 * if c^2 < a^2 + b^2, it is an acute triangle 342 * if c^2 > a^2 + b^2, it is an obtuse triangle 343 */ 344 345 if (lengthC * lengthC > lengthA * lengthA + lengthB * lengthB) { 346 return true; 347 } 348 349 return false; 350 } 351 352 /** 353 * Adds the given way to the map of assigned ways. Assumes that the given 354 * way is not contained in the map. 355 * 356 * @param stop stop 357 * @param way way 358 */ 359 private void addAssignedWayToMap(PTStop stop, Way way) { 360 if (stopToWay.containsKey(stop)) { 361 List<Way> assignedWays = stopToWay.get(stop); 362 assignedWays.add(way); 363 } else { 364 List<Way> assignedWays = new ArrayList<>(); 365 assignedWays.add(way); 366 stopToWay.put(stop, assignedWays); 367 } 368 } 369 370 /** 371 * May be needed if the correspondence between stops and ways has changed 372 * significantly 373 */ 374 public static void reinitiate() { 375 stopToWay = new HashMap<>(); 376 } 377 377 378 378 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/utils/StopUtils.java
r32990 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.utils; 2 3 … … 6 7 /** 7 8 * Utils class for stop areas 8 * 9 * 9 10 * @author 10 11 * 11 12 */ 12 public class StopUtils {13 public final class StopUtils { 13 14 14 15 16 15 private StopUtils() { 16 // private constructor for util classes 17 } 17 18 18 19 20 * 21 22 23 24 25 19 /** 20 * Checks if a given relation is a stop_area. 21 * 22 * @param r 23 * Relation to be checked 24 * @return true if the relation is a stop_area, false otherwise. 25 */ 26 public static boolean isStopArea(Relation r) { 26 27 27 28 29 28 if (r == null) { 29 return false; 30 } 30 31 31 32 33 34 35 32 if (r.hasTag("public_transport", "stop_area")) { 33 return true; 34 } 35 return false; 36 } 36 37 37 38 39 * 40 41 42 43 44 38 /** 39 * Checks if a given object is a stop_position. 40 * 41 * @param r 42 * Relation to be checked 43 * @return true if the object is a stop_position, false otherwise. 44 */ 45 public static boolean verifyStopAreaStopPosition(OsmPrimitive rm) { 45 46 46 47 48 47 if (rm == null) { 48 return false; 49 } 49 50 50 51 52 53 54 51 if (rm.hasTag("public_transport", "stop_position")) { 52 return true; 53 } 54 return false; 55 } 55 56 56 57 58 * 59 60 61 62 63 57 /** 58 * Checks if a given object is a platform. 59 * 60 * @param r 61 * Relation to be checked 62 * @return true if the object is a platform, false otherwise. 63 */ 64 public static boolean verifyStopAreaPlatform(OsmPrimitive rm) { 64 65 65 66 67 66 if (rm == null) { 67 return false; 68 } 68 69 69 70 71 72 73 74 70 if (rm.hasTag("public_transport", "platform") || rm.hasTag("highway", "bus_stop") 71 || rm.hasTag("highway", "platform") || rm.hasTag("railway", "platform")) { 72 return true; 73 } 74 return false; 75 } 75 76 76 77 78 * 79 80 81 82 83 77 /** 78 * Checks if a given object is part of an stop area relation 79 * 80 * @param r 81 * Object to be checked 82 * @return true if the object part of stop area relation, false otherwise. 83 */ 84 public static boolean verifyIfMemberOfStopArea(OsmPrimitive member) { 84 85 85 86 87 88 89 90 91 86 for (Relation parentRelation : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) { 87 if (StopUtils.isStopArea(parentRelation)) { 88 return true; 89 } 90 } 91 return false; 92 } 92 93 93 94 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/Checker.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 25 26 /** 26 27 * Represents tests and fixed of the PT_Assistant plugin 27 * 28 * 28 29 * @author darya 29 30 * … … 31 32 public abstract class Checker { 32 33 33 // test which created this WayChecker: 34 protected final Test test; 35 36 // node that is checked: 37 protected Node node; 38 39 // relation that is checked: 40 protected Relation relation; 41 42 // stores all found errors: 43 protected ArrayList<TestError> errors = new ArrayList<>(); 44 45 protected Checker(Node node, Test test) { 46 this.node = node; 47 this.test = test; 48 } 49 50 protected Checker(Relation relation, Test test) { 51 this.relation = relation; 52 this.test = test; 53 } 54 55 /** 56 * Returns errors 57 */ 58 public List<TestError> getErrors() { 59 60 return errors; 61 } 62 63 /** 64 * Returns a list of stop-related route relation members with corrected 65 * roles (if necessary) 66 * 67 * @return list of stop-related route relation members 68 */ 69 protected static List<RelationMember> listStopMembers(Relation r) { 70 71 List<RelationMember> resultList = new ArrayList<>(); 72 73 for (RelationMember rm : r.getMembers()) { 74 75 if (RouteUtils.isPTStop(rm)) { 76 77 if (rm.getMember().hasTag("public_transport", "stop_position")) { 78 if (!rm.hasRole("stop") && !rm.hasRole("stop_entry_only") && !rm.hasRole("stop_exit_only")) { 79 RelationMember newMember = new RelationMember("stop", rm.getMember()); 80 resultList.add(newMember); 81 } else { 82 resultList.add(rm); 83 } 84 } else { // if platform 85 if (!rm.hasRole("platform") && !rm.hasRole("platform_entry_only") 86 && !rm.hasRole("platform_exit_only")) { 87 RelationMember newMember = new RelationMember("platform", rm.getMember()); 88 resultList.add(newMember); 89 } else { 90 resultList.add(rm); 91 } 92 } 93 94 } 95 } 96 97 return resultList; 98 } 99 100 /** 101 * Returns a list of other (not stop-related) route relation members with 102 * corrected roles (if necessary) 103 * 104 * @return list of other (not stop-related) route relation members 105 */ 106 protected static List<RelationMember> listNotStopMembers(Relation r) { 107 108 List<RelationMember> resultList = new ArrayList<RelationMember>(); 109 110 for (RelationMember rm : r.getMembers()) { 111 112 if (!RouteUtils.isPTStop(rm)) { 113 114 if (rm.hasRole("forward") || rm.hasRole("backward")) { 115 RelationMember newMember = new RelationMember("", rm.getMember()); 116 resultList.add(newMember); 117 } else { 118 119 resultList.add(rm); 120 121 } 122 } 123 124 } 125 126 return resultList; 127 } 128 129 /** 130 * 131 * @param testError 132 * @return 133 */ 134 protected static Command fixErrorByZooming(TestError testError) { 135 136 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP 137 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_DIRECTION 138 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_CONSTRUCTION 139 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE) { 140 return null; 141 } 142 143 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 144 Relation originalRelation = (Relation) primitives.iterator().next(); 145 ArrayList<OsmPrimitive> primitivesToZoom = new ArrayList<>(); 146 for (Object primitiveToZoom : testError.getHighlighted()) { 147 primitivesToZoom.add((OsmPrimitive) primitiveToZoom); 148 } 149 150 SelectCommand command = new SelectCommand(primitivesToZoom); 151 152 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class); 153 for (OsmDataLayer osmDataLayer : listOfLayers) { 154 if (osmDataLayer.data == originalRelation.getDataSet()) { 155 156 final OsmDataLayer layerParameter = osmDataLayer; 157 final Relation relationParameter = originalRelation; 158 final Collection<OsmPrimitive> zoomParameter = primitivesToZoom; 159 160 if (SwingUtilities.isEventDispatchThread()) { 161 162 showRelationEditorAndZoom(layerParameter, relationParameter, zoomParameter); 163 164 } else { 165 166 SwingUtilities.invokeLater(new Runnable() { 167 @Override 168 public void run() { 169 170 showRelationEditorAndZoom(layerParameter, relationParameter, zoomParameter); 171 172 } 173 }); 174 175 } 176 177 return command; 178 } 179 } 180 181 return null; 182 183 } 184 185 private static void showRelationEditorAndZoom(OsmDataLayer layer, Relation r, Collection<OsmPrimitive> primitives) { 186 187 // zoom to problem: 188 AutoScaleAction.zoomTo(primitives); 189 190 // put stop-related members to the front and edit roles if necessary: 191 List<RelationMember> sortedRelationMembers = listStopMembers(r); 192 sortedRelationMembers.addAll(listNotStopMembers(r)); 193 r.setMembers(sortedRelationMembers); 194 195 // create editor: 196 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, r, 197 r.getMembersFor(primitives)); 198 199 // open editor: 200 editor.setVisible(true); 201 202 // make the current relation purple in the pt_assistant layer: 203 PTAssistantLayer.getLayer().repaint(r); 204 205 } 34 // test which created this WayChecker: 35 protected final Test test; 36 37 // node that is checked: 38 protected Node node; 39 40 // relation that is checked: 41 protected Relation relation; 42 43 // stores all found errors: 44 protected ArrayList<TestError> errors = new ArrayList<>(); 45 46 protected Checker(Node node, Test test) { 47 this.node = node; 48 this.test = test; 49 } 50 51 protected Checker(Relation relation, Test test) { 52 this.relation = relation; 53 this.test = test; 54 } 55 56 /** 57 * Returns errors 58 */ 59 public List<TestError> getErrors() { 60 61 return errors; 62 } 63 64 /** 65 * Returns a list of stop-related route relation members with corrected 66 * roles (if necessary) 67 * 68 * @return list of stop-related route relation members 69 */ 70 protected static List<RelationMember> listStopMembers(Relation r) { 71 72 List<RelationMember> resultList = new ArrayList<>(); 73 74 for (RelationMember rm : r.getMembers()) { 75 76 if (RouteUtils.isPTStop(rm)) { 77 78 if (rm.getMember().hasTag("public_transport", "stop_position")) { 79 if (!rm.hasRole("stop") && !rm.hasRole("stop_entry_only") && !rm.hasRole("stop_exit_only")) { 80 RelationMember newMember = new RelationMember("stop", rm.getMember()); 81 resultList.add(newMember); 82 } else { 83 resultList.add(rm); 84 } 85 } else { // if platform 86 if (!rm.hasRole("platform") && !rm.hasRole("platform_entry_only") 87 && !rm.hasRole("platform_exit_only")) { 88 RelationMember newMember = new RelationMember("platform", rm.getMember()); 89 resultList.add(newMember); 90 } else { 91 resultList.add(rm); 92 } 93 } 94 95 } 96 } 97 98 return resultList; 99 } 100 101 /** 102 * Returns a list of other (not stop-related) route relation members with 103 * corrected roles (if necessary) 104 * 105 * @return list of other (not stop-related) route relation members 106 */ 107 protected static List<RelationMember> listNotStopMembers(Relation r) { 108 109 List<RelationMember> resultList = new ArrayList<>(); 110 111 for (RelationMember rm : r.getMembers()) { 112 113 if (!RouteUtils.isPTStop(rm)) { 114 115 if (rm.hasRole("forward") || rm.hasRole("backward")) { 116 RelationMember newMember = new RelationMember("", rm.getMember()); 117 resultList.add(newMember); 118 } else { 119 120 resultList.add(rm); 121 122 } 123 } 124 125 } 126 127 return resultList; 128 } 129 130 protected static Command fixErrorByZooming(TestError testError) { 131 132 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP 133 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_DIRECTION 134 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_CONSTRUCTION 135 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE) { 136 return null; 137 } 138 139 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 140 Relation originalRelation = (Relation) primitives.iterator().next(); 141 ArrayList<OsmPrimitive> primitivesToZoom = new ArrayList<>(); 142 for (Object primitiveToZoom : testError.getHighlighted()) { 143 primitivesToZoom.add((OsmPrimitive) primitiveToZoom); 144 } 145 146 SelectCommand command = new SelectCommand(primitivesToZoom); 147 148 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class); 149 for (OsmDataLayer osmDataLayer : listOfLayers) { 150 if (osmDataLayer.data == originalRelation.getDataSet()) { 151 152 final OsmDataLayer layerParameter = osmDataLayer; 153 final Relation relationParameter = originalRelation; 154 final Collection<OsmPrimitive> zoomParameter = primitivesToZoom; 155 156 if (SwingUtilities.isEventDispatchThread()) { 157 158 showRelationEditorAndZoom(layerParameter, relationParameter, zoomParameter); 159 160 } else { 161 162 SwingUtilities.invokeLater(new Runnable() { 163 @Override 164 public void run() { 165 166 showRelationEditorAndZoom(layerParameter, relationParameter, zoomParameter); 167 168 } 169 }); 170 171 } 172 173 return command; 174 } 175 } 176 177 return null; 178 179 } 180 181 private static void showRelationEditorAndZoom(OsmDataLayer layer, Relation r, Collection<OsmPrimitive> primitives) { 182 183 // zoom to problem: 184 AutoScaleAction.zoomTo(primitives); 185 186 // put stop-related members to the front and edit roles if necessary: 187 List<RelationMember> sortedRelationMembers = listStopMembers(r); 188 sortedRelationMembers.addAll(listNotStopMembers(r)); 189 r.setMembers(sortedRelationMembers); 190 191 // create editor: 192 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, r, 193 r.getMembersFor(primitives)); 194 195 // open editor: 196 editor.setVisible(true); 197 198 // make the current relation purple in the pt_assistant layer: 199 PTAssistantLayer.getLayer().repaint(r); 200 201 } 206 202 207 203 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/NodeChecker.java
r32871 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 26 27 public class NodeChecker extends Checker { 27 28 28 29 29 protected NodeChecker(Node node, Test test) { 30 super(node, test); 30 31 31 32 } 32 33 33 /** 34 * Checks if the given stop_position node belongs to any way 35 * 36 * @param n 37 */ 38 protected void performSolitaryStopPositionTest() { 34 /** 35 * Checks if the given stop_position node belongs to any way 36 */ 37 protected void performSolitaryStopPositionTest() { 39 38 40 39 List<OsmPrimitive> referrers = node.getReferrers(); 41 40 42 43 44 45 46 47 41 for (OsmPrimitive referrer : referrers) { 42 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 43 Way referrerWay = (Way) referrer; 44 if (RouteUtils.isWaySuitableForPublicTransport(referrerWay)) { 45 return; 46 } 48 47 49 50 48 } 49 } 51 50 52 53 54 55 56 51 List<OsmPrimitive> primitives = new ArrayList<>(1); 52 primitives.add(node); 53 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop_position is not part of a way"), 54 PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION, primitives); 55 errors.add(e); 57 56 58 57 } 59 58 60 /** 61 * Checks if the given platform node belongs to any way 62 * 63 * @param n 64 */ 65 protected void performPlatformPartOfWayTest() { 59 /** 60 * Checks if the given platform node belongs to any way 61 */ 62 protected void performPlatformPartOfWayTest() { 66 63 67 64 List<OsmPrimitive> referrers = node.getReferrers(); 68 65 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 66 for (OsmPrimitive referrer : referrers) { 67 List<Node> primitives = new ArrayList<>(1); 68 primitives.add(node); 69 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 70 Way referringWay = (Way) referrer; 71 if (RouteUtils.isWaySuitableForPublicTransport(referringWay)) { 72 TestError e = new TestError(this.test, Severity.WARNING, 73 tr("PT: Platform should not be part of a way"), 74 PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY, primitives); 75 errors.add(e); 76 return; 77 } 78 } 79 } 80 } 84 81 85 /** 86 * Checks if the given stop_position node belongs to any stop_area relation 87 * @author xamanu 88 * @param n 89 */ 90 protected void performNodePartOfStopAreaTest() { 82 /** 83 * Checks if the given stop_position node belongs to any stop_area relation 84 * @author xamanu 85 */ 86 protected void performNodePartOfStopAreaTest() { 91 87 92 88 if (!StopUtils.verifyIfMemberOfStopArea(node)) { 93 89 94 95 96 97 98 99 100 101 90 List<OsmPrimitive> primitives = new ArrayList<>(1); 91 primitives.add(node); 92 TestError e = new TestError(this.test, Severity.WARNING, 93 tr("PT: Stop position or platform is not part of a stop area relation"), 94 PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA, primitives); 95 errors.add(e); 96 } 97 } 102 98 103 104 105 106 * 107 * @param testError108 * @return 109 110 99 /** 100 * Fixes errors: solitary stop position and platform which is part of a way. 101 * Asks the user first. 102 * 103 * @param testError test error 104 * @return fix command 105 */ 106 protected static Command fixError(TestError testError) { 111 107 112 113 114 115 108 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 109 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 110 return null; 111 } 116 112 117 113 Node problematicNode = (Node) testError.getPrimitives().iterator().next(); 118 114 119 final int[] userSelection = { JOptionPane.YES_OPTION};120 121 115 final int[] userSelection = {JOptionPane.YES_OPTION}; 116 final TestError errorParameter = testError; 117 if (SwingUtilities.isEventDispatchThread()) { 122 118 123 119 userSelection[0] = showFixNodeTagDialog(errorParameter); 124 120 125 121 } else { 126 122 127 128 129 130 131 132 133 134 135 136 137 138 123 try { 124 SwingUtilities.invokeAndWait(new Runnable() { 125 @Override 126 public void run() { 127 userSelection[0] = showFixNodeTagDialog(errorParameter); 128 } 129 }); 130 } catch (InvocationTargetException | InterruptedException e) { 131 e.printStackTrace(); 132 return null; 133 } 134 } 139 135 140 136 if (userSelection[0] == JOptionPane.YES_OPTION) { 141 137 142 143 144 145 146 147 148 149 150 151 152 138 Node modifiedNode = new Node(problematicNode); 139 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) { 140 modifiedNode.put("public_transport", "platform"); 141 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode); 142 return command; 143 } else { 144 modifiedNode.put("public_transport", "stop_position"); 145 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode); 146 return command; 147 } 148 } 153 149 154 150 return null; 155 151 156 152 } 157 153 158 159 160 161 162 163 164 154 private static int showFixNodeTagDialog(TestError e) { 155 Node problematicNode = (Node) e.getPrimitives().iterator().next(); 156 // Main.map.mapView.zoomTo(problematicNode.getCoor()); 157 // zoom to problem: 158 Collection<OsmPrimitive> primitives = new ArrayList<>(1); 159 primitives.add(problematicNode); 160 AutoScaleAction.zoomTo(primitives); 165 161 166 String[] options = { tr("Yes"), tr("No")};167 168 169 170 171 172 173 174 175 162 String[] options = {tr("Yes"), tr("No")}; 163 String message; 164 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) { 165 message = "Do you want to change the tag public_transport=stop_position to public_transport=platform?"; 166 } else { 167 message = "Do you want to change the tag public_transport=platform to public_transport=stop_position?"; 168 } 169 return JOptionPane.showOptionDialog(null, message, tr("PT_Assistant Message"), JOptionPane.YES_NO_OPTION, 170 JOptionPane.QUESTION_MESSAGE, null, options, 0); 171 } 176 172 177 173 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java
r32990 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 40 41 public class PTAssistantValidatorTest extends Test { 41 42 42 public static final int ERROR_CODE_SORTING = 3711; 43 public static final int ERROR_CODE_ROAD_TYPE = 3721; 44 public static final int ERROR_CODE_CONSTRUCTION = 3722; 45 public static final int ERROR_CODE_DIRECTION = 3731; 46 public static final int ERROR_CODE_END_STOP = 3741; 47 public static final int ERROR_CODE_SPLIT_WAY = 3742; 48 public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743; 49 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751; 50 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752; 51 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753; 52 public static final int ERROR_CODE_STOP_BY_STOP = 3754; 53 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761; 54 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762; 55 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763; 56 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764; 57 58 private PTAssistantLayer layer; 59 60 public PTAssistantValidatorTest() { 61 super(tr("Public Transport Assistant tests"), 62 tr("Check if route relations are compatible with public transport version 2")); 63 64 layer = PTAssistantLayer.getLayer(); 65 DataSet.addSelectionListener(layer); 66 67 } 68 69 @Override 70 public void visit(Node n) { 71 72 if (n.isIncomplete()) { 73 return; 74 } 75 76 NodeChecker nodeChecker = new NodeChecker(n, this); 77 78 // select only stop_positions 79 if (n.hasTag("public_transport", "stop_position")) { 80 81 // check if stop positions are on a way: 82 nodeChecker.performSolitaryStopPositionTest(); 83 84 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 85 // check if stop positions are in any stop_area relation: 86 nodeChecker.performNodePartOfStopAreaTest(); 87 } 88 89 } 90 91 // select only platforms 92 if (n.hasTag("public_transport", "platform")) { 93 94 // check that platforms are not part of any way: 95 nodeChecker.performPlatformPartOfWayTest(); 96 97 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 98 // check if platforms are in any stop_area relation: 99 nodeChecker.performNodePartOfStopAreaTest(); 100 } 101 102 } 103 104 this.errors.addAll(nodeChecker.getErrors()); 105 106 } 107 108 @Override 109 public void visit(Relation r) { 110 111 // Download incomplete members. If the download does not work, return 112 // and do not do any testing. 113 if (r.hasIncompleteMembers()) { 114 115 boolean downloadSuccessful = this.downloadIncompleteMembers(); 116 if (!downloadSuccessful) { 117 return; 118 } 119 } 120 121 if (r.hasIncompleteMembers()) { 122 return; 123 } 124 125 126 // Do some testing on stop area relations 127 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true && StopUtils.isStopArea(r)) { 128 129 StopChecker stopChecker = new StopChecker(r, this); 130 131 // Check if stop area relation has one stop position. 132 stopChecker.performStopAreaStopPositionTest(); 133 134 // Check if stop area relation has one platform. 135 stopChecker.performStopAreaPlatformTest(); 136 137 // Check if stop position(s) belong the same route relation as 138 // related platform(s) 139 stopChecker.performStopAreaRelationsTest(); 140 141 // Attach thrown errors 142 this.errors.addAll(stopChecker.getErrors()); 143 } 144 145 146 if (!RouteUtils.isTwoDirectionRoute(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 */ 229 private int showIncompleteMembersDownloadDialog() throws InterruptedException { 230 231 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) { 232 return JOptionPane.YES_OPTION; 233 } 234 235 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) { 236 return JOptionPane.NO_OPTION; 237 } 238 239 IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog(); 240 return incompleteMembersDownloadDialog.getUserSelection(); 241 242 } 243 244 /** 245 * Gets user input after errors were detected by WayChecker. Although this 246 * method is not used in the current implementation, it can be used to fix 247 * errors from the previous testing stage and modify the route before the 248 * second stage of testing is carried out. 249 */ 250 @SuppressWarnings("unused") 251 private void proceedAfterWayCheckerErrors(Relation r) { 252 253 // count errors of each type: 254 int numberOfDirectionErrors = 0; 255 int numberOfRoadTypeErrors = 0; 256 for (TestError e : this.errors) { 257 if (e.getCode() == ERROR_CODE_DIRECTION) { 258 numberOfDirectionErrors++; 259 } 260 if (e.getCode() == ERROR_CODE_ROAD_TYPE) { 261 numberOfRoadTypeErrors++; 262 } 263 } 264 265 final int[] userInput = { 0 }; 266 final long idParameter = r.getId(); 267 final int directionErrorParameter = numberOfDirectionErrors; 268 final int roadTypeErrorParameter = numberOfRoadTypeErrors; 269 270 if (SwingUtilities.isEventDispatchThread()) { 271 272 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 273 274 } else { 275 276 try { 277 SwingUtilities.invokeAndWait(new Runnable() { 278 @Override 279 public void run() { 280 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 281 282 } 283 }); 284 } catch (InvocationTargetException | InterruptedException e1) { 285 e1.printStackTrace(); 286 } 287 288 } 289 290 if (userInput[0] == 0) { 291 this.fixErrorFromPlugin(this.errors); 292 proceedWithSorting(r); 293 return; 294 } 295 296 if (userInput[0] == 1) { 297 JOptionPane.showMessageDialog(null, "This is not implemented yet!"); 298 return; 299 } 300 301 if (userInput[0] == 2) { 302 proceedWithSorting(r); 303 } 304 305 // if userInput==-1 (i.e. no input), do nothing and stop testing of the 306 // route. 307 308 } 309 310 private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 311 312 if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) { 313 return 2; 314 } 315 316 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) { 317 return 0; 318 } 319 320 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) { 321 return 2; 322 } 323 324 ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors); 325 return proceedDialog.getUserSelection(); 326 327 } 328 329 /** 330 * Carries out the second stage of the testing: sorting 331 * 332 * @param r 333 */ 334 private void proceedWithSorting(Relation r) { 335 336 // Check if the relation is correct, or only has a wrong sorting order: 337 RouteChecker routeChecker = new RouteChecker(r, this); 338 routeChecker.performSortingTest(); 339 List<TestError> routeCheckerErrors = routeChecker.getErrors(); 340 341 /*- At this point, there are 3 variants: 342 * 343 * 1) There are no errors => route is correct 344 * 2) There is only a sorting error (can only be 1), but otherwise 345 * correct. 346 * 3) There are some other errors/gaps that cannot be fixed by 347 * sorting => start further test (stop-by-stop) 348 * 349 * */ 350 351 if (!routeCheckerErrors.isEmpty()) { 352 // Variant 2 353 // If there is only the sorting error, add it 354 this.errors.addAll(routeChecker.getErrors()); 355 } 356 357 // if (!routeChecker.getHasGap()) { 358 // // Variant 1 359 // storeCorrectRouteSegments(r); 360 // } 361 362 // Variant 3: 363 proceedAfterSorting(r); 364 365 } 366 367 /** 368 * Carries out the stop-by-stop testing which includes building the route 369 * data model. 370 * 371 * @param r route relation 372 */ 373 private void proceedAfterSorting(Relation r) { 374 375 SegmentChecker segmentChecker = new SegmentChecker(r, this); 376 377 // Check if the creation of the route data model in the segment checker 378 // worked. If it did not, it means the roles in the route relation do 379 // not match the tags of the route members. 380 if (!segmentChecker.getErrors().isEmpty()) { 381 this.errors.addAll(segmentChecker.getErrors()); 382 } 383 384 segmentChecker.performFirstStopTest(); 385 segmentChecker.performLastStopTest(); 386 segmentChecker.performStopNotServedTest(); 387 388 boolean sortingErrorFound = false; 389 for (TestError error : this.errors) { 390 if (error.getCode() == ERROR_CODE_SORTING) { 391 sortingErrorFound = true; 392 break; 393 } 394 } 395 if (!sortingErrorFound) { 396 segmentChecker.performStopByStopTest(); 397 segmentChecker.findFixes(); 398 } 399 400 for (TestError error: segmentChecker.getErrors()) { 401 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) { 402 this.errors.add(error); 403 } 404 } 405 } 406 407 /** 408 * Creates the PTRouteSegments of a route that has been found correct and 409 * stores them in the list of correct route segments 410 * 411 * @param r 412 * route relation 413 */ 414 @SuppressWarnings("unused") 415 private void storeCorrectRouteSegments(Relation r) { 416 PTRouteDataManager manager = new PTRouteDataManager(r); 417 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 418 if (manager.getPTStops().size() > 1) { 419 for (int i = 1; i < manager.getPTStops().size(); i++) { 420 PTStop segmentStartStop = manager.getPTStops().get(i - 1); 421 PTStop segmentEndStop = manager.getPTStops().get(i); 422 Way segmentStartWay = assigner.get(segmentStartStop); 423 Way segmentEndWay = assigner.get(segmentEndStop); 424 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay); 425 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r); 426 SegmentChecker.addCorrectSegment(routeSegment); 427 } 428 } 429 } 430 431 /** 432 * Checks if the test error is fixable 433 */ 434 @Override 435 public boolean isFixable(TestError testError) { 436 if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE 437 || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING 438 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 439 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 440 return true; 441 } 442 443 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) { 444 return true; 445 } 446 447 return false; 448 } 449 450 /** 451 * Fixes the given error 452 */ 453 @Override 454 public Command fixError(TestError testError) { 455 456 // repaint the relation in the pt_assistant layer: 457 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) { 458 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next(); 459 this.layer.repaint(relationToBeFixed); 460 } 461 462 // reset the last fix: 463 PTAssistantPlugin.setLastFix(null); 464 465 List<Command> commands = new ArrayList<>(); 466 467 if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) { 468 commands.add(WayChecker.fixErrorByZooming(testError)); 469 } 470 471 if (testError.getCode() == ERROR_CODE_DIRECTION) { 472 commands.add(WayChecker.fixErrorByZooming(testError)); 473 474 } 475 476 if (testError.getCode() == ERROR_CODE_SORTING) { 477 commands.add(RouteChecker.fixSortingError(testError)); 478 } 479 480 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION 481 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 482 commands.add(NodeChecker.fixError(testError)); 483 } 484 485 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) { 486 commands.add(SegmentChecker.fixError(testError)); 487 // make sure the primitives of this testError are selected: 488 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>(); 489 for (Object obj : testError.getPrimitives()) { 490 primitivesToSelect.add((OsmPrimitive) obj); 491 } 492 SelectCommand selectCommand = new SelectCommand(primitivesToSelect); 493 SwingUtilities.invokeLater(new Runnable() { 494 @Override 495 public void run() { 496 selectCommand.executeCommand(); 497 } 498 }); 499 } 500 501 if (commands.isEmpty()) { 502 return null; 503 } 504 505 if (commands.size() == 1) { 506 return commands.get(0); 507 } 508 509 return new SequenceCommand(tr("Fix error"), commands); 510 } 511 512 /** 513 * This method is the counterpart of the fixError(TestError testError) 514 * method. The fixError method is invoked from the core validator (e.g. when 515 * user presses the "Fix" button in the validator). This method is invoken 516 * when the fix is initiated from within the plugin (e.g. automated fixes). 517 * 518 * @return 519 */ 520 private void fixErrorFromPlugin(List<TestError> testErrors) { 521 522 // run fix task asynchronously 523 FixTask fixTask = new FixTask(testErrors); 524 525 Thread t = new Thread(fixTask); 526 t.start(); 527 try { 528 t.join(); 529 errors.removeAll(testErrors); 530 531 } catch (InterruptedException e) { 532 JOptionPane.showMessageDialog(null, "Error occurred during fixing"); 533 } 534 535 } 536 537 public void addFixVariants(List<List<PTWay>> fixVariants) { 538 layer.addFixVariants(fixVariants); 539 } 540 541 public void clearFixVariants() { 542 layer.clearFixVariants(); 543 } 544 545 public List<PTWay> getFixVariant(Character c) { 546 return layer.getFixVariant(c); 547 } 548 549 @SuppressWarnings("unused") 550 private void performDummyTest(Relation r) { 551 List<Relation> primitives = new ArrayList<>(1); 552 primitives.add(r); 553 errors.add( 554 new TestError(this, Severity.WARNING, tr("PT: dummy test warning"), ERROR_CODE_DIRECTION, primitives)); 555 } 43 public static final int ERROR_CODE_SORTING = 3711; 44 public static final int ERROR_CODE_ROAD_TYPE = 3721; 45 public static final int ERROR_CODE_CONSTRUCTION = 3722; 46 public static final int ERROR_CODE_DIRECTION = 3731; 47 public static final int ERROR_CODE_END_STOP = 3741; 48 public static final int ERROR_CODE_SPLIT_WAY = 3742; 49 public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743; 50 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751; 51 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752; 52 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753; 53 public static final int ERROR_CODE_STOP_BY_STOP = 3754; 54 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761; 55 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762; 56 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763; 57 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764; 58 59 private PTAssistantLayer layer; 60 61 public PTAssistantValidatorTest() { 62 super(tr("Public Transport Assistant tests"), 63 tr("Check if route relations are compatible with public transport version 2")); 64 65 layer = PTAssistantLayer.getLayer(); 66 DataSet.addSelectionListener(layer); 67 68 } 69 70 @Override 71 public void visit(Node n) { 72 73 if (n.isIncomplete()) { 74 return; 75 } 76 77 NodeChecker nodeChecker = new NodeChecker(n, this); 78 79 // select only stop_positions 80 if (n.hasTag("public_transport", "stop_position")) { 81 82 // check if stop positions are on a way: 83 nodeChecker.performSolitaryStopPositionTest(); 84 85 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 86 // check if stop positions are in any stop_area relation: 87 nodeChecker.performNodePartOfStopAreaTest(); 88 } 89 90 } 91 92 // select only platforms 93 if (n.hasTag("public_transport", "platform")) { 94 95 // check that platforms are not part of any way: 96 nodeChecker.performPlatformPartOfWayTest(); 97 98 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 99 // check if platforms are in any stop_area relation: 100 nodeChecker.performNodePartOfStopAreaTest(); 101 } 102 103 } 104 105 this.errors.addAll(nodeChecker.getErrors()); 106 107 } 108 109 @Override 110 public void visit(Relation r) { 111 112 // Download incomplete members. If the download does not work, return 113 // and do not do any testing. 114 if (r.hasIncompleteMembers()) { 115 116 boolean downloadSuccessful = this.downloadIncompleteMembers(); 117 if (!downloadSuccessful) { 118 return; 119 } 120 } 121 122 if (r.hasIncompleteMembers()) { 123 return; 124 } 125 126 127 // Do some testing on stop area relations 128 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == 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 147 if (!RouteUtils.isTwoDirectionRoute(r)) { 148 return; 149 } 150 151 // Check individual ways using the oneway direction test and the road 152 // type test: 153 WayChecker wayChecker = new WayChecker(r, this); 154 wayChecker.performDirectionTest(); 155 wayChecker.performRoadTypeTest(); 156 this.errors.addAll(wayChecker.getErrors()); 157 158 proceedWithSorting(r); 159 160 // This allows to modify the route before the sorting and 161 // SegmentChecker are carried out: 162 // if (this.errors.isEmpty()) { 163 // proceedWithSorting(r); 164 // } else { 165 // this.proceedAfterWayCheckerErrors(r); 166 // } 167 168 } 169 170 /** 171 * Downloads incomplete relation members in an extra thread (user input 172 * required) 173 * 174 * @return true if successful, false if not successful 175 */ 176 private boolean downloadIncompleteMembers() { 177 178 final int[] userSelection = {0}; 179 180 try { 181 182 if (SwingUtilities.isEventDispatchThread()) { 183 184 userSelection[0] = showIncompleteMembersDownloadDialog(); 185 186 } else { 187 188 SwingUtilities.invokeAndWait(new Runnable() { 189 @Override 190 public void run() { 191 try { 192 userSelection[0] = showIncompleteMembersDownloadDialog(); 193 } catch (InterruptedException e) { 194 e.printStackTrace(); 195 } 196 197 } 198 }); 199 200 } 201 202 } catch (InterruptedException | InvocationTargetException e) { 203 return false; 204 } 205 206 if (userSelection[0] == JOptionPane.YES_OPTION) { 207 208 Thread t = new IncompleteMembersDownloadThread(); 209 t.start(); 210 synchronized (t) { 211 try { 212 t.wait(); 213 } catch (InterruptedException e) { 214 return false; 215 } 216 } 217 218 } 219 220 return true; 221 222 } 223 224 /** 225 * Shows the dialog asking the user about an incomplete member download 226 * 227 * @return user's selection 228 * @throws InterruptedException 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 relation 334 */ 335 private void proceedWithSorting(Relation r) { 336 337 // Check if the relation is correct, or only has a wrong sorting order: 338 RouteChecker routeChecker = new RouteChecker(r, this); 339 routeChecker.performSortingTest(); 340 List<TestError> routeCheckerErrors = routeChecker.getErrors(); 341 342 /*- At this point, there are 3 variants: 343 * 344 * 1) There are no errors => route is correct 345 * 2) There is only a sorting error (can only be 1), but otherwise 346 * correct. 347 * 3) There are some other errors/gaps that cannot be fixed by 348 * sorting => start further test (stop-by-stop) 349 * 350 * */ 351 352 if (!routeCheckerErrors.isEmpty()) { 353 // Variant 2 354 // If there is only the sorting error, add it 355 this.errors.addAll(routeChecker.getErrors()); 356 } 357 358 // if (!routeChecker.getHasGap()) { 359 // // Variant 1 360 // storeCorrectRouteSegments(r); 361 // } 362 363 // Variant 3: 364 proceedAfterSorting(r); 365 366 } 367 368 /** 369 * Carries out the stop-by-stop testing which includes building the route 370 * data model. 371 * 372 * @param r route relation 373 */ 374 private void proceedAfterSorting(Relation r) { 375 376 SegmentChecker segmentChecker = new SegmentChecker(r, this); 377 378 // Check if the creation of the route data model in the segment checker 379 // worked. If it did not, it means the roles in the route relation do 380 // not match the tags of the route members. 381 if (!segmentChecker.getErrors().isEmpty()) { 382 this.errors.addAll(segmentChecker.getErrors()); 383 } 384 385 segmentChecker.performFirstStopTest(); 386 segmentChecker.performLastStopTest(); 387 segmentChecker.performStopNotServedTest(); 388 389 boolean sortingErrorFound = false; 390 for (TestError error : this.errors) { 391 if (error.getCode() == ERROR_CODE_SORTING) { 392 sortingErrorFound = true; 393 break; 394 } 395 } 396 if (!sortingErrorFound) { 397 segmentChecker.performStopByStopTest(); 398 segmentChecker.findFixes(); 399 } 400 401 for (TestError error: segmentChecker.getErrors()) { 402 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) { 403 this.errors.add(error); 404 } 405 } 406 } 407 408 /** 409 * Creates the PTRouteSegments of a route that has been found correct and 410 * stores them in the list of correct route segments 411 * 412 * @param r 413 * route relation 414 */ 415 @SuppressWarnings("unused") 416 private void storeCorrectRouteSegments(Relation r) { 417 PTRouteDataManager manager = new PTRouteDataManager(r); 418 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 419 if (manager.getPTStops().size() > 1) { 420 for (int i = 1; i < manager.getPTStops().size(); i++) { 421 PTStop segmentStartStop = manager.getPTStops().get(i - 1); 422 PTStop segmentEndStop = manager.getPTStops().get(i); 423 Way segmentStartWay = assigner.get(segmentStartStop); 424 Way segmentEndWay = assigner.get(segmentEndStop); 425 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay); 426 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r); 427 SegmentChecker.addCorrectSegment(routeSegment); 428 } 429 } 430 } 431 432 /** 433 * Checks if the test error is fixable 434 */ 435 @Override 436 public boolean isFixable(TestError testError) { 437 if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE 438 || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING 439 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 440 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 441 return true; 442 } 443 444 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) { 445 return true; 446 } 447 448 return false; 449 } 450 451 /** 452 * Fixes the given error 453 */ 454 @Override 455 public Command fixError(TestError testError) { 456 457 // repaint the relation in the pt_assistant layer: 458 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) { 459 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next(); 460 this.layer.repaint(relationToBeFixed); 461 } 462 463 // reset the last fix: 464 PTAssistantPlugin.setLastFix(null); 465 466 List<Command> commands = new ArrayList<>(); 467 468 if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) { 469 commands.add(WayChecker.fixErrorByZooming(testError)); 470 } 471 472 if (testError.getCode() == ERROR_CODE_DIRECTION) { 473 commands.add(WayChecker.fixErrorByZooming(testError)); 474 475 } 476 477 if (testError.getCode() == ERROR_CODE_SORTING) { 478 commands.add(RouteChecker.fixSortingError(testError)); 479 } 480 481 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION 482 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 483 commands.add(NodeChecker.fixError(testError)); 484 } 485 486 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) { 487 commands.add(SegmentChecker.fixError(testError)); 488 // make sure the primitives of this testError are selected: 489 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>(); 490 for (Object obj : testError.getPrimitives()) { 491 primitivesToSelect.add((OsmPrimitive) obj); 492 } 493 SelectCommand selectCommand = new SelectCommand(primitivesToSelect); 494 SwingUtilities.invokeLater(new Runnable() { 495 @Override 496 public void run() { 497 selectCommand.executeCommand(); 498 } 499 }); 500 } 501 502 if (commands.isEmpty()) { 503 return null; 504 } 505 506 if (commands.size() == 1) { 507 return commands.get(0); 508 } 509 510 return new SequenceCommand(tr("Fix error"), commands); 511 } 512 513 /** 514 * This method is the counterpart of the fixError(TestError testError) 515 * method. The fixError method is invoked from the core validator (e.g. when 516 * user presses the "Fix" button in the validator). This method is invoken 517 * when the fix is initiated from within the plugin (e.g. automated fixes). 518 */ 519 private void fixErrorFromPlugin(List<TestError> testErrors) { 520 521 // run fix task asynchronously 522 FixTask fixTask = new FixTask(testErrors); 523 524 Thread t = new Thread(fixTask); 525 t.start(); 526 try { 527 t.join(); 528 errors.removeAll(testErrors); 529 530 } catch (InterruptedException e) { 531 JOptionPane.showMessageDialog(null, "Error occurred during fixing"); 532 } 533 534 } 535 536 public void addFixVariants(List<List<PTWay>> fixVariants) { 537 layer.addFixVariants(fixVariants); 538 } 539 540 public void clearFixVariants() { 541 layer.clearFixVariants(); 542 } 543 544 public List<PTWay> getFixVariant(Character c) { 545 return layer.getFixVariant(c); 546 } 547 548 @SuppressWarnings("unused") 549 private void performDummyTest(Relation r) { 550 List<Relation> primitives = new ArrayList<>(1); 551 primitives.add(r); 552 errors.add( 553 new TestError(this, Severity.WARNING, tr("PT: dummy test warning"), ERROR_CODE_DIRECTION, primitives)); 554 } 556 555 557 556 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/RouteChecker.java
r32567 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 23 24 /** 24 25 * Performs tests of a route at the level of the whole route: sorting test 25 * 26 * 26 27 * @author darya 27 28 * … … 29 30 public class RouteChecker extends Checker { 30 31 31 32 private boolean hasGap; 32 33 33 34 List<RelationMember> sortedMembers; 34 35 35 36 public RouteChecker(Relation relation, Test test) { 36 37 37 38 super(relation, test); 38 39 39 40 this.hasGap = false; 40 41 41 42 } 42 43 43 44 protected void performSortingTest() { 44 45 45 46 46 final List<RelationMember> waysToCheck = new ArrayList<>(); 47 for (RelationMember rm : relation.getMembers()) { 47 48 48 49 50 51 49 if (RouteUtils.isPTWay(rm) && rm.getType().equals(OsmPrimitiveType.WAY)) { 50 waysToCheck.add(rm); 51 } 52 } 52 53 53 54 55 54 if (waysToCheck.isEmpty()) { 55 return; 56 } 56 57 57 58 if (hasGap(waysToCheck)) { 58 59 59 60 this.hasGap = true; 60 61 61 62 62 RelationSorter sorter = new RelationSorter(); 63 sortedMembers = sorter.sortMembers(waysToCheck); 63 64 64 65 66 67 68 65 if (!hasGap(sortedMembers)) { 66 TestError e = new TestError(this.test, Severity.WARNING, 67 tr("PT: Route contains a gap that can be fixed by sorting"), 68 PTAssistantValidatorTest.ERROR_CODE_SORTING, relation); 69 this.errors.add(e); 69 70 70 71 } 71 72 72 73 } 73 74 74 75 } 75 76 76 77 78 79 80 * 81 * @param waysToCheck82 83 84 85 86 87 88 89 90 91 92 93 77 /** 78 * Checks if there is a gap for a given list of ways. It does not check if 79 * the way actually stands for a public transport platform - that should be 80 * checked beforehand. 81 * 82 * @param waysToCheck ways to check 83 * @return true if has gap (in the sense of continuity of ways in the 84 * Relation Editor), false otherwise 85 */ 86 private boolean hasGap(List<RelationMember> waysToCheck) { 87 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator(); 88 final List<WayConnectionType> links = connectionTypeCalculator.updateLinks(waysToCheck); 89 for (int i = 0; i < links.size(); i++) { 90 final WayConnectionType link = links.get(i); 91 final boolean hasError = !(i == 0 || link.linkPrev) || !(i == links.size() - 1 || link.linkNext) 92 || link.direction == null || WayConnectionType.Direction.NONE.equals(link.direction); 93 if (hasError) { 94 return true; 94 95 95 96 96 } 97 } 97 98 98 99 99 return false; 100 } 100 101 101 102 public List<RelationMember> getSortedMembers() { 102 103 103 104 return sortedMembers; 104 105 105 106 } 106 107 107 108 public boolean getHasGap() { 108 109 109 110 return this.hasGap; 110 111 111 } 112 113 protected static Command fixSortingError(TestError testError) { 114 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SORTING) { 115 return null; 116 } 112 } 117 113 118 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 119 Relation originalRelation = (Relation) primitives.iterator().next(); 114 protected static Command fixSortingError(TestError testError) { 115 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SORTING) { 116 return null; 117 } 120 118 121 // separate ways from stops (because otherwise the order of 122 // stops/platforms can be messed up by the sorter: 123 List<RelationMember> members = originalRelation.getMembers(); 124 final List<RelationMember> stops = new ArrayList<>(); 125 final List<RelationMember> ways = new ArrayList<>(); 126 for (RelationMember member : members) { 127 if (RouteUtils.isPTWay(member)) { 128 if (member.getRole().equals("")) { 129 ways.add(member); 130 } else { 131 RelationMember modifiedMember = new RelationMember("", member.getWay()); 132 ways.add(modifiedMember); 133 } 119 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 120 Relation originalRelation = (Relation) primitives.iterator().next(); 134 121 135 } else { // stops: 136 if (member.getRole().equals("stop_positon")) { 137 // it is not expected that stop_positions could 138 // be relations 139 if (member.getType().equals(OsmPrimitiveType.NODE)) { 140 RelationMember modifiedMember = new RelationMember("stop", member.getNode()); 141 stops.add(modifiedMember); 142 } else { // if it is a primitive of type way: 143 RelationMember modifiedMember = new RelationMember("stop", member.getWay()); 144 stops.add(modifiedMember); 145 } 146 } else { // if it is not a stop_position: 147 stops.add(member); 148 } 122 // separate ways from stops (because otherwise the order of 123 // stops/platforms can be messed up by the sorter: 124 List<RelationMember> members = originalRelation.getMembers(); 125 final List<RelationMember> stops = new ArrayList<>(); 126 final List<RelationMember> ways = new ArrayList<>(); 127 for (RelationMember member : members) { 128 if (RouteUtils.isPTWay(member)) { 129 if (member.getRole().equals("")) { 130 ways.add(member); 131 } else { 132 RelationMember modifiedMember = new RelationMember("", member.getWay()); 133 ways.add(modifiedMember); 134 } 149 135 150 } 151 } 136 } else { // stops: 137 if (member.getRole().equals("stop_positon")) { 138 // it is not expected that stop_positions could 139 // be relations 140 if (member.getType().equals(OsmPrimitiveType.NODE)) { 141 RelationMember modifiedMember = new RelationMember("stop", member.getNode()); 142 stops.add(modifiedMember); 143 } else { // if it is a primitive of type way: 144 RelationMember modifiedMember = new RelationMember("stop", member.getWay()); 145 stops.add(modifiedMember); 146 } 147 } else { // if it is not a stop_position: 148 stops.add(member); 149 } 152 150 153 // sort the ways: 154 RelationSorter sorter = new RelationSorter(); 155 List<RelationMember> sortedWays = sorter.sortMembers(ways); 151 } 152 } 156 153 157 // create a new relation to pass to the command: 158 Relation sortedRelation = new Relation(originalRelation); 159 List<RelationMember> sortedRelationMembers = new ArrayList<>(members.size()); 160 for (RelationMember rm : stops) { 161 sortedRelationMembers.add(rm); 162 } 163 for (RelationMember rm : sortedWays) { 164 sortedRelationMembers.add(rm); 165 } 166 sortedRelation.setMembers(sortedRelationMembers); 154 // sort the ways: 155 RelationSorter sorter = new RelationSorter(); 156 List<RelationMember> sortedWays = sorter.sortMembers(ways); 167 157 168 ChangeCommand changeCommand = new ChangeCommand(originalRelation, sortedRelation); 158 // create a new relation to pass to the command: 159 Relation sortedRelation = new Relation(originalRelation); 160 List<RelationMember> sortedRelationMembers = new ArrayList<>(members.size()); 161 for (RelationMember rm : stops) { 162 sortedRelationMembers.add(rm); 163 } 164 for (RelationMember rm : sortedWays) { 165 sortedRelationMembers.add(rm); 166 } 167 sortedRelation.setMembers(sortedRelationMembers); 169 168 170 return changeCommand;169 ChangeCommand changeCommand = new ChangeCommand(originalRelation, sortedRelation); 171 170 172 } 171 return changeCommand; 172 173 } 173 174 174 175 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java
r32871 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 40 41 * Performs tests of a route at the level of route segments (the stop-by-stop 41 42 * approach). 42 * 43 * 43 44 * @author darya 44 45 * … … 46 47 public class SegmentChecker extends Checker { 47 48 48 /* PTRouteSegments that have been validated and are correct */ 49 private static List<PTRouteSegment> correctSegments = new ArrayList<PTRouteSegment>(); 50 51 /* PTRouteSegments that are wrong, stored in case the user calls the fix */ 52 private static HashMap<TestError, PTRouteSegment> wrongSegments = new HashMap<TestError, PTRouteSegment>(); 53 54 /* Manager of the PTStops and PTWays of the current route */ 55 private PTRouteDataManager manager; 56 57 /* Assigns PTStops to nearest PTWays and stores that correspondence */ 58 private StopToWayAssigner assigner; 59 60 public SegmentChecker(Relation relation, Test test) { 61 62 super(relation, test); 63 64 this.manager = new PTRouteDataManager(relation); 65 66 for (RelationMember rm : manager.getFailedMembers()) { 67 List<Relation> primitives = new ArrayList<>(1); 68 primitives.add(relation); 69 List<OsmPrimitive> highlighted = new ArrayList<>(1); 70 highlighted.add(rm.getMember()); 71 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Relation member roles do not match tags"), 72 PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES, primitives, highlighted); 73 this.errors.add(e); 74 } 75 76 this.assigner = new StopToWayAssigner(manager.getPTWays()); 77 78 } 79 80 /** 81 * Returns the number of route segments that have been already successfully 82 * verified 83 * 84 * @return 85 */ 86 public static int getCorrectSegmentCount() { 87 return correctSegments.size(); 88 } 89 90 /** 91 * Adds the given correct segment to the list of correct segments without 92 * checking its correctness 93 * 94 * @param segment 95 * to add to the list of correct segments 96 */ 97 public synchronized static void addCorrectSegment(PTRouteSegment segment) { 98 for (PTRouteSegment correctSegment : correctSegments) { 99 if (correctSegment.equalsRouteSegment(segment)) { 100 return; 101 } 102 } 103 correctSegments.add(segment); 104 } 105 106 /** 107 * Used for unit tests 108 * @param error 109 * @return 110 */ 111 protected static PTRouteSegment getWrongSegment(TestError error) { 112 return wrongSegments.get(error); 113 } 114 115 public void performFirstStopTest() { 116 117 performEndStopTest(manager.getFirstStop()); 118 119 } 120 121 public void performLastStopTest() { 122 123 performEndStopTest(manager.getLastStop()); 124 125 } 126 127 private void performEndStopTest(PTStop endStop) { 128 129 if (endStop == null) { 130 return; 131 } 132 133 /* 134 * This test checks: (1) that a stop position exists; (2) that it is the 135 * first or last node of its parent ways which belong to this route. 136 */ 137 138 if (endStop.getStopPosition() == null) { 139 140 List<Node> potentialStopPositionList = endStop.findPotentialStopPositions(); 141 List<Node> stopPositionsOfThisRoute = new ArrayList<>(); 142 boolean containsAtLeastOneStopPositionAsFirstOrLastNode = false; 143 144 for (Node potentialStopPosition : potentialStopPositionList) { 145 146 int belongsToWay = belongsToAWayOfThisRoute(potentialStopPosition); 147 148 if (belongsToWay == 0) { 149 stopPositionsOfThisRoute.add(potentialStopPosition); 150 containsAtLeastOneStopPositionAsFirstOrLastNode = true; 151 } 152 153 if (belongsToWay == 1) { 154 stopPositionsOfThisRoute.add(potentialStopPosition); 155 } 156 } 157 158 if (stopPositionsOfThisRoute.isEmpty()) { 159 List<Relation> primitives = new ArrayList<>(1); 160 primitives.add(relation); 161 List<OsmPrimitive> highlighted = new ArrayList<>(1); 162 highlighted.add(endStop.getPlatform()); 163 TestError e = new TestError(this.test, Severity.WARNING, 164 tr("PT: Route should start and end with a stop_position"), 165 PTAssistantValidatorTest.ERROR_CODE_END_STOP, primitives, highlighted); 166 this.errors.add(e); 167 return; 168 } 169 170 if (stopPositionsOfThisRoute.size() == 1) { 171 endStop.setStopPosition(stopPositionsOfThisRoute.get(0)); 172 } 173 174 // At this point, there is at least one stop_position for this 175 // endStop: 176 if (!containsAtLeastOneStopPositionAsFirstOrLastNode) { 177 List<Relation> primitives = new ArrayList<>(1); 178 primitives.add(relation); 179 List<OsmPrimitive> highlighted = new ArrayList<>(); 180 highlighted.addAll(stopPositionsOfThisRoute); 181 182 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: First or last way needs to be split"), 183 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY, primitives, highlighted); 184 this.errors.add(e); 185 } 186 187 } else { 188 189 // if the stop_position is known: 190 int belongsToWay = this.belongsToAWayOfThisRoute(endStop.getStopPosition()); 191 192 if (belongsToWay == 1) { 193 194 List<Relation> primitives = new ArrayList<>(1); 195 primitives.add(relation); 196 List<OsmPrimitive> highlighted = new ArrayList<>(); 197 highlighted.add(endStop.getStopPosition()); 198 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: First or last way needs to be split"), 199 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY, primitives, highlighted); 200 this.errors.add(e); 201 } 202 } 203 204 } 205 206 /** 207 * Checks if the given node belongs to the ways of this route. 208 * 209 * @param node 210 * Node to be checked 211 * @return 1 if belongs only as an inner node, 0 if belongs as a first or 212 * last node for at least one way, -1 if does not belong to any way. 213 */ 214 private int belongsToAWayOfThisRoute(Node node) { 215 216 boolean contains = false; 217 218 List<PTWay> ptways = manager.getPTWays(); 219 for (PTWay ptway : ptways) { 220 List<Way> ways = ptway.getWays(); 221 for (Way way : ways) { 222 if (way.containsNode(node)) { 223 224 if (way.firstNode().equals(node) || way.lastNode().equals(node)) { 225 return 0; 226 } 227 228 contains = true; 229 } 230 } 231 } 232 233 if (contains) { 234 return 1; 235 } 236 237 return -1; 238 } 239 240 public void performStopNotServedTest() { 241 for (PTStop stop : manager.getPTStops()) { 242 Way way = assigner.get(stop); 243 if (way == null) { 244 createStopError(stop); 245 } 246 } 247 } 248 249 /** 250 * Performs the stop-by-stop test by visiting each segment between two 251 * consecutive stops and checking if the ways between them are correct 252 */ 253 public void performStopByStopTest() { 254 255 if (manager.getPTStopCount() < 2) { 256 return; 257 } 258 259 // Check each route segment: 260 for (int i = 1; i < manager.getPTStopCount(); i++) { 261 262 PTStop startStop = manager.getPTStops().get(i - 1); 263 PTStop endStop = manager.getPTStops().get(i); 264 265 Way startWay = assigner.get(startStop); 266 Way endWay = assigner.get(endStop); 267 if (startWay == null || endWay == null || (startWay == endWay && startWay == manager.getLastWay())) { 268 continue; 269 } 270 271 List<PTWay> segmentWays = manager.getPTWaysBetween(startWay, endWay); 272 273 Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0)); 274 if (firstNode == null) { 275 // check if this error has just been reported: 276 if (!this.errors.isEmpty() && this.errors.get(this.errors.size() - 1).getHighlighted().size() == 1 277 && this.errors.get(this.errors.size() - 1).getHighlighted().iterator().next() == startWay) { 278 // do nothing, this error has already been reported in 279 // the previous route segment 280 } else { 281 List<Relation> primitives = new ArrayList<>(1); 282 primitives.add(relation); 283 List<OsmPrimitive> highlighted = new ArrayList<>(); 284 highlighted.add(startWay); 285 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 286 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 287 this.errors.add(e); 288 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 289 wrongSegments.put(e, routeSegment); 290 } 291 continue; 292 } 293 294 boolean sortingCorrect = existingWaySortingIsCorrect(segmentWays.get(0), firstNode, 295 segmentWays.get(segmentWays.size() - 1)); 296 if (sortingCorrect) { 297 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 298 addCorrectSegment(routeSegment); 299 } else { 300 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 301 TestError error = this.errors.get(this.errors.size() - 1); 302 wrongSegments.put(error, routeSegment); 303 } 304 } 305 } 306 307 /** 308 * Creates a TestError and adds it to the list of errors for a stop that is 309 * not served. 310 * 311 * @param stop 312 */ 313 private void createStopError(PTStop stop) { 314 List<Relation> primitives = new ArrayList<>(1); 315 primitives.add(relation); 316 List<OsmPrimitive> highlighted = new ArrayList<>(); 317 OsmPrimitive stopPrimitive = stop.getPlatform(); 318 if (stopPrimitive == null) { 319 stopPrimitive = stop.getStopPosition(); 320 } 321 highlighted.add(stopPrimitive); 322 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop not served"), 323 PTAssistantValidatorTest.ERROR_CODE_STOP_NOT_SERVED, primitives, highlighted); 324 this.errors.add(e); 325 } 326 327 private Node findFirstNodeOfRouteSegmentInDirectionOfTravel(PTWay startWay) { 328 329 // 1) at first check if one of the first or last node of the first ptway 330 // is a deadend node: 331 Node[] startWayEndnodes = startWay.getEndNodes(); 332 if (isDeadendNode(startWayEndnodes[0])) { 333 return startWayEndnodes[0]; 334 } 335 if (isDeadendNode(startWayEndnodes[1])) { 336 return startWayEndnodes[1]; 337 } 338 339 // 2) failing that, check which node this startWay shares with the 340 // following way: 341 PTWay nextWay = manager.getNextPTWay(startWay); 342 if (nextWay == null) { 343 return null; 344 } 345 PTWay wayAfterNext = manager.getNextPTWay(nextWay); 346 Node[] nextWayEndnodes = nextWay.getEndNodes(); 347 if ((startWayEndnodes[0] == nextWayEndnodes[0] && startWayEndnodes[1] == nextWayEndnodes[1]) 348 || (startWayEndnodes[0] == nextWayEndnodes[1] && startWayEndnodes[1] == nextWayEndnodes[0])) { 349 // if this is a split roundabout: 350 Node[] wayAfterNextEndnodes = wayAfterNext.getEndNodes(); 351 if (startWayEndnodes[0] == wayAfterNextEndnodes[0] || startWayEndnodes[0] == wayAfterNextEndnodes[1]) { 352 return startWayEndnodes[0]; 353 } 354 if (startWayEndnodes[1] == wayAfterNextEndnodes[0] || startWayEndnodes[1] == wayAfterNextEndnodes[1]) { 355 return startWayEndnodes[1]; 356 } 357 } 358 359 if (startWayEndnodes[0] == nextWayEndnodes[0] || startWayEndnodes[0] == nextWayEndnodes[1]) { 360 return startWayEndnodes[1]; 361 } 362 if (startWayEndnodes[1] == nextWayEndnodes[0] || startWayEndnodes[1] == nextWayEndnodes[1]) { 363 return startWayEndnodes[0]; 364 } 365 366 return null; 367 368 } 369 370 /** 371 * 372 * @param node 373 * @return 374 */ 375 private boolean isDeadendNode(Node node) { 376 int count = 0; 377 for (PTWay ptway : manager.getPTWays()) { 378 List<Way> ways = ptway.getWays(); 379 for (Way way : ways) { 380 if (way.firstNode() == node || way.lastNode() == node) { 381 count++; 382 } 383 } 384 } 385 return count == 1; 386 } 387 388 /** 389 * Finds the deadend node closest to the given node represented by its 390 * coordinates 391 * 392 * @param coord 393 * coordinates of the givenn node 394 * @param deadendNodes 395 * @return the closest deadend node 396 */ 397 @SuppressWarnings("unused") 398 private Node findClosestDeadendNode(LatLon coord, List<Node> deadendNodes) { 399 400 Node closestDeadendNode = null; 401 double minSqDistance = Double.MAX_VALUE; 402 for (Node deadendNode : deadendNodes) { 403 double distanceSq = coord.distanceSq(deadendNode.getCoor()); 404 if (distanceSq < minSqDistance) { 405 minSqDistance = distanceSq; 406 closestDeadendNode = deadendNode; 407 } 408 } 409 return closestDeadendNode; 410 411 } 412 413 /** 414 * Checks if the existing sorting of the given route segment is correct 415 * 416 * @param start 417 * PTWay assigned to the first stop of the segment 418 * @param startWayPreviousNodeInDirectionOfTravel 419 * Node if the start way which is furthest away from the rest of 420 * the route 421 * @param end 422 * PTWay assigned to the end stop of the segment 423 * @return true if the sorting is correct, false otherwise. 424 */ 425 private boolean existingWaySortingIsCorrect(PTWay start, Node startWayPreviousNodeInDirectionOfTravel, PTWay end) { 426 427 if (start == end) { 428 // if both PTStops are on the same PTWay 429 return true; 430 } 431 432 PTWay current = start; 433 Node currentNode = startWayPreviousNodeInDirectionOfTravel; 434 435 while (!current.equals(end)) { 436 // "equals" is used here instead of "==" because when the same way 437 // is passed multiple times by the bus, the algorithm should stop no 438 // matter which of the geometrically equal PTWays it finds 439 440 PTWay nextPTWayAccortingToExistingSorting = manager.getNextPTWay(current); 441 442 // if current contains an unsplit roundabout: 443 if (current.containsUnsplitRoundabout()) { 444 currentNode = manager.getCommonNode(current, nextPTWayAccortingToExistingSorting); 445 if (currentNode == null) { 446 List<Relation> primitives = new ArrayList<>(1); 447 primitives.add(relation); 448 List<OsmPrimitive> highlighted = new ArrayList<>(); 449 highlighted.addAll(current.getWays()); 450 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 451 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 452 this.errors.add(e); 453 return false; 454 } 455 } else { 456 // if this is a regular way, not an unsplit roundabout 457 458 // find the next node in direction of travel (which is part of 459 // the PTWay start): 460 currentNode = getOppositeEndNode(current, currentNode); 461 462 List<PTWay> nextWaysInDirectionOfTravel = this.findNextPTWaysInDirectionOfTravel(current, currentNode); 463 464 if (!nextWaysInDirectionOfTravel.contains(nextPTWayAccortingToExistingSorting)) { 465 List<Relation> primitives = new ArrayList<>(1); 466 primitives.add(relation); 467 List<OsmPrimitive> highlighted = new ArrayList<>(); 468 469 highlighted.addAll(current.getWays()); 470 471 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 472 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 473 this.errors.add(e); 474 return false; 475 476 } 477 } 478 479 current = nextPTWayAccortingToExistingSorting; 480 481 } 482 483 return true; 484 } 485 486 /** 487 * Will return the same node if the way is an unsplit roundabout 488 * 489 * @param way 490 * @param node 491 * @return 492 */ 493 private Node getOppositeEndNode(Way way, Node node) { 494 495 if (node == way.firstNode()) { 496 return way.lastNode(); 497 } 498 499 if (node == way.lastNode()) { 500 return way.firstNode(); 501 } 502 503 return null; 504 } 505 506 /** 507 * Does not work correctly for unsplit roundabouts 508 * 509 * @param ptway 510 * @param node 511 * @return 512 */ 513 private Node getOppositeEndNode(PTWay ptway, Node node) { 514 if (ptway.isWay()) { 515 return getOppositeEndNode(ptway.getWays().get(0), node); 516 } 517 518 Way firstWay = ptway.getWays().get(0); 519 Way lastWay = ptway.getWays().get(ptway.getWays().size() - 1); 520 Node oppositeNode = node; 521 if (firstWay.firstNode() == node || firstWay.lastNode() == node) { 522 for (int i = 0; i < ptway.getWays().size(); i++) { 523 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 524 } 525 return oppositeNode; 526 } else if (lastWay.firstNode() == node || lastWay.lastNode() == node) { 527 for (int i = ptway.getWays().size() - 1; i >= 0; i--) { 528 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 529 } 530 return oppositeNode; 531 } 532 533 return null; 534 535 } 536 537 /** 538 * Finds the next ways for the route stop-by-stop parsing procedure 539 * 540 * @param way 541 * @param nodeInDirectionOfTravel 542 * @return 543 */ 544 private List<PTWay> findNextPTWaysInDirectionOfTravel(PTWay currentWay, Node nextNodeInDirectionOfTravel) { 545 546 List<PTWay> nextPtways = new ArrayList<>(); 547 548 List<PTWay> ptways = manager.getPTWays(); 549 550 for (PTWay ptway : ptways) { 551 552 if (ptway != currentWay) { 553 for (Way way : ptway.getWays()) { 554 if (way.containsNode(nextNodeInDirectionOfTravel)) { 555 nextPtways.add(ptway); 556 } 557 } 558 } 559 } 560 561 return nextPtways; 562 563 } 564 565 protected static boolean isFixable(TestError testError) { 566 567 /*- 568 * When is an error fixable (outdated)? 569 * - if there is a correct segment 570 * - if it can be fixed by sorting 571 * - if the route is compete even without some ways 572 * - if simple routing closes the gap 573 */ 574 575 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP) { 576 return true; 577 } 578 579 return false; 580 581 } 582 583 @SuppressWarnings("unused") 584 private static boolean isFixableByUsingCorrectSegment(TestError testError) { 585 PTRouteSegment wrongSegment = wrongSegments.get(testError); 586 PTRouteSegment correctSegment = null; 587 for (PTRouteSegment segment : correctSegments) { 588 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 589 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 590 correctSegment = segment; 591 break; 592 } 593 } 594 return correctSegment != null; 595 } 596 597 @SuppressWarnings("unused") 598 private static boolean isFixableBySortingAndRemoval(TestError testError) { 599 PTRouteSegment wrongSegment = wrongSegments.get(testError); 600 List<List<PTWay>> fixVariants = wrongSegment.getFixVariants(); 601 if (!fixVariants.isEmpty()) { 602 return true; 603 } 604 return false; 605 } 606 607 /** 608 * Finds fixes using sorting and removal. Modifies the messages in the test 609 * error according to the availability of automatic fixes. 610 */ 611 protected void findFixes() { 612 613 for (TestError error : wrongSegments.keySet()) { 614 // look for fixes using sorting and removing: 615 findFix(error); 616 617 // change the error code based on the availability of fixes: 618 PTRouteSegment wrongSegment = wrongSegments.get(error); 619 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 620 for (PTRouteSegment segment : correctSegments) { 621 if (wrongSegment.getFirstWay().getId() == segment.getFirstWay().getId() 622 && wrongSegment.getLastWay().getId() == segment.getLastWay().getId()) { 623 correctSegmentsForThisError.add(segment); 624 } 625 } 626 627 int numberOfFixes = correctSegmentsForThisError.size(); 628 629 if (numberOfFixes == 0) { 630 numberOfFixes = wrongSegment.getFixVariants().size(); 631 } 632 if (numberOfFixes == 0) { 633 for (PTRouteSegment segment : correctSegments) { 634 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 635 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 636 correctSegmentsForThisError.add(segment); 637 } 638 } 639 numberOfFixes = correctSegmentsForThisError.size(); 640 } 641 642 // change the error code: 643 if (numberOfFixes == 0) { 644 error.setMessage(tr("PT: Problem in the route segment with no automatic fix")); 645 } else if (numberOfFixes == 1) { 646 error.setMessage(tr("PT: Problem in the route segment with one automatic fix")); 647 } else { 648 error.setMessage("PT: Problem in the route segment with several automatic fixes"); 649 } 650 } 651 652 } 653 654 /** 655 * This method assumes that the first and the second ways of the route 656 * segment are correctly connected. If they are not, the error will be 657 * marked as not fixable. 658 * 659 * @param testError 660 */ 661 private void findFix(TestError testError) { 662 663 PTRouteSegment wrongSegment = wrongSegments.get(testError); 664 PTWay startPTWay = wrongSegment.getFirstPTWay(); 665 PTWay endPTWay = wrongSegment.getLastPTWay(); 666 667 Node previousNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(startPTWay); 668 if (previousNode == null) { 669 return; 670 } 671 672 List<List<PTWay>> initialFixes = new ArrayList<>(); 673 List<PTWay> initialFix = new ArrayList<>(); 674 initialFix.add(startPTWay); 675 initialFixes.add(initialFix); 676 677 List<List<PTWay>> allFixes = findWaysForFix(initialFixes, initialFix, previousNode, endPTWay); 678 for (List<PTWay> fix : allFixes) { 679 if (!fix.isEmpty() && fix.get(fix.size() - 1).equals(endPTWay)) { 680 wrongSegment.addFixVariant(fix); 681 } 682 } 683 684 } 685 686 /** 687 * Recursive method to parse the route segment 688 * 689 * @param allFixes 690 * @param currentFix 691 * @param previousNode 692 * @param endWay 693 * @return 694 */ 695 private List<List<PTWay>> findWaysForFix(List<List<PTWay>> allFixes, List<PTWay> currentFix, Node previousNode, 696 PTWay endWay) { 697 698 PTWay currentWay = currentFix.get(currentFix.size() - 1); 699 Node nextNode = getOppositeEndNode(currentWay, previousNode); 700 701 List<PTWay> nextWays = this.findNextPTWaysInDirectionOfTravel(currentWay, nextNode); 702 703 if (nextWays.size() > 1) { 704 for (int i = 1; i < nextWays.size(); i++) { 705 List<PTWay> newFix = new ArrayList<>(); 706 newFix.addAll(currentFix); 707 newFix.add(nextWays.get(i)); 708 allFixes.add(newFix); 709 if (!nextWays.get(i).equals(endWay) && !currentFix.contains(nextWays.get(i))) { 710 allFixes = findWaysForFix(allFixes, newFix, nextNode, endWay); 711 } 712 } 713 } 714 715 if (!nextWays.isEmpty()) { 716 boolean contains = currentFix.contains(nextWays.get(0)); 717 currentFix.add(nextWays.get(0)); 718 if (!nextWays.get(0).equals(endWay) && !contains) { 719 allFixes = findWaysForFix(allFixes, currentFix, nextNode, endWay); 720 } 721 } 722 723 return allFixes; 724 } 725 726 /** 727 * Fixes the error by first searching in the list of correct segments and 728 * then trying to sort and remove existing route relation members 729 * 730 * @param testError 731 * @return 732 */ 733 protected static Command fixError(TestError testError) { 734 735 // if fix options for another route are displayed in the pt_assistant 736 // layer, clear them: 737 ((PTAssistantValidatorTest) testError.getTester()).clearFixVariants(); 738 739 PTRouteSegment wrongSegment = wrongSegments.get(testError); 740 741 // 1) try to fix by using the correct segment: 742 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 743 for (PTRouteSegment segment : correctSegments) { 744 if (wrongSegment.getFirstWay().getId() == segment.getFirstWay().getId() 745 && wrongSegment.getLastWay().getId() == segment.getLastWay().getId()) { 746 correctSegmentsForThisError.add(segment); 747 } 748 } 749 750 // if no correct segment found, apply less strict criteria to look for 751 // one: 752 if (correctSegmentsForThisError.isEmpty() && wrongSegment.getFixVariants().isEmpty()) { 753 for (PTRouteSegment segment : correctSegments) { 754 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 755 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 756 correctSegmentsForThisError.add(segment); 757 } 758 } 759 if (!correctSegmentsForThisError.isEmpty()) { 760 // display the notification: 761 if (SwingUtilities.isEventDispatchThread()) { 762 Notification notification = new Notification( 763 tr("Warning: the diplayed fix variants are based on less strict criteria")); 764 notification.show(); 765 } else { 766 SwingUtilities.invokeLater(new Runnable() { 767 @Override 768 public void run() { 769 Notification notification = new Notification( 770 tr("Warning: the diplayed fix variants are based on less strict criteria")); 771 notification.show(); 772 } 773 }); 774 } 775 } 776 } 777 778 if (!correctSegmentsForThisError.isEmpty()) { 779 780 if (correctSegmentsForThisError.size() > 1) { 781 List<List<PTWay>> fixVariants = new ArrayList<>(); 782 for (PTRouteSegment segment : correctSegmentsForThisError) { 783 fixVariants.add(segment.getPTWays()); 784 } 785 displayFixVariants(fixVariants, testError); 786 return null; 787 } 788 789 PTAssistantPlugin.setLastFix(correctSegmentsForThisError.get(0)); 790 return carryOutSingleFix(testError, correctSegmentsForThisError.get(0).getPTWays()); 791 792 } else if (!wrongSegment.getFixVariants().isEmpty()) { 793 // 2) try to fix using the sorting and removal of existing ways 794 // of the wrong segment: 795 if (wrongSegment.getFixVariants().size() > 1) { 796 displayFixVariants(wrongSegment.getFixVariants(), testError); 797 return null; 798 } 799 800 PTAssistantPlugin.setLastFix(new PTRouteSegment(wrongSegment.getFirstStop(), 801 wrongSegment.getLastStop(), wrongSegment.getFixVariants().get(0), (Relation) testError.getPrimitives().iterator().next())); 802 return carryOutSingleFix(testError, wrongSegment.getFixVariants().get(0)); 803 } 804 805 // if there is no fix: 806 return fixErrorByZooming(testError); 807 808 } 809 810 /** 811 * This is largely a copy of the displayFixVariants() method, adapted for 812 * use with the key listener 813 * 814 * @param fixVariants 815 * @param testError 816 */ 817 private static void displayFixVariants(List<List<PTWay>> fixVariants, TestError testError) { 818 // find the letters of the fix variants: 819 char alphabet = 'A'; 820 final List<Character> allowedCharacters = new ArrayList<>(); 821 for (int i = 0; i < fixVariants.size(); i++) { 822 allowedCharacters.add(alphabet); 823 alphabet++; 824 } 825 826 // zoom to problem: 827 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 828 for (Object highlightedPrimitive : testError.getHighlighted()) { 829 waysToZoom.add((OsmPrimitive) highlightedPrimitive); 830 } 831 if (SwingUtilities.isEventDispatchThread()) { 832 AutoScaleAction.zoomTo(waysToZoom); 833 } else { 834 SwingUtilities.invokeLater(new Runnable() { 835 @Override 836 public void run() { 837 AutoScaleAction.zoomTo(waysToZoom); 838 } 839 }); 840 } 841 842 // display the fix variants: 843 final PTAssistantValidatorTest test = (PTAssistantValidatorTest) testError.getTester(); 844 test.addFixVariants(fixVariants); 845 PTAssistantLayer.getLayer().repaint((Relation) testError.getPrimitives().iterator().next()); 846 847 // prepare the variables for the key listener: 848 final TestError testErrorParameter = testError; 849 850 // add the key listener: 851 Main.map.mapView.requestFocus(); 852 Main.map.mapView.addKeyListener(new KeyListener() { 853 854 @Override 855 public void keyTyped(KeyEvent e) { 856 // TODO Auto-generated method stub 857 } 858 859 @Override 860 public void keyPressed(KeyEvent e) { 861 Character typedKey = e.getKeyChar(); 862 Character typedKeyUpperCase = typedKey.toString().toUpperCase().toCharArray()[0]; 863 if (allowedCharacters.contains(typedKeyUpperCase)) { 864 Main.map.mapView.removeKeyListener(this); 865 List<PTWay> selectedFix = test.getFixVariant(typedKeyUpperCase); 866 test.clearFixVariants(); 867 carryOutSelectedFix(testErrorParameter, selectedFix); 868 } 869 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 870 Main.map.mapView.removeKeyListener(this); 871 test.clearFixVariants(); 872 } 873 } 874 875 @Override 876 public void keyReleased(KeyEvent e) { 877 // TODO Auto-generated method stub 878 } 879 }); 880 881 // display the notification: 882 if (SwingUtilities.isEventDispatchThread()) { 883 Notification notification = new Notification( 884 tr("Type letter to select the fix variant or press Escape for no fix")); 885 notification.show(); 886 } else { 887 SwingUtilities.invokeLater(new Runnable() { 888 @Override 889 public void run() { 890 Notification notification = new Notification( 891 tr("Type letter to select the fix variant or press Escape for no fix")); 892 notification.show(); 893 } 894 }); 895 } 896 } 897 898 /** 899 * Carries out the fix (i.e. modifies the route) after the user has picked 900 * the fix from several fix variants. 901 * 902 * @param testError 903 * test error to be fixed 904 * @param fix 905 * the fix variant to be adopted 906 */ 907 private static void carryOutSelectedFix(TestError testError, List<PTWay> fix){ 908 // modify the route: 909 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 910 Relation modifiedRelation = new Relation(originalRelation); 911 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 912 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 913 Main.main.undoRedo.addNoRedraw(changeCommand); 914 Main.main.undoRedo.afterAdd(); 915 PTRouteSegment wrongSegment = wrongSegments.get(testError); 916 wrongSegments.remove(testError); 917 wrongSegment.setPTWays(fix); 918 addCorrectSegment(wrongSegment); 919 PTAssistantPlugin.setLastFixNoGui(wrongSegment); 920 921 // get ways for the fix: 922 List<Way> primitives = new ArrayList<>(); 923 for (PTWay ptway : fix) { 924 primitives.addAll(ptway.getWays()); 925 } 926 927 // get layer: 928 OsmDataLayer layer = null; 929 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class); 930 for (OsmDataLayer osmDataLayer : listOfLayers) { 931 if (osmDataLayer.data == originalRelation.getDataSet()) { 932 layer = osmDataLayer; 933 break; 934 } 935 } 936 937 // create editor: 938 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, originalRelation, 939 originalRelation.getMembersFor(primitives)); 940 941 // open editor: 942 editor.setVisible(true); 943 944 } 945 946 /** 947 * Carries out the fix (i.e. modifies the route) when there is only one fix 948 * variant. 949 * 950 * @param testError 951 * @param fix 952 */ 953 private static Command carryOutSingleFix(TestError testError, List<PTWay> fix) { 954 // Zoom to the problematic ways: 955 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 956 for (Object highlightedPrimitive : testError.getHighlighted()) { 957 waysToZoom.add((OsmPrimitive) highlightedPrimitive); 958 } 959 if (SwingUtilities.isEventDispatchThread()) { 960 AutoScaleAction.zoomTo(waysToZoom); 961 } else { 962 SwingUtilities.invokeLater(new Runnable() { 963 @Override 964 public void run() { 965 AutoScaleAction.zoomTo(waysToZoom); 966 } 967 }); 968 } 969 970 // wait: 971 synchronized (SegmentChecker.class) { 972 try { 973 SegmentChecker.class.wait(1500); 974 } catch (InterruptedException e) { 975 // TODO Auto-generated catch block 976 e.printStackTrace(); 977 } 978 } 979 980 // modify the route: 981 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 982 Relation modifiedRelation = new Relation(originalRelation); 983 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 984 wrongSegments.remove(testError); 985 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 986 return changeCommand; 987 } 988 989 /** 990 * Returns a list of the modified relation members. This list can be used by 991 * the calling method (relation.setMemers()) to modify the modify the route 992 * relation. The route relation is not modified by this method. The lists of 993 * wrong and correct segments are not updated. 994 * 995 * @param testError 996 * test error to be fixed 997 * @param fix 998 * the fix variant to be adopted 999 * @return List of modified relation members to be applied to the route 1000 * relation 1001 */ 1002 private static List<RelationMember> getModifiedRelationMembers(TestError testError, List<PTWay> fix) { 1003 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1004 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 1005 1006 // copy stops first: 1007 List<RelationMember> modifiedRelationMembers = listStopMembers(originalRelation); 1008 1009 // copy PTWays last: 1010 List<RelationMember> waysOfOriginalRelation = listNotStopMembers(originalRelation); 1011 for (int i = 0; i < waysOfOriginalRelation.size(); i++) { 1012 if (waysOfOriginalRelation.get(i).getWay() == wrongSegment.getPTWays().get(0).getWays().get(0)) { 1013 modifiedRelationMembers.addAll(fix); 1014 i = i + wrongSegment.getPTWays().size() - 1; 1015 } else { 1016 modifiedRelationMembers.add(waysOfOriginalRelation.get(i)); 1017 } 1018 } 1019 1020 return modifiedRelationMembers; 1021 } 1022 1023 public static void carryOutRepeatLastFix(PTRouteSegment segment) { 1024 1025 List<TestError> wrongSegmentsToRemove = new ArrayList<>(); 1026 1027 // find all wrong ways that have the same segment: 1028 for (TestError testError: wrongSegments.keySet()) { 1029 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1030 if (wrongSegment.getFirstWay() == segment.getFirstWay() && wrongSegment.getLastWay() == segment.getLastWay()) { 1031 // modify the route: 1032 Relation originalRelation = wrongSegment.getRelation(); 1033 Relation modifiedRelation = new Relation(originalRelation); 1034 modifiedRelation.setMembers(getModifiedRelationMembers(testError, segment.getPTWays())); 1035 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 1036 Main.main.undoRedo.addNoRedraw(changeCommand); 1037 Main.main.undoRedo.afterAdd(); 1038 wrongSegmentsToRemove.add(testError); 1039 } 1040 } 1041 1042 // update the errors displayed in the validator dialog: 1043 List<TestError> modifiedValidatorTestErrors = new ArrayList<>(); 1044 for (TestError validatorTestError: Main.map.validatorDialog.tree.getErrors()) { 1045 if (!wrongSegmentsToRemove.contains(validatorTestError)) { 1046 modifiedValidatorTestErrors.add(validatorTestError); 1047 } 1048 } 1049 Main.map.validatorDialog.tree.setErrors(modifiedValidatorTestErrors); 1050 1051 // update wrong segments: 1052 for (TestError testError: wrongSegmentsToRemove) { 1053 wrongSegments.remove(testError); 1054 } 1055 1056 } 1057 1058 /** 1059 * Resets the static list variables (used for unit testing) 1060 */ 1061 protected static void reset() { 1062 correctSegments.clear(); 1063 wrongSegments.clear(); 1064 } 49 /* PTRouteSegments that have been validated and are correct */ 50 private static List<PTRouteSegment> correctSegments = new ArrayList<>(); 51 52 /* PTRouteSegments that are wrong, stored in case the user calls the fix */ 53 private static HashMap<TestError, PTRouteSegment> wrongSegments = new HashMap<>(); 54 55 /* Manager of the PTStops and PTWays of the current route */ 56 private PTRouteDataManager manager; 57 58 /* Assigns PTStops to nearest PTWays and stores that correspondence */ 59 private StopToWayAssigner assigner; 60 61 public SegmentChecker(Relation relation, Test test) { 62 63 super(relation, test); 64 65 this.manager = new PTRouteDataManager(relation); 66 67 for (RelationMember rm : manager.getFailedMembers()) { 68 List<Relation> primitives = new ArrayList<>(1); 69 primitives.add(relation); 70 List<OsmPrimitive> highlighted = new ArrayList<>(1); 71 highlighted.add(rm.getMember()); 72 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Relation member roles do not match tags"), 73 PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES, primitives, highlighted); 74 this.errors.add(e); 75 } 76 77 this.assigner = new StopToWayAssigner(manager.getPTWays()); 78 79 } 80 81 /** 82 * Returns the number of route segments that have been already successfully 83 * verified 84 * 85 * @return the number of route segments 86 */ 87 public static int getCorrectSegmentCount() { 88 return correctSegments.size(); 89 } 90 91 /** 92 * Adds the given correct segment to the list of correct segments without 93 * checking its correctness 94 * 95 * @param segment 96 * to add to the list of correct segments 97 */ 98 public static synchronized void addCorrectSegment(PTRouteSegment segment) { 99 for (PTRouteSegment correctSegment : correctSegments) { 100 if (correctSegment.equalsRouteSegment(segment)) { 101 return; 102 } 103 } 104 correctSegments.add(segment); 105 } 106 107 /** 108 * Used for unit tests 109 * @param error test error 110 * @return wrong route segment 111 */ 112 protected static PTRouteSegment getWrongSegment(TestError error) { 113 return wrongSegments.get(error); 114 } 115 116 public void performFirstStopTest() { 117 118 performEndStopTest(manager.getFirstStop()); 119 120 } 121 122 public void performLastStopTest() { 123 124 performEndStopTest(manager.getLastStop()); 125 126 } 127 128 private void performEndStopTest(PTStop endStop) { 129 130 if (endStop == null) { 131 return; 132 } 133 134 /* 135 * This test checks: (1) that a stop position exists; (2) that it is the 136 * first or last node of its parent ways which belong to this route. 137 */ 138 139 if (endStop.getStopPosition() == null) { 140 141 List<Node> potentialStopPositionList = endStop.findPotentialStopPositions(); 142 List<Node> stopPositionsOfThisRoute = new ArrayList<>(); 143 boolean containsAtLeastOneStopPositionAsFirstOrLastNode = false; 144 145 for (Node potentialStopPosition : potentialStopPositionList) { 146 147 int belongsToWay = belongsToAWayOfThisRoute(potentialStopPosition); 148 149 if (belongsToWay == 0) { 150 stopPositionsOfThisRoute.add(potentialStopPosition); 151 containsAtLeastOneStopPositionAsFirstOrLastNode = true; 152 } 153 154 if (belongsToWay == 1) { 155 stopPositionsOfThisRoute.add(potentialStopPosition); 156 } 157 } 158 159 if (stopPositionsOfThisRoute.isEmpty()) { 160 List<Relation> primitives = new ArrayList<>(1); 161 primitives.add(relation); 162 List<OsmPrimitive> highlighted = new ArrayList<>(1); 163 highlighted.add(endStop.getPlatform()); 164 TestError e = new TestError(this.test, Severity.WARNING, 165 tr("PT: Route should start and end with a stop_position"), 166 PTAssistantValidatorTest.ERROR_CODE_END_STOP, primitives, highlighted); 167 this.errors.add(e); 168 return; 169 } 170 171 if (stopPositionsOfThisRoute.size() == 1) { 172 endStop.setStopPosition(stopPositionsOfThisRoute.get(0)); 173 } 174 175 // At this point, there is at least one stop_position for this 176 // endStop: 177 if (!containsAtLeastOneStopPositionAsFirstOrLastNode) { 178 List<Relation> primitives = new ArrayList<>(1); 179 primitives.add(relation); 180 List<OsmPrimitive> highlighted = new ArrayList<>(); 181 highlighted.addAll(stopPositionsOfThisRoute); 182 183 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: First or last way needs to be split"), 184 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY, primitives, highlighted); 185 this.errors.add(e); 186 } 187 188 } else { 189 190 // if the stop_position is known: 191 int belongsToWay = this.belongsToAWayOfThisRoute(endStop.getStopPosition()); 192 193 if (belongsToWay == 1) { 194 195 List<Relation> primitives = new ArrayList<>(1); 196 primitives.add(relation); 197 List<OsmPrimitive> highlighted = new ArrayList<>(); 198 highlighted.add(endStop.getStopPosition()); 199 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: First or last way needs to be split"), 200 PTAssistantValidatorTest.ERROR_CODE_SPLIT_WAY, primitives, highlighted); 201 this.errors.add(e); 202 } 203 } 204 205 } 206 207 /** 208 * Checks if the given node belongs to the ways of this route. 209 * 210 * @param node 211 * Node to be checked 212 * @return 1 if belongs only as an inner node, 0 if belongs as a first or 213 * last node for at least one way, -1 if does not belong to any way. 214 */ 215 private int belongsToAWayOfThisRoute(Node node) { 216 217 boolean contains = false; 218 219 List<PTWay> ptways = manager.getPTWays(); 220 for (PTWay ptway : ptways) { 221 List<Way> ways = ptway.getWays(); 222 for (Way way : ways) { 223 if (way.containsNode(node)) { 224 225 if (way.firstNode().equals(node) || way.lastNode().equals(node)) { 226 return 0; 227 } 228 229 contains = true; 230 } 231 } 232 } 233 234 if (contains) { 235 return 1; 236 } 237 238 return -1; 239 } 240 241 public void performStopNotServedTest() { 242 for (PTStop stop : manager.getPTStops()) { 243 Way way = assigner.get(stop); 244 if (way == null) { 245 createStopError(stop); 246 } 247 } 248 } 249 250 /** 251 * Performs the stop-by-stop test by visiting each segment between two 252 * consecutive stops and checking if the ways between them are correct 253 */ 254 public void performStopByStopTest() { 255 256 if (manager.getPTStopCount() < 2) { 257 return; 258 } 259 260 // Check each route segment: 261 for (int i = 1; i < manager.getPTStopCount(); i++) { 262 263 PTStop startStop = manager.getPTStops().get(i - 1); 264 PTStop endStop = manager.getPTStops().get(i); 265 266 Way startWay = assigner.get(startStop); 267 Way endWay = assigner.get(endStop); 268 if (startWay == null || endWay == null || (startWay == endWay && startWay == manager.getLastWay())) { 269 continue; 270 } 271 272 List<PTWay> segmentWays = manager.getPTWaysBetween(startWay, endWay); 273 274 Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0)); 275 if (firstNode == null) { 276 // check if this error has just been reported: 277 if (!this.errors.isEmpty() && this.errors.get(this.errors.size() - 1).getHighlighted().size() == 1 278 && this.errors.get(this.errors.size() - 1).getHighlighted().iterator().next() == startWay) { 279 // do nothing, this error has already been reported in 280 // the previous route segment 281 } else { 282 List<Relation> primitives = new ArrayList<>(1); 283 primitives.add(relation); 284 List<OsmPrimitive> highlighted = new ArrayList<>(); 285 highlighted.add(startWay); 286 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 287 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 288 this.errors.add(e); 289 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 290 wrongSegments.put(e, routeSegment); 291 } 292 continue; 293 } 294 295 boolean sortingCorrect = existingWaySortingIsCorrect(segmentWays.get(0), firstNode, 296 segmentWays.get(segmentWays.size() - 1)); 297 if (sortingCorrect) { 298 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 299 addCorrectSegment(routeSegment); 300 } else { 301 PTRouteSegment routeSegment = new PTRouteSegment(startStop, endStop, segmentWays, relation); 302 TestError error = this.errors.get(this.errors.size() - 1); 303 wrongSegments.put(error, routeSegment); 304 } 305 } 306 } 307 308 /** 309 * Creates a TestError and adds it to the list of errors for a stop that is 310 * not served. 311 * 312 * @param stop stop 313 */ 314 private void createStopError(PTStop stop) { 315 List<Relation> primitives = new ArrayList<>(1); 316 primitives.add(relation); 317 List<OsmPrimitive> highlighted = new ArrayList<>(); 318 OsmPrimitive stopPrimitive = stop.getPlatform(); 319 if (stopPrimitive == null) { 320 stopPrimitive = stop.getStopPosition(); 321 } 322 highlighted.add(stopPrimitive); 323 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop not served"), 324 PTAssistantValidatorTest.ERROR_CODE_STOP_NOT_SERVED, primitives, highlighted); 325 this.errors.add(e); 326 } 327 328 private Node findFirstNodeOfRouteSegmentInDirectionOfTravel(PTWay startWay) { 329 330 // 1) at first check if one of the first or last node of the first ptway 331 // is a deadend node: 332 Node[] startWayEndnodes = startWay.getEndNodes(); 333 if (isDeadendNode(startWayEndnodes[0])) { 334 return startWayEndnodes[0]; 335 } 336 if (isDeadendNode(startWayEndnodes[1])) { 337 return startWayEndnodes[1]; 338 } 339 340 // 2) failing that, check which node this startWay shares with the 341 // following way: 342 PTWay nextWay = manager.getNextPTWay(startWay); 343 if (nextWay == null) { 344 return null; 345 } 346 PTWay wayAfterNext = manager.getNextPTWay(nextWay); 347 Node[] nextWayEndnodes = nextWay.getEndNodes(); 348 if ((startWayEndnodes[0] == nextWayEndnodes[0] && startWayEndnodes[1] == nextWayEndnodes[1]) 349 || (startWayEndnodes[0] == nextWayEndnodes[1] && startWayEndnodes[1] == nextWayEndnodes[0])) { 350 // if this is a split roundabout: 351 Node[] wayAfterNextEndnodes = wayAfterNext.getEndNodes(); 352 if (startWayEndnodes[0] == wayAfterNextEndnodes[0] || startWayEndnodes[0] == wayAfterNextEndnodes[1]) { 353 return startWayEndnodes[0]; 354 } 355 if (startWayEndnodes[1] == wayAfterNextEndnodes[0] || startWayEndnodes[1] == wayAfterNextEndnodes[1]) { 356 return startWayEndnodes[1]; 357 } 358 } 359 360 if (startWayEndnodes[0] == nextWayEndnodes[0] || startWayEndnodes[0] == nextWayEndnodes[1]) { 361 return startWayEndnodes[1]; 362 } 363 if (startWayEndnodes[1] == nextWayEndnodes[0] || startWayEndnodes[1] == nextWayEndnodes[1]) { 364 return startWayEndnodes[0]; 365 } 366 367 return null; 368 369 } 370 371 private boolean isDeadendNode(Node node) { 372 int count = 0; 373 for (PTWay ptway : manager.getPTWays()) { 374 List<Way> ways = ptway.getWays(); 375 for (Way way : ways) { 376 if (way.firstNode() == node || way.lastNode() == node) { 377 count++; 378 } 379 } 380 } 381 return count == 1; 382 } 383 384 /** 385 * Finds the deadend node closest to the given node represented by its 386 * coordinates 387 * 388 * @param coord 389 * coordinates of the givenn node 390 * @param deadendNodes dead end nodes 391 * @return the closest deadend node 392 */ 393 @SuppressWarnings("unused") 394 private Node findClosestDeadendNode(LatLon coord, List<Node> deadendNodes) { 395 396 Node closestDeadendNode = null; 397 double minSqDistance = Double.MAX_VALUE; 398 for (Node deadendNode : deadendNodes) { 399 double distanceSq = coord.distanceSq(deadendNode.getCoor()); 400 if (distanceSq < minSqDistance) { 401 minSqDistance = distanceSq; 402 closestDeadendNode = deadendNode; 403 } 404 } 405 return closestDeadendNode; 406 407 } 408 409 /** 410 * Checks if the existing sorting of the given route segment is correct 411 * 412 * @param start 413 * PTWay assigned to the first stop of the segment 414 * @param startWayPreviousNodeInDirectionOfTravel 415 * Node if the start way which is furthest away from the rest of 416 * the route 417 * @param end 418 * PTWay assigned to the end stop of the segment 419 * @return true if the sorting is correct, false otherwise. 420 */ 421 private boolean existingWaySortingIsCorrect(PTWay start, Node startWayPreviousNodeInDirectionOfTravel, PTWay end) { 422 423 if (start == end) { 424 // if both PTStops are on the same PTWay 425 return true; 426 } 427 428 PTWay current = start; 429 Node currentNode = startWayPreviousNodeInDirectionOfTravel; 430 431 while (!current.equals(end)) { 432 // "equals" is used here instead of "==" because when the same way 433 // is passed multiple times by the bus, the algorithm should stop no 434 // matter which of the geometrically equal PTWays it finds 435 436 PTWay nextPTWayAccortingToExistingSorting = manager.getNextPTWay(current); 437 438 // if current contains an unsplit roundabout: 439 if (current.containsUnsplitRoundabout()) { 440 currentNode = manager.getCommonNode(current, nextPTWayAccortingToExistingSorting); 441 if (currentNode == null) { 442 List<Relation> primitives = new ArrayList<>(1); 443 primitives.add(relation); 444 List<OsmPrimitive> highlighted = new ArrayList<>(); 445 highlighted.addAll(current.getWays()); 446 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 447 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 448 this.errors.add(e); 449 return false; 450 } 451 } else { 452 // if this is a regular way, not an unsplit roundabout 453 454 // find the next node in direction of travel (which is part of 455 // the PTWay start): 456 currentNode = getOppositeEndNode(current, currentNode); 457 458 List<PTWay> nextWaysInDirectionOfTravel = this.findNextPTWaysInDirectionOfTravel(current, currentNode); 459 460 if (!nextWaysInDirectionOfTravel.contains(nextPTWayAccortingToExistingSorting)) { 461 List<Relation> primitives = new ArrayList<>(1); 462 primitives.add(relation); 463 List<OsmPrimitive> highlighted = new ArrayList<>(); 464 465 highlighted.addAll(current.getWays()); 466 467 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Problem in the route segment"), 468 PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP, primitives, highlighted); 469 this.errors.add(e); 470 return false; 471 472 } 473 } 474 475 current = nextPTWayAccortingToExistingSorting; 476 477 } 478 479 return true; 480 } 481 482 /** 483 * Will return the same node if the way is an unsplit roundabout 484 * 485 * @param way way 486 * @param node node 487 * @return the same node if the way is an unsplit roundabout 488 */ 489 private Node getOppositeEndNode(Way way, Node node) { 490 491 if (node == way.firstNode()) { 492 return way.lastNode(); 493 } 494 495 if (node == way.lastNode()) { 496 return way.firstNode(); 497 } 498 499 return null; 500 } 501 502 /** 503 * Does not work correctly for unsplit roundabouts 504 * 505 * @param ptway way 506 * @param node node 507 * @return node 508 */ 509 private Node getOppositeEndNode(PTWay ptway, Node node) { 510 if (ptway.isWay()) { 511 return getOppositeEndNode(ptway.getWays().get(0), node); 512 } 513 514 Way firstWay = ptway.getWays().get(0); 515 Way lastWay = ptway.getWays().get(ptway.getWays().size() - 1); 516 Node oppositeNode = node; 517 if (firstWay.firstNode() == node || firstWay.lastNode() == node) { 518 for (int i = 0; i < ptway.getWays().size(); i++) { 519 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 520 } 521 return oppositeNode; 522 } else if (lastWay.firstNode() == node || lastWay.lastNode() == node) { 523 for (int i = ptway.getWays().size() - 1; i >= 0; i--) { 524 oppositeNode = getOppositeEndNode(ptway.getWays().get(i), oppositeNode); 525 } 526 return oppositeNode; 527 } 528 529 return null; 530 531 } 532 533 /** 534 * Finds the next ways for the route stop-by-stop parsing procedure 535 * 536 * @param currentWay current way 537 * @param nextNodeInDirectionOfTravel next node in direction of travel 538 * @return the next ways for the route stop-by-stop parsing procedure 539 */ 540 private List<PTWay> findNextPTWaysInDirectionOfTravel(PTWay currentWay, Node nextNodeInDirectionOfTravel) { 541 542 List<PTWay> nextPtways = new ArrayList<>(); 543 544 List<PTWay> ptways = manager.getPTWays(); 545 546 for (PTWay ptway : ptways) { 547 548 if (ptway != currentWay) { 549 for (Way way : ptway.getWays()) { 550 if (way.containsNode(nextNodeInDirectionOfTravel)) { 551 nextPtways.add(ptway); 552 } 553 } 554 } 555 } 556 557 return nextPtways; 558 559 } 560 561 protected static boolean isFixable(TestError testError) { 562 563 /*- 564 * When is an error fixable (outdated)? 565 * - if there is a correct segment 566 * - if it can be fixed by sorting 567 * - if the route is compete even without some ways 568 * - if simple routing closes the gap 569 */ 570 571 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_STOP_BY_STOP) { 572 return true; 573 } 574 575 return false; 576 577 } 578 579 @SuppressWarnings("unused") 580 private static boolean isFixableByUsingCorrectSegment(TestError testError) { 581 PTRouteSegment wrongSegment = wrongSegments.get(testError); 582 PTRouteSegment correctSegment = null; 583 for (PTRouteSegment segment : correctSegments) { 584 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 585 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 586 correctSegment = segment; 587 break; 588 } 589 } 590 return correctSegment != null; 591 } 592 593 @SuppressWarnings("unused") 594 private static boolean isFixableBySortingAndRemoval(TestError testError) { 595 PTRouteSegment wrongSegment = wrongSegments.get(testError); 596 List<List<PTWay>> fixVariants = wrongSegment.getFixVariants(); 597 if (!fixVariants.isEmpty()) { 598 return true; 599 } 600 return false; 601 } 602 603 /** 604 * Finds fixes using sorting and removal. Modifies the messages in the test 605 * error according to the availability of automatic fixes. 606 */ 607 protected void findFixes() { 608 609 for (TestError error : wrongSegments.keySet()) { 610 // look for fixes using sorting and removing: 611 findFix(error); 612 613 // change the error code based on the availability of fixes: 614 PTRouteSegment wrongSegment = wrongSegments.get(error); 615 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 616 for (PTRouteSegment segment : correctSegments) { 617 if (wrongSegment.getFirstWay().getId() == segment.getFirstWay().getId() 618 && wrongSegment.getLastWay().getId() == segment.getLastWay().getId()) { 619 correctSegmentsForThisError.add(segment); 620 } 621 } 622 623 int numberOfFixes = correctSegmentsForThisError.size(); 624 625 if (numberOfFixes == 0) { 626 numberOfFixes = wrongSegment.getFixVariants().size(); 627 } 628 if (numberOfFixes == 0) { 629 for (PTRouteSegment segment : correctSegments) { 630 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 631 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 632 correctSegmentsForThisError.add(segment); 633 } 634 } 635 numberOfFixes = correctSegmentsForThisError.size(); 636 } 637 638 // change the error code: 639 if (numberOfFixes == 0) { 640 error.setMessage(tr("PT: Problem in the route segment with no automatic fix")); 641 } else if (numberOfFixes == 1) { 642 error.setMessage(tr("PT: Problem in the route segment with one automatic fix")); 643 } else { 644 error.setMessage("PT: Problem in the route segment with several automatic fixes"); 645 } 646 } 647 648 } 649 650 /** 651 * This method assumes that the first and the second ways of the route 652 * segment are correctly connected. If they are not, the error will be 653 * marked as not fixable. 654 * 655 * @param testError test error 656 */ 657 private void findFix(TestError testError) { 658 659 PTRouteSegment wrongSegment = wrongSegments.get(testError); 660 PTWay startPTWay = wrongSegment.getFirstPTWay(); 661 PTWay endPTWay = wrongSegment.getLastPTWay(); 662 663 Node previousNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(startPTWay); 664 if (previousNode == null) { 665 return; 666 } 667 668 List<List<PTWay>> initialFixes = new ArrayList<>(); 669 List<PTWay> initialFix = new ArrayList<>(); 670 initialFix.add(startPTWay); 671 initialFixes.add(initialFix); 672 673 List<List<PTWay>> allFixes = findWaysForFix(initialFixes, initialFix, previousNode, endPTWay); 674 for (List<PTWay> fix : allFixes) { 675 if (!fix.isEmpty() && fix.get(fix.size() - 1).equals(endPTWay)) { 676 wrongSegment.addFixVariant(fix); 677 } 678 } 679 680 } 681 682 /** 683 * Recursive method to parse the route segment 684 * 685 * @param allFixes all fixes 686 * @param currentFix current fix 687 * @param previousNode previous node 688 * @param endWay end way 689 * @return list of list of ways 690 */ 691 private List<List<PTWay>> findWaysForFix(List<List<PTWay>> allFixes, List<PTWay> currentFix, Node previousNode, 692 PTWay endWay) { 693 694 PTWay currentWay = currentFix.get(currentFix.size() - 1); 695 Node nextNode = getOppositeEndNode(currentWay, previousNode); 696 697 List<PTWay> nextWays = this.findNextPTWaysInDirectionOfTravel(currentWay, nextNode); 698 699 if (nextWays.size() > 1) { 700 for (int i = 1; i < nextWays.size(); i++) { 701 List<PTWay> newFix = new ArrayList<>(); 702 newFix.addAll(currentFix); 703 newFix.add(nextWays.get(i)); 704 allFixes.add(newFix); 705 if (!nextWays.get(i).equals(endWay) && !currentFix.contains(nextWays.get(i))) { 706 allFixes = findWaysForFix(allFixes, newFix, nextNode, endWay); 707 } 708 } 709 } 710 711 if (!nextWays.isEmpty()) { 712 boolean contains = currentFix.contains(nextWays.get(0)); 713 currentFix.add(nextWays.get(0)); 714 if (!nextWays.get(0).equals(endWay) && !contains) { 715 allFixes = findWaysForFix(allFixes, currentFix, nextNode, endWay); 716 } 717 } 718 719 return allFixes; 720 } 721 722 /** 723 * Fixes the error by first searching in the list of correct segments and 724 * then trying to sort and remove existing route relation members 725 * 726 * @param testError test error 727 * @return fix command 728 */ 729 protected static Command fixError(TestError testError) { 730 731 // if fix options for another route are displayed in the pt_assistant 732 // layer, clear them: 733 ((PTAssistantValidatorTest) testError.getTester()).clearFixVariants(); 734 735 PTRouteSegment wrongSegment = wrongSegments.get(testError); 736 737 // 1) try to fix by using the correct segment: 738 List<PTRouteSegment> correctSegmentsForThisError = new ArrayList<>(); 739 for (PTRouteSegment segment : correctSegments) { 740 if (wrongSegment.getFirstWay().getId() == segment.getFirstWay().getId() 741 && wrongSegment.getLastWay().getId() == segment.getLastWay().getId()) { 742 correctSegmentsForThisError.add(segment); 743 } 744 } 745 746 // if no correct segment found, apply less strict criteria to look for 747 // one: 748 if (correctSegmentsForThisError.isEmpty() && wrongSegment.getFixVariants().isEmpty()) { 749 for (PTRouteSegment segment : correctSegments) { 750 if (wrongSegment.getFirstStop().equalsStop(segment.getFirstStop()) 751 && wrongSegment.getLastStop().equalsStop(segment.getLastStop())) { 752 correctSegmentsForThisError.add(segment); 753 } 754 } 755 if (!correctSegmentsForThisError.isEmpty()) { 756 // display the notification: 757 if (SwingUtilities.isEventDispatchThread()) { 758 Notification notification = new Notification( 759 tr("Warning: the diplayed fix variants are based on less strict criteria")); 760 notification.show(); 761 } else { 762 SwingUtilities.invokeLater(new Runnable() { 763 @Override 764 public void run() { 765 Notification notification = new Notification( 766 tr("Warning: the diplayed fix variants are based on less strict criteria")); 767 notification.show(); 768 } 769 }); 770 } 771 } 772 } 773 774 if (!correctSegmentsForThisError.isEmpty()) { 775 776 if (correctSegmentsForThisError.size() > 1) { 777 List<List<PTWay>> fixVariants = new ArrayList<>(); 778 for (PTRouteSegment segment : correctSegmentsForThisError) { 779 fixVariants.add(segment.getPTWays()); 780 } 781 displayFixVariants(fixVariants, testError); 782 return null; 783 } 784 785 PTAssistantPlugin.setLastFix(correctSegmentsForThisError.get(0)); 786 return carryOutSingleFix(testError, correctSegmentsForThisError.get(0).getPTWays()); 787 788 } else if (!wrongSegment.getFixVariants().isEmpty()) { 789 // 2) try to fix using the sorting and removal of existing ways 790 // of the wrong segment: 791 if (wrongSegment.getFixVariants().size() > 1) { 792 displayFixVariants(wrongSegment.getFixVariants(), testError); 793 return null; 794 } 795 796 PTAssistantPlugin.setLastFix(new PTRouteSegment(wrongSegment.getFirstStop(), 797 wrongSegment.getLastStop(), wrongSegment.getFixVariants().get(0), (Relation) testError.getPrimitives().iterator().next())); 798 return carryOutSingleFix(testError, wrongSegment.getFixVariants().get(0)); 799 } 800 801 // if there is no fix: 802 return fixErrorByZooming(testError); 803 804 } 805 806 /** 807 * This is largely a copy of the displayFixVariants() method, adapted for 808 * use with the key listener 809 * 810 * @param fixVariants fix variants 811 * @param testError test error 812 */ 813 private static void displayFixVariants(List<List<PTWay>> fixVariants, TestError testError) { 814 // find the letters of the fix variants: 815 char alphabet = 'A'; 816 final List<Character> allowedCharacters = new ArrayList<>(); 817 for (int i = 0; i < fixVariants.size(); i++) { 818 allowedCharacters.add(alphabet); 819 alphabet++; 820 } 821 822 // zoom to problem: 823 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 824 for (Object highlightedPrimitive : testError.getHighlighted()) { 825 waysToZoom.add((OsmPrimitive) highlightedPrimitive); 826 } 827 if (SwingUtilities.isEventDispatchThread()) { 828 AutoScaleAction.zoomTo(waysToZoom); 829 } else { 830 SwingUtilities.invokeLater(new Runnable() { 831 @Override 832 public void run() { 833 AutoScaleAction.zoomTo(waysToZoom); 834 } 835 }); 836 } 837 838 // display the fix variants: 839 final PTAssistantValidatorTest test = (PTAssistantValidatorTest) testError.getTester(); 840 test.addFixVariants(fixVariants); 841 PTAssistantLayer.getLayer().repaint((Relation) testError.getPrimitives().iterator().next()); 842 843 // prepare the variables for the key listener: 844 final TestError testErrorParameter = testError; 845 846 // add the key listener: 847 Main.map.mapView.requestFocus(); 848 Main.map.mapView.addKeyListener(new KeyListener() { 849 850 @Override 851 public void keyTyped(KeyEvent e) { 852 // TODO Auto-generated method stub 853 } 854 855 @Override 856 public void keyPressed(KeyEvent e) { 857 Character typedKey = e.getKeyChar(); 858 Character typedKeyUpperCase = typedKey.toString().toUpperCase().toCharArray()[0]; 859 if (allowedCharacters.contains(typedKeyUpperCase)) { 860 Main.map.mapView.removeKeyListener(this); 861 List<PTWay> selectedFix = test.getFixVariant(typedKeyUpperCase); 862 test.clearFixVariants(); 863 carryOutSelectedFix(testErrorParameter, selectedFix); 864 } 865 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 866 Main.map.mapView.removeKeyListener(this); 867 test.clearFixVariants(); 868 } 869 } 870 871 @Override 872 public void keyReleased(KeyEvent e) { 873 // TODO Auto-generated method stub 874 } 875 }); 876 877 // display the notification: 878 if (SwingUtilities.isEventDispatchThread()) { 879 Notification notification = new Notification( 880 tr("Type letter to select the fix variant or press Escape for no fix")); 881 notification.show(); 882 } else { 883 SwingUtilities.invokeLater(new Runnable() { 884 @Override 885 public void run() { 886 Notification notification = new Notification( 887 tr("Type letter to select the fix variant or press Escape for no fix")); 888 notification.show(); 889 } 890 }); 891 } 892 } 893 894 /** 895 * Carries out the fix (i.e. modifies the route) after the user has picked 896 * the fix from several fix variants. 897 * 898 * @param testError 899 * test error to be fixed 900 * @param fix 901 * the fix variant to be adopted 902 */ 903 private static void carryOutSelectedFix(TestError testError, List<PTWay> fix) { 904 // modify the route: 905 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 906 Relation modifiedRelation = new Relation(originalRelation); 907 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 908 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 909 Main.main.undoRedo.addNoRedraw(changeCommand); 910 Main.main.undoRedo.afterAdd(); 911 PTRouteSegment wrongSegment = wrongSegments.get(testError); 912 wrongSegments.remove(testError); 913 wrongSegment.setPTWays(fix); 914 addCorrectSegment(wrongSegment); 915 PTAssistantPlugin.setLastFixNoGui(wrongSegment); 916 917 // get ways for the fix: 918 List<Way> primitives = new ArrayList<>(); 919 for (PTWay ptway : fix) { 920 primitives.addAll(ptway.getWays()); 921 } 922 923 // get layer: 924 OsmDataLayer layer = null; 925 List<OsmDataLayer> listOfLayers = Main.getLayerManager().getLayersOfType(OsmDataLayer.class); 926 for (OsmDataLayer osmDataLayer : listOfLayers) { 927 if (osmDataLayer.data == originalRelation.getDataSet()) { 928 layer = osmDataLayer; 929 break; 930 } 931 } 932 933 // create editor: 934 GenericRelationEditor editor = (GenericRelationEditor) RelationEditor.getEditor(layer, originalRelation, 935 originalRelation.getMembersFor(primitives)); 936 937 // open editor: 938 editor.setVisible(true); 939 940 } 941 942 /** 943 * Carries out the fix (i.e. modifies the route) when there is only one fix 944 * variant. 945 * 946 * @param testError test error 947 * @param fix fix 948 */ 949 private static Command carryOutSingleFix(TestError testError, List<PTWay> fix) { 950 // Zoom to the problematic ways: 951 final Collection<OsmPrimitive> waysToZoom = new ArrayList<>(); 952 for (Object highlightedPrimitive : testError.getHighlighted()) { 953 waysToZoom.add((OsmPrimitive) highlightedPrimitive); 954 } 955 if (SwingUtilities.isEventDispatchThread()) { 956 AutoScaleAction.zoomTo(waysToZoom); 957 } else { 958 SwingUtilities.invokeLater(new Runnable() { 959 @Override 960 public void run() { 961 AutoScaleAction.zoomTo(waysToZoom); 962 } 963 }); 964 } 965 966 // wait: 967 synchronized (SegmentChecker.class) { 968 try { 969 SegmentChecker.class.wait(1500); 970 } catch (InterruptedException e) { 971 // TODO Auto-generated catch block 972 e.printStackTrace(); 973 } 974 } 975 976 // modify the route: 977 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 978 Relation modifiedRelation = new Relation(originalRelation); 979 modifiedRelation.setMembers(getModifiedRelationMembers(testError, fix)); 980 wrongSegments.remove(testError); 981 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 982 return changeCommand; 983 } 984 985 /** 986 * Returns a list of the modified relation members. This list can be used by 987 * the calling method (relation.setMemers()) to modify the modify the route 988 * relation. The route relation is not modified by this method. The lists of 989 * wrong and correct segments are not updated. 990 * 991 * @param testError 992 * test error to be fixed 993 * @param fix 994 * the fix variant to be adopted 995 * @return List of modified relation members to be applied to the route 996 * relation 997 */ 998 private static List<RelationMember> getModifiedRelationMembers(TestError testError, List<PTWay> fix) { 999 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1000 Relation originalRelation = (Relation) testError.getPrimitives().iterator().next(); 1001 1002 // copy stops first: 1003 List<RelationMember> modifiedRelationMembers = listStopMembers(originalRelation); 1004 1005 // copy PTWays last: 1006 List<RelationMember> waysOfOriginalRelation = listNotStopMembers(originalRelation); 1007 for (int i = 0; i < waysOfOriginalRelation.size(); i++) { 1008 if (waysOfOriginalRelation.get(i).getWay() == wrongSegment.getPTWays().get(0).getWays().get(0)) { 1009 modifiedRelationMembers.addAll(fix); 1010 i = i + wrongSegment.getPTWays().size() - 1; 1011 } else { 1012 modifiedRelationMembers.add(waysOfOriginalRelation.get(i)); 1013 } 1014 } 1015 1016 return modifiedRelationMembers; 1017 } 1018 1019 public static void carryOutRepeatLastFix(PTRouteSegment segment) { 1020 1021 List<TestError> wrongSegmentsToRemove = new ArrayList<>(); 1022 1023 // find all wrong ways that have the same segment: 1024 for (TestError testError: wrongSegments.keySet()) { 1025 PTRouteSegment wrongSegment = wrongSegments.get(testError); 1026 if (wrongSegment.getFirstWay() == segment.getFirstWay() && wrongSegment.getLastWay() == segment.getLastWay()) { 1027 // modify the route: 1028 Relation originalRelation = wrongSegment.getRelation(); 1029 Relation modifiedRelation = new Relation(originalRelation); 1030 modifiedRelation.setMembers(getModifiedRelationMembers(testError, segment.getPTWays())); 1031 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 1032 Main.main.undoRedo.addNoRedraw(changeCommand); 1033 Main.main.undoRedo.afterAdd(); 1034 wrongSegmentsToRemove.add(testError); 1035 } 1036 } 1037 1038 // update the errors displayed in the validator dialog: 1039 List<TestError> modifiedValidatorTestErrors = new ArrayList<>(); 1040 for (TestError validatorTestError: Main.map.validatorDialog.tree.getErrors()) { 1041 if (!wrongSegmentsToRemove.contains(validatorTestError)) { 1042 modifiedValidatorTestErrors.add(validatorTestError); 1043 } 1044 } 1045 Main.map.validatorDialog.tree.setErrors(modifiedValidatorTestErrors); 1046 1047 // update wrong segments: 1048 for (TestError testError: wrongSegmentsToRemove) { 1049 wrongSegments.remove(testError); 1050 } 1051 1052 } 1053 1054 /** 1055 * Resets the static list variables (used for unit testing) 1056 */ 1057 protected static void reset() { 1058 correctSegments.clear(); 1059 wrongSegments.clear(); 1060 } 1065 1061 1066 1062 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/StopChecker.java
r32990 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 17 18 /** 18 19 * Performs tests of the stop area relations 19 * 20 * 20 21 * @author 21 22 * … … 23 24 public class StopChecker extends Checker { 24 25 25 26 Set<OsmPrimitive> members; 26 27 27 28 28 protected StopChecker(Relation relation, Test test) { 29 super(relation, test); 29 30 30 31 31 this.members = relation.getMemberPrimitives(); 32 } 32 33 33 34 35 36 34 /** 35 * Checks if the given stop area relation has a stop position. 36 */ 37 protected void performStopAreaStopPositionTest() { 37 38 38 39 40 41 42 43 39 // No errors if there is a member tagged as stop position. 40 for (OsmPrimitive member : members) { 41 if (StopUtils.verifyStopAreaStopPosition(member)) { 42 return; 43 } 44 } 44 45 45 46 47 48 49 50 51 46 // Throw error message 47 List<OsmPrimitive> primitives = new ArrayList<>(1); 48 primitives.add(relation); 49 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop area relation has no stop position"), 50 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_STOPS, primitives); 51 errors.add(e); 52 } 52 53 53 54 55 56 54 /** 55 * Checks if the given stop area relation has a platform. 56 */ 57 protected void performStopAreaPlatformTest() { 57 58 58 59 60 61 62 63 59 // No errors if there is a member tagged as platform. 60 for (OsmPrimitive member : members) { 61 if (StopUtils.verifyStopAreaPlatform(member)) { 62 return; 63 } 64 } 64 65 65 66 67 68 69 70 66 // Throw error message 67 List<OsmPrimitive> primitives = new ArrayList<>(1); 68 primitives.add(relation); 69 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop area relation has no platform"), 70 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_PLATFORM, primitives); 71 errors.add(e); 71 72 72 73 } 73 74 74 /** 75 * Checks if the stop_position(s) of an stop area belong to the same route 76 * relations as its related platform(s). 77 * 78 * @param n 79 */ 80 protected void performStopAreaRelationsTest() { 75 /** 76 * Checks if the stop_position(s) of an stop area belong to the same route 77 * relations as its related platform(s). 78 */ 79 protected void performStopAreaRelationsTest() { 81 80 82 83 81 HashMap<Long, Long> stopPositionRelationIds = new HashMap<>(); 82 HashMap<Long, Long> platformRelationIds = new HashMap<>(); 84 83 85 86 84 // Loop through all members 85 for (OsmPrimitive member : members) { 87 86 88 89 87 // For stop positions... 88 if (StopUtils.verifyStopAreaStopPosition(member)) { 90 89 91 // Create a list of assigned route relations 92 for (Relation referrer : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) { 93 if (referrer.get("type") == "route") { 94 stopPositionRelationIds.put(referrer.getId(), referrer.getId()); 95 } 96 } 97 } 90 // Create a list of assigned route relations 91 for (Relation referrer : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) { 92 if (referrer.get("type") == "route") { 93 stopPositionRelationIds.put(referrer.getId(), referrer.getId()); 94 } 95 } 96 // For platforms... 97 } else if (StopUtils.verifyStopAreaPlatform(member)) { 98 98 99 // For platforms... 100 else if (StopUtils.verifyStopAreaPlatform(member)) { 99 // Create a list of assigned route relations 100 for (Relation referrer : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) { 101 if (referrer.get("type") == "route") { 102 platformRelationIds.put(referrer.getId(), referrer.getId()); 103 } 104 } 105 } 106 } 101 107 102 // Create a list of assigned route relations 103 for (Relation referrer : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) { 104 if (referrer.get("type") == "route") { 105 platformRelationIds.put(referrer.getId(), referrer.getId()); 106 } 107 } 108 } 109 } 108 // Check if the stop_position has no referrers at all. If it has no 109 // referrers, then no error should be reported (changed on 11.08.2016 by 110 // darya): 111 if (stopPositionRelationIds.isEmpty()) { 112 return; 113 } 110 114 111 // Check if the stop_position has no referrers at all. If it has no 112 // referrers, then no error should be reported (changed on 11.08.2016 by 113 // darya): 114 if (stopPositionRelationIds.isEmpty()) { 115 return; 116 } 115 // Check if route relation lists are identical 116 if (stopPositionRelationIds.equals(platformRelationIds)) { 117 return; 118 } 117 119 118 // Check if route relation lists are identical 119 if (stopPositionRelationIds.equals(platformRelationIds)) { 120 return; 121 } 122 123 // Throw error message 124 List<OsmPrimitive> primitives = new ArrayList<>(1); 125 primitives.add(relation); 126 TestError e = new TestError(this.test, Severity.WARNING, 127 tr("PT: Route relations of stop position(s) and platform(s) of stop area members diverge"), 128 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_COMPARE_RELATIONS, primitives); 129 errors.add(e); 130 } 120 // Throw error message 121 List<OsmPrimitive> primitives = new ArrayList<>(1); 122 primitives.add(relation); 123 TestError e = new TestError(this.test, Severity.WARNING, 124 tr("PT: Route relations of stop position(s) and platform(s) of stop area members diverge"), 125 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_COMPARE_RELATIONS, primitives); 126 errors.add(e); 127 } 131 128 132 129 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/WayChecker.java
r32784 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 25 26 * Performs tests of a route at the level of single ways: DirectionTest and 26 27 * RoadTypeTest 27 * 28 * 28 29 * @author darya 29 30 * … … 31 32 public class WayChecker extends Checker { 32 33 33 public WayChecker(Relation relation, Test test) { 34 35 super(relation, test); 36 37 } 38 39 protected void performRoadTypeTest() { 40 41 if (!relation.hasTag("route", "bus") && !relation.hasTag("route", "trolleybus") 42 && !relation.hasTag("route", "share_taxi")) { 43 return; 44 } 45 46 for (RelationMember rm : relation.getMembers()) { 47 if (RouteUtils.isPTWay(rm) && rm.getType().equals(OsmPrimitiveType.WAY)) { 48 49 Way way = rm.getWay(); 50 // at this point, the relation has already been checked to 51 // be a route of public_transport:version 2 52 53 boolean isCorrectRoadType = true; 54 boolean isUnderConstruction = false; 55 if (way.hasKey("construction")) { 56 isUnderConstruction = true; 57 } 58 if (relation.hasTag("route", "bus") || relation.hasTag("route", "share_taxi")) { 59 if (!RouteUtils.isWaySuitableForBuses(way)) { 60 isCorrectRoadType = false; 61 } 62 if (way.hasTag("highway", "construction")) { 63 isUnderConstruction = true; 64 } 65 } else if (relation.hasTag("route", "trolleybus")) { 66 if (!(RouteUtils.isWaySuitableForBuses(way) && way.hasTag("trolley_wire", "yes"))) { 67 isCorrectRoadType = false; 68 } 69 if (way.hasTag("highway", "construction")) { 70 isUnderConstruction = true; 71 } 72 } else if (relation.hasTag("route", "tram")) { 73 if (!way.hasTag("railway", "tram")) { 74 isCorrectRoadType = false; 75 } 76 if (way.hasTag("railway", "construction")) { 77 isUnderConstruction = true; 78 } 79 } else if (relation.hasTag("route", "subway")) { 80 if (!way.hasTag("railway", "subway")) { 81 isCorrectRoadType = false; 82 } 83 if (way.hasTag("railway", "construction")) { 84 isUnderConstruction = true; 85 } 86 } else if (relation.hasTag("route", "light_rail")) { 87 if (!way.hasTag("railway", "subway")) { 88 isCorrectRoadType = false; 89 } 90 if (way.hasTag("railway", "construction")) { 91 isUnderConstruction = true; 92 } 93 } else if (relation.hasTag("route", "light_rail")) { 94 if (!way.hasTag("railway", "light_rail")) { 95 isCorrectRoadType = false; 96 } 97 if (way.hasTag("railway", "construction")) { 98 isUnderConstruction = true; 99 } 100 } else if (relation.hasTag("route", "train")) { 101 if (!way.hasTag("railway", "rail")) { 102 isCorrectRoadType = false; 103 } 104 if (way.hasTag("railway", "construction")) { 105 isUnderConstruction = true; 106 } 107 } 108 109 if (!isCorrectRoadType && !isUnderConstruction) { 110 111 List<Relation> primitives = new ArrayList<>(1); 112 primitives.add(relation); 113 List<Way> highlighted = new ArrayList<>(1); 114 highlighted.add(way); 115 TestError e = new TestError(this.test, Severity.WARNING, 116 tr("PT: Route type does not match the type of the road it passes on"), 117 PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE, primitives, highlighted); 118 errors.add(e); 119 120 } 121 122 if (isUnderConstruction) { 123 List<Relation> primitives = new ArrayList<>(1); 124 primitives.add(relation); 125 List<Way> highlighted = new ArrayList<>(1); 126 highlighted.add(way); 127 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Road is under construction"), 128 PTAssistantValidatorTest.ERROR_CODE_CONSTRUCTION, primitives, highlighted); 129 errors.add(e); 130 } 131 } 132 } 133 134 } 135 136 protected void performDirectionTest() { 137 138 List<Way> waysToCheck = new ArrayList<>(); 139 140 for (RelationMember rm : relation.getMembers()) { 141 if (RouteUtils.isPTWay(rm)) { 142 if (rm.isWay()) { 143 waysToCheck.add(rm.getWay()); 144 } else { 145 Relation nestedRelation = rm.getRelation(); 146 for (RelationMember nestedRelationMember : nestedRelation.getMembers()) { 147 waysToCheck.add(nestedRelationMember.getWay()); 148 } 149 } 150 } 151 } 152 153 if (waysToCheck.size() <= 1) { 154 return; 155 } 156 157 List<Way> problematicWays = new ArrayList<>(); 158 159 for (int i = 0; i < waysToCheck.size(); i++) { 160 161 Way curr = waysToCheck.get(i); 162 163 if (i == 0) { 164 // first way: 165 Way next = waysToCheck.get(i + 1); 166 if (!touchCorrectly(null, curr, next)) { 167 problematicWays.add(curr); 168 } 169 170 } else if (i == waysToCheck.size() - 1) { 171 // last way: 172 Way prev = waysToCheck.get(i - 1); 173 if (!touchCorrectly(prev, curr, null)) { 174 problematicWays.add(curr); 175 } 176 177 } else { 178 // all other ways: 179 Way prev = waysToCheck.get(i - 1); 180 Way next = waysToCheck.get(i + 1); 181 if (!touchCorrectly(prev, curr, next)) { 182 problematicWays.add(curr); 183 } 184 } 185 } 186 187 List<Relation> primitives = new ArrayList<>(1); 188 primitives.add(this.relation); 189 190 List<Set<Way>> listOfSets = new ArrayList<>(); 191 for (Way problematicWay : problematicWays) { 192 Set<Way> primitivesToReport = new HashSet<>(); 193 primitivesToReport.add(problematicWay); 194 primitivesToReport.addAll(checkAdjacentWays(problematicWay, new HashSet<Way>())); 195 listOfSets.add(primitivesToReport); 196 } 197 198 boolean changed = true; 199 while (changed) { 200 changed = false; 201 for (int i = 0; i < listOfSets.size(); i++) { 202 for (int j = i; j < listOfSets.size(); j++) { 203 if (i != j && RouteUtils.waysTouch(listOfSets.get(i), listOfSets.get(j))) { 204 listOfSets.get(i).addAll(listOfSets.get(j)); 205 listOfSets.remove(j); 206 j = listOfSets.size(); 207 changed = true; 208 } 209 } 210 } 211 } 212 213 for (Set<Way> currentSet : listOfSets) { 214 TestError e = new TestError(this.test, Severity.WARNING, 215 tr("PT: Route passes a oneway road in the wrong direction"), 216 PTAssistantValidatorTest.ERROR_CODE_DIRECTION, primitives, currentSet); 217 this.errors.add(e); 218 } 219 220 } 221 222 /** 223 * Checks if the current way touches its neighboring ways correctly 224 * 225 * @param prev 226 * can be null 227 * @param curr 228 * cannot be null 229 * @param next 230 * can be null 231 * @return 232 */ 233 private boolean touchCorrectly(Way prev, Way curr, Way next) { 234 235 if (RouteUtils.isOnewayForPublicTransport(curr) == 0) { 236 return true; 237 } 238 239 if (prev != null) { 240 241 if (RouteUtils.waysTouch(curr, prev)) { 242 Node nodeInQuestion; 243 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 244 nodeInQuestion = curr.firstNode(); 245 } else { 246 nodeInQuestion = curr.lastNode(); 247 } 248 249 List<Way> nb = findNeighborWays(curr, nodeInQuestion); 250 251 if (nb.size() < 2 && nodeInQuestion != prev.firstNode() && nodeInQuestion != prev.lastNode()) { 252 return false; 253 } 254 } 255 } 256 257 if (next != null) { 258 259 if (RouteUtils.waysTouch(curr, next)) { 260 Node nodeInQuestion; 261 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 262 nodeInQuestion = curr.lastNode(); 263 } else { 264 nodeInQuestion = curr.firstNode(); 265 } 266 267 List<Way> nb = findNeighborWays(curr, nodeInQuestion); 268 269 if (nb.size() < 2 && nodeInQuestion != next.firstNode() && nodeInQuestion != next.lastNode()) { 270 return false; 271 } 272 } 273 } 274 275 return true; 276 277 } 278 279 protected Set<Way> checkAdjacentWays(Way curr, Set<Way> flags) { 280 // curr is supposed to be a wrong oneway way!! 281 282 Set<Way> resultSet = new HashSet<>(); 283 resultSet.addAll(flags); 284 resultSet.add(curr); 285 286 if (RouteUtils.isOnewayForPublicTransport(curr) == 0) { 287 return null; 288 } 289 290 Node firstNodeInRouteDirection; 291 Node lastNodeInRouteDirection; 292 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 293 firstNodeInRouteDirection = curr.lastNode(); 294 lastNodeInRouteDirection = curr.firstNode(); 295 } else { 296 firstNodeInRouteDirection = curr.firstNode(); 297 lastNodeInRouteDirection = curr.lastNode(); 298 } 299 300 List<Way> firstNodeInRouteDirectionNeighbors = findNeighborWays(curr, firstNodeInRouteDirection); 301 List<Way> lastNodeInRouteDirectionNeighbors = findNeighborWays(curr, lastNodeInRouteDirection); 302 303 for (Way nb : firstNodeInRouteDirectionNeighbors) { 304 305 if (resultSet.contains(nb)) { 306 continue; 307 } 308 309 if (RouteUtils.isOnewayForPublicTransport(nb) == 1 && nb.firstNode() == firstNodeInRouteDirection) { 310 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 311 resultSet.addAll(newSet); 312 313 } else if (RouteUtils.isOnewayForPublicTransport(nb) == -1 && nb.lastNode() == firstNodeInRouteDirection) { 314 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 315 resultSet.addAll(newSet); 316 317 } 318 } 319 320 for (Way nb : lastNodeInRouteDirectionNeighbors) { 321 322 if (resultSet.contains(nb)) { 323 continue; 324 } 325 326 if (RouteUtils.isOnewayForPublicTransport(nb) == 1 && nb.lastNode() == lastNodeInRouteDirection) { 327 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 328 resultSet.addAll(newSet); 329 } else if (RouteUtils.isOnewayForPublicTransport(nb) == -1 && nb.firstNode() == lastNodeInRouteDirection) { 330 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 331 resultSet.addAll(newSet); 332 } 333 334 } 335 336 return resultSet; 337 338 } 339 340 /** 341 * Finds all ways that touch the given way at the given node AND belong to 342 * the relation of this WayChecker 343 * 344 * @param way 345 * @param node 346 * @return 347 */ 348 private List<Way> findNeighborWays(Way way, Node node) { 349 350 List<Way> resultList = new ArrayList<>(); 351 352 List<OsmPrimitive> nodeReferrers = node.getReferrers(); 353 354 for (OsmPrimitive referrer : nodeReferrers) { 355 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 356 Way neighborWay = (Way) referrer; 357 if (neighborWay != way && containsWay(neighborWay)) { 358 resultList.add(neighborWay); 359 } 360 } 361 } 362 363 return resultList; 364 } 365 366 /** 367 * Checks if the relation of this WayChecker contains the given way 368 * 369 * @param way 370 * @return 371 */ 372 private boolean containsWay(Way way) { 373 374 List<RelationMember> members = relation.getMembers(); 375 376 for (RelationMember rm : members) { 377 if (rm.isWay() && rm.getWay() == way) { 378 return true; 379 } 380 } 381 382 return false; 383 384 } 385 386 protected static Command fixErrorByRemovingWay(TestError testError) { 387 388 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE 389 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_DIRECTION) { 390 return null; 391 } 392 393 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 394 Relation originalRelation = (Relation) primitives.iterator().next(); 395 Collection<?> highlighted = testError.getHighlighted(); 396 Way wayToRemove = (Way) highlighted.iterator().next(); 397 398 Relation modifiedRelation = new Relation(originalRelation); 399 List<RelationMember> modifiedRelationMembers = new ArrayList<>(originalRelation.getMembersCount() - 1); 400 401 // copy PT stops first, PT ways last: 402 for (RelationMember rm : originalRelation.getMembers()) { 403 if (RouteUtils.isPTStop(rm)) { 404 405 if (rm.getRole().equals("stop_position")) { 406 if (rm.getType().equals(OsmPrimitiveType.NODE)) { 407 RelationMember newMember = new RelationMember("stop", rm.getNode()); 408 modifiedRelationMembers.add(newMember); 409 } else { // if it is a way: 410 RelationMember newMember = new RelationMember("stop", rm.getWay()); 411 modifiedRelationMembers.add(newMember); 412 } 413 } else { 414 // if the relation member does not have the role 415 // "stop_position": 416 modifiedRelationMembers.add(rm); 417 } 418 419 } 420 } 421 422 // now copy PT ways: 423 for (RelationMember rm : originalRelation.getMembers()) { 424 if (RouteUtils.isPTWay(rm)) { 425 Way wayToCheck = rm.getWay(); 426 if (wayToCheck != wayToRemove) { 427 if (rm.getRole().equals("forward") || rm.getRole().equals("backward")) { 428 RelationMember modifiedMember = new RelationMember("", wayToCheck); 429 modifiedRelationMembers.add(modifiedMember); 430 } else { 431 modifiedRelationMembers.add(rm); 432 } 433 } 434 } 435 } 436 437 modifiedRelation.setMembers(modifiedRelationMembers); 438 439 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 440 441 return changeCommand; 442 } 34 public WayChecker(Relation relation, Test test) { 35 36 super(relation, test); 37 38 } 39 40 protected void performRoadTypeTest() { 41 42 if (!relation.hasTag("route", "bus") && !relation.hasTag("route", "trolleybus") 43 && !relation.hasTag("route", "share_taxi")) { 44 return; 45 } 46 47 for (RelationMember rm : relation.getMembers()) { 48 if (RouteUtils.isPTWay(rm) && rm.getType().equals(OsmPrimitiveType.WAY)) { 49 50 Way way = rm.getWay(); 51 // at this point, the relation has already been checked to 52 // be a route of public_transport:version 2 53 54 boolean isCorrectRoadType = true; 55 boolean isUnderConstruction = false; 56 if (way.hasKey("construction")) { 57 isUnderConstruction = true; 58 } 59 if (relation.hasTag("route", "bus") || relation.hasTag("route", "share_taxi")) { 60 if (!RouteUtils.isWaySuitableForBuses(way)) { 61 isCorrectRoadType = false; 62 } 63 if (way.hasTag("highway", "construction")) { 64 isUnderConstruction = true; 65 } 66 } else if (relation.hasTag("route", "trolleybus")) { 67 if (!(RouteUtils.isWaySuitableForBuses(way) && way.hasTag("trolley_wire", "yes"))) { 68 isCorrectRoadType = false; 69 } 70 if (way.hasTag("highway", "construction")) { 71 isUnderConstruction = true; 72 } 73 } else if (relation.hasTag("route", "tram")) { 74 if (!way.hasTag("railway", "tram")) { 75 isCorrectRoadType = false; 76 } 77 if (way.hasTag("railway", "construction")) { 78 isUnderConstruction = true; 79 } 80 } else if (relation.hasTag("route", "subway")) { 81 if (!way.hasTag("railway", "subway")) { 82 isCorrectRoadType = false; 83 } 84 if (way.hasTag("railway", "construction")) { 85 isUnderConstruction = true; 86 } 87 } else if (relation.hasTag("route", "light_rail")) { 88 if (!way.hasTag("railway", "subway")) { 89 isCorrectRoadType = false; 90 } 91 if (way.hasTag("railway", "construction")) { 92 isUnderConstruction = true; 93 } 94 } else if (relation.hasTag("route", "light_rail")) { 95 if (!way.hasTag("railway", "light_rail")) { 96 isCorrectRoadType = false; 97 } 98 if (way.hasTag("railway", "construction")) { 99 isUnderConstruction = true; 100 } 101 } else if (relation.hasTag("route", "train")) { 102 if (!way.hasTag("railway", "rail")) { 103 isCorrectRoadType = false; 104 } 105 if (way.hasTag("railway", "construction")) { 106 isUnderConstruction = true; 107 } 108 } 109 110 if (!isCorrectRoadType && !isUnderConstruction) { 111 112 List<Relation> primitives = new ArrayList<>(1); 113 primitives.add(relation); 114 List<Way> highlighted = new ArrayList<>(1); 115 highlighted.add(way); 116 TestError e = new TestError(this.test, Severity.WARNING, 117 tr("PT: Route type does not match the type of the road it passes on"), 118 PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE, primitives, highlighted); 119 errors.add(e); 120 121 } 122 123 if (isUnderConstruction) { 124 List<Relation> primitives = new ArrayList<>(1); 125 primitives.add(relation); 126 List<Way> highlighted = new ArrayList<>(1); 127 highlighted.add(way); 128 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Road is under construction"), 129 PTAssistantValidatorTest.ERROR_CODE_CONSTRUCTION, primitives, highlighted); 130 errors.add(e); 131 } 132 } 133 } 134 135 } 136 137 protected void performDirectionTest() { 138 139 List<Way> waysToCheck = new ArrayList<>(); 140 141 for (RelationMember rm : relation.getMembers()) { 142 if (RouteUtils.isPTWay(rm)) { 143 if (rm.isWay()) { 144 waysToCheck.add(rm.getWay()); 145 } else { 146 Relation nestedRelation = rm.getRelation(); 147 for (RelationMember nestedRelationMember : nestedRelation.getMembers()) { 148 waysToCheck.add(nestedRelationMember.getWay()); 149 } 150 } 151 } 152 } 153 154 if (waysToCheck.size() <= 1) { 155 return; 156 } 157 158 List<Way> problematicWays = new ArrayList<>(); 159 160 for (int i = 0; i < waysToCheck.size(); i++) { 161 162 Way curr = waysToCheck.get(i); 163 164 if (i == 0) { 165 // first way: 166 Way next = waysToCheck.get(i + 1); 167 if (!touchCorrectly(null, curr, next)) { 168 problematicWays.add(curr); 169 } 170 171 } else if (i == waysToCheck.size() - 1) { 172 // last way: 173 Way prev = waysToCheck.get(i - 1); 174 if (!touchCorrectly(prev, curr, null)) { 175 problematicWays.add(curr); 176 } 177 178 } else { 179 // all other ways: 180 Way prev = waysToCheck.get(i - 1); 181 Way next = waysToCheck.get(i + 1); 182 if (!touchCorrectly(prev, curr, next)) { 183 problematicWays.add(curr); 184 } 185 } 186 } 187 188 List<Relation> primitives = new ArrayList<>(1); 189 primitives.add(this.relation); 190 191 List<Set<Way>> listOfSets = new ArrayList<>(); 192 for (Way problematicWay : problematicWays) { 193 Set<Way> primitivesToReport = new HashSet<>(); 194 primitivesToReport.add(problematicWay); 195 primitivesToReport.addAll(checkAdjacentWays(problematicWay, new HashSet<Way>())); 196 listOfSets.add(primitivesToReport); 197 } 198 199 boolean changed = true; 200 while (changed) { 201 changed = false; 202 for (int i = 0; i < listOfSets.size(); i++) { 203 for (int j = i; j < listOfSets.size(); j++) { 204 if (i != j && RouteUtils.waysTouch(listOfSets.get(i), listOfSets.get(j))) { 205 listOfSets.get(i).addAll(listOfSets.get(j)); 206 listOfSets.remove(j); 207 j = listOfSets.size(); 208 changed = true; 209 } 210 } 211 } 212 } 213 214 for (Set<Way> currentSet : listOfSets) { 215 TestError e = new TestError(this.test, Severity.WARNING, 216 tr("PT: Route passes a oneway road in the wrong direction"), 217 PTAssistantValidatorTest.ERROR_CODE_DIRECTION, primitives, currentSet); 218 this.errors.add(e); 219 } 220 221 } 222 223 /** 224 * Checks if the current way touches its neighboring ways correctly 225 * 226 * @param prev 227 * can be null 228 * @param curr 229 * cannot be null 230 * @param next 231 * can be null 232 * @return {@code true} if the current way touches its neighboring ways correctly 233 */ 234 private boolean touchCorrectly(Way prev, Way curr, Way next) { 235 236 if (RouteUtils.isOnewayForPublicTransport(curr) == 0) { 237 return true; 238 } 239 240 if (prev != null) { 241 242 if (RouteUtils.waysTouch(curr, prev)) { 243 Node nodeInQuestion; 244 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 245 nodeInQuestion = curr.firstNode(); 246 } else { 247 nodeInQuestion = curr.lastNode(); 248 } 249 250 List<Way> nb = findNeighborWays(curr, nodeInQuestion); 251 252 if (nb.size() < 2 && nodeInQuestion != prev.firstNode() && nodeInQuestion != prev.lastNode()) { 253 return false; 254 } 255 } 256 } 257 258 if (next != null) { 259 260 if (RouteUtils.waysTouch(curr, next)) { 261 Node nodeInQuestion; 262 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 263 nodeInQuestion = curr.lastNode(); 264 } else { 265 nodeInQuestion = curr.firstNode(); 266 } 267 268 List<Way> nb = findNeighborWays(curr, nodeInQuestion); 269 270 if (nb.size() < 2 && nodeInQuestion != next.firstNode() && nodeInQuestion != next.lastNode()) { 271 return false; 272 } 273 } 274 } 275 276 return true; 277 278 } 279 280 protected Set<Way> checkAdjacentWays(Way curr, Set<Way> flags) { 281 // curr is supposed to be a wrong oneway way!! 282 283 Set<Way> resultSet = new HashSet<>(); 284 resultSet.addAll(flags); 285 resultSet.add(curr); 286 287 if (RouteUtils.isOnewayForPublicTransport(curr) == 0) { 288 return null; 289 } 290 291 Node firstNodeInRouteDirection; 292 Node lastNodeInRouteDirection; 293 if (RouteUtils.isOnewayForPublicTransport(curr) == 1) { 294 firstNodeInRouteDirection = curr.lastNode(); 295 lastNodeInRouteDirection = curr.firstNode(); 296 } else { 297 firstNodeInRouteDirection = curr.firstNode(); 298 lastNodeInRouteDirection = curr.lastNode(); 299 } 300 301 List<Way> firstNodeInRouteDirectionNeighbors = findNeighborWays(curr, firstNodeInRouteDirection); 302 List<Way> lastNodeInRouteDirectionNeighbors = findNeighborWays(curr, lastNodeInRouteDirection); 303 304 for (Way nb : firstNodeInRouteDirectionNeighbors) { 305 306 if (resultSet.contains(nb)) { 307 continue; 308 } 309 310 if (RouteUtils.isOnewayForPublicTransport(nb) == 1 && nb.firstNode() == firstNodeInRouteDirection) { 311 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 312 resultSet.addAll(newSet); 313 314 } else if (RouteUtils.isOnewayForPublicTransport(nb) == -1 && nb.lastNode() == firstNodeInRouteDirection) { 315 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 316 resultSet.addAll(newSet); 317 318 } 319 } 320 321 for (Way nb : lastNodeInRouteDirectionNeighbors) { 322 323 if (resultSet.contains(nb)) { 324 continue; 325 } 326 327 if (RouteUtils.isOnewayForPublicTransport(nb) == 1 && nb.lastNode() == lastNodeInRouteDirection) { 328 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 329 resultSet.addAll(newSet); 330 } else if (RouteUtils.isOnewayForPublicTransport(nb) == -1 && nb.firstNode() == lastNodeInRouteDirection) { 331 Set<Way> newSet = this.checkAdjacentWays(nb, resultSet); 332 resultSet.addAll(newSet); 333 } 334 335 } 336 337 return resultSet; 338 339 } 340 341 /** 342 * Finds all ways that touch the given way at the given node AND belong to 343 * the relation of this WayChecker 344 * 345 * @param way way 346 * @param node node 347 * @return all ways that touch the given way at the given node AND belong to 348 * the relation of this WayChecker 349 */ 350 private List<Way> findNeighborWays(Way way, Node node) { 351 352 List<Way> resultList = new ArrayList<>(); 353 354 List<OsmPrimitive> nodeReferrers = node.getReferrers(); 355 356 for (OsmPrimitive referrer : nodeReferrers) { 357 if (referrer.getType().equals(OsmPrimitiveType.WAY)) { 358 Way neighborWay = (Way) referrer; 359 if (neighborWay != way && containsWay(neighborWay)) { 360 resultList.add(neighborWay); 361 } 362 } 363 } 364 365 return resultList; 366 } 367 368 /** 369 * Checks if the relation of this WayChecker contains the given way 370 * 371 * @param way way 372 * @return {@code true} if the relation of this WayChecker contains the given way 373 */ 374 private boolean containsWay(Way way) { 375 376 List<RelationMember> members = relation.getMembers(); 377 378 for (RelationMember rm : members) { 379 if (rm.isWay() && rm.getWay() == way) { 380 return true; 381 } 382 } 383 384 return false; 385 386 } 387 388 protected static Command fixErrorByRemovingWay(TestError testError) { 389 390 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE 391 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_DIRECTION) { 392 return null; 393 } 394 395 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 396 Relation originalRelation = (Relation) primitives.iterator().next(); 397 Collection<?> highlighted = testError.getHighlighted(); 398 Way wayToRemove = (Way) highlighted.iterator().next(); 399 400 Relation modifiedRelation = new Relation(originalRelation); 401 List<RelationMember> modifiedRelationMembers = new ArrayList<>(originalRelation.getMembersCount() - 1); 402 403 // copy PT stops first, PT ways last: 404 for (RelationMember rm : originalRelation.getMembers()) { 405 if (RouteUtils.isPTStop(rm)) { 406 407 if (rm.getRole().equals("stop_position")) { 408 if (rm.getType().equals(OsmPrimitiveType.NODE)) { 409 RelationMember newMember = new RelationMember("stop", rm.getNode()); 410 modifiedRelationMembers.add(newMember); 411 } else { // if it is a way: 412 RelationMember newMember = new RelationMember("stop", rm.getWay()); 413 modifiedRelationMembers.add(newMember); 414 } 415 } else { 416 // if the relation member does not have the role 417 // "stop_position": 418 modifiedRelationMembers.add(rm); 419 } 420 421 } 422 } 423 424 // now copy PT ways: 425 for (RelationMember rm : originalRelation.getMembers()) { 426 if (RouteUtils.isPTWay(rm)) { 427 Way wayToCheck = rm.getWay(); 428 if (wayToCheck != wayToRemove) { 429 if (rm.getRole().equals("forward") || rm.getRole().equals("backward")) { 430 RelationMember modifiedMember = new RelationMember("", wayToCheck); 431 modifiedRelationMembers.add(modifiedMember); 432 } else { 433 modifiedRelationMembers.add(rm); 434 } 435 } 436 } 437 } 438 439 modifiedRelation.setMembers(modifiedRelationMembers); 440 441 ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation); 442 443 return changeCommand; 444 } 443 445 444 446 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/AbstractTest.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant; 2 3 … … 13 14 public abstract class AbstractTest { 14 15 15 public static final String PATH_TO_DL131_BEFORE = "test/data/DL131_before.osm"; // 16 public static final String PATH_TO_DL131_BEFORE = "test/data/DL131_before.osm"; // 16 17 public static final String PATH_TO_DL131_AFTER = "test/data/DL131_after.osm"; 17 18 18 19 public static final String PATH_TO_DL4_BEFORE = "test/data/DL4_before.osm"; 19 20 public static final String PATH_TO_DL4_AFTER = "test/data/DL4_after.osm"; 20 21 21 22 public static final String PATH_TO_DL49_BEFORE = "test/data/DL49_before.osm"; // has wrong way sorting 22 23 public static final String PATH_TO_DL49_AFTER = "test/data/DL49_after.osm"; 23 24 24 25 public static final String PATH_TO_DL60_BEFORE = "test/data/DL60_before.osm"; 25 26 public static final String PATH_TO_DL60_AFTER = "test/data/DL60_after.osm"; 26 27 27 28 public static final String PATH_TO_DL94_BEFORE = "test/data/DL94_before.osm"; 28 29 public static final String PATH_TO_DL94_AFTER = "test/data/DL94_after.osm"; 29 30 30 31 public static final String PATH_TO_DL286_BEFORE = "test/data/DL286_before.osm"; 31 32 public static final String PATH_TO_DL286_AFTER = "test/data/DL286_after.osm"; 32 33 33 34 public static final String PATH_TO_TEC366_BEFORE = "test/data/TL366_before.osm"; 34 35 public static final String PATH_TO_TEC366_AFTER = "test/data/TL366_after.osm"; 35 36 36 37 public static final String PATH_TO_PLATFORM_AS_WAY = "test/data/route-with-platform-as-way.osm"; 37 38 38 39 public static final String PATH_TO_ROUNDABOUT_ONEWAY = "test/data/duesseldorf_roundabout.osm"; 39 40 40 41 public static final String PATH_TO_ROAD_TYPE_ERROR = "test/data/road-type.osm"; 41 42 42 43 public static final String PATH_TO_ONEWAY_BAD_MEMBER_SORTING = "test/data/oneway-bad-member-sorting.osm"; 43 44 44 45 public static final String PATH_TO_ONEWAY_WRONG_DIRECTION = "test/data/oneway-wrong-direction.osm"; 45 46 public static final String PATH_TO_ONEWAY_WRONG_DIRECTION2 = "test/data/oneway-wrong-direction2.osm"; 46 47 47 48 public static final String PATH_TO_SOLITARY_STOP_POSITION = "test/data/solitary-stop-position.osm"; 48 49 … … 54 55 public static final String PATH_TO_STOP_AREA_MANY_PLATFORMS = "test/data/stop-area-many-platforms.osm"; 55 56 56 57 57 58 public static final String PATH_TO_SEGMENT_TEST = "test/data/segment-test.osm"; 58 59 -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/ImportUtils.java
r32506 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant; 2 3 /**4 * This class provides functionality used by multiple test classes of pt_assistant plugin.5 */6 3 7 4 import java.io.File; … … 18 15 import org.openstreetmap.josm.io.OsmImporter.OsmImporterData; 19 16 20 public class ImportUtils { 21 17 /** 18 * This class provides functionality used by multiple test classes of pt_assistant plugin. 19 */ 20 public final class ImportUtils { 21 22 22 private ImportUtils() { 23 23 // private constructor for utils classes … … 42 42 e.printStackTrace(); 43 43 } 44 44 45 45 return null; 46 47 46 } 48 49 50 51 47 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/TestUtil.java
r32883 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant; 2 3 … … 34 35 * That is needed e.g. to use {@link MapillaryLayer#getInstance()} 35 36 */ 36 public static finalsynchronized void initPlugin() {37 public static synchronized void initPlugin() { 37 38 if (!isInitialized) { 38 39 System.setProperty("josm.home", "test/data/preferences"); -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/data/RouteRepresentationTest.java
r32567 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 15 16 * Tests if the representation of a route relation is created correctly in the 16 17 * pt_assistant plugin 17 * 18 * 18 19 * @author darya 19 20 * 20 21 */ 21 22 public class RouteRepresentationTest extends AbstractTest { 22 23 23 24 @Test 24 25 public void correctRouteTest() { 25 26 26 27 /*- 27 28 * Create a [correct] route which has: … … 36 37 * way4 (Way) 37 38 * stop5 (platform_exit_only, Relation) 38 * 39 * 39 40 */ 40 41 41 42 ArrayList<RelationMember> members = new ArrayList<>(); 42 43 43 44 // Create stops: 44 Node n1 = new Node(); 45 Node n1 = new Node(); 45 46 n1.put("name", "Stop1"); 46 47 n1.put("public_transport", "stop_position"); … … 72 73 RelationMember rm6 = new RelationMember("platform_exit_only", n5); 73 74 members.add(rm6); 74 75 75 76 // Create ways: 76 77 Way w2 = new Way(); … … 92 93 RelationMember rm10 = new RelationMember("", w7); 93 94 members.add(rm10); 94 95 95 96 Relation route = new Relation(); 96 97 route.setMembers(members); 97 98 98 99 PTRouteDataManager manager = new PTRouteDataManager(route); 99 100 100 101 assertEquals(manager.getPTStopCount(), 5); 101 102 assertEquals(manager.getPTWayCount(), 4); 102 103 103 104 } 104 105 105 106 @Test 106 107 public void nestedRelationTest() { 107 108 108 109 // Same as above, but the nested Relation has a Node (only ways are allowed) 109 110 110 111 ArrayList<RelationMember> members = new ArrayList<>(); 111 112 112 113 // Create stops: 113 Node n1 = new Node(); 114 Node n1 = new Node(); 114 115 n1.put("name", "Stop1"); 115 116 n1.put("public_transport", "stop_position"); … … 141 142 RelationMember rm6 = new RelationMember("platform_exit_only", n5); 142 143 members.add(rm6); 143 144 144 145 // Create ways: 145 146 Way w2 = new Way(); … … 161 162 RelationMember rm10 = new RelationMember("", w7); 162 163 members.add(rm10); 163 164 164 165 165 166 Relation route = new Relation(); 166 167 route.setMembers(members); 167 168 168 169 PTRouteDataManager manager = new PTRouteDataManager(route); 169 170 170 171 assertEquals(manager.getFailedMembers().size(), 1); 171 172 assertEquals(manager.getPTStopCount(), 5); 172 173 assertEquals(manager.getPTWayCount(), 3); 173 174 174 } 175 176 175 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/data/StopToWayAssignerTest.java
r32707 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.data; 2 3 … … 14 15 15 16 public class StopToWayAssignerTest extends AbstractTest { 16 17 @Test18 public void test() {19 20 File file = new File(AbstractTest.PATH_TO_ONEWAY_BAD_MEMBER_SORTING);21 DataSet ds = ImportUtils.importOsmFile(file, "testLayer");22 23 Relation route = null;24 for (Relation r: ds.getRelations()) {25 if (r.getId() == 4552871) {26 route = r;27 break;28 }29 }30 31 PTRouteDataManager manager = new PTRouteDataManager(route);32 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays());33 34 // test with a [correct] stop_position:35 PTStop ptstop1 = manager.getPTStop(447358573l);36 // PTWay ptway1 = assigner.get(ptstop1);37 // Way way1 = ptway1.getWays().get(0);38 Way way1 = assigner.get(ptstop1);39 assertEquals(way1.getId(), 26956744l);40 41 // test with a [wrong] stop_position:42 PTStop ptstop2 = manager.getPTStop(427562058l);43 Way way2 = assigner.get(ptstop2);44 assertEquals(way2.getId(), 46349880l);45 46 // test with a stop_area:47 PTStop ptstop3 = manager.getPTStop(2987217064l);48 Way way3 = assigner.get(ptstop3);49 assertEquals(way3.getId(), 7045925l);50 51 // test with a platform without a stop_area:52 PTStop ptstop4 = manager.getPTStop(3327206909l);53 Way way4 = assigner.get(ptstop4);54 assertEquals(way4.getId(), 120277227l);55 56 57 }58 59 60 17 18 @Test 19 public void test() { 20 21 File file = new File(AbstractTest.PATH_TO_ONEWAY_BAD_MEMBER_SORTING); 22 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 23 24 Relation route = null; 25 for (Relation r: ds.getRelations()) { 26 if (r.getId() == 4552871) { 27 route = r; 28 break; 29 } 30 } 31 32 PTRouteDataManager manager = new PTRouteDataManager(route); 33 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 34 35 // test with a [correct] stop_position: 36 PTStop ptstop1 = manager.getPTStop(447358573L); 37 // PTWay ptway1 = assigner.get(ptstop1); 38 // Way way1 = ptway1.getWays().get(0); 39 Way way1 = assigner.get(ptstop1); 40 assertEquals(way1.getId(), 26956744L); 41 42 // test with a [wrong] stop_position: 43 PTStop ptstop2 = manager.getPTStop(427562058L); 44 Way way2 = assigner.get(ptstop2); 45 assertEquals(way2.getId(), 46349880L); 46 47 // test with a stop_area: 48 PTStop ptstop3 = manager.getPTStop(2987217064L); 49 Way way3 = assigner.get(ptstop3); 50 assertEquals(way3.getId(), 7045925L); 51 52 // test with a platform without a stop_area: 53 PTStop ptstop4 = manager.getPTStop(3327206909L); 54 Way way4 = assigner.get(ptstop4); 55 assertEquals(way4.getId(), 120277227L); 56 } 61 57 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/AdjacentWaysTest.java
r32603 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 18 19 public class AdjacentWaysTest extends AbstractTest { 19 20 20 21 21 @Test 22 public void test1() { 22 23 23 24 24 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION); 25 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 25 26 26 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 27 long id = 24215210; 28 Way way = (Way) ds.getPrimitiveById(id, OsmPrimitiveType.WAY); 29 30 assertEquals(RouteUtils.isOnewayForPublicTransport(way), -1); 31 32 Relation route = null; 33 for (Relation r : ds.getRelations()) { 34 if (r.hasKey("route")) { 35 route = r; 36 } 37 } 38 39 WayChecker wayChecker = new WayChecker(route, test); 40 Set<Way> set = wayChecker.checkAdjacentWays(way, new HashSet<Way>()); 41 42 assertEquals(set.size(), 1); 27 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 28 long id = 24215210; 29 Way way = (Way) ds.getPrimitiveById(id, OsmPrimitiveType.WAY); 43 30 44 } 45 46 @Test 47 public void test2() { 31 assertEquals(RouteUtils.isOnewayForPublicTransport(way), -1); 48 32 49 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION2); 50 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 33 Relation route = null; 34 for (Relation r : ds.getRelations()) { 35 if (r.hasKey("route")) { 36 route = r; 37 } 38 } 51 39 52 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 53 long id = 24215210; 54 Way way = (Way) ds.getPrimitiveById(id, OsmPrimitiveType.WAY); 55 56 assertEquals(RouteUtils.isOnewayForPublicTransport(way), -1); 57 58 Relation route = null; 59 for (Relation r : ds.getRelations()) { 60 if (r.hasKey("route")) { 61 route = r; 62 } 63 } 40 WayChecker wayChecker = new WayChecker(route, test); 41 Set<Way> set = wayChecker.checkAdjacentWays(way, new HashSet<Way>()); 64 42 65 WayChecker wayChecker = new WayChecker(route, test); 66 Set<Way> set = wayChecker.checkAdjacentWays(way, new HashSet<Way>()); 67 68 assertEquals(set.size(), 2); 43 assertEquals(set.size(), 1); 69 44 70 } 45 } 46 47 @Test 48 public void test2() { 49 50 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION2); 51 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 52 53 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 54 long id = 24215210; 55 Way way = (Way) ds.getPrimitiveById(id, OsmPrimitiveType.WAY); 56 57 assertEquals(RouteUtils.isOnewayForPublicTransport(way), -1); 58 59 Relation route = null; 60 for (Relation r : ds.getRelations()) { 61 if (r.hasKey("route")) { 62 route = r; 63 } 64 } 65 66 WayChecker wayChecker = new WayChecker(route, test); 67 Set<Way> set = wayChecker.checkAdjacentWays(way, new HashSet<Way>()); 68 69 assertEquals(set.size(), 2); 70 71 } 71 72 72 73 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/DirecionTestTest.java
r32647 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 19 20 public class DirecionTestTest extends AbstractTest { 20 21 21 22 22 @Test 23 public void testOnewayTrue() { 23 24 24 25 25 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION); 26 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 26 27 27 28 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 28 29 29 30 List<TestError> errors = new ArrayList<>(); 30 31 31 32 33 34 35 32 for (Relation r : ds.getRelations()) { 33 WayChecker wayChecker = new WayChecker(r, test); 34 wayChecker.performDirectionTest(); 35 errors.addAll(wayChecker.getErrors()); 36 } 36 37 37 38 39 40 41 42 43 38 assertEquals(errors.size(), 2); 39 int onewayErrorCaught = 0; 40 for (TestError e : errors) { 41 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_DIRECTION) { 42 onewayErrorCaught++; 43 } 44 } 44 45 45 46 assertEquals(onewayErrorCaught, 2); 46 47 47 48 49 50 51 52 53 54 55 56 57 58 48 boolean detectedErrorsAreCorrect = true; 49 for (TestError e : errors) { 50 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_DIRECTION) { 51 @SuppressWarnings("unchecked") 52 Collection<OsmPrimitive> highlighted = (Collection<OsmPrimitive>) e.getHighlighted(); 53 for (OsmPrimitive highlightedPrimitive: highlighted) { 54 if (highlightedPrimitive.getId() != 225732678 && highlightedPrimitive.getId() != 24215210) { 55 detectedErrorsAreCorrect = false; 56 } 57 } 58 } 59 } 59 60 60 61 61 assertTrue(detectedErrorsAreCorrect); 62 } 62 63 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/PlatformAsWayTest.java
r32582 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 14 15 import org.openstreetmap.josm.plugins.pt_assistant.ImportUtils; 15 16 16 public class PlatformAsWayTest extends AbstractTest {17 17 public class PlatformAsWayTest extends AbstractTest { 18 18 19 @Test 19 20 public void sortingTest() { 20 21 File file = new File(AbstractTest.PATH_TO_PLATFORM_AS_WAY); 21 22 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 22 23 23 24 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 24 25 25 26 List<TestError> errors = new ArrayList<>(); 26 27 27 28 for (Relation r: ds.getRelations()) { 28 29 30 31 32 33 34 29 WayChecker wayChecker = new WayChecker(r, test); 30 wayChecker.performDirectionTest(); 31 wayChecker.performRoadTypeTest(); 32 errors.addAll(wayChecker.getErrors()); 33 RouteChecker routeChecker = new RouteChecker(r, test); 34 routeChecker.performSortingTest(); 35 errors.addAll(routeChecker.getErrors()); 35 36 } 36 37 37 38 assertEquals(errors.size(), 0); 38 39 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/RoadTypeTestTest.java
r32582 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 18 19 19 20 public class RoadTypeTestTest extends AbstractTest { 20 21 21 22 @Test 22 23 public void test() { 23 24 24 25 File file = new File(AbstractTest.PATH_TO_ROAD_TYPE_ERROR); 25 26 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 26 27 27 28 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 28 29 List<TestError> errors = new ArrayList<>(); 29 30 30 31 for (Relation r: ds.getRelations()) { 31 32 33 32 WayChecker wayChecker = new WayChecker(r, test); 33 wayChecker.performRoadTypeTest(); 34 errors.addAll(wayChecker.getErrors()); 34 35 } 35 36 36 37 assertEquals(errors.size(), 2); 37 38 38 39 for (TestError e: errors) { 39 40 assertEquals(e.getCode(), PTAssistantValidatorTest.ERROR_CODE_ROAD_TYPE); -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentCheckerTest.java
r32874 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 13 14 14 15 public class SegmentCheckerTest extends AbstractTest { 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 16 17 @Test 18 public void test() { 19 20 21 File file = new File(AbstractTest.PATH_TO_SEGMENT_TEST); 22 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 23 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 24 25 Relation route = null; 26 27 for (Relation r: ds.getRelations()) { 28 if (RouteUtils.isTwoDirectionRoute(r)) { 29 route = r; 30 break; 31 } 32 } 33 34 SegmentChecker segmentChecker = new SegmentChecker(route, test); 35 segmentChecker.performStopByStopTest(); 36 assertEquals(SegmentChecker.getCorrectSegmentCount(), 27); 37 assertEquals(segmentChecker.getErrors().size(), 0); 38 39 40 41 42 } 42 43 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SolitaryStopPositionTest.java
r32616 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 3 4 import static org.junit.Assert.assertEquals; 2 5 3 6 import java.io.File; 4 7 5 8 import org.junit.Test; 6 import static org.junit.Assert.assertEquals;7 9 import org.openstreetmap.josm.data.osm.DataSet; 8 10 import org.openstreetmap.josm.data.osm.Node; … … 12 14 public class SolitaryStopPositionTest extends AbstractTest { 13 15 14 15 16 @Test 17 public void test1() { 16 18 17 18 19 19 File file = new File(AbstractTest.PATH_TO_SOLITARY_STOP_POSITION); 20 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 21 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 20 22 21 22 23 24 25 26 27 28 29 30 23 Node platform = null; 24 Node stopPosition = null; 25 for (Node n : ds.getNodes()) { 26 if (n.hasTag("public_transport", "stop_position")) { 27 stopPosition = n; 28 } 29 if (n.hasTag("public_transport", "platform")) { 30 platform = n; 31 } 32 } 31 33 32 33 34 35 36 34 NodeChecker checkerPlatform = new NodeChecker(platform, test); 35 checkerPlatform.performPlatformPartOfWayTest(); 36 assertEquals(checkerPlatform.getErrors().size(), 1); 37 assertEquals(checkerPlatform.getErrors().get(0).getCode(), 38 PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY); 37 39 38 39 40 41 42 40 NodeChecker checkerStopPosition = new NodeChecker(stopPosition, test); 41 checkerStopPosition.performSolitaryStopPositionTest(); 42 assertEquals(checkerStopPosition.getErrors().size(), 1); 43 assertEquals(checkerStopPosition.getErrors().get(0).getCode(), 44 PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION); 43 45 44 46 } 45 47 } -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SortingTestTest.java
r32582 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 … … 20 21 File file = new File(AbstractTest.PATH_TO_DL131_BEFORE); 21 22 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 22 23 23 24 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 24 25 25 26 List<TestError> errors = new ArrayList<>(); 26 27 27 28 for (Relation r: ds.getRelations()) { 28 29 30 31 29 RouteChecker routeChecker = new RouteChecker(r, test); 30 routeChecker.performSortingTest(); 31 errors.addAll(routeChecker.getErrors()); 32 32 33 } 33 34 … … 41 42 File file = new File(AbstractTest.PATH_TO_DL131_AFTER); 42 43 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 43 44 44 45 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 45 46 46 47 List<TestError> errors = new ArrayList<>(); 47 48 48 49 for (Relation r: ds.getRelations()) { 49 50 51 52 50 RouteChecker routeChecker = new RouteChecker(r, test); 51 routeChecker.performSortingTest(); 52 errors.addAll(routeChecker.getErrors()); 53 53 54 } 54 55 … … 80 81 File file = new File(AbstractTest.PATH_TO_DL286_AFTER); 81 82 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 82 83 83 84 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 84 85 85 86 List<TestError> errors = new ArrayList<>(); 86 87 87 88 for (Relation r: ds.getRelations()) { 88 89 90 89 RouteChecker routeChecker = new RouteChecker(r, test); 90 routeChecker.performSortingTest(); 91 errors.addAll(routeChecker.getErrors()); 91 92 } 92 93 -
applications/editors/josm/plugins/pt_assistant/test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/StopCheckerTest.java
r32822 r33055 1 // License: GPL. For details, see LICENSE file. 1 2 package org.openstreetmap.josm.plugins.pt_assistant.validation; 2 3 3 4 import java.io.File; 4 5 6 import org.junit.Assert; 5 7 import org.junit.Test; 6 import org.junit.Assert;7 8 import org.openstreetmap.josm.data.osm.DataSet; 8 9 import org.openstreetmap.josm.data.osm.Node; … … 13 14 public class StopCheckerTest extends AbstractTest { 14 15 15 16 16 @Test 17 public void nodePartOfStopAreaTest() { 17 18 18 // check if stop positions or platforms are in any stop_area relation: 19 20 File file = new File(AbstractTest.PATH_TO_STOP_AREA_MEMBERS); 21 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 22 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 23 Node node = null; 24 25 for (Node n : ds.getNodes()) { 26 if (n.hasTag("public_transport", "stop_position") | n.hasTag("public_transport", "platform")) { 27 node = n; 28 } 29 } 19 // check if stop positions or platforms are in any stop_area relation: 30 20 31 NodeChecker nodeChecker = new NodeChecker(node, test); 32 nodeChecker.performNodePartOfStopAreaTest(); 33 Assert.assertEquals(nodeChecker.getErrors().size(), 1); 34 Assert.assertEquals(nodeChecker.getErrors().get(0).getCode(), 35 PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA); 36 } 37 21 File file = new File(AbstractTest.PATH_TO_STOP_AREA_MEMBERS); 22 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 23 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 24 Node node = null; 38 25 26 for (Node n : ds.getNodes()) { 27 if (n.hasTag("public_transport", "stop_position") | n.hasTag("public_transport", "platform")) { 28 node = n; 29 } 30 } 39 31 40 @Test 41 public void stopAreaRelationsTest() { 42 43 // Check if stop positions belong the same routes as related platform(s) 44 45 File file = new File(AbstractTest.PATH_TO_STOP_AREA_RELATIONS); 46 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 47 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 48 Relation stopArea = null; 49 50 for (Relation r : ds.getRelations()) { 51 if (r.hasTag("public_transport", "stop_area")) { 52 stopArea = r; 53 } 54 } 55 56 StopChecker stopChecker = new StopChecker(stopArea, test); 57 stopChecker.performStopAreaRelationsTest(); 58 Assert.assertEquals(stopChecker.getErrors().size(), 1); 59 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 60 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_COMPARE_RELATIONS); 61 } 62 32 NodeChecker nodeChecker = new NodeChecker(node, test); 33 nodeChecker.performNodePartOfStopAreaTest(); 34 Assert.assertEquals(nodeChecker.getErrors().size(), 1); 35 Assert.assertEquals(nodeChecker.getErrors().get(0).getCode(), 36 PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA); 37 } 63 38 64 @Test 65 public void stopAreaStopPositionTest() { 66 67 // Check if stop area relation has at least one stop position. 68 69 File file = new File(AbstractTest.PATH_TO_STOP_AREA_NO_STOPS); 70 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 71 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 72 Relation stopArea = null; 39 @Test 40 public void stopAreaRelationsTest() { 73 41 74 for (Relation r : ds.getRelations()) { 75 if (r.hasTag("public_transport", "stop_area")) { 76 stopArea = r; 77 } 78 } 79 80 StopChecker stopChecker = new StopChecker(stopArea, test); 81 stopChecker.performStopAreaStopPositionTest(); 82 Assert.assertEquals(stopChecker.getErrors().size(), 1); 83 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 84 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_STOPS); 42 // Check if stop positions belong the same routes as related platform(s) 85 43 86 } 87 44 File file = new File(AbstractTest.PATH_TO_STOP_AREA_RELATIONS); 45 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 46 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 47 Relation stopArea = null; 88 48 89 @Test 90 public void stopAreaPlatformTest() { 91 92 // Check if stop area relation has at least one platform. 93 94 File file = new File(AbstractTest.PATH_TO_STOP_AREA_NO_PLATFORMS); 95 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 96 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 97 Relation stopArea = null; 49 for (Relation r : ds.getRelations()) { 50 if (r.hasTag("public_transport", "stop_area")) { 51 stopArea = r; 52 } 53 } 98 54 99 for (Relation r : ds.getRelations()) { 100 if (r.hasTag("public_transport", "stop_area")) { 101 stopArea = r; 102 } 103 } 104 105 StopChecker stopChecker = new StopChecker(stopArea, test); 106 stopChecker.performStopAreaPlatformTest(); 107 Assert.assertEquals(stopChecker.getErrors().size(), 1); 108 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 109 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_PLATFORM); 55 StopChecker stopChecker = new StopChecker(stopArea, test); 56 stopChecker.performStopAreaRelationsTest(); 57 Assert.assertEquals(stopChecker.getErrors().size(), 1); 58 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 59 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_COMPARE_RELATIONS); 60 } 110 61 111 } 62 @Test 63 public void stopAreaStopPositionTest() { 112 64 65 // Check if stop area relation has at least one stop position. 66 67 File file = new File(AbstractTest.PATH_TO_STOP_AREA_NO_STOPS); 68 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 69 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 70 Relation stopArea = null; 71 72 for (Relation r : ds.getRelations()) { 73 if (r.hasTag("public_transport", "stop_area")) { 74 stopArea = r; 75 } 76 } 77 78 StopChecker stopChecker = new StopChecker(stopArea, test); 79 stopChecker.performStopAreaStopPositionTest(); 80 Assert.assertEquals(stopChecker.getErrors().size(), 1); 81 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 82 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_STOPS); 83 } 84 85 @Test 86 public void stopAreaPlatformTest() { 87 88 // Check if stop area relation has at least one platform. 89 90 File file = new File(AbstractTest.PATH_TO_STOP_AREA_NO_PLATFORMS); 91 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 92 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 93 Relation stopArea = null; 94 95 for (Relation r : ds.getRelations()) { 96 if (r.hasTag("public_transport", "stop_area")) { 97 stopArea = r; 98 } 99 } 100 101 StopChecker stopChecker = new StopChecker(stopArea, test); 102 stopChecker.performStopAreaPlatformTest(); 103 Assert.assertEquals(stopChecker.getErrors().size(), 1); 104 Assert.assertEquals(stopChecker.getErrors().get(0).getCode(), 105 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_PLATFORM); 106 107 } 113 108 }
Note:
See TracChangeset
for help on using the changeset viewer.