Changeset 33055 in osm for applications/editors/josm/plugins
- Timestamp:
- 2016-11-12T20:44:31+01:00 (9 years ago)
- Location:
- applications/editors/josm/plugins/pt_assistant
- Files:
-
- 2 added
- 40 edited
-
.checkstyle (added)
-
.project (modified) (1 diff)
-
.settings/org.eclipse.jdt.ui.prefs (added)
-
src/org/openstreetmap/josm/plugins/pt_assistant/PTAssistantPlugin.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/AddStopPositionAction.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/DownloadReferrersThread.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/FixTask.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/IncompleteMembersDownloadThread.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/actions/RepeatLastFixAction.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteDataManager.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/data/PTRouteSegment.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/data/PTStop.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/data/PTWay.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/DownloadReferrersDialog.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/IncompleteMembersDownloadDialog.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantLayer.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPaintVisitor.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/PTAssistantPreferenceSetting.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/gui/ProceedDialog.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/utils/RouteUtils.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/utils/StopToWayAssigner.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/utils/StopUtils.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/Checker.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/NodeChecker.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java (modified) (2 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/RouteChecker.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/StopChecker.java (modified) (3 diffs)
-
src/org/openstreetmap/josm/plugins/pt_assistant/validation/WayChecker.java (modified) (3 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/AbstractTest.java (modified) (3 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/ImportUtils.java (modified) (3 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/TestUtil.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/data/RouteRepresentationTest.java (modified) (7 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/data/StopToWayAssignerTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/AdjacentWaysTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/DirecionTestTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/PlatformAsWayTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/RoadTypeTestTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentCheckerTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SolitaryStopPositionTest.java (modified) (2 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/SortingTestTest.java (modified) (4 diffs)
-
test/unit/org/openstreetmap/josm/plugins/pt_assistant/validation/StopCheckerTest.java (modified) (2 diffs)
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 * last fix that was can be re-applied to all similar route segments, can be30 * null if unavailable31 */32 private static PTRouteSegment lastFix;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 private static final long serialVersionUID = -5140181388906670207L;30 /** 31 * 32 */ 33 private static final long serialVersionUID = -5140181388906670207L; 33 34 34 public AddStopPositionAction() {35 super(tr("Add stop position"), new ImageProvider("presets/transport", "bus.svg"), tr("Add stop position"),36 Shortcut.registerShortcut("Add stop position", tr("Add stop position"), KeyEvent.VK_T, Shortcut.NONE),37 false, "addStopPosition", false);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 * Actions that add the new node, set tags and update the map frame.43 */44 @Override45 public void actionPerformed(ActionEvent e) {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 private Node node;14 private Node node; 14 15 15 public DownloadReferrersThread(Node node) {16 super();17 this.node = node;16 public DownloadReferrersThread(Node node) { 17 super(); 18 this.node = node; 18 19 19 }20 } 20 21 21 @Override22 public void run() {22 @Override 23 public void run() { 23 24 24 synchronized (this) {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 @Override42 protected voidfinish() {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 * Default constructor25 */26 public IncompleteMembersDownloadThread() {27 super();24 /** 25 * Default constructor 26 */ 27 public IncompleteMembersDownloadThread() { 28 super(); 28 29 29 }30 } 30 31 31 @Override32 public void run() {32 @Override 33 public void run() { 33 34 34 try {35 synchronized (this) {35 try { 36 synchronized (this) { 36 37 37 ArrayList<PrimitiveId> list = new ArrayList<>();38 ArrayList<PrimitiveId> list = new ArrayList<>(); 38 39 39 // if there are selected routes, try adding them first:40 for (Relation currentSelectedRelation : Main.getLayerManager().getEditDataSet()41 .getSelectedRelations()) {42 if (RouteUtils.isTwoDirectionRoute(currentSelectedRelation)) {43 list.add(currentSelectedRelation);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 if (list.isEmpty()) {48 // add all route relations that are of public_transport49 // version 2:50 Collection<Relation> allRelations = Main.getLayerManager().getEditDataSet().getRelations();51 for (Relation currentRelation : allRelations) {52 if (RouteUtils.isTwoDirectionRoute(currentRelation)) {53 list.add(currentRelation);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 // add all stop_positions:59 Collection<Node> allNodes = Main.getLayerManager().getEditDataSet().getNodes();60 for (Node currentNode : allNodes) {61 if (currentNode.hasTag("public_transport", "stop_position")) {62 List<OsmPrimitive> referrers = currentNode.getReferrers();63 boolean parentWayExists = false;64 for (OsmPrimitive referrer : referrers) {65 if (referrer.getType().equals(OsmPrimitiveType.WAY)) {66 parentWayExists = true;67 break;68 }69 }70 if (!parentWayExists) {71 list.add(currentNode);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 DownloadPrimitivesWithReferrersTask task = new DownloadPrimitivesWithReferrersTask(false, list, false,79 true, null, null);80 Thread t = new Thread(task);81 t.start();82 t.join();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 private static final long serialVersionUID = 2681464946469047054L;24 private static final long serialVersionUID = 2681464946469047054L; 24 25 25 /**26 * Default constructor27 */28 public RepeatLastFixAction() {29 super(tr("Repeat last fix"), new ImageProvider("presets/transport", "bus.svg"), tr("Repeat last fix"),30 Shortcut.registerShortcut("Repeat last fix", tr("Repeat last fix"), KeyEvent.VK_E, Shortcut.NONE),31 false, "repeatLastFix", false);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 * Applies the fixes, resets the last fix attribute37 */38 @Override39 public void actionPerformed(ActionEvent e) {36 /** 37 * Applies the fixes, resets the last fix attribute 38 */ 39 @Override 40 public void actionPerformed(ActionEvent e) { 40 41 41 if (!isEnabled() || !Main.isDisplayingMapView()) {42 return;43 }42 if (!isEnabled() || !Main.isDisplayingMapView()) { 43 return; 44 } 44 45 45 SegmentChecker.carryOutRepeatLastFix(PTAssistantPlugin.getLastFix());46 SegmentChecker.carryOutRepeatLastFix(PTAssistantPlugin.getLastFix()); 46 47 47 PTAssistantPlugin.setLastFix(null);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 /* first stop of the route segment */22 private PTStop firstStop;23 24 /* last stop of the route segment */25 private PTStop lastStop;26 27 /* ptways that belong to this route segment */28 private List<PTWay> ptways;29 30 /* fix variants available for this route segment */31 private List<List<PTWay>> fixVariants;32 33 /* route relation for which this route segment was created */34 private Relation relation;35 36 /**37 * Constructor38 * @param firstStop first stop of the route segment39 * @param lastStop last stop of the route segment40 * @param ways ways PTWays that belong to this route segment41 * @param relation the route relation for which this route segment is created42 */43 public PTRouteSegment(PTStop firstStop, PTStop lastStop, List<PTWay> ways, Relation relation) {44 this.firstStop = firstStop;45 this.lastStop = lastStop;46 this.ptways = new ArrayList<>(ways.size());47 ptways.addAll(ways);48 fixVariants = new ArrayList<>();49 this.relation = relation;50 }51 52 /**53 * Returns the PTWays of this route segment54 * @return55 */56 public List<PTWay> getPTWays() {57 return this.ptways;58 }59 60 /**61 * Sets the PTWays of this route segment to the given list62 * @param ptwayList63 */64 public void setPTWays(List<PTWay> ptwayList) {65 this.ptways = ptwayList;66 this.fixVariants.clear();67 }68 69 /**70 * Returns the first stop of this route segment71 * @return72 */73 public PTStop getFirstStop() {74 return this.firstStop;75 }76 77 /**78 * Returns the last stop of this route segment79 * @return80 */81 public PTStop getLastStop() {82 return this.lastStop;83 }84 85 /**86 * Returns the first PTWay of this route segment87 * @return88 */89 public PTWay getFirstPTWay() {90 if (ptways.isEmpty()) {91 return null;92 }93 return ptways.get(0);94 }95 96 /**97 * Returns the last PTWay of this route segment98 * @return99 */100 public PTWay getLastPTWay() {101 if (ptways.isEmpty()) {102 return null;103 }104 return ptways.get(ptways.size() - 1);105 }106 107 /**108 * Returns the first way of this route segment109 * @return110 */111 public Way getFirstWay() {112 if (ptways.isEmpty()) {113 return null;114 }115 return ptways.get(0).getWays().get(0);116 }117 118 /**119 * Returns the last way of this route segment120 * @return121 */122 public Way getLastWay() {123 if (ptways.isEmpty()) {124 return null;125 }126 List<Way> waysOfLast = ptways.get(ptways.size() - 1).getWays();127 return waysOfLast.get(waysOfLast.size() - 1);128 }129 130 /**131 * Adds the new fix variant if an identical fix variant (i.e. same ways) is132 * not already contained in the list of the fix variants of this.133 * 134 * @param list the PTWays of the new fix variant135 */136 public synchronized void addFixVariant(List<PTWay> list) {137 List<Way> otherWays = new ArrayList<>();138 for (PTWay ptway : list) {139 otherWays.addAll(ptway.getWays());140 }141 142 for (List<PTWay> fixVariant : this.fixVariants) {143 List<Way> thisWays = new ArrayList<>();144 for (PTWay ptway : fixVariant) {145 thisWays.addAll(ptway.getWays());146 }147 boolean listsEqual = (thisWays.size() == otherWays.size());148 if (listsEqual) {149 for (int i = 0; i < thisWays.size(); i++) {150 if (thisWays.get(i).getId() != otherWays.get(i).getId()) {151 listsEqual = false;152 break;153 }154 }155 }156 if (listsEqual) {157 return;158 }159 }160 161 this.fixVariants.add(list);162 }163 164 /**165 * Returns the fix variants stored for this route segment166 * @return167 */168 public List<List<PTWay>> getFixVariants() {169 return this.fixVariants;170 }171 172 /**173 * Returns the route relation for which this route segment was created174 * @return175 */176 public Relation getRelation() {177 return this.relation;178 }179 180 /**181 * Checks if this and the other route segments are equal182 * 183 * @param other184 * @return185 */186 public boolean equalsRouteSegment(PTRouteSegment other) {187 188 List<Way> thisWays = new ArrayList<>();189 for (PTWay ptway : this.ptways) {190 thisWays.addAll(ptway.getWays());191 }192 List<Way> otherWays = new ArrayList<>();193 for (PTWay ptway : other.getPTWays()) {194 otherWays.addAll(ptway.getWays());195 }196 197 if (thisWays.size() != otherWays.size()) {198 return false;199 }200 201 for (int i = 0; i < thisWays.size(); i++) {202 if (thisWays.get(i).getId() != otherWays.get(i).getId()) {203 return false;204 }205 }206 207 return true;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 /* stop_position element of this stop */23 private Node stopPosition = null;24 25 /* platform element of this stop */26 private OsmPrimitive platform = null;27 28 /* the name of this stop */29 private String name = "";30 31 /**32 * Constructor33 * 34 * @param other35 * @throws IllegalArgumentException36 * if the given relation member does not fit to the data model37 * used in the plugin38 */39 public PTStop(RelationMember other) throws IllegalArgumentException {40 41 super(other);42 43 // if ((other.hasRole("stop") || other.hasRole("stop_entry_only") ||44 // other.hasRole("stop_exit_only"))45 // && other.getType().equals(OsmPrimitiveType.NODE)) {46 47 if (other.getMember().hasTag("public_transport", "stop_position")) {48 49 this.stopPosition = other.getNode();50 this.name = stopPosition.get("name");51 52 // } else if (other.getRole().equals("platform") ||53 // other.getRole().equals("platform_entry_only")54 // || other.getRole().equals("platform_exit_only")) {55 } else if (other.getMember().hasTag("highway", "bus_stop")56 || other.getMember().hasTag("public_transport", "platform")57 || other.getMember().hasTag("highway", "platform") || other.getMember().hasTag("railway", "platform")) {58 59 this.platform = other.getMember();60 this.name = platform.get("name");61 62 } else {63 throw new IllegalArgumentException(64 "The RelationMember type does not match its role " + other.getMember().getName());65 }66 67 }68 69 /**70 * Adds the given element to the stop after a check71 * 72 * @param member73 * Element to add74 * @return true if added successfully, false otherwise. A false value75 * indicates either that the OsmPrimitiveType of the given76 * RelationMember does not match its role or that this PTStop77 * already has an attribute with that role.78 */79 protected boolean addStopElement(RelationMember member) {80 81 // each element is only allowed once per stop82 83 // add stop position:84 // if (member.hasRole("stop") || member.hasRole("stop_entry_only") ||85 // member.hasRole("stop_exit_only")) {86 if (member.getMember().hasTag("public_transport", "stop_position")) {87 if (member.getType().equals(OsmPrimitiveType.NODE) && stopPosition == null) {88 this.stopPosition = member.getNode();89 return true;90 }91 }92 93 // add platform:94 // if (member.getRole().equals("platform") ||95 // member.getRole().equals("platform_entry_only")96 // || member.getRole().equals("platform_exit_only")) {97 if (member.getMember().hasTag("highway", "bus_stop")98 || member.getMember().hasTag("public_transport", "platform")99 || member.getMember().hasTag("highway", "platform")100 || member.getMember().hasTag("railway", "platform")) {101 if (platform == null) {102 platform = member.getMember();103 return true;104 }105 }106 107 return false;108 109 }110 111 /**112 * Returns the stop_position for this PTstop. If the stop_position is not113 * available directly, the method searches for a stop_area relation114 * 115 * @return116 */117 public Node getStopPosition() {118 119 return this.stopPosition;120 }121 122 /**123 * Returns platform (including platform_entry_only and platform_exit_only)124 * 125 * @return126 */127 public OsmPrimitive getPlatform() {128 return this.platform;129 }130 131 /**132 * Returns the name of this stop133 * @return134 */135 protected String getName() {136 return this.name;137 }138 139 /**140 * Sets the stop_position for this stop to the given node141 * @param newStopPosition142 */143 public void setStopPosition(Node newStopPosition) {144 145 this.stopPosition = newStopPosition;146 147 }148 149 /**150 * Finds potential stop_positions of the platform of this PTStop. It only151 * makes sense to call this method if the stop_position attribute is null.152 * The stop_positions are potential because they may refer to a different153 * route, which this method does not check.154 * 155 * @return List of potential stop_positions for this PTStop156 */157 public List<Node> findPotentialStopPositions() {158 159 ArrayList<Node> potentialStopPositions = new ArrayList<>();160 161 if (platform == null) {162 return potentialStopPositions;163 }164 165 // Look for a stop position within 0.002 degrees (around 100 m) of this166 // platform:167 168 LatLon platformCenter = platform.getBBox().getCenter();169 Double ax = platformCenter.getX() - 0.002;170 Double bx = platformCenter.getX() + 0.002;171 Double ay = platformCenter.getY() - 0.002;172 Double by = platformCenter.getY() + 0.002;173 BBox platformBBox = new BBox(ax, ay, bx, by);174 175 Collection<Node> allNodes = platform.getDataSet().getNodes();176 for (Node currentNode : allNodes) {177 if (platformBBox.bounds(currentNode.getBBox()) && currentNode.hasTag("public_transport", "stop_position")) {178 potentialStopPositions.add(currentNode);179 }180 }181 182 return potentialStopPositions;183 }184 185 /**186 * Checks if this stop equals to other by comparing if they have the same187 * stop_position or a platform188 * 189 * @param other190 * PTStop to be compared191 * @return true if equal, false otherwise192 */193 public boolean equalsStop(PTStop other) {194 195 if (other == null) {196 return false;197 }198 199 if (this.stopPosition != null200 && (this.stopPosition == other.getStopPosition() || this.stopPosition == other.getPlatform())) {201 return true;202 }203 204 if (this.platform != null205 && (this.platform == other.getPlatform() || this.platform == other.getStopPosition())) {206 return true;207 }208 209 return false;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 * Ways that belong to this PTWay. If the corresponding relation member is21 * OsmPrimitiveType.WAY, this list size is 1. If the corresponding relation22 * member is a nested relation, the list size is >= 1.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 * @param other29 * the corresponding RelationMember30 * @throws IllegalArgumentException31 * if the given relation member cannot be a PTWay due to its32 * OsmPrimitiveType and/or role.33 */34 public PTWay(RelationMember other) throws IllegalArgumentException {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 super(other);37 super(other); 37 38 38 if (other.getType().equals(OsmPrimitiveType.WAY)) {39 ways.add(other.getWay());40 } else if (other.getType().equals(OsmPrimitiveType.RELATION)) {41 for (RelationMember rm : other.getRelation().getMembers()) {42 if (rm.getType().equals(OsmPrimitiveType.WAY)) {43 ways.add(rm.getWay());44 } else {45 throw new IllegalArgumentException(46 "A route relation member of OsmPrimitiveType.RELATION can only have ways as members");47 }48 }49 } else {50 // the RelationMember other cannot be a OsmPrimitiveType.NODE51 throw new IllegalArgumentException("A node cannot be used to model a public transport way");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 * Returns the course of this PTWay. In most cases, this list only has 158 * element. In the case of nested relations in a route, the list can have59 * multiple elements.60 * 61 * @return62 */63 public List<Way> getWays() {64 return this.ways;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 * Returns the end nodes of this PTWay. If this PTWay is a nested relation,90 * the order of the composing ways is assumed to be correct91 * 92 * @return93 */94 public Node[] getEndNodes() {95 Node[] endNodes = new Node[2];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 if (this.isWay()) {98 endNodes[0] = this.getWay().firstNode();99 endNodes[1] = this.getWay().lastNode();100 // TODO: if this is a roundabout101 } else { // nested relation:102 Way firstWay = this.getWays().get(0);103 Way secondWay = this.getWays().get(1);104 Way prelastWay = this.getWays().get(this.getWays().size() - 2);105 Way lastWay = this.getWays().get(this.getWays().size() - 1);106 if (firstWay.firstNode() == secondWay.firstNode() || firstWay.firstNode() == secondWay.lastNode()) {107 endNodes[0] = firstWay.lastNode();108 } else {109 endNodes[0] = firstWay.firstNode();110 }111 if (lastWay.firstNode() == prelastWay.firstNode() || lastWay.firstNode() == prelastWay.lastNode()) {112 endNodes[1] = lastWay.lastNode();113 } else {114 endNodes[1] = lastWay.firstNode();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 return endNodes;119 }121 return endNodes; 122 } 120 123 121 /**122 * Checks if this PTWay contains an unsplit roundabout (i.e. a way that123 * touches itself) among its ways124 * 125 * @return126 */127 public boolean containsUnsplitRoundabout() {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 List<Way> ways = this.getWays();130 for (Way way : ways) {131 if (way.firstNode() == way.lastNode()) {132 return true;133 }134 }135 return false;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 * Checks if the first Way of this PTWay is an unsplit roundabout (i.e. a140 * way that touches itself)141 * 142 * @return143 */144 public boolean startsWithUnsplitRoundabout() {145 if (this.ways.get(0).firstNode() == this.ways.get(0).lastNode()) {146 return true;147 }148 return false;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 * Checks if the last Way of this PTWay is an unsplit roundabout (i.e. a way153 * that touches itself)154 * 155 * @return156 */157 public boolean endsWithUnsplitRoundabout() {158 if (this.ways.get(this.ways.size() - 1).firstNode() == this.ways.get(this.ways.size() - 1).lastNode()) {159 return true;160 }161 return false;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 private static final long serialVersionUID = -4275151182361040329L;19 private static final long serialVersionUID = -4275151182361040329L; 19 20 20 // indicates if the user needs to be asked before fetching incomplete21 // members of a relation.22 public enum ASK_TO_FETCH {23 DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH24 }; 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 // by default, the user should be asked27 public static ASK_TO_FETCH askToFetch;27 // by default, the user should be asked 28 public static ASK_TO_FETCH askToFetch; 28 29 29 String message;30 private JCheckBox checkbox;31 private String[] options;32 private int selectedOption;30 String message; 31 private JCheckBox checkbox; 32 private String[] options; 33 private int selectedOption; 33 34 34 public IncompleteMembersDownloadDialog() {35 public IncompleteMembersDownloadDialog() { 35 36 36 selectedOption = Integer.MIN_VALUE;37 message = tr(38 "Route relations have incomplete members.\nThey need to be downloaded to proceed with validation.\nDo you want to download them?");39 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session"));40 options = new String[2];41 options[0] = tr("Yes");42 options[1] = tr("No");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 * Finds out whether the user wants to download incomplete members. In the48 * default case, creates a JOptionPane to ask.49 * 50 * @return JOptionPane.YES_OPTION if the incomplete members should be51 * downloaded, JOptionPane.NO_OPTION otherwise.52 */53 public int getUserSelection() {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 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) {56 return JOptionPane.YES_OPTION;57 }56 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) { 57 return JOptionPane.YES_OPTION; 58 } 58 59 59 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH) {60 return JOptionPane.NO_OPTION;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 selectedOption = JOptionPane.showOptionDialog(this, params, tr("PT_Assistant Fetch Request"),65 JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);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 if (checkbox.isSelected()) {68 if (selectedOption == JOptionPane.YES_OPTION) {69 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_FETCH;70 } else {71 askToFetch = ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH;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 return selectedOption;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 Layer 47 implements SelectionChangedListener, PropertyChangeListener, LayerChangeListener {48 49 private static PTAssistantLayer layer;50 private List<OsmPrimitive> primitives = new ArrayList<>();51 private PTAssistantPaintVisitor paintVisitor;52 private HashMap<Character, List<PTWay>> fixVariants = new HashMap<>();53 private HashMap<Way, List<Character>> wayColoring = new HashMap<>();54 55 private PTAssistantLayer() {56 super("pt_assistant layer");57 KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(this);58 Main.getLayerManager().addLayerChangeListener(this);59 layer = this;60 }61 62 public static PTAssistantLayer getLayer() {63 if (layer == null) {64 new PTAssistantLayer();65 }66 return layer;67 }68 69 /**70 * Adds a primitive (route) to be displayed in this layer71 * 72 * @param primitive73 */74 public void addPrimitive(OsmPrimitive primitive) {75 this.primitives.add(primitive);76 }77 78 /**79 * Clears all primitives (routes) from being displayed.80 */81 public void clear() {82 this.primitives.clear();83 }84 85 public void clearFixVariants() {86 fixVariants.clear();87 wayColoring.clear();88 Main.map.mapView.repaint();89 }90 91 /**92 * Adds the first 5 fix variants to be displayed in the pt_assistant layer93 * 94 * @param fixVariants95 */96 public void addFixVariants(List<List<PTWay>> fixVariants) {97 HashMap<List<PTWay>, Character> fixVariantLetterMap = new HashMap<>();98 99 char alphabet = 'A';100 for (int i = 0; i < 5 && i < fixVariants.size(); i++) {101 List<PTWay> fixVariant = fixVariants.get(i);102 this.fixVariants.put(alphabet, fixVariant);103 fixVariantLetterMap.put(fixVariant, alphabet);104 alphabet++;105 }106 107 for (Character currentFixVariantLetter : this.fixVariants.keySet()) {108 List<PTWay> fixVariant = this.fixVariants.get(currentFixVariantLetter);109 for (PTWay ptway : fixVariant) {110 for (Way way : ptway.getWays()) {111 if (wayColoring.containsKey(way)) {112 if (!wayColoring.get(way).contains(currentFixVariantLetter)) {113 wayColoring.get(way).add(currentFixVariantLetter);114 }115 } else {116 List<Character> letterList = new ArrayList<>();117 letterList.add(currentFixVariantLetter);118 wayColoring.put(way, letterList);119 }120 }121 }122 }123 }124 125 /**126 * Returns fix variant (represented by a list of PTWays) that corresponds to127 * the given character.128 * 129 * @param c130 * @return131 */132 public List<PTWay> getFixVariant(char c) {133 return this.fixVariants.get(Character.toUpperCase(c));134 }135 136 @Override137 public void paint(final Graphics2D g, final MapView mv, Bounds bounds) {138 139 paintVisitor = new PTAssistantPaintVisitor(g, mv);140 141 for (OsmPrimitive primitive : primitives) {142 paintVisitor.visit(primitive);143 }144 145 paintVisitor.visitFixVariants(this.fixVariants, this.wayColoring);146 147 }148 149 @Override150 public Icon getIcon() {151 return ImageProvider.get("layer", "osmdata_small");152 }153 154 @Override155 public Object getInfoComponent() {156 return getToolTipText();157 }158 159 @Override160 public Action[] getMenuEntries() {161 return new Action[] {LayerListDialog.getInstance().createShowHideLayerAction(),162 LayerListDialog.getInstance().createDeleteLayerAction(), SeparatorLayerAction.INSTANCE,163 new RenameLayerAction(null, this), SeparatorLayerAction.INSTANCE, new LayerListPopup.InfoAction(this)};164 }165 166 @Override167 public String getToolTipText() {168 return "pt_assistant layer";169 }170 171 @Override172 public boolean isMergable(Layer arg0) {173 return false;174 }175 176 @Override177 public void mergeFrom(Layer arg0) {178 // do nothing179 180 }181 182 @Override183 public void visitBoundingBox(BoundingXYVisitor arg0) {184 // do nothing185 186 }187 188 @Override189 public LayerPositionStrategy getDefaultLayerPosition() {190 return LayerPositionStrategy.IN_FRONT;191 }192 193 /**194 * Listens to a selection change195 */196 @Override197 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {198 199 ArrayList<Relation> routes = new ArrayList<>();200 201 for (OsmPrimitive primitive : newSelection) {202 if (primitive.getType().equals(OsmPrimitiveType.RELATION)) {203 Relation relation = (Relation) primitive;204 if (RouteUtils.isTwoDirectionRoute(relation)) {205 routes.add(relation);206 }207 208 }209 }210 211 if (!routes.isEmpty()) {212 this.primitives.clear();213 this.primitives.addAll(routes);214 if (!Main.getLayerManager().containsLayer(this)) {215 Main.getLayerManager().addLayer(this);216 }217 }218 219 }220 221 /**222 * Listens to a focus change, sets the primitives attribute to the route223 * relation in the top Relation Editor and repaints the map224 */225 @Override226 public void propertyChange(PropertyChangeEvent evt) {227 228 if ("focusedWindow".equals(evt.getPropertyName())) {229 230 if (evt.getNewValue() == null) {231 return;232 }233 234 if (evt.getNewValue().getClass().equals(GenericRelationEditor.class)) {235 236 GenericRelationEditor editor = (GenericRelationEditor) evt.getNewValue();237 Relation relation = editor.getRelation();238 239 if (RouteUtils.isTwoDirectionRoute(relation)) {240 241 this.repaint(relation);242 243 }244 245 }246 }247 }248 249 /**250 * Repaints the layer in cases when there was no selection change251 * 252 * @param relation253 */254 public void repaint(Relation relation) {255 this.primitives.clear();256 this.primitives.add(relation);257 if (!Main.getLayerManager().containsLayer(this)) {258 Main.getLayerManager().addLayer(this);259 }260 261 if (paintVisitor == null) {262 Graphics g = Main.map.mapView.getGraphics();263 MapView mv = Main.map.mapView;264 paintVisitor = new PTAssistantPaintVisitor(g, mv);265 }266 267 for (OsmPrimitive primitive : primitives) {268 paintVisitor.visit(primitive);269 }270 271 paintVisitor.visitFixVariants(this.fixVariants, this.wayColoring);272 273 Main.map.mapView.repaint();274 }275 276 @Override277 public void layerAdded(LayerAddEvent arg0) {278 // do nothing279 }280 281 @Override282 public void layerOrderChanged(LayerOrderChangeEvent arg0) {283 // do nothing284 285 }286 287 @Override288 public void layerRemoving(LayerRemoveEvent event) {289 290 if (event.getRemovedLayer() instanceof OsmDataLayer) {291 this.primitives.clear();292 this.fixVariants.clear();293 this.wayColoring.clear();294 Main.map.mapView.repaint();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 private static final long serialVersionUID = 2986537034076698693L;28 private static final long serialVersionUID = 2986537034076698693L; 28 29 29 public enum ASK_TO_PROCEED {30 DO_ASK, DONT_ASK_AND_FIX_AUTOMATICALLY, DONT_ASK_AND_FIX_MANUALLY, DONT_ASK_AND_DONT_FIX31 }; 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 // by default, the user should be asked34 public static ASK_TO_PROCEED askToProceed;34 // by default, the user should be asked 35 public static ASK_TO_PROCEED askToProceed; 35 36 36 private JRadioButton radioButtonFixAutomatically;37 private JRadioButton radioButtonFixManually;38 private JRadioButton radioButtonDontFix;39 private JCheckBox checkbox;40 private String[] options;41 private JPanel panel;42 private int selectedOption;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 public ProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {45 public ProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 45 46 46 panel = new JPanel();47 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));47 panel = new JPanel(); 48 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 48 49 49 JLabel label1 = new JLabel(tr("PT_Assistant plugin found that this relation (id={0}) has errors:", id));50 panel.add(label1);51 label1.setAlignmentX(Component.LEFT_ALIGNMENT);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 if (true) {54 JLabel label2 = new JLabel(" " + trn("{0} direction error", "{0} direction errors",55 numberOfDirectionErrors, numberOfDirectionErrors));56 panel.add(label2);57 label2.setAlignmentX(Component.LEFT_ALIGNMENT);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 if (numberOfRoadTypeErrors != 0) {61 JLabel label3 = new JLabel(" " + trn("{0} road type error", "{0} road type errors",62 numberOfRoadTypeErrors, numberOfRoadTypeErrors));63 panel.add(label3);64 label3.setAlignmentX(Component.LEFT_ALIGNMENT);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 JLabel label4 = new JLabel(tr("How do you want to proceed?"));68 panel.add(label4);69 label4.setAlignmentX(Component.LEFT_ALIGNMENT);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 radioButtonFixAutomatically = new JRadioButton("Fix all errors automatically and proceed");72 radioButtonFixManually = new JRadioButton("I will fix the errors manually and click the button to proceed");73 radioButtonDontFix = new JRadioButton("Do not fix anything and proceed with further tests", true);74 ButtonGroup fixOptionButtonGroup = new ButtonGroup();75 fixOptionButtonGroup.add(radioButtonFixAutomatically);76 fixOptionButtonGroup.add(radioButtonFixManually);77 fixOptionButtonGroup.add(radioButtonDontFix);78 panel.add(radioButtonFixAutomatically);79 // panel.add(radioButtonFixManually);80 panel.add(radioButtonDontFix);81 radioButtonFixAutomatically.setAlignmentX(Component.LEFT_ALIGNMENT);82 radioButtonFixManually.setAlignmentX(Component.LEFT_ALIGNMENT);83 radioButtonDontFix.setAlignmentX(Component.LEFT_ALIGNMENT);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 checkbox = new JCheckBox(tr("Remember my choice and do not ask me again in this session"));86 panel.add(checkbox);87 checkbox.setAlignmentX(Component.LEFT_ALIGNMENT);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 options = new String[2];90 options[0] = "OK";91 options[1] = "Cancel & stop testing";90 options = new String[2]; 91 options[0] = "OK"; 92 options[1] = "Cancel & stop testing"; 92 93 93 selectedOption = Integer.MIN_VALUE;94 selectedOption = Integer.MIN_VALUE; 94 95 95 }96 } 96 97 97 /**98 * Finds out whether the user wants to download incomplete members. In the99 * default case, creates a JOptionPane to ask.100 * 101 * @return 0 to fix automatically, 1 to fix manually, 2 to proceed without102 * fixing, -1 to stop testing or if dialog is closed without answer103 * 104 */105 public int getUserSelection() {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 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_FIX_AUTOMATICALLY) {108 return 0;109 }110 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_FIX_MANUALLY) {111 return 1;112 }113 if (askToProceed == ASK_TO_PROCEED.DONT_ASK_AND_DONT_FIX) {114 return 2;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 // showDialog(); FIXME118 selectedOption = JOptionPane.showOptionDialog(this, panel, tr("PT_Assistant Proceed Request"),119 JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);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 if (selectedOption == 0) {122 if (radioButtonFixAutomatically.isSelected()) {123 if (checkbox.isSelected()) {124 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_FIX_AUTOMATICALLY;125 }126 return 0;127 }128 if (radioButtonFixManually.isSelected()) {129 if (checkbox.isSelected()) {130 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_FIX_MANUALLY;131 }132 return 1;133 }134 if (radioButtonDontFix.isSelected()) {135 if (checkbox.isSelected()) {136 askToProceed = ASK_TO_PROCEED.DONT_ASK_AND_DONT_FIX;137 }138 return 2;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 return -1;143 }143 return -1; 144 } 144 145 145 /**146 * 147 */148 @SuppressWarnings("unused")149 private void showDialog() {146 /** 147 * 148 */ 149 @SuppressWarnings("unused") 150 private void showDialog() { 150 151 151 if (!SwingUtilities.isEventDispatchThread()) {152 selectedOption = JOptionPane.showOptionDialog(this, panel, tr("PT_Assistant Proceed Request"),153 JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);154 } else {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 SwingUtilities.invokeLater(new Runnable() {157 @Override158 public void run() {159 showDialog();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 private RouteUtils() {21 // private constructor for util classes22 }23 24 /**25 * Checks if the relation is a route of one of the following categories:26 * bus, trolleybus, share_taxi, tram, light_rail, subway, train.27 * 28 * @param r29 * Relation to be checked30 * @return true if the route belongs to the categories that can be validated31 * with the pt_assistant plugin, false otherwise.32 */33 public static boolean isTwoDirectionRoute(Relation r) {34 35 if (r == null) {36 return false;37 }38 39 if (!r.hasKey("route") || !r.hasTag("public_transport:version", "2")) {40 return false;41 }42 if (r.hasTag("route", "bus") || r.hasTag("route", "trolleybus") || r.hasTag("route", "share_taxi")43 || r.hasTag("route", "tram") || r.hasTag("route", "light_rail") || r.hasTag("route", "subway")44 || r.hasTag("route", "train")) {45 46 if (!r.hasTag("bus", "on_demand")) {47 return true;48 }49 50 }51 return false;52 }53 54 /**55 * Checks if the relation member refers to a stop in a public transport56 * route. Some stops can be modeled with ways.57 * 58 * @param rm59 * relation member to be checked60 * @return true if the relation member refers to a stop, false otherwise61 */62 public static boolean isPTStop(RelationMember rm) {63 64 65 if (rm.getType().equals(OsmPrimitiveType.NODE)) {66 return true;67 }68 69 if (rm.getType().equals(OsmPrimitiveType.WAY)) {70 if (rm.getWay().hasTag("public_transport", "platform") || rm.getWay().hasTag("highway", "platform")71 || rm.getWay().hasTag("railway", "platform")) {72 return true;73 }74 }75 76 return false;77 78 }79 80 /**81 * Checks if the relation member refers to a way in a public transport82 * route. Some OsmPrimitiveType.WAY have to be excluded because platforms83 * can be modeled with ways.84 * 85 * @param rm86 * relation member to be checked87 * @return true if the relation member refers to a way in a public transport88 * route, false otherwise.89 */90 public static boolean isPTWay(RelationMember rm) {91 92 if (rm.getType().equals(OsmPrimitiveType.NODE)) {93 return false;94 }95 96 if (rm.getType().equals(OsmPrimitiveType.WAY)) {97 if (rm.getWay().hasTag("public_transport", "platform") || rm.getWay().hasTag("highway", "platform")98 || rm.getWay().hasTag("railway", "platform")) {99 return false;100 }101 return true;102 }103 104 Relation nestedRelation = rm.getRelation();105 106 for (RelationMember nestedRelationMember : nestedRelation.getMembers()) {107 if (!nestedRelationMember.getType().equals(OsmPrimitiveType.WAY)) {108 return false;109 }110 }111 112 return true;113 }114 115 /**116 * Checks if the given way has tags that make it oneway for public117 * transport. The test does not check whether the way violates those118 * restrictions.119 * 120 * @return 0 if the way is not oneway for public transport, 1 if the way is121 * oneway for public transport, -1 if the way is reversely oneway122 * for public transport123 */124 public static int isOnewayForPublicTransport(Way way) {125 126 if (OsmUtils.isTrue(way.get("oneway")) || OsmUtils.isReversed(way.get("oneway"))127 || way.hasTag("junction", "roundabout") || way.hasTag("highway", "motorway")) {128 129 if (!way.hasTag("busway", "lane") && !way.hasTag("busway:left", "lane")130 && !way.hasTag("busway:right", "lane") && !way.hasTag("oneway:bus", "no")131 && !way.hasTag("busway", "opposite_lane") && !way.hasTag("oneway:psv", "no")132 && !way.hasTag("trolley_wire", "backward")) {133 134 if (OsmUtils.isReversed(way.get("oneway"))) {135 return -1;136 }137 138 return 1;139 140 }141 142 }143 144 return 0;145 }146 147 /**148 * Checks if the ways have a common node149 * 150 * @param w1151 * @param w2152 * @return153 */154 public static boolean waysTouch(Way w1, Way w2) {155 156 if (w1 == null || w2 == null) {157 return false;158 }159 160 Node w1FirstNode = w1.firstNode();161 Node w1LastNode = w1.lastNode();162 Node w2FirstNode = w2.firstNode();163 Node w2LastNode = w2.lastNode();164 165 if (w1FirstNode == w2FirstNode || w1FirstNode == w2LastNode || w1LastNode == w2FirstNode166 || w1LastNode == w2LastNode) {167 return true;168 }169 170 return false;171 }172 173 /**174 * Checks if any way from the first collection touches any way from the175 * second collection176 * 177 * @param c1 first collection178 * @param c2 second collection179 * @return true if ways touch, false otherwise180 */181 public static boolean waysTouch(Collection<Way> c1, Collection<Way> c2) {182 183 if (c1 == null || c2 == null) {184 return false;185 }186 187 for (Way w1 : c1) {188 for (Way w2 : c2) {189 if (waysTouch(w1, w2)) {190 return true;191 }192 }193 }194 195 return false;196 }197 198 /**199 * Checks if the type of the way is suitable for buses to go on it. The200 * direction of the way (i.e. one-way roads) is irrelevant for this test.201 * 202 * @param way203 * to be checked204 * @return true if the way is suitable for buses, false otherwise.205 */206 public static boolean isWaySuitableForBuses(Way way) {207 if (way.hasTag("highway", "motorway") || way.hasTag("highway", "trunk") || way.hasTag("highway", "primary")208 || way.hasTag("highway", "secondary") || way.hasTag("highway", "tertiary")209 || way.hasTag("highway", "unclassified") || way.hasTag("highway", "road")210 || way.hasTag("highway", "residential") || way.hasTag("highway", "service")211 || way.hasTag("highway", "motorway_link") || way.hasTag("highway", "trunk_link")212 || way.hasTag("highway", "primary_link") || way.hasTag("highway", "secondary_link")213 || way.hasTag("highway", "tertiary_link") || way.hasTag("highway", "living_street")214 || way.hasTag("highway", "bus_guideway") || way.hasTag("highway", "road")215 || way.hasTag("cycleway", "share_busway") || way.hasTag("cycleway", "shared_lane")) {216 return true;217 }218 219 if (way.hasTag("highway", "pedestrian") && (way.hasTag("bus", "yes") || way.hasTag("psv", "yes")220 || way.hasTag("bus", "designated") || way.hasTag("psv", "designated"))) {221 return true;222 }223 224 return false;225 }226 227 /**228 * Checks if this way is suitable for public transport (not only for buses)229 * @param way230 * @return231 */232 public static boolean isWaySuitableForPublicTransport(Way way) {233 234 if (isWaySuitableForBuses(way) || way.hasTag("railway", "tram") || way.hasTag("railway", "subway")235 || way.hasTag("railway", "subway") || way.hasTag("railway", "light_rail")236 || way.hasTag("railway", "rail")) {237 return true;238 }239 240 return false;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 private StopUtils() {15 // private constructor for util classes16 }15 private StopUtils() { 16 // private constructor for util classes 17 } 17 18 18 /**19 * Checks if a given relation is a stop_area.20 * 21 * @param r22 * Relation to be checked23 * @return true if the relation is a stop_area, false otherwise.24 */25 public static boolean isStopArea(Relation r) {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 if (r == null) {28 return false;29 }28 if (r == null) { 29 return false; 30 } 30 31 31 if (r.hasTag("public_transport", "stop_area")) {32 return true;33 }34 return false;35 }32 if (r.hasTag("public_transport", "stop_area")) { 33 return true; 34 } 35 return false; 36 } 36 37 37 /**38 * Checks if a given object is a stop_position.39 * 40 * @param r41 * Relation to be checked42 * @return true if the object is a stop_position, false otherwise.43 */44 public static boolean verifyStopAreaStopPosition(OsmPrimitive rm) {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 if (rm == null) {47 return false;48 }47 if (rm == null) { 48 return false; 49 } 49 50 50 if (rm.hasTag("public_transport", "stop_position")) {51 return true;52 }53 return false;54 }51 if (rm.hasTag("public_transport", "stop_position")) { 52 return true; 53 } 54 return false; 55 } 55 56 56 /**57 * Checks if a given object is a platform.58 * 59 * @param r60 * Relation to be checked61 * @return true if the object is a platform, false otherwise.62 */63 public static boolean verifyStopAreaPlatform(OsmPrimitive rm) {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 if (rm == null) {66 return false;67 }66 if (rm == null) { 67 return false; 68 } 68 69 69 if (rm.hasTag("public_transport", "platform") || rm.hasTag("highway", "bus_stop")70 || rm.hasTag("highway", "platform") || rm.hasTag("railway", "platform")) {71 return true;72 }73 return false;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 * Checks if a given object is part of an stop area relation78 * 79 * @param r80 * Object to be checked81 * @return true if the object part of stop area relation, false otherwise.82 */83 public static boolean verifyIfMemberOfStopArea(OsmPrimitive member) {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 for (Relation parentRelation : OsmPrimitive.getFilteredList(member.getReferrers(), Relation.class)) {86 if (StopUtils.isStopArea(parentRelation)) {87 return true;88 }89 }90 return false;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 protected NodeChecker(Node node, Test test) {29 super(node, test);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 List<OsmPrimitive> referrers = node.getReferrers();39 List<OsmPrimitive> referrers = node.getReferrers(); 41 40 42 for (OsmPrimitive referrer : referrers) {43 if (referrer.getType().equals(OsmPrimitiveType.WAY)) {44 Way referrerWay = (Way) referrer;45 if (RouteUtils.isWaySuitableForPublicTransport(referrerWay)) {46 return;47 }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 List<OsmPrimitive> primitives = new ArrayList<>(1);53 primitives.add(node);54 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop_position is not part of a way"),55 PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION, primitives);56 errors.add(e);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 List<OsmPrimitive> referrers = node.getReferrers();64 List<OsmPrimitive> referrers = node.getReferrers(); 68 65 69 for (OsmPrimitive referrer : referrers) {70 List<Node> primitives = new ArrayList<>(1);71 primitives.add(node);72 if (referrer.getType().equals(OsmPrimitiveType.WAY)) {73 Way referringWay = (Way) referrer;74 if (RouteUtils.isWaySuitableForPublicTransport(referringWay)) {75 TestError e = new TestError(this.test, Severity.WARNING,76 tr("PT: Platform should not be part of a way"),77 PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY, primitives);78 errors.add(e);79 return;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 if (!StopUtils.verifyIfMemberOfStopArea(node)) {88 if (!StopUtils.verifyIfMemberOfStopArea(node)) { 93 89 94 List<OsmPrimitive> primitives = new ArrayList<>(1);95 primitives.add(node);96 TestError e = new TestError(this.test, Severity.WARNING,97 tr("PT: Stop position or platform is not part of a stop area relation"),98 PTAssistantValidatorTest.ERROR_CODE_NOT_PART_OF_STOP_AREA, primitives);99 errors.add(e);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 * Fixes errors: solitary stop position and platform which is part of a way.105 * Asks the user first.106 * 107 * @param testError108 * @return109 */110 protected static Command fixError(TestError testError) {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 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION113 && testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {114 return null;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 Node problematicNode = (Node) testError.getPrimitives().iterator().next();113 Node problematicNode = (Node) testError.getPrimitives().iterator().next(); 118 114 119 final int[] userSelection = {JOptionPane.YES_OPTION};120 final TestError errorParameter = testError;121 if (SwingUtilities.isEventDispatchThread()) {115 final int[] userSelection = {JOptionPane.YES_OPTION}; 116 final TestError errorParameter = testError; 117 if (SwingUtilities.isEventDispatchThread()) { 122 118 123 userSelection[0] = showFixNodeTagDialog(errorParameter);119 userSelection[0] = showFixNodeTagDialog(errorParameter); 124 120 125 } else {121 } else { 126 122 127 try {128 SwingUtilities.invokeAndWait(new Runnable() {129 @Override130 public void run() {131 userSelection[0] = showFixNodeTagDialog(errorParameter);132 }133 });134 } catch (InvocationTargetException | InterruptedException e) {135 e.printStackTrace();136 return null;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 if (userSelection[0] == JOptionPane.YES_OPTION) {136 if (userSelection[0] == JOptionPane.YES_OPTION) { 141 137 142 Node modifiedNode = new Node(problematicNode);143 if (testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) {144 modifiedNode.put("public_transport", "platform");145 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode);146 return command;147 } else {148 modifiedNode.put("public_transport", "stop_position");149 ChangeCommand command = new ChangeCommand(problematicNode, modifiedNode);150 return command;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 return null;150 return null; 155 151 156 }152 } 157 153 158 private static int showFixNodeTagDialog(TestError e) {159 Node problematicNode = (Node) e.getPrimitives().iterator().next();160 // Main.map.mapView.zoomTo(problematicNode.getCoor());161 // zoom to problem:162 Collection<OsmPrimitive> primitives = new ArrayList<>(1);163 primitives.add(problematicNode);164 AutoScaleAction.zoomTo(primitives);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 String message;168 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION) {169 message = "Do you want to change the tag public_transport=stop_position to public_transport=platform?";170 } else {171 message = "Do you want to change the tag public_transport=platform to public_transport=stop_position?";172 }173 return JOptionPane.showOptionDialog(null, message, tr("PT_Assistant Message"), JOptionPane.YES_NO_OPTION,174 JOptionPane.QUESTION_MESSAGE, null, options, 0);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 private boolean hasGap;32 private boolean hasGap; 32 33 33 List<RelationMember> sortedMembers;34 List<RelationMember> sortedMembers; 34 35 35 public RouteChecker(Relation relation, Test test) {36 public RouteChecker(Relation relation, Test test) { 36 37 37 super(relation, test);38 super(relation, test); 38 39 39 this.hasGap = false;40 this.hasGap = false; 40 41 41 }42 } 42 43 43 protected void performSortingTest() {44 protected void performSortingTest() { 44 45 45 final List<RelationMember> waysToCheck = new ArrayList<>();46 for (RelationMember rm : relation.getMembers()) {46 final List<RelationMember> waysToCheck = new ArrayList<>(); 47 for (RelationMember rm : relation.getMembers()) { 47 48 48 if (RouteUtils.isPTWay(rm) && rm.getType().equals(OsmPrimitiveType.WAY)) {49 waysToCheck.add(rm);50 }51 }49 if (RouteUtils.isPTWay(rm) && rm.getType().equals(OsmPrimitiveType.WAY)) { 50 waysToCheck.add(rm); 51 } 52 } 52 53 53 if (waysToCheck.isEmpty()) {54 return;55 }54 if (waysToCheck.isEmpty()) { 55 return; 56 } 56 57 57 if (hasGap(waysToCheck)) {58 if (hasGap(waysToCheck)) { 58 59 59 this.hasGap = true;60 this.hasGap = true; 60 61 61 RelationSorter sorter = new RelationSorter();62 sortedMembers = sorter.sortMembers(waysToCheck);62 RelationSorter sorter = new RelationSorter(); 63 sortedMembers = sorter.sortMembers(waysToCheck); 63 64 64 if (!hasGap(sortedMembers)) {65 TestError e = new TestError(this.test, Severity.WARNING,66 tr("PT: Route contains a gap that can be fixed by sorting"),67 PTAssistantValidatorTest.ERROR_CODE_SORTING, relation);68 this.errors.add(e);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 * Checks if there is a gap for a given list of ways. It does not check if78 * the way actually stands for a public transport platform - that should be79 * checked beforehand.80 * 81 * @param waysToCheck82 * @return true if has gap (in the sense of continuity of ways in the83 * Relation Editor), false otherwise84 */85 private boolean hasGap(List<RelationMember> waysToCheck) {86 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator();87 final List<WayConnectionType> links = connectionTypeCalculator.updateLinks(waysToCheck);88 for (int i = 0; i < links.size(); i++) {89 final WayConnectionType link = links.get(i);90 final boolean hasError = !(i == 0 || link.linkPrev) || !(i == links.size() - 1 || link.linkNext)91 || link.direction == null || WayConnectionType.Direction.NONE.equals(link.direction);92 if (hasError) {93 return true;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 return false;99 }99 return false; 100 } 100 101 101 public List<RelationMember> getSortedMembers() {102 public List<RelationMember> getSortedMembers() { 102 103 103 return sortedMembers;104 return sortedMembers; 104 105 105 }106 } 106 107 107 public boolean getHasGap() {108 public boolean getHasGap() { 108 109 109 return this.hasGap;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 returnchangeCommand;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 Set<OsmPrimitive> members;26 Set<OsmPrimitive> members; 26 27 27 protected StopChecker(Relation relation, Test test) {28 super(relation, test);28 protected StopChecker(Relation relation, Test test) { 29 super(relation, test); 29 30 30 this.members = relation.getMemberPrimitives();31 }31 this.members = relation.getMemberPrimitives(); 32 } 32 33 33 /**34 * Checks if the given stop area relation has a stop position.35 */36 protected void performStopAreaStopPositionTest() {34 /** 35 * Checks if the given stop area relation has a stop position. 36 */ 37 protected void performStopAreaStopPositionTest() { 37 38 38 // No errors if there is a member tagged as stop position.39 for (OsmPrimitive member : members) {40 if (StopUtils.verifyStopAreaStopPosition(member)) {41 return;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 // Throw error message46 List<OsmPrimitive> primitives = new ArrayList<>(1);47 primitives.add(relation);48 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop area relation has no stop position"),49 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_STOPS, primitives);50 errors.add(e);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 * Checks if the given stop area relation has a platform.55 */56 protected void performStopAreaPlatformTest() {54 /** 55 * Checks if the given stop area relation has a platform. 56 */ 57 protected void performStopAreaPlatformTest() { 57 58 58 // No errors if there is a member tagged as platform.59 for (OsmPrimitive member : members) {60 if (StopUtils.verifyStopAreaPlatform(member)) {61 return;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 // Throw error message66 List<OsmPrimitive> primitives = new ArrayList<>(1);67 primitives.add(relation);68 TestError e = new TestError(this.test, Severity.WARNING, tr("PT: Stop area relation has no platform"),69 PTAssistantValidatorTest.ERROR_CODE_STOP_AREA_NO_PLATFORM, primitives);70 errors.add(e);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 HashMap<Long, Long> stopPositionRelationIds = new HashMap<>();83 HashMap<Long, Long> platformRelationIds = new HashMap<>();81 HashMap<Long, Long> stopPositionRelationIds = new HashMap<>(); 82 HashMap<Long, Long> platformRelationIds = new HashMap<>(); 84 83 85 // Loop through all members86 for (OsmPrimitive member : members) {84 // Loop through all members 85 for (OsmPrimitive member : members) { 87 86 88 // For stop positions...89 if (StopUtils.verifyStopAreaStopPosition(member)) {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 @Test21 public void test1() {21 @Test 22 public void test1() { 22 23 23 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION);24 DataSet ds = ImportUtils.importOsmFile(file, "testLayer");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 @Test22 public void testOnewayTrue() {22 @Test 23 public void testOnewayTrue() { 23 24 24 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION);25 DataSet ds = ImportUtils.importOsmFile(file, "testLayer");25 File file = new File(AbstractTest.PATH_TO_ONEWAY_WRONG_DIRECTION); 26 DataSet ds = ImportUtils.importOsmFile(file, "testLayer"); 26 27 27 PTAssistantValidatorTest test = new PTAssistantValidatorTest();28 PTAssistantValidatorTest test = new PTAssistantValidatorTest(); 28 29 29 List<TestError> errors = new ArrayList<>();30 List<TestError> errors = new ArrayList<>(); 30 31 31 for (Relation r : ds.getRelations()) {32 WayChecker wayChecker = new WayChecker(r, test);33 wayChecker.performDirectionTest();34 errors.addAll(wayChecker.getErrors());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 assertEquals(errors.size(), 2);38 int onewayErrorCaught = 0;39 for (TestError e : errors) {40 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_DIRECTION) {41 onewayErrorCaught++;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 assertEquals(onewayErrorCaught, 2);46 assertEquals(onewayErrorCaught, 2); 46 47 47 boolean detectedErrorsAreCorrect = true;48 for (TestError e : errors) {49 if (e.getCode() == PTAssistantValidatorTest.ERROR_CODE_DIRECTION) {50 @SuppressWarnings("unchecked")51 Collection<OsmPrimitive> highlighted = (Collection<OsmPrimitive>) e.getHighlighted();52 for (OsmPrimitive highlightedPrimitive: highlighted) {53 if (highlightedPrimitive.getId() != 225732678 && highlightedPrimitive.getId() != 24215210) {54 detectedErrorsAreCorrect = false;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 assertTrue(detectedErrorsAreCorrect);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 WayChecker wayChecker = new WayChecker(r, test);29 wayChecker.performDirectionTest();30 wayChecker.performRoadTypeTest();31 errors.addAll(wayChecker.getErrors());32 RouteChecker routeChecker = new RouteChecker(r, test);33 routeChecker.performSortingTest();34 errors.addAll(routeChecker.getErrors());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 WayChecker wayChecker = new WayChecker(r, test);32 wayChecker.performRoadTypeTest();33 errors.addAll(wayChecker.getErrors());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 @Test17 public void test() {18 19 20 File file = new File(AbstractTest.PATH_TO_SEGMENT_TEST);21 DataSet ds = ImportUtils.importOsmFile(file, "testLayer");22 PTAssistantValidatorTest test = new PTAssistantValidatorTest();23 24 Relation route = null;25 26 for (Relation r: ds.getRelations()) {27 if (RouteUtils.isTwoDirectionRoute(r)) {28 route = r;29 break;30 }31 }32 33 SegmentChecker segmentChecker = new SegmentChecker(route, test);34 segmentChecker.performStopByStopTest();35 assertEquals(SegmentChecker.getCorrectSegmentCount(), 27);36 assertEquals(segmentChecker.getErrors().size(), 0);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 @Test15 public void test1() {16 @Test 17 public void test1() { 16 18 17 File file = new File(AbstractTest.PATH_TO_SOLITARY_STOP_POSITION);18 DataSet ds = ImportUtils.importOsmFile(file, "testLayer");19 PTAssistantValidatorTest test = new PTAssistantValidatorTest();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 Node platform = null;22 Node stopPosition = null;23 for (Node n : ds.getNodes()) {24 if (n.hasTag("public_transport", "stop_position")) {25 stopPosition = n;26 }27 if (n.hasTag("public_transport", "platform")) {28 platform = n;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 NodeChecker checkerPlatform = new NodeChecker(platform, test);33 checkerPlatform.performPlatformPartOfWayTest();34 assertEquals(checkerPlatform.getErrors().size(), 1);35 assertEquals(checkerPlatform.getErrors().get(0).getCode(),36 PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY);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 NodeChecker checkerStopPosition = new NodeChecker(stopPosition, test);39 checkerStopPosition.performSolitaryStopPositionTest();40 assertEquals(checkerStopPosition.getErrors().size(), 1);41 assertEquals(checkerStopPosition.getErrors().get(0).getCode(),42 PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION);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 RouteChecker routeChecker = new RouteChecker(r, test);29 routeChecker.performSortingTest();30 errors.addAll(routeChecker.getErrors());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 RouteChecker routeChecker = new RouteChecker(r, test);50 routeChecker.performSortingTest();51 errors.addAll(routeChecker.getErrors());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 RouteChecker routeChecker = new RouteChecker(r, test);89 routeChecker.performSortingTest();90 errors.addAll(routeChecker.getErrors());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 @Test16 public void nodePartOfStopAreaTest() {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.
