Ignore:
Timestamp:
2016-06-04T11:30:23+02:00 (9 years ago)
Author:
darya
Message:

Correction to exclude platforms modeled as ways from sorting, fix for single overshoot segments added

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

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/GapTest.java

    r32209 r32217  
    66import java.util.List;
    77
     8import org.openstreetmap.josm.command.ChangeCommand;
     9import org.openstreetmap.josm.command.Command;
     10import org.openstreetmap.josm.command.SequenceCommand;
     11import org.openstreetmap.josm.data.osm.OsmPrimitive;
    812import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    913import org.openstreetmap.josm.data.osm.Relation;
    1014import org.openstreetmap.josm.data.osm.RelationMember;
     15import org.openstreetmap.josm.data.osm.Way;
    1116import org.openstreetmap.josm.data.validation.Severity;
    1217import org.openstreetmap.josm.data.validation.Test;
     
    1520import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
    1621import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionTypeCalculator;
     22import org.openstreetmap.josm.plugins.pt_assistant.utils.RouteUtils;
    1723
    1824public class GapTest extends Test {
    19        
     25
    2026        public static final int ERROR_CODE_SORTING = 3711;
    21         public static final int ERROR_CODE_OTHER_GAP = 3712;
     27        public static final int ERROR_CODE_OVERSHOOT = 3712;
     28        public static final int ERROR_CODE_OTHER_GAP = 3719;
     29
     30        private List<RelationMember> overshootList = new ArrayList<>();
    2231
    2332        public GapTest() {
     
    2837        public void visit(Relation r) {
    2938
    30                 if (r.hasKey("route")) {
    31 
     39                if (RouteUtils.isTwoDirectionRoute(r)) {
    3240                        List<RelationMember> members = r.getMembers();
    3341                        final List<RelationMember> waysToCheck = new ArrayList<>();
    3442                        for (RelationMember member : members) {
    3543                                if (member.hasRole("") && OsmPrimitiveType.WAY.equals(member.getType())) {
    36                                         waysToCheck.add(member);
     44                                        Way way = member.getWay();
     45                                        if (!way.hasTag("public_transport", "platform") && !way.hasTag("highway", "platform")
     46                                                        && !way.hasTag("railway", "platform")) {
     47                                                waysToCheck.add(member);
     48                                        }
    3749                                }
    3850                        }
     
    4557                                RelationSorter sorter = new RelationSorter();
    4658                                List<RelationMember> correctedList = sorter.sortMembers(waysToCheck);
    47                                 if (hasGap(correctedList)) {
    48                                         System.out.println("other error type");
    49                                         errors.add(new TestError(this, Severity.WARNING,
    50                                                         tr("PT: Route contains a gap that cannot be fixed by sorting the ways."), ERROR_CODE_OTHER_GAP, r));
    51                                 } else {
    52                                         System.out.println("sorting error");
     59
     60                                if (!hasGap(correctedList)) {
    5361                                        errors.add(new TestError(this, Severity.WARNING,
    5462                                                        tr("PT: Route contains a gap that can be fixed by sorting"), ERROR_CODE_SORTING, r));
    55                                 }
     63                                } else {
     64                                        List<RelationMember> overshoots = this.getOvershoots(correctedList);
     65                                        if (!overshoots.isEmpty()) {
     66                                                // TODO: make sure that duplicates are removed first
     67                                                overshootList = overshoots;
     68                                                errors.add(new TestError(this, Severity.WARNING, tr("PT: Route contains an overshoot"),
     69                                                                ERROR_CODE_OVERSHOOT, r));
     70                                        } else {
     71                                                errors.add(new TestError(this, Severity.WARNING,
     72                                                                tr("PT: Route contains a gap that cannot be fixed by sorting the ways"),
     73                                                                ERROR_CODE_OTHER_GAP, r));
     74                                        }
     75                                }
     76
    5677                        }
    5778
     
    82103        }
    83104
     105        /**
     106         * Checks if there is a single "hanging" way (perhaps left after a way
     107         * split) that can be easily removed.
     108         *
     109         * @param sortedWays
     110         *            is a list of ways only that should be sorted with the
     111         *            RelationSorter before this method is called. No error occurs
     112         *            if they are unsorted, but the method call is pointless if they
     113         *            are in a wrong order.
     114         * @return true is there is such a way, false otherwise
     115         */
     116        private List<RelationMember> getOvershoots(List<RelationMember> sortedWays) {
     117
     118                List<RelationMember> overshoots = new ArrayList<>();
     119
     120                if (sortedWays.size() < 5) {
     121                        // the route has to have at least five ways to be able to have an
     122                        // overshoot. I assume that the overshoot cannot touch the very
     123                        // first or the very last way in a route because then it would not
     124                        // be clear which of the ways would be an overshoot.
     125                        /*-
     126                         *  x              x             x
     127                         *   \ A           |D           / G
     128                         *    \            |           /
     129                         *     x-----------x----------x
     130                         *    /      C     |    F      \
     131                         *   / B           |E           \ H
     132                         *  x                      x             x
     133                         * 
     134                         *  Example: ways D and E can be overshoots (from the point of
     135                         *  view of this method), but ways A, B, G and H cannot.
     136                         *  Therefore, a relation must have at least 4 "good" ways
     137                         *  in order to be able to have an overshoot.
     138                         */
     139
     140                        return overshoots;
     141                }
     142
     143                for (int i = 2; i < sortedWays.size() - 3; i++) {
     144                        Way prev = sortedWays.get(i - 1).getWay();
     145                        Way curr = sortedWays.get(i).getWay();
     146                        Way next = sortedWays.get(i + 1).getWay();
     147                        boolean firstNodeConnectedToPrev = (curr.firstNode() == prev.firstNode()
     148                                        || curr.firstNode() == prev.lastNode());
     149                        boolean lastNodeConnectedToPrev = (curr.lastNode() == prev.firstNode()
     150                                        || curr.lastNode() == prev.lastNode());
     151                        boolean firstNodeConnectedToNext = (curr.firstNode() == next.firstNode()
     152                                        || curr.firstNode() == next.lastNode());
     153                        boolean lastNodeConnectedToNext = (curr.lastNode() == next.firstNode()
     154                                        || curr.lastNode() == next.lastNode());
     155                        if ((firstNodeConnectedToPrev && firstNodeConnectedToNext)
     156                                        || (lastNodeConnectedToPrev && lastNodeConnectedToNext)) {
     157                                overshoots.add(sortedWays.get(i));
     158                        }
     159
     160                }
     161
     162                return overshoots;
     163        }
     164
     165        @Override
     166        public Command fixError(TestError testError) {
     167
     168                List<Command> commands = new ArrayList<>(50);
     169
     170                if (testError.getTester().getClass().equals(GapTest.class) && testError.isFixable()) {
     171
     172                        // If this is an error that can be fixed simply by sorting the ways:
     173                        if (testError.getCode() == ERROR_CODE_SORTING) {
     174                                for (OsmPrimitive primitive : testError.getPrimitives()) {
     175                                        Relation relation = (Relation) primitive;
     176                                        // separate ways from stops (because otherwise the order of
     177                                        // stops/platforms can be messed up by the sorter:
     178                                        List<RelationMember> members = relation.getMembers();
     179                                        final List<RelationMember> stops = new ArrayList<>();
     180                                        final List<RelationMember> ways = new ArrayList<>();
     181                                        for (RelationMember member : members) {
     182                                                if (member.hasRole("") && OsmPrimitiveType.WAY.equals(member.getType())) {
     183                                                        ways.add(member);
     184                                                } else { // stops (and if the relation has anything
     185                                                                        // besides ways and stops:
     186                                                        stops.add(member);
     187                                                }
     188                                        }
     189
     190                                        // sort the ways:
     191                                        RelationSorter sorter = new RelationSorter();
     192                                        List<RelationMember> sortedWays = sorter.sortMembers(ways);
     193
     194                                        // create a new relation to pass to the command:
     195                                        Relation sortedRelation = new Relation(relation);
     196                                        List<RelationMember> sortedRelationMembers = new ArrayList<>(members.size());
     197                                        for (RelationMember rm : stops) {
     198                                                sortedRelationMembers.add(rm);
     199                                        }
     200                                        for (RelationMember rm : sortedWays) {
     201                                                sortedRelationMembers.add(rm);
     202                                        }
     203                                        sortedRelation.setMembers(sortedRelationMembers);
     204
     205                                        ChangeCommand changeCommand = new ChangeCommand(relation, sortedRelation);
     206
     207                                        commands.add(changeCommand);
     208
     209                                }
     210
     211                        }
     212
     213                        // if the error is a single overshoot:
     214                        if (testError.getCode() == ERROR_CODE_OVERSHOOT) {
     215                                // commands.add(testError.getFix());
     216                                for (OsmPrimitive primitive : testError.getPrimitives()) {
     217                                        Relation originalRelation = (Relation) primitive;
     218                                        Relation modifiedRelation = new Relation(originalRelation);
     219                                        List<RelationMember> modifiedMembers = new ArrayList<>();
     220                                        for (RelationMember rm : originalRelation.getMembers()) {
     221                                                if (rm.getType().equals(OsmPrimitiveType.WAY) && !overshootList.contains(rm)) {
     222                                                        modifiedMembers.add(rm);
     223                                                }
     224                                        }
     225                                        modifiedRelation.setMembers(modifiedMembers);
     226
     227                                        ChangeCommand changeCommand = new ChangeCommand(originalRelation, modifiedRelation);
     228                                        commands.add(changeCommand);
     229                                }
     230
     231                        }
     232                }
     233
     234                if (commands.isEmpty()) {
     235                        return null;
     236                }
     237
     238                if (commands.size() == 1) {
     239                        return commands.get(0);
     240                }
     241
     242                return new SequenceCommand(tr("Fix gaps in public transport route"), commands);
     243
     244        }
     245
     246        /**
     247         * Checks if the test error is fixable
     248         */
     249        @Override
     250        public boolean isFixable(TestError testError) {
     251                if (testError.getCode() == ERROR_CODE_SORTING || testError.getCode() == ERROR_CODE_OVERSHOOT) {
     252                        return true;
     253                }
     254                return false;
     255        }
    84256
    85257}
Note: See TracChangeset for help on using the changeset viewer.