Changeset 33055 in osm


Ignore:
Timestamp:
2016-11-12T20:44:31+01:00 (8 years ago)
Author:
donvip
Message:

checkstyle

Location:
applications/editors/josm/plugins/pt_assistant
Files:
2 added
40 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pt_assistant/.project

    r32261 r33055  
    1616                        </arguments>
    1717                </buildCommand>
     18                <buildCommand>
     19                        <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
     20                        <arguments>
     21                        </arguments>
     22                </buildCommand>
    1823        </buildSpec>
    1924        <natures>
    2025                <nature>org.eclipse.jdt.core.javanature</nature>
     26                <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
    2127        </natures>
    2228</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.
    22package org.openstreetmap.josm.plugins.pt_assistant;
    33
     
    2222 *
    2323 * @author darya / Darya Golovko
    24  * 
     24 *
    2525 */
    2626public class PTAssistantPlugin extends Plugin {
    2727
    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;
     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;
    3333
    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;
    3936
    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;
    4939
    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);
    5149
    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);
    5651
    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);
    5856
    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    }
    7258
    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    }
    8072
    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    }
    8480
    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    }
    9384
    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;
    10193
    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    }
    110110
    111111}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.actions;
    23
     
    2122/**
    2223 * Action to add stop position and split the relevant way
    23  * 
     24 *
    2425 * @author darya
    2526 *
     
    2728public class AddStopPositionAction extends JosmAction {
    2829
    29         /**
    30          *
    31         */
    32         private static final long serialVersionUID = -5140181388906670207L;
     30    /**
     31     *
     32    */
     33    private static final long serialVersionUID = -5140181388906670207L;
    3334
    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);
    3839
    39         }
     40    }
    4041
    41         /**
    42         * Actions that add the new node, set tags and update the map frame.
    43         */
    44         @Override
    45         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) {
    4647
    47                 if (!isEnabled() || !Main.isDisplayingMapView()) {
    48                         return;
    49                 }
    50                
    51                 final ActionEvent actionEventParameter = e;
     48        if (!isEnabled() || !Main.isDisplayingMapView()) {
     49            return;
     50        }
    5251
    53                 Main.map.mapView.addMouseListener(new MouseAdapter() {
     52        final ActionEvent actionEventParameter = e;
    5453
    55                         LatLon clickPosition;
     54        Main.map.mapView.addMouseListener(new MouseAdapter() {
    5655
     56            LatLon clickPosition;
    5757
    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) {
    6360
    64                                         Layer activeLayer = Main.getLayerManager().getActiveLayer();
     61                if (clickPosition == null) {
     62                    clickPosition = Main.map.mapView.getLatLon(e.getX(), e.getY());
    6563
    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();
    8265
    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();
    8474
    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);
    8778
    88                                 }
    89                         }
    90                 });
     79                        // split the way:
     80                        SplitWayAction splitWayAction = new SplitWayAction();
     81                        splitWayAction.actionPerformed(actionEventParameter);
    9182
    92         }
     83                    }
     84
     85                    Main.map.mapView.removeMouseListener(this);
     86                    Main.map.mapView.removeMouseMotionListener(this);
     87
     88                }
     89            }
     90        });
     91
     92    }
    9393
    9494}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.actions;
    23
     
    1112public class DownloadReferrersThread extends Thread {
    1213
    13         private Node node;
     14    private Node node;
    1415
    15         public DownloadReferrersThread(Node node) {
    16                 super();
    17                 this.node = node;
     16    public DownloadReferrersThread(Node node) {
     17        super();
     18        this.node = node;
    1819
    19         }
     20    }
    2021
    21         @Override
    22         public void run() {
     22    @Override
     23    public void run() {
    2324
    24                 synchronized (this) {
     25        synchronized (this) {
    2526
    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            }
    4536
    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        }
    4748
    4849
    49         }
     50    }
    5051
    5152}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.actions;
    23
     
    2021/**
    2122 * This class was copied with minor changes from ValidatorDialog.FixTask
    22  * 
     23 *
    2324 * @author darya
    2425 *
    2526 */
    26 public class FixTask extends PleaseWaitRunnable {
    27        
    28         private final Collection<TestError> testErrors;
    29         private boolean canceled;
     27public class FixTask extends PleaseWaitRunnable {
    3028
    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;
    3531
    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    }
    4036
    41         @Override
    42         protected void finish() {
    43                 // do nothing
    44         }
     37    @Override
     38    protected void cancel() {
     39        this.canceled = true;
     40    }
    4541
    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    }
    6546
    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    }
    115116
    116117}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.actions;
    23
     
    2122public class IncompleteMembersDownloadThread extends Thread {
    2223
    23         /**
    24         * Default constructor
    25         */
    26         public IncompleteMembersDownloadThread() {
    27                 super();
     24    /**
     25    * Default constructor
     26    */
     27    public IncompleteMembersDownloadThread() {
     28        super();
    2829
    29         }
     30    }
    3031
    31         @Override
    32         public void run() {
     32    @Override
     33    public void run() {
    3334
    34                 try {
    35                         synchronized (this) {
     35        try {
     36            synchronized (this) {
    3637
    37                                 ArrayList<PrimitiveId> list = new ArrayList<>();
     38                ArrayList<PrimitiveId> list = new ArrayList<>();
    3839
    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                }
    4647
    47                                 if (list.isEmpty()) {
    48                                         // add all route relations that are of public_transport
    49                                         // 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                }
    5758
    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);
    7273
    73                                                 }
     74                        }
    7475
    75                                         }
    76                                 }
     76                    }
     77                }
    7778
    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();
    8384
    84                         }
     85            }
    8586
    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        }
    8991
    90         }
     92    }
    9193}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.actions;
    23
     
    1516/**
    1617 * Carries out the changes after the Repeat last fix button has been pressed
    17  * 
     18 *
    1819 * @author darya
    1920 *
     
    2122public class RepeatLastFixAction extends JosmAction {
    2223
    23         private static final long serialVersionUID = 2681464946469047054L;
     24    private static final long serialVersionUID = 2681464946469047054L;
    2425
    25         /**
    26         * Default constructor
    27         */
    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);
    3233
    33         }
     34    }
    3435
    35         /**
    36         * Applies the fixes, resets the last fix attribute
    37         */
    38         @Override
    39         public void actionPerformed(ActionEvent e) {
     36    /**
     37    * Applies the fixes, resets the last fix attribute
     38    */
     39    @Override
     40    public void actionPerformed(ActionEvent e) {
    4041
    41                 if (!isEnabled() || !Main.isDisplayingMapView()) {
    42                         return;
    43                 }
     42        if (!isEnabled() || !Main.isDisplayingMapView()) {
     43            return;
     44        }
    4445
    45                 SegmentChecker.carryOutRepeatLastFix(PTAssistantPlugin.getLastFix());
     46        SegmentChecker.carryOutRepeatLastFix(PTAssistantPlugin.getLastFix());
    4647
    47                 PTAssistantPlugin.setLastFix(null);
     48        PTAssistantPlugin.setLastFix(null);
    4849
    49         }
     50    }
    5051
    5152}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1617 * Creates a representation of a route relation in the pt_assistant data model,
    1718 * then maintains a list of PTStops and PTWays of a route.
    18  * 
     19 *
    1920 * @author darya
    2021 *
     
    2223public class PTRouteDataManager {
    2324
    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    }
    429433
    430434}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1213 * will be two route segments between each pair of consecutive stops, one in
    1314 * each direction.
    14  * 
     15 *
    1516 * @author darya
    1617 *
     
    1920public class PTRouteSegment {
    2021
    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         * Constructor
    38         * @param firstStop first stop of the route segment
    39         * @param lastStop last stop of the route segment
    40         * @param ways ways PTWays that belong to this route segment
    41         * @param relation the route relation for which this route segment is created
    42         */
    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 segment
    54          * @return
    55         */
    56         public List<PTWay> getPTWays() {
    57                 return this.ptways;
    58         }
    59 
    60         /**
    61         * Sets the PTWays of this route segment to the given list
    62          * @param ptwayList
    63         */
    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 segment
    71          * @return
    72         */
    73         public PTStop getFirstStop() {
    74                 return this.firstStop;
    75         }
    76        
    77         /**
    78         * Returns the last stop of this route segment
    79          * @return
    80         */
    81         public PTStop getLastStop() {
    82                 return this.lastStop;
    83         }
    84 
    85         /**
    86         * Returns the first PTWay of this route segment
    87          * @return
    88         */
    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 segment
    98          * @return
    99         */
    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 segment
    109          * @return
    110         */
    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 segment
    120          * @return
    121         */
    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) is
    132         * not already contained in the list of the fix variants of this.
    133          *
    134         * @param list the PTWays of the new fix variant
    135         */
    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 segment
    166          * @return
    167         */
    168         public List<List<PTWay>> getFixVariants() {
    169                 return this.fixVariants;
    170         }
    171        
    172         /**
    173         * Returns the route relation for which this route segment was created
    174          * @return
    175         */
    176         public Relation getRelation() {
    177                 return this.relation;
    178         }
    179 
    180         /**
    181         * Checks if this and the other route segments are equal
    182          *
    183          * @param other
    184          * @return
    185         */
    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    }
    209210
    210211}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1415/**
    1516 * Model a stop with one or two elements (platform and/or stop_position)
    16  * 
     17 *
    1718 * @author darya
    1819 *
     
    2021public class PTStop extends RelationMember {
    2122
    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         * Constructor
    33          *
    34          * @param other
    35         * @throws IllegalArgumentException
    36         *             if the given relation member does not fit to the data model
    37         *             used in the plugin
    38         */
    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 check
    71          *
    72         * @param member
    73         *            Element to add
    74         * @return true if added successfully, false otherwise. A false value
    75         *         indicates either that the OsmPrimitiveType of the given
    76         *         RelationMember does not match its role or that this PTStop
    77         *         already has an attribute with that role.
    78         */
    79         protected boolean addStopElement(RelationMember member) {
    80 
    81                 // each element is only allowed once per stop
    82 
    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 not
    113         * available directly, the method searches for a stop_area relation
    114          *
    115          * @return
    116         */
    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          * @return
    126         */
    127         public OsmPrimitive getPlatform() {
    128                 return this.platform;
    129         }
    130 
    131         /**
    132         * Returns the name of this stop
    133          * @return
    134         */
    135         protected String getName() {
    136                 return this.name;
    137         }
    138 
    139         /**
    140         * Sets the stop_position for this stop to the given node
    141          * @param newStopPosition
    142         */
    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 only
    151         * 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 different
    153         * route, which this method does not check.
    154          *
    155         * @return List of potential stop_positions for this PTStop
    156         */
    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 this
    166                 // 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 same
    187         * stop_position or a platform
    188          *
    189         * @param other
    190         *            PTStop to be compared
    191         * @return true if equal, false otherwise
    192         */
    193         public boolean equalsStop(PTStop other) {
    194 
    195                 if (other == null) {
    196                         return false;
    197                 }
    198 
    199                 if (this.stopPosition != null
    200                                 && (this.stopPosition == other.getStopPosition() || this.stopPosition == other.getPlatform())) {
    201                         return true;
    202                 }
    203 
    204                 if (this.platform != null
    205                                 && (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    }
    211212
    212213}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1112/**
    1213 * Representation of PTWays, which can be of OsmPrimitiveType Way or Relation
    13  * 
     14 *
    1415 * @author darya
    1516 *
     
    1718public class PTWay extends RelationMember {
    1819
    19         /*
    20         * Ways that belong to this PTWay. If the corresponding relation member is
    21         * OsmPrimitiveType.WAY, this list size is 1. If the corresponding relation
    22         * 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<>();
    2526
    26         /**
    27          *
    28         * @param other
    29         *            the corresponding RelationMember
    30         * @throws IllegalArgumentException
    31         *             if the given relation member cannot be a PTWay due to its
    32         *             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 {
    3536
    36                 super(other);
     37        super(other);
    3738
    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.NODE
    51                         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        }
    5354
    54         }
     55    }
    5556
    56         /**
    57         * Returns the course of this PTWay. In most cases, this list only has 1
    58         * element. In the case of nested relations in a route, the list can have
    59         * multiple elements.
    60          *
    61          * @return
    62         */
    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    }
    6667
    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    }
    7678
    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    }
    8790
    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 correct
    91          *
    92          * @return
    93         */
    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];
    9699
    97                 if (this.isWay()) {
    98                         endNodes[0] = this.getWay().firstNode();
    99                         endNodes[1] = this.getWay().lastNode();
    100                         // TODO: if this is a roundabout
    101                 } 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        }
    117120
    118                 return endNodes;
    119         }
     121        return endNodes;
     122    }
    120123
    121         /**
    122         * Checks if this PTWay contains an unsplit roundabout (i.e. a way that
    123         * touches itself) among its ways
    124          *
    125          * @return
    126         */
    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() {
    128131
    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    }
    137140
    138         /**
    139         * Checks if the first Way of this PTWay is an unsplit roundabout (i.e. a
    140         * way that touches itself)
    141          *
    142          * @return
    143         */
    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    }
    150153
    151         /**
    152         * Checks if the last Way of this PTWay is an unsplit roundabout (i.e. a way
    153         * that touches itself)
    154          *
    155          * @return
    156         */
    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    }
    163166
    164167}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    1415public class DownloadReferrersDialog extends JPanel {
    1516
    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;
    2318
    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    }
    2624
    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;
    3127
    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;
    4032
    41         }
     33    public DownloadReferrersDialog() {
    4234
    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");
    5141
    52                 if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_FETCH) {
    53                         return JOptionPane.YES_OPTION;
    54                 }
     42    }
    5543
    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() {
    5952
    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        }
    7256
    73                 return selectedOption;
    74         }
     57        if (askToFetch == ASK_TO_FETCH.DONT_ASK_AND_DONT_FETCH) {
     58            return JOptionPane.NO_OPTION;
     59        }
    7560
    7661
     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    }
    7776}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    1011 * Dialog that asks the user whether the incomplete relation members should be
    1112 * downloaded.
    12  * 
     13 *
    1314 * @author darya
    1415 *
     
    1617public class IncompleteMembersDownloadDialog extends JPanel {
    1718
    18         private static final long serialVersionUID = -4275151182361040329L;
     19    private static final long serialVersionUID = -4275151182361040329L;
    1920
    20         // indicates if the user needs to be asked before fetching incomplete
    21         // members of a relation.
    22         public enum ASK_TO_FETCH {
    23                 DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH
    24         };
     21    // indicates if the user needs to be asked before fetching incomplete
     22    // members of a relation.
     23    public enum ASK_TO_FETCH {
     24        DO_ASK, DONT_ASK_AND_FETCH, DONT_ASK_AND_DONT_FETCH
     25    }
    2526
    26         // by default, the user should be asked
    27         public static ASK_TO_FETCH askToFetch;
     27    // by default, the user should be asked
     28    public static ASK_TO_FETCH askToFetch;
    2829
    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;
    3334
    34         public IncompleteMembersDownloadDialog() {
     35    public IncompleteMembersDownloadDialog() {
    3536
    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");
    4344
    44         }
     45    }
    4546
    46         /**
    47         * Finds out whether the user wants to download incomplete members. In the
    48         * default case, creates a JOptionPane to ask.
    49          *
    50         * @return JOptionPane.YES_OPTION if the incomplete members should be
    51         *         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() {
    5455
    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        }
    5859
    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        }
    6263
    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);
    6667
    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        }
    7475
    75                 return selectedOption;
    76         }
     76        return selectedOption;
     77    }
    7778
    7879}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    4041/**
    4142 * Layer that visualizes the routes in a more convenient way
    42  * 
     43 *
    4344 * @author darya
    4445 *
    4546 */
    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 layer
    71          *
    72          * @param primitive
    73         */
    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 layer
    93          *
    94          * @param fixVariants
    95         */
    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 to
    127         * the given character.
    128          *
    129          * @param c
    130          * @return
    131         */
    132         public List<PTWay> getFixVariant(char c) {
    133                 return this.fixVariants.get(Character.toUpperCase(c));
    134         }
    135 
    136         @Override
    137         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         @Override
    150         public Icon getIcon() {
    151                 return ImageProvider.get("layer", "osmdata_small");
    152         }
    153 
    154         @Override
    155         public Object getInfoComponent() {
    156                 return getToolTipText();
    157         }
    158 
    159         @Override
    160         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         @Override
    167         public String getToolTipText() {
    168                 return "pt_assistant layer";
    169         }
    170 
    171         @Override
    172         public boolean isMergable(Layer arg0) {
    173                 return false;
    174         }
    175 
    176         @Override
    177         public void mergeFrom(Layer arg0) {
    178                 // do nothing
    179 
    180         }
    181 
    182         @Override
    183         public void visitBoundingBox(BoundingXYVisitor arg0) {
    184                 // do nothing
    185 
    186         }
    187 
    188         @Override
    189         public LayerPositionStrategy getDefaultLayerPosition() {
    190                 return LayerPositionStrategy.IN_FRONT;
    191         }
    192 
    193         /**
    194         * Listens to a selection change
    195         */
    196         @Override
    197         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 route
    223         * relation in the top Relation Editor and repaints the map
    224         */
    225         @Override
    226         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 change
    251          *
    252          * @param relation
    253         */
    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         @Override
    277         public void layerAdded(LayerAddEvent arg0) {
    278                 // do nothing
    279         }
    280 
    281         @Override
    282         public void layerOrderChanged(LayerOrderChangeEvent arg0) {
    283                 // do nothing
    284 
    285         }
    286 
    287         @Override
    288         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         }
     47public 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    }
    298299}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    2728/**
    2829 * Visits the primitives to be visualized in the pt_assistant layer
    29  * 
     30 *
    3031 * @author darya
    3132 *
     
    3334public class PTAssistantPaintVisitor extends PaintVisitor {
    3435
    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    }
    595589
    596590}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    2122public class PTAssistantPreferenceSetting implements SubPreferenceSetting {
    2223
    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"));
    3126
    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) {
    4132
    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));
    4636
    47                 }
     37        mainPanel.add(downloadIncompleteMembers);
     38        mainPanel.add(stopArea);
    4839
    49         }
     40        downloadIncompleteMembers.setSelected(Main.pref.getBoolean("pt_assistant.download-incomplete", false));
     41        stopArea.setSelected(Main.pref.getBoolean("pt_assistant.stop-area-tests", true));
    5042
    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());
    5547
    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        }
    6549
    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    }
    7071
    7172}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.gui;
    23
     
    1920 * (i.e. if the errors found in the first stage of testing should be fixed
    2021 * before continuing with the testing).
    21  * 
     22 *
    2223 * @author darya
    2324 *
     
    2526public class ProceedDialog extends JPanel {
    2627
    27         private static final long serialVersionUID = 2986537034076698693L;
     28    private static final long serialVersionUID = 2986537034076698693L;
    2829
    29         public enum ASK_TO_PROCEED {
    30                 DO_ASK, DONT_ASK_AND_FIX_AUTOMATICALLY, DONT_ASK_AND_FIX_MANUALLY, DONT_ASK_AND_DONT_FIX
    31         };
     30    public enum ASK_TO_PROCEED {
     31        DO_ASK, DONT_ASK_AND_FIX_AUTOMATICALLY, DONT_ASK_AND_FIX_MANUALLY, DONT_ASK_AND_DONT_FIX
     32    }
    3233
    33         // by default, the user should be asked
    34         public static ASK_TO_PROCEED askToProceed;
     34    // by default, the user should be asked
     35    public static ASK_TO_PROCEED askToProceed;
    3536
    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;
    4344
    44         public ProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {
     45    public ProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {
    4546
    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));
    4849
    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);
    5253
    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        }
    5960
    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        }
    6667
    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);
    7071
    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);
    8485
    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);
    8889
    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";
    9293
    93                 selectedOption = Integer.MIN_VALUE;
     94        selectedOption = Integer.MIN_VALUE;
    9495
    95         }
     96    }
    9697
    97         /**
    98         * Finds out whether the user wants to download incomplete members. In the
    99         * default case, creates a JOptionPane to ask.
    100          *
    101         * @return 0 to fix automatically, 1 to fix manually, 2 to proceed without
    102         *         fixing, -1 to stop testing or if dialog is closed without answer
    103          *
    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() {
    106107
    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        }
    116117
    117                 // showDialog(); FIXME
    118                 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);
    120121
    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        }
    141142
    142                 return -1;
    143         }
     143        return -1;
     144    }
    144145
    145         /**
    146          *
    147         */
    148         @SuppressWarnings("unused")
    149         private void showDialog() {
     146    /**
     147     *
     148    */
     149    @SuppressWarnings("unused")
     150    private void showDialog() {
    150151
    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 {
    155156
    156                         SwingUtilities.invokeLater(new Runnable() {
    157                                 @Override
    158                                 public void run() {
    159                                         showDialog();
    160                                 }
    161                         });
     157            SwingUtilities.invokeLater(new Runnable() {
     158                @Override
     159                public void run() {
     160                    showDialog();
     161                }
     162            });
    162163
    163                 }
     164        }
    164165
    165         }
     166    }
    166167
    167168}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.utils;
    23
     
    1213/**
    1314 * Utils class for routes
    14  * 
     15 *
    1516 * @author darya
    1617 *
    1718 */
    18 public class RouteUtils {
    19 
    20         private RouteUtils() {
    21                 // private constructor for util classes
    22         }
    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 r
    29         *            Relation to be checked
    30         * @return true if the route belongs to the categories that can be validated
    31         *         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 transport
    56         * route. Some stops can be modeled with ways.
    57          *
    58         * @param rm
    59         *            relation member to be checked
    60         * @return true if the relation member refers to a stop, false otherwise
    61         */
    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 transport
    82         * route. Some OsmPrimitiveType.WAY have to be excluded because platforms
    83         * can be modeled with ways.
    84          *
    85         * @param rm
    86         *            relation member to be checked
    87         * @return true if the relation member refers to a way in a public transport
    88         *         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 public
    117         * transport. The test does not check whether the way violates those
    118         * restrictions.
    119          *
    120         * @return 0 if the way is not oneway for public transport, 1 if the way is
    121         *         oneway for public transport, -1 if the way is reversely oneway
    122         *         for public transport
    123         */
    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 node
    149          *
    150          * @param w1
    151          * @param w2
    152          * @return
    153         */
    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 == w2FirstNode
    166                                 || 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 the
    175         * second collection
    176          *
    177         * @param c1 first collection
    178         * @param c2 second collection
    179         * @return true if ways touch, false otherwise
    180         */
    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. The
    200         * direction of the way (i.e. one-way roads) is irrelevant for this test.
    201          *
    202         * @param way
    203         *            to be checked
    204         * @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 way
    230          * @return
    231         */
    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         }
     19public 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    }
    243244
    244245}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.utils;
    23
     
    2425 * list of already assigned stops, (2) checks if the stop has a stop position,
    2526 * (3) calculates it using proximity / growing bounding boxes
    26  * 
     27 *
    2728 * @author darya
    2829 *
     
    3031public class StopToWayAssigner {
    3132
    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    }
    377377
    378378}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.utils;
    23
     
    67/**
    78 * Utils class for stop areas
    8  * 
     9 *
    910 * @author
    1011 *
    1112 */
    12 public class StopUtils {
     13public final class StopUtils {
    1314
    14         private StopUtils() {
    15                 // private constructor for util classes
    16         }
     15    private StopUtils() {
     16        // private constructor for util classes
     17    }
    1718
    18         /**
    19         * Checks if a given relation is a stop_area.
    20          *
    21         * @param r
    22         *            Relation to be checked
    23         * @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) {
    2627
    27                 if (r == null) {
    28                         return false;
    29                 }
     28        if (r == null) {
     29            return false;
     30        }
    3031
    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    }
    3637
    37         /**
    38         * Checks if a given object is a stop_position.
    39          *
    40         * @param r
    41         *            Relation to be checked
    42         * @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) {
    4546
    46                 if (rm == null) {
    47                         return false;
    48                 }
     47        if (rm == null) {
     48            return false;
     49        }
    4950
    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    }
    5556
    56         /**
    57         * Checks if a given object is a platform.
    58          *
    59         * @param r
    60         *            Relation to be checked
    61         * @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) {
    6465
    65                 if (rm == null) {
    66                         return false;
    67                 }
     66        if (rm == null) {
     67            return false;
     68        }
    6869
    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    }
    7576
    76         /**
    77         * Checks if a given object is part of an stop area relation
    78          *
    79         * @param r
    80         *            Object to be checked
    81         * @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) {
    8485
    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    }
    9293
    9394}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    2526/**
    2627 * Represents tests and fixed of the PT_Assistant plugin
    27  * 
     28 *
    2829 * @author darya
    2930 *
     
    3132public abstract class Checker {
    3233
    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    }
    206202
    207203}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    2627public class NodeChecker extends Checker {
    2728
    28         protected NodeChecker(Node node, Test test) {
    29                 super(node, test);
     29    protected NodeChecker(Node node, Test test) {
     30        super(node, test);
    3031
    31         }
     32    }
    3233
    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() {
    3938
    40                 List<OsmPrimitive> referrers = node.getReferrers();
     39        List<OsmPrimitive> referrers = node.getReferrers();
    4140
    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                }
    4847
    49                         }
    50                 }
     48            }
     49        }
    5150
    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);
    5756
    58         }
     57    }
    5958
    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() {
    6663
    67                 List<OsmPrimitive> referrers = node.getReferrers();
     64        List<OsmPrimitive> referrers = node.getReferrers();
    6865
    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    }
    8481
    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() {
    9187
    92                 if (!StopUtils.verifyIfMemberOfStopArea(node)) {
     88        if (!StopUtils.verifyIfMemberOfStopArea(node)) {
    9389
    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    }
    10298
    103         /**
    104         * Fixes errors: solitary stop position and platform which is part of a way.
    105         * Asks the user first.
    106          *
    107          * @param testError
    108          * @return
    109         */
    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) {
    111107
    112                 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION
    113                                 && 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        }
    116112
    117                 Node problematicNode = (Node) testError.getPrimitives().iterator().next();
     113        Node problematicNode = (Node) testError.getPrimitives().iterator().next();
    118114
    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()) {
    122118
    123                         userSelection[0] = showFixNodeTagDialog(errorParameter);
     119            userSelection[0] = showFixNodeTagDialog(errorParameter);
    124120
    125                 } else {
     121        } else {
    126122
    127                         try {
    128                                 SwingUtilities.invokeAndWait(new Runnable() {
    129                                         @Override
    130                                         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        }
    139135
    140                 if (userSelection[0] == JOptionPane.YES_OPTION) {
     136        if (userSelection[0] == JOptionPane.YES_OPTION) {
    141137
    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        }
    153149
    154                 return null;
     150        return null;
    155151
    156         }
     152    }
    157153
    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);
    165161
    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    }
    176172
    177173}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    4041public class PTAssistantValidatorTest extends Test {
    4142
    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    }
    556555
    557556}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    2324/**
    2425 * Performs tests of a route at the level of the whole route: sorting test
    25  * 
     26 *
    2627 * @author darya
    2728 *
     
    2930public class RouteChecker extends Checker {
    3031
    31         private boolean hasGap;
     32    private boolean hasGap;
    3233
    33         List<RelationMember> sortedMembers;
     34    List<RelationMember> sortedMembers;
    3435
    35         public RouteChecker(Relation relation, Test test) {
     36    public RouteChecker(Relation relation, Test test) {
    3637
    37                 super(relation, test);
     38        super(relation, test);
    3839
    39                 this.hasGap = false;
     40        this.hasGap = false;
    4041
    41         }
     42    }
    4243
    43         protected void performSortingTest() {
     44    protected void performSortingTest() {
    4445
    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()) {
    4748
    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        }
    5253
    53                 if (waysToCheck.isEmpty()) {
    54                         return;
    55                 }
     54        if (waysToCheck.isEmpty()) {
     55            return;
     56        }
    5657
    57                 if (hasGap(waysToCheck)) {
     58        if (hasGap(waysToCheck)) {
    5859
    59                         this.hasGap = true;
     60            this.hasGap = true;
    6061
    61                         RelationSorter sorter = new RelationSorter();
    62                         sortedMembers = sorter.sortMembers(waysToCheck);
     62            RelationSorter sorter = new RelationSorter();
     63            sortedMembers = sorter.sortMembers(waysToCheck);
    6364
    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);
    6970
    70                         }
     71            }
    7172
    72                 }
     73        }
    7374
    74         }
     75    }
    7576
    76         /**
    77         * Checks if there is a gap for a given list of ways. It does not check if
    78         * the way actually stands for a public transport platform - that should be
    79         * checked beforehand.
    80          *
    81          * @param waysToCheck
    82         * @return true if has gap (in the sense of continuity of ways in the
    83         *         Relation Editor), false otherwise
    84         */
    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;
    9495
    95                         }
    96                 }
     96            }
     97        }
    9798
    98                 return false;
    99         }
     99        return false;
     100    }
    100101
    101         public List<RelationMember> getSortedMembers() {
     102    public List<RelationMember> getSortedMembers() {
    102103
    103                 return sortedMembers;
     104        return sortedMembers;
    104105
    105         }
     106    }
    106107
    107         public boolean getHasGap() {
     108    public boolean getHasGap() {
    108109
    109                 return this.hasGap;
     110        return this.hasGap;
    110111
    111         }
    112        
    113         protected static Command fixSortingError(TestError testError) {
    114                 if (testError.getCode() != PTAssistantValidatorTest.ERROR_CODE_SORTING) {
    115                         return null;
    116                 }
     112    }
    117113
    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        }
    120118
    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();
    134121
    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                }
    149135
    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                }
    152150
    153                 // sort the ways:
    154                 RelationSorter sorter = new RelationSorter();
    155                 List<RelationMember> sortedWays = sorter.sortMembers(ways);
     151            }
     152        }
    156153
    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);
    167157
    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);
    169168
    170                 return changeCommand;
     169        ChangeCommand changeCommand = new ChangeCommand(originalRelation, sortedRelation);
    171170
    172         }
     171        return changeCommand;
     172
     173    }
    173174
    174175}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    4041 * Performs tests of a route at the level of route segments (the stop-by-stop
    4142 * approach).
    42  * 
     43 *
    4344 * @author darya
    4445 *
     
    4647public class SegmentChecker extends Checker {
    4748
    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    }
    10651061
    10661062}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1718/**
    1819 * Performs tests of the stop area relations
    19  * 
     20 *
    2021 * @author
    2122 *
     
    2324public class StopChecker extends Checker {
    2425
    25         Set<OsmPrimitive> members;
     26    Set<OsmPrimitive> members;
    2627
    27         protected StopChecker(Relation relation, Test test) {
    28                 super(relation, test);
     28    protected StopChecker(Relation relation, Test test) {
     29        super(relation, test);
    2930
    30                 this.members = relation.getMemberPrimitives();
    31         }
     31        this.members = relation.getMemberPrimitives();
     32    }
    3233
    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() {
    3738
    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        }
    4445
    45                 // Throw error message
    46                 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    }
    5253
    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() {
    5758
    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        }
    6465
    65                 // Throw error message
    66                 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);
    7172
    72         }
     73    }
    7374
    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() {
    8180
    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<>();
    8483
    85                 // Loop through all members
    86                 for (OsmPrimitive member : members) {
     84        // Loop through all members
     85        for (OsmPrimitive member : members) {
    8786
    88                         // For stop positions...
    89                         if (StopUtils.verifyStopAreaStopPosition(member)) {
     87            // For stop positions...
     88            if (StopUtils.verifyStopAreaStopPosition(member)) {
    9089
    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)) {
    9898
    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        }
    101107
    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        }
    110114
    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        }
    117119
    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    }
    131128
    132129}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    2526 * Performs tests of a route at the level of single ways: DirectionTest and
    2627 * RoadTypeTest
    27  * 
     28 *
    2829 * @author darya
    2930 *
     
    3132public class WayChecker extends Checker {
    3233
    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    }
    443445
    444446}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant;
    23
     
    1314public abstract class AbstractTest {
    1415
    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"; //
    1617 public static final String PATH_TO_DL131_AFTER = "test/data/DL131_after.osm";
    17  
     18
    1819 public static final String PATH_TO_DL4_BEFORE = "test/data/DL4_before.osm";
    1920 public static final String PATH_TO_DL4_AFTER = "test/data/DL4_after.osm";
    20  
     21
    2122 public static final String PATH_TO_DL49_BEFORE = "test/data/DL49_before.osm"; // has wrong way sorting
    2223 public static final String PATH_TO_DL49_AFTER = "test/data/DL49_after.osm";
    23  
     24
    2425 public static final String PATH_TO_DL60_BEFORE = "test/data/DL60_before.osm";
    2526 public static final String PATH_TO_DL60_AFTER = "test/data/DL60_after.osm";
    26  
     27
    2728 public static final String PATH_TO_DL94_BEFORE = "test/data/DL94_before.osm";
    2829 public static final String PATH_TO_DL94_AFTER = "test/data/DL94_after.osm";
    29  
     30
    3031 public static final String PATH_TO_DL286_BEFORE = "test/data/DL286_before.osm";
    3132 public static final String PATH_TO_DL286_AFTER = "test/data/DL286_after.osm";
    32  
     33
    3334 public static final String PATH_TO_TEC366_BEFORE = "test/data/TL366_before.osm";
    3435 public static final String PATH_TO_TEC366_AFTER = "test/data/TL366_after.osm";
    35  
     36
    3637 public static final String PATH_TO_PLATFORM_AS_WAY = "test/data/route-with-platform-as-way.osm";
    37  
     38
    3839 public static final String PATH_TO_ROUNDABOUT_ONEWAY = "test/data/duesseldorf_roundabout.osm";
    39  
     40
    4041 public static final String PATH_TO_ROAD_TYPE_ERROR = "test/data/road-type.osm";
    41  
     42
    4243 public static final String PATH_TO_ONEWAY_BAD_MEMBER_SORTING = "test/data/oneway-bad-member-sorting.osm";
    43  
     44
    4445 public static final String PATH_TO_ONEWAY_WRONG_DIRECTION = "test/data/oneway-wrong-direction.osm";
    4546 public static final String PATH_TO_ONEWAY_WRONG_DIRECTION2 = "test/data/oneway-wrong-direction2.osm";
    46  
     47
    4748 public static final String PATH_TO_SOLITARY_STOP_POSITION = "test/data/solitary-stop-position.osm";
    4849
     
    5455 public static final String PATH_TO_STOP_AREA_MANY_PLATFORMS = "test/data/stop-area-many-platforms.osm";
    5556
    56  
     57
    5758 public static final String PATH_TO_SEGMENT_TEST = "test/data/segment-test.osm";
    5859
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant;
    2 
    3 /**
    4  * This class provides functionality used by multiple test classes of pt_assistant plugin.
    5  */
    63
    74import java.io.File;
     
    1815import org.openstreetmap.josm.io.OsmImporter.OsmImporterData;
    1916
    20 public class ImportUtils {
    21    
     17/**
     18 * This class provides functionality used by multiple test classes of pt_assistant plugin.
     19 */
     20public final class ImportUtils {
     21
    2222    private ImportUtils() {
    2323        // private constructor for utils classes
     
    4242            e.printStackTrace();
    4343        }
    44        
     44
    4545        return null;
    46 
    4746    }
    48 
    49 
    50 
    5147}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant;
    23
     
    3435   * That is needed e.g. to use {@link MapillaryLayer#getInstance()}
    3536   */
    36   public static final synchronized void initPlugin() {
     37  public static synchronized void initPlugin() {
    3738    if (!isInitialized) {
    3839      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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1516 * Tests if the representation of a route relation is created correctly in the
    1617 * pt_assistant plugin
    17  * 
     18 *
    1819 * @author darya
    1920 *
    2021 */
    2122public class RouteRepresentationTest extends AbstractTest {
    22    
     23
    2324    @Test
    2425    public void correctRouteTest() {
    25        
     26
    2627        /*-
    2728         * Create a [correct] route which has:
     
    3637         * way4 (Way)
    3738         * stop5 (platform_exit_only, Relation)
    38          * 
     39         *
    3940         */
    40        
     41
    4142        ArrayList<RelationMember> members = new ArrayList<>();
    42        
     43
    4344        // Create stops:
    44         Node n1 = new Node(); 
     45        Node n1 = new Node();
    4546        n1.put("name", "Stop1");
    4647        n1.put("public_transport", "stop_position");
     
    7273        RelationMember rm6 = new RelationMember("platform_exit_only", n5);
    7374        members.add(rm6);
    74                
     75
    7576        // Create ways:
    7677        Way w2 = new Way();
     
    9293        RelationMember rm10 = new RelationMember("", w7);
    9394        members.add(rm10);
    94        
     95
    9596        Relation route = new Relation();
    9697        route.setMembers(members);
    97        
     98
    9899        PTRouteDataManager manager = new PTRouteDataManager(route);
    99    
     100
    100101        assertEquals(manager.getPTStopCount(), 5);
    101102        assertEquals(manager.getPTWayCount(), 4);
    102        
     103
    103104    }
    104    
     105
    105106    @Test
    106107    public void nestedRelationTest() {
    107        
     108
    108109        // Same as above, but the nested Relation has a Node (only ways are allowed)
    109        
     110
    110111        ArrayList<RelationMember> members = new ArrayList<>();
    111        
     112
    112113        // Create stops:
    113         Node n1 = new Node(); 
     114        Node n1 = new Node();
    114115        n1.put("name", "Stop1");
    115116        n1.put("public_transport", "stop_position");
     
    141142        RelationMember rm6 = new RelationMember("platform_exit_only", n5);
    142143        members.add(rm6);
    143                
     144
    144145        // Create ways:
    145146        Way w2 = new Way();
     
    161162        RelationMember rm10 = new RelationMember("", w7);
    162163        members.add(rm10);
    163        
    164        
     164
     165
    165166        Relation route = new Relation();
    166167        route.setMembers(members);
    167        
     168
    168169        PTRouteDataManager manager = new PTRouteDataManager(route);
    169        
     170
    170171        assertEquals(manager.getFailedMembers().size(), 1);
    171172        assertEquals(manager.getPTStopCount(), 5);
    172173        assertEquals(manager.getPTWayCount(), 3);
    173        
    174174    }
    175    
    176175}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.data;
    23
     
    1415
    1516public class StopToWayAssignerTest extends AbstractTest {
    16        
    17         @Test
    18         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        
    6017
     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    }
    6157}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1819public class AdjacentWaysTest extends AbstractTest {
    1920
    20         @Test
    21         public void test1() {
     21    @Test
     22    public void test1() {
    2223
    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");
    2526
    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);
    4330
    44         }
    45        
    46         @Test
    47         public void test2() {
     31        assertEquals(RouteUtils.isOnewayForPublicTransport(way), -1);
    4832
    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        }
    5139
    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>());
    6442
    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);
    6944
    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    }
    7172
    7273}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1920public class DirecionTestTest extends AbstractTest {
    2021
    21         @Test
    22         public void testOnewayTrue() {
     22    @Test
     23    public void testOnewayTrue() {
    2324
    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");
    2627
    27                 PTAssistantValidatorTest test = new PTAssistantValidatorTest();
     28        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    2829
    29                 List<TestError> errors = new ArrayList<>();
     30        List<TestError> errors = new ArrayList<>();
    3031
    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        }
    3637
    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        }
    4445
    45                 assertEquals(onewayErrorCaught, 2);
     46        assertEquals(onewayErrorCaught, 2);
    4647
    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        }
    5960
    60                 assertTrue(detectedErrorsAreCorrect);
    61         }
     61        assertTrue(detectedErrorsAreCorrect);
     62    }
    6263}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1415import org.openstreetmap.josm.plugins.pt_assistant.ImportUtils;
    1516
    16 public class PlatformAsWayTest extends AbstractTest{
    17    
     17public class PlatformAsWayTest extends AbstractTest {
     18
    1819    @Test
    1920    public void sortingTest() {
    2021        File file = new File(AbstractTest.PATH_TO_PLATFORM_AS_WAY);
    2122        DataSet ds = ImportUtils.importOsmFile(file, "testLayer");
    22        
     23
    2324        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    24        
     25
    2526        List<TestError> errors = new ArrayList<>();
    26        
     27
    2728        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());
    3536        }
    36        
     37
    3738        assertEquals(errors.size(), 0);
    3839    }
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1819
    1920public class RoadTypeTestTest extends AbstractTest {
    20    
     21
    2122    @Test
    2223    public void test() {
    23        
     24
    2425        File file = new File(AbstractTest.PATH_TO_ROAD_TYPE_ERROR);
    2526        DataSet ds = ImportUtils.importOsmFile(file, "testLayer");
    26        
     27
    2728        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    2829        List<TestError> errors = new ArrayList<>();
    29        
     30
    3031        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());
    3435        }
    35        
     36
    3637        assertEquals(errors.size(), 2);
    37        
     38
    3839        for (TestError e: errors) {
    3940            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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    1314
    1415public class SegmentCheckerTest extends AbstractTest {
    15        
    16         @Test
    17         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    }
    4243}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
     3
     4import static org.junit.Assert.assertEquals;
    25
    36import java.io.File;
    47
    58import org.junit.Test;
    6 import static org.junit.Assert.assertEquals;
    79import org.openstreetmap.josm.data.osm.DataSet;
    810import org.openstreetmap.josm.data.osm.Node;
     
    1214public class SolitaryStopPositionTest extends AbstractTest {
    1315
    14         @Test
    15         public void test1() {
     16    @Test
     17    public void test1() {
    1618
    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();
    2022
    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        }
    3133
    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);
    3739
    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);
    4345
    44         }
     46    }
    4547}
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
     
    2021        File file = new File(AbstractTest.PATH_TO_DL131_BEFORE);
    2122        DataSet ds = ImportUtils.importOsmFile(file, "testLayer");
    22        
     23
    2324        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    2425
    2526        List<TestError> errors = new ArrayList<>();
    26        
     27
    2728        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
    3233        }
    3334
     
    4142        File file = new File(AbstractTest.PATH_TO_DL131_AFTER);
    4243        DataSet ds = ImportUtils.importOsmFile(file, "testLayer");
    43        
     44
    4445        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    4546
    4647        List<TestError> errors = new ArrayList<>();
    47        
     48
    4849        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
    5354        }
    5455
     
    8081        File file = new File(AbstractTest.PATH_TO_DL286_AFTER);
    8182        DataSet ds = ImportUtils.importOsmFile(file, "testLayer");
    82        
     83
    8384        PTAssistantValidatorTest test = new PTAssistantValidatorTest();
    8485
    8586        List<TestError> errors = new ArrayList<>();
    86        
     87
    8788        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());
    9192        }
    9293
  • 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.
    12package org.openstreetmap.josm.plugins.pt_assistant.validation;
    23
    34import java.io.File;
    45
     6import org.junit.Assert;
    57import org.junit.Test;
    6 import org.junit.Assert;
    78import org.openstreetmap.josm.data.osm.DataSet;
    89import org.openstreetmap.josm.data.osm.Node;
     
    1314public class StopCheckerTest extends AbstractTest {
    1415
    15         @Test
    16         public void nodePartOfStopAreaTest() {
     16    @Test
     17    public void nodePartOfStopAreaTest() {
    1718
    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:
    3020
    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;
    3825
     26        for (Node n : ds.getNodes()) {
     27            if (n.hasTag("public_transport", "stop_position") | n.hasTag("public_transport", "platform")) {
     28                node = n;
     29            }
     30        }
    3931
    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    }
    6338
    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() {
    7341
    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)
    8543
    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;
    8848
    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        }
    9854
    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    }
    11061
    111         }
     62    @Test
     63    public void stopAreaStopPositionTest() {
    11264
     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    }
    113108}
Note: See TracChangeset for help on using the changeset viewer.