Ticket #10682: PT.diff

File PT.diff, 21.3 KB (added by freeExec, 11 years ago)
  • relcontext/RelContextDialog.java

     
    8888import relcontext.actions.EditChosenRelationAction;
    8989import relcontext.actions.FindRelationAction;
    9090import relcontext.actions.ReconstructPolygonAction;
     91import relcontext.actions.ReconstructRouteAction;
    9192import relcontext.actions.RelationHelpAction;
    9293import relcontext.actions.SelectInRelationPanelAction;
    9394import relcontext.actions.SelectMembersAction;
     
    423424
    424425    private static Map<String, List<String>> loadRoles() {
    425426        Map<String, List<String>> result = new HashMap<>();
     427
    426428        ClassLoader classLoader = RelContextDialog.class.getClassLoader();
    427429        try (
    428430            InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE);
     
    525527            add(new DeleteChosenRelationAction(chosenRelation));
    526528            add(new DownloadParentsAction(chosenRelation));
    527529            add(new ReconstructPolygonAction(chosenRelation));
     530            add(new ReconstructRouteAction(chosenRelation));
    528531            addSeparator();
    529532            add(new SelectInRelationPanelAction(chosenRelation));
    530533            add(new RelationHelpAction(chosenRelation));
  • relcontext/actions/PublicTransportHelper.java

     
     1package relcontext.actions;
     2
     3import org.openstreetmap.josm.data.osm.Node;
     4import org.openstreetmap.josm.data.osm.OsmPrimitive;
     5import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     6import org.openstreetmap.josm.data.osm.RelationMember;
     7import org.openstreetmap.josm.data.osm.Way;
     8
     9/**
     10 * @see http://wiki.openstreetmap.org/wiki/Key:public_transport
     11 */
     12
     13/**
     14 *
     15 * @author freeExec
     16 */
     17public final class PublicTransportHelper {
     18
     19    public final static String PUBLIC_TRANSPORT = "public_transport";
     20    public final static String STOP_POSITION = "stop_position";
     21    public final static String STOP = "stop";
     22    public final static String STOP_AREA = "stop_area";
     23    public final static String PLATFORM = "platform";
     24    public final static String HIGHWAY = "highway";
     25    public final static String RAILWAY = "railway";
     26    public final static String BUS_STOP = "bus_stop";
     27    public final static String RAILWAY_HALT = "halt";
     28    public final static String RAILWAY_STATION = "station";   
     29   
     30    private PublicTransportHelper() {
     31        // Hide default constructor for utils classes
     32    }       
     33   
     34    public static String getRoleByMember(RelationMember m) {
     35        if (isMemberStop(m)) return STOP;
     36        else if (isMemberPlatform(m)) return PLATFORM;
     37        return null;
     38    }
     39   
     40    public static boolean isMemberStop(RelationMember m) {
     41        return isNodeStop(m);   // stop is only node
     42    }
     43   
     44    public static boolean isMemberPlatform(RelationMember m) {
     45        return isNodePlatform(m) || isWayPlatform(m);
     46    }
     47   
     48    public static boolean isNodeStop(RelationMember m) {
     49        return isNodeStop(m.getMember());
     50    }
     51   
     52    public static boolean isNodeStop(OsmPrimitive p) {
     53        if (p.getType() == OsmPrimitiveType.NODE && !p.isIncomplete()) {
     54            if (p.hasKey(PUBLIC_TRANSPORT)) {
     55                String pt = p.get(PUBLIC_TRANSPORT);
     56                if (STOP_POSITION.equals(pt)) return true;
     57            }
     58            else if (p.hasKey(RAILWAY)) {
     59                String rw = p.get(RAILWAY);
     60                if (RAILWAY_HALT.equals(rw) || RAILWAY_STATION.equals(rw)) return true;
     61            }
     62        }
     63        return false;
     64    }
     65   
     66    public static boolean isNodePlatform(RelationMember m) {
     67        return isNodePlatform(m.getMember());
     68    }
     69   
     70    public static boolean isNodePlatform(OsmPrimitive p) {
     71        if (p.getType() == OsmPrimitiveType.NODE && !p.isIncomplete()) {
     72            if (p.hasKey(PUBLIC_TRANSPORT)) {
     73                String pt = p.get(PUBLIC_TRANSPORT);
     74                if (PLATFORM.equals(pt)) return true;
     75            } else if (p.hasKey(HIGHWAY)) {
     76                String hw = p.get(HIGHWAY);
     77                if (BUS_STOP.equals(hw)) return true;
     78                else if (PLATFORM.equals(hw)) return true;
     79            } else if (p.hasKey(RAILWAY)) {
     80                String rw = p.get(RAILWAY);
     81                if (PLATFORM.equals(rw)) return true;
     82            }
     83        }
     84        return false;
     85    }
     86    public static boolean isWayPlatform(RelationMember m) {
     87        return isWayPlatform(m.getMember());
     88    }
     89   
     90    public static boolean isWayPlatform(OsmPrimitive p) {
     91        if (p.getType() == OsmPrimitiveType.WAY && !p.isIncomplete()) {
     92            if (p.hasKey(PUBLIC_TRANSPORT)) {
     93                String pt = p.get(PUBLIC_TRANSPORT);
     94                if (PLATFORM.equals(pt)) return true;
     95            } else if (p.hasKey(HIGHWAY)) {
     96                String hw = p.get(HIGHWAY);
     97                if (PLATFORM.equals(hw)) return true;
     98            } else if (p.hasKey(RAILWAY)) {
     99                String rw = p.get(RAILWAY);
     100                if (PLATFORM.equals(rw)) return true;
     101            }
     102        }
     103        return false;
     104    }
     105   
     106    public static boolean isMemberRouteway(RelationMember m) {
     107        return isWayRouteway(m.getMember());
     108    }
     109   
     110    public static boolean isWayRouteway(OsmPrimitive p) {
     111        if (p.getType() == OsmPrimitiveType.WAY && !p.isIncomplete()) {
     112            return p.hasKey(HIGHWAY) || p.hasKey(RAILWAY);
     113        }
     114        return false;
     115    }
     116   
     117    public static String getNameViaStoparea(RelationMember m) {
     118        return getNameViaStoparea(m.getMember());
     119    }
     120   
     121    public static String getNameViaStoparea(OsmPrimitive prim) {
     122        String result = prim.getName();
     123        if (result != null) return result;
     124        // try to get name by stop_area
     125        for (OsmPrimitive refOp : prim.getReferrers())
     126            if (refOp.getType() == OsmPrimitiveType.RELATION
     127                && refOp.hasTag(PUBLIC_TRANSPORT, STOP_AREA)) {
     128                result = refOp.getName();
     129                if (result != null) return result;
     130            }
     131        return result;
     132    }   
     133}
  • relcontext/actions/ReconstructRouteAction.java

     
     1package relcontext.actions;
     2
     3import java.awt.event.ActionEvent;
     4import java.util.ArrayList;
     5import java.util.LinkedHashMap;
     6import java.util.List;
     7import java.util.Map;
     8import javax.swing.AbstractAction;
     9import static javax.swing.Action.LONG_DESCRIPTION;
     10import static javax.swing.Action.SMALL_ICON;
     11import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.command.ChangeCommand;
     13import org.openstreetmap.josm.command.Command;
     14import org.openstreetmap.josm.data.coor.EastNorth;
     15import org.openstreetmap.josm.data.osm.Node;
     16import org.openstreetmap.josm.data.osm.OsmPrimitive;
     17import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     18import org.openstreetmap.josm.data.osm.Relation;
     19import org.openstreetmap.josm.data.osm.RelationMember;
     20import org.openstreetmap.josm.data.osm.Way;
     21import org.openstreetmap.josm.gui.dialogs.relation.sort.RelationSorter;
     22import org.openstreetmap.josm.tools.Geometry;
     23import static org.openstreetmap.josm.tools.I18n.tr;
     24import org.openstreetmap.josm.tools.ImageProvider;
     25import relcontext.ChosenRelation;
     26import relcontext.ChosenRelationListener;
     27
     28/**
     29 * Build in order stop/platforms, stop/platforms ... route
     30 * @author freeExec
     31 */
     32public class ReconstructRouteAction  extends AbstractAction implements ChosenRelationListener {
     33    private final ChosenRelation rel;
     34   
     35    public ReconstructRouteAction (ChosenRelation rel) {
     36        super(tr("Reconstruct route"));
     37        putValue(SMALL_ICON, ImageProvider.get("dialogs", "filter"));
     38        putValue(LONG_DESCRIPTION, "Reconstruct route relation to scheme of public_transport");
     39        this.rel = rel;
     40        rel.addChosenRelationListener(this);
     41        setEnabled(isSuitableRelation(rel.get()));
     42    }
     43   
     44    public void actionPerformed( ActionEvent e ) {
     45        Relation r = rel.get();
     46        Relation recRel = new Relation(r);       
     47        recRel.removeMembersFor(recRel.getMemberPrimitives());
     48       
     49        Map<OsmPrimitive, RelationMember> stopMembers = new LinkedHashMap<>();
     50        Map<String, List<RelationMember>> platformMembers = new LinkedHashMap<>();
     51
     52        List<RelationMember> routeMembers = new ArrayList<>();
     53        List<RelationMember> wtfMembers = new ArrayList<>();
     54       
     55        int mCount = r.getMembersCount();
     56        for (int i = 0; i < mCount; i++) {
     57            RelationMember m = r.getMember(i);
     58            if (PublicTransportHelper.isMemberStop(m)) {
     59                RelationMember rm = new RelationMember(
     60                        m.hasRole() ? m.getRole() : PublicTransportHelper.STOP,
     61                        m.getMember());
     62                stopMembers.put(rm.getMember(), rm);
     63            }
     64            else if (PublicTransportHelper.isMemberPlatform(m)) {
     65                RelationMember rm = new RelationMember(
     66                        m.hasRole() ? m.getRole() : PublicTransportHelper.PLATFORM,
     67                        m.getMember());
     68                String platformName = PublicTransportHelper.getNameViaStoparea(rm);
     69                if (platformName == null) platformName = "";
     70                if (platformMembers.containsKey(platformName)) platformMembers.get(platformName).add(rm);
     71                else {
     72                    List<RelationMember> nList = new ArrayList<>();
     73                    nList.add(rm);
     74                    platformMembers.put(platformName, nList);
     75                }               
     76            }
     77            else if (PublicTransportHelper.isMemberRouteway(m)) routeMembers.add(new RelationMember(m));
     78            else wtfMembers.add(new RelationMember(m));
     79        }
     80       
     81        routeMembers = RelationSorter.sortMembersByConnectivity(routeMembers);
     82       
     83        Node lastNode = null;
     84        for (int rIndex = 0; rIndex < routeMembers.size(); rIndex++) {
     85            Way w = (Way)routeMembers.get(rIndex).getMember();
     86            boolean dirForward = false;
     87            if (lastNode == null) { // first segment
     88                if (routeMembers.size() > 2) {
     89                    Way nextWay = (Way)routeMembers.get(rIndex + 1).getMember();
     90                    if (w.lastNode().equals(nextWay.lastNode()) || w.lastNode().equals(nextWay.firstNode())) {
     91                        dirForward = true;
     92                        lastNode = w.lastNode();
     93                    } else lastNode = w.firstNode();
     94                } // else one segment - direction unknown
     95            } else {
     96                if (lastNode.equals(w.firstNode())) { dirForward = true; lastNode = w.lastNode(); }
     97                else lastNode = w.firstNode();
     98            }
     99            final int wayNodeBeginIndex = (dirForward ? 0 : w.getNodesCount() - 1);
     100            final int wayNodeEndIndex = (dirForward ? w.getNodesCount() - 1 : 0);
     101            final int increment = (dirForward ? 1 : -1);
     102            for(int nIndex = wayNodeBeginIndex;
     103                    nIndex != wayNodeEndIndex;
     104                    nIndex += increment) {
     105                Node refNode = w.getNode(nIndex);
     106                if (PublicTransportHelper.isNodeStop(refNode)) {
     107                    if (stopMembers.containsKey(refNode)) {
     108                        recRel.addMember(stopMembers.get(refNode));
     109                        stopMembers.remove(refNode);
     110                        String stopName = PublicTransportHelper.getNameViaStoparea(refNode);
     111                        if (stopName == null) stopName = "";
     112                        boolean existsPlatform = platformMembers.containsKey(stopName);
     113                        if (!existsPlatform) { stopName = ""; } // find of the nameless
     114                        if (existsPlatform || platformMembers.containsKey(stopName)) {
     115                            List<RelationMember> lMember = platformMembers.get(stopName);
     116                            if (lMember.size() == 1) {
     117                                recRel.addMember(lMember.get(0));
     118                                lMember.remove(0);
     119                            } else {
     120                                // choose closest                               
     121                                RelationMember candidat = getClosestPlatform(lMember, refNode);
     122                                if (candidat != null) {
     123                                    recRel.addMember(candidat);
     124                                    lMember.remove(candidat);
     125                                }
     126                            }
     127                            if (lMember.isEmpty()) platformMembers.remove(stopName);                           
     128                        }
     129                    }
     130                }
     131            }
     132        }
     133       
     134        for (RelationMember stop : stopMembers.values()) {
     135            recRel.addMember(stop);
     136            String stopName = PublicTransportHelper.getNameViaStoparea(stop);
     137            boolean existsPlatform = platformMembers.containsKey(stopName);
     138            if (!existsPlatform) { stopName = ""; } // find of the nameless
     139            if (existsPlatform || platformMembers.containsKey(stopName)) {           
     140                List<RelationMember> lMember = platformMembers.get(stopName);
     141                if (lMember.size() == 1) {
     142                    recRel.addMember(lMember.get(0));
     143                    lMember.remove(0);
     144                } else {
     145                    // choose closest                               
     146                    RelationMember candidat = getClosestPlatform(lMember, stop.getNode());
     147                    if (candidat != null) {
     148                        recRel.addMember(candidat);
     149                        lMember.remove(candidat);
     150                    }
     151                }
     152                if (lMember.isEmpty()) platformMembers.remove(stopName);                           
     153            }
     154        }
     155       
     156        for (List<RelationMember> lPlatforms : platformMembers.values())
     157            for (RelationMember platform : lPlatforms)
     158                recRel.addMember(platform);
     159       
     160        for (RelationMember route : routeMembers)
     161            recRel.addMember(route);
     162        for (RelationMember wtf : wtfMembers)
     163            recRel.addMember(wtf);       
     164        Command command = new ChangeCommand(r, recRel);
     165        Main.main.undoRedo.add(command);
     166    }
     167   
     168    private static final double maxSqrDistBetweenStopAndPlatform = 2000; // ~ 26m   
     169    private RelationMember getClosestPlatform(List<RelationMember> members, Node stop) {
     170        if (stop == null || members.isEmpty()) return null;
     171        double maxDist = maxSqrDistBetweenStopAndPlatform;
     172        RelationMember result = null;
     173        for (RelationMember member : members) {
     174            if (member.getType() == OsmPrimitiveType.NODE) {
     175                Node node = member.getNode();
     176                double sqrDist = stop.getEastNorth().distanceSq(node.getEastNorth());
     177                if (sqrDist < maxDist) {
     178                    maxDist = sqrDist;
     179                    result = member;
     180                }
     181            } else if (member.getType() == OsmPrimitiveType.WAY) {
     182                Way way = member.getWay();
     183                EastNorth closest = Geometry.closestPointToSegment(
     184                                way.firstNode().getEastNorth(),
     185                                way.lastNode().getEastNorth(),
     186                                stop.getEastNorth()
     187                );
     188                double sqrDist = stop.getEastNorth().distanceSq(closest);
     189                if (sqrDist < maxDist) {
     190                    maxDist = sqrDist;
     191                    result = member;
     192                }
     193            }
     194        }
     195        return result;
     196    }
     197 
     198    public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     199        setEnabled(isSuitableRelation(newRelation));
     200    }   
     201   
     202    private boolean isSuitableRelation (Relation newRelation) {
     203        return !(newRelation == null || !"route".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0);
     204    }
     205}
  • relcontext/actions/SortAndFixAction.java

     
    2121import relcontext.relationfix.BoundaryFixer;
    2222import relcontext.relationfix.MultipolygonFixer;
    2323import relcontext.relationfix.NothingFixer;
     24import relcontext.relationfix.PublicTransportFixer;
    2425import relcontext.relationfix.RelationFixer;
    2526
    2627public class SortAndFixAction extends AbstractAction implements ChosenRelationListener {
     
    4344        fixers.add(new BoundaryFixer()); // boundary, multipolygon, boundary=administrative
    4445        fixers.add(new MultipolygonFixer()); // multipolygon
    4546        fixers.add(new AssociatedStreetFixer()); //associatedStreet
     47        fixers.add(new PublicTransportFixer()); //public_transport
    4648
    4749        for(RelationFixer fix : fixers) {
    4850            fix.setFixAction(this);
  • relcontext/possible_roles.txt

     
    11boundary: admin_centre, label, subarea
    2 route: stop, platform, forward, backward, stop_exit_only, stop_entry_only, platform_exit_only, platform_entry_only
     2route: forward, backward, stop, platform, stop_exit_only, stop_entry_only, platform_exit_only, platform_entry_only
     3public_transport: stop, platform
    34restriction: from, to, via, location_hint
    45enforcement: device, from, to, force
    56destination_sign: to, from, intersection, sign
  • relcontext/relationfix/PublicTransportFixer.java

     
     1package relcontext.relationfix;
     2
     3import org.openstreetmap.josm.command.ChangeCommand;
     4import org.openstreetmap.josm.command.Command;
     5import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     6import org.openstreetmap.josm.data.osm.Relation;
     7import org.openstreetmap.josm.data.osm.RelationMember;
     8import static org.openstreetmap.josm.tools.I18n.tr;
     9import relcontext.actions.PublicTransportHelper;
     10
     11/**
     12 * @see http://wiki.openstreetmap.org/wiki/Key:public_transport
     13 */
     14
     15/**
     16 * Helper function for determinate role in public_transport relation
     17 * @author freeExec
     18 */
     19public class PublicTransportFixer extends RelationFixer {
     20       
     21    public PublicTransportFixer() {
     22        super("route", "public_transport");
     23    }
     24
     25    /*protected PublicTransportFixer(String...types) {
     26        super(types);
     27    }*/
     28
     29    @Override
     30    public boolean isRelationGood(Relation rel) {
     31        for (RelationMember m : rel.getMembers()) {
     32            if (m.getType().equals(OsmPrimitiveType.NODE)
     33                    && !(m.getRole().startsWith(PublicTransportHelper.STOP) || m.getRole().startsWith(PublicTransportHelper.PLATFORM))) {
     34                setWarningMessage(tr("Node without ''stop'' or ''platform'' role found"));
     35                return false;
     36            }
     37            if (m.getType().equals(OsmPrimitiveType.WAY)
     38                    && PublicTransportHelper.isWayPlatform(m)
     39                    && !m.getRole().startsWith(PublicTransportHelper.PLATFORM)) {
     40                setWarningMessage(tr("Way platform without ''platform'' role found") + " r" + m.getUniqueId());
     41                return false;
     42            }
     43        }
     44        clearWarningMessage();
     45        return true;
     46    }
     47
     48    /*@Override
     49    public boolean isFixerApplicable(Relation rel) {
     50        return true;
     51    }*/
     52
     53    @Override
     54    public Command fixRelation(Relation rel) {
     55        Relation r = rel;
     56        Relation rr = fixStopPlatformRole(r);
     57        boolean fixed = false;
     58        if (rr != null) {
     59            fixed = true;
     60            r = rr;
     61        }
     62        return fixed ? new ChangeCommand(rel, r) : null;
     63    }
     64   
     65    private Relation fixStopPlatformRole(Relation source) {
     66        Relation r = new Relation(source);
     67        boolean fixed = false;
     68        for( int i = 0; i < r.getMembersCount(); i++ ) {
     69            RelationMember m = r.getMember(i);
     70            String role = PublicTransportHelper.getRoleByMember(m);
     71
     72            if (role != null && !m.getRole().startsWith(role)) {
     73                r.setMember(i, new RelationMember(role, m.getMember()));
     74                fixed = true;
     75            }
     76        }
     77        return fixed ? r : null;           
     78    }
     79}