Ticket #5109: forward_backward.patch

File forward_backward.patch, 20.9 KB (added by PetrDlouhy, 15 years ago)

forward/bacward analyzator for relation editor

  • MemberTableLinkedCellRenderer.java

     
    3939            return;
    4040
    4141        int ymax=this.getSize().height - 1;
    42         int xloop = 8;
     42        int xloop = 10;
     43        int xowloop = 3;
    4344        int xoff = this.getSize().width / 2;
    4445        if (value.isLoop) {
    4546            xoff -= xloop / 2 - 1;
     
    9091
    9192        /* vertical lines */
    9293        g.setColor(Color.black);
    93         g.drawLine(xoff, y1, xoff, y2);
    9494        if (value.isLoop) {
    9595            g.drawLine(xoff+xloop, y1, xoff+xloop, y2);
    9696        }
    9797
     98        if (value.isOnewayHead) {
     99            g.setColor(Color.green);
     100            y1 = 6;
     101            g.drawImage(corners,xoff-xowloop,y1-3,xoff-xowloop+3,y1, 0,0,3,3, new Color(0,0,0,0), null);
     102            g.drawImage(corners,xoff+xowloop-2,y1-3,xoff+xowloop+1,y1, 2,0,5,3, new Color(0,0,0,0), null);
     103            g.drawLine(xoff-xowloop+3,y1-3,xoff+xowloop-3,y1-3);
     104
     105            g.setColor(Color.black);
     106            if(value.linkPrev) g.drawLine(xoff, 0, xoff, y1-3);
     107        }
     108
     109        if(value.isOnewayTail){
     110            g.setColor(Color.green);
     111            y2 = ymax - 6;
     112            g.drawLine(xoff-xowloop, y2, xoff-xowloop, y2+2);
     113            g.drawImage(corners,xoff-xowloop,y2+1,xoff-xowloop+3,y2+4, 0,2,3,5, new Color(0,0,0,0), null);
     114            g.drawImage(corners,xoff+xowloop-2,y2+1,xoff+xowloop+1,y2+4, 2,2,5,5, new Color(0,0,0,0), null);
     115            g.drawLine(xoff-xowloop+3,y2+3,xoff+xowloop-3,y2+3);
     116
     117            g.setColor(Color.black);
     118            if(value.linkNext) g.drawLine(xoff, y2+3, xoff, ymax+4);
     119        }
     120
     121        if (value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) {
     122            g.setColor(Color.green);
     123            g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2);
     124            g.drawLine(xoff-xowloop, y1, xoff-xowloop, y2);
     125        }
     126
     127        g.setColor(Color.black);
     128        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart){
     129            g.drawLine(xoff, y1, xoff, y2);
     130        }
     131        if (value.isOnewayLoopForwardPart) {
     132            g.drawLine(xoff-xowloop, y1, xoff-xowloop, y2);
     133        }
     134        if (value.isOnewayLoopBackwardPart) {
     135            g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2);
     136        }
     137       
     138
    98139        /* special icons */
    99140        Image arrow = null;
    100141        switch (value.direction) {
     
    105146            arrow = arrowUp;
    106147            break;
    107148        }
    108         if ((arrow != null) && (value.linkPrev || value.linkNext)) {
    109             g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
    110         }
    111         else if (value.direction == Direction.ROUNDABOUT_LEFT) {
     149        if (value.direction == Direction.ROUNDABOUT_LEFT) {
    112150            g.drawImage(roundabout_left, xoff-6, 1, null);
    113151        } else if (value.direction == Direction.ROUNDABOUT_RIGHT) {
    114152            g.drawImage(roundabout_right, xoff-6, 1, null);
    115153        }
     154
     155        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart &&
     156                (arrow != null)) {
     157            g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
    116158    }
     159
     160        if (value.isOnewayLoopForwardPart) {
     161            if ((arrow != null)) {
     162                g.drawImage(arrow, xoff-xowloop-3, (y1 + y2) / 2 - 2, null);
    117163}
     164        }
     165
     166        if (value.isOnewayLoopBackwardPart) {
     167            if(value.isOnewayLoopForwardPart) {
     168                if(arrow == arrowDown)
     169                    arrow = arrowUp;
     170                else if (arrow == arrowUp)
     171                    arrow = arrowDown;
     172            }
     173
     174            if ((arrow != null)) {
     175                g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null);
     176            }
     177        }
     178    }
     179}
  • MemberTableModel.java

     
    795795     *
    796796     * Else the direction is given as follows:
    797797     * Let the relation be a route of oneway streets, and someone travels them in the given order.
    798      * Direction is FORWARD if it is legel and BACKWARD if it is illegal to do so for the given way.
     798     * Direction is FORWARD if it is legal and BACKWARD if it is illegal to do so for the given way.
    799799     *
    800800     **/
    801801    private Direction determineDirection(int ref_i,Direction ref_direction, int k) {
     
    940940        int firstGroupIdx=0;
    941941        boolean resetFirstGoupIdx=false;
    942942
     943        Integer firstOnewayGroupIdx=null;
     944        boolean isReversePart = false;
     945        Integer lastForwardPart = null;
     946
    943947        for (int i=0; i<members.size(); ++i) {
    944948            if (resetFirstGoupIdx) {
    945949                firstGroupIdx = i;
     
    960964                continue;
    961965            }
    962966
     967            if (isOneway(m)) {
     968                if(firstOnewayGroupIdx == null){
     969                    firstOnewayGroupIdx = i;
     970                    isReversePart = false;
     971                }
     972            } else {
     973                isReversePart = false;
     974                firstOnewayGroupIdx = null;
     975                if(i > 0 && !con.get(i-1).isOnewayTail && (con.get(i-1).isOnewayLoopBackwardPart
     976                        || con.get(i-1).isOnewayLoopForwardPart))
     977                    firstGroupIdx = i;
     978            }
     979
    963980            boolean linkPrev = (i != firstGroupIdx);
    964981            boolean linkNext;
    965982            Direction dir;
    966983            if (linkPrev) {
    967                 dir = determineDirection(i-1, con.get(i-1).direction, i);
     984                Direction refDir = con.get(i-1).direction;
     985               
     986                dir = determineDirection(i-1, refDir, i);
    968987                linkNext = (determineDirection(i, dir, i+1) != NONE);
     988               
     989                if(firstOnewayGroupIdx != null && !isReversePart) { //oneway loop - forward part
     990                    Direction dirow = NONE;
     991                    if (con.get(firstOnewayGroupIdx) != null)
     992                        dirow = reverse(con.get(firstOnewayGroupIdx).direction);
     993                    else //first in oneway loop
     994                        dirow = reverse(dir);
     995               
     996                    if (firstOnewayGroupIdx != i && determineDirection(firstOnewayGroupIdx, dirow, i) != NONE) { // start of backward part
     997                        dir = determineDirection(firstOnewayGroupIdx, dirow, i);
     998                        linkNext = (determineDirection(i, dir, i+1) != NONE);
     999                        lastForwardPart = i-1;
     1000                        isReversePart = true;
    9691001            }
    970             else {
     1002
     1003                    if (determineDirection(firstOnewayGroupIdx, dirow, i+1) != NONE) {
     1004                        linkNext = true;
     1005                    }
     1006                }
     1007                   
     1008            } else {
     1009                if (isOneway(m)){
     1010                    if(m.getRole().equals("backward")) dir = BACKWARD;
     1011                    else dir = FORWARD;
     1012                } else
    9711013                if (roundaboutType(i) != NONE) {
    9721014                    dir = determineDirection(i, roundaboutType(i), i+1) != NONE ? roundaboutType(i) : NONE;
    9731015                } else { /** guess the direction and see if it fits with the next member */
     
    9871029
    9881030            con.set(i, new WayConnectionType(linkPrev, linkNext, dir));
    9891031
     1032            if (isOneway(m)) {
     1033                if (firstOnewayGroupIdx == i) {
     1034                    con.get(i).isOnewayHead = true;
     1035                    con.get(i).isOnewayLoopForwardPart = true;
     1036                }
     1037
     1038                if(isReversePart) con.get(i).isOnewayLoopBackwardPart = true;
     1039                else con.get(i).isOnewayLoopForwardPart = true;
     1040
     1041                if(lastForwardPart != null && determineDirection(i, dir, lastForwardPart) != NONE){
     1042                    con.get(i).isOnewayTail = true;
     1043                    firstOnewayGroupIdx = null; 
     1044                }
     1045            }
     1046
    9901047            if (! linkNext) {
    9911048                boolean loop;
    992                 if (i == firstGroupIdx) {
    993                     loop = determineDirection(i, FORWARD, i) == FORWARD;
     1049                int lastGroupIdx = i;
     1050                if(isOneway(m) && lastForwardPart != null) lastGroupIdx = lastForwardPart;
     1051                if (lastGroupIdx == firstGroupIdx) { //is primitive loop
     1052                    loop = determineDirection(lastGroupIdx, FORWARD, lastGroupIdx) == FORWARD;
    9941053                } else {
    995                     loop = determineDirection(i, dir, firstGroupIdx) == con.get(firstGroupIdx).direction;
     1054                    loop = determineDirection(lastGroupIdx, con.get(lastGroupIdx).direction, firstGroupIdx) == con.get(firstGroupIdx).direction;
    9961055                }
    9971056                if (loop) {
    9981057                    for (int j=firstGroupIdx; j <= i; ++j) {
     
    10071066        //            System.err.println(con.get(i));
    10081067        //        }
    10091068    }
     1069
     1070    private static Direction reverse(Direction dir){
     1071        if(dir == FORWARD) return BACKWARD;
     1072        if(dir == BACKWARD) return FORWARD;
     1073        return dir;
    10101074}
     1075
     1076    public static boolean isOneway(RelationMember m){
     1077        return m.getRole().equals("forward") || m.getRole().equals("backward");
     1078    }
     1079}
  • RelationNodeMap.java

     
    44import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.NONE;
    55
    66import java.util.ArrayList;
    7 import java.util.Iterator;
    87import java.util.List;
    9 import java.util.Map;
    108import java.util.TreeMap;
    119import java.util.TreeSet;
    1210
     
    3533    private TreeMap<Node, TreeSet<Integer>> nodesMap;
    3634    private TreeMap<Integer, TreeSet<Node>> waysMap;
    3735    /*
     36     * Maps for oneways (forward/backward roles)
     37     */
     38    private TreeMap<Node, TreeSet<Integer>> nodesOnewayMap = new TreeMap<Node, TreeSet<Integer>>();;
     39    private TreeMap<Integer, TreeSet<Node>> waysOnewayMap = new TreeMap<Integer, TreeSet<Node>>();
     40    private TreeMap<Node, TreeSet<Integer>> nodesOnewayReverseMap = new TreeMap<Node, TreeSet<Integer>>();;
     41    private TreeMap<Integer, TreeSet<Node>> waysOnewayReverseMap = new TreeMap<Integer, TreeSet<Node>>();
     42    /*
    3843     * Used to keep track of what members are done.
    3944     */
    4045    private TreeSet<Integer> remaining;
     46    private TreeMap<Integer, TreeSet<Node>> remainingOneway = new TreeMap<Integer, TreeSet<Node>>();;
    4147
    4248    /**
    4349     * All members that are incomplete or not a way
    4450     */
    4551    private List<Integer> notSortable = new ArrayList<Integer>();
    4652
     53    private static Node firstOnewayNode(RelationMember m){
     54        if(!m.isWay()) return null;
     55        if(m.getRole().equals("backward")) return m.getWay().lastNode();
     56        return m.getWay().firstNode();
     57    }
     58
     59    private static Node lastOnewayNode(RelationMember m){
     60        if(!m.isWay()) return null;
     61        if(m.getRole().equals("backward")) return m.getWay().firstNode();
     62        return m.getWay().lastNode();
     63    }
     64
    4765    RelationNodeMap(List<RelationMember> members) {
    4866        nodesMap = new TreeMap<Node, TreeSet<Integer>>();
    4967        waysMap = new TreeMap<Integer, TreeSet<Node>>();
     
    5674            }
    5775            else {
    5876                Way w = m.getWay();
    59                 if (MemberTableModel.roundaboutType(w) != NONE) {
     77                if((MemberTableModel.roundaboutType(w) != NONE) || MemberTableModel.isOneway(m)) {
     78                    if ((MemberTableModel.roundaboutType(w) != NONE) || w.firstNode() == w.lastNode()) {
    6079                    for (Node nd : w.getNodes()) {
    6180                        addPair(nd, i);
    6281                    }
    6382                } else {
     83                        addNodeWayMap(firstOnewayNode(m), i);
     84                        addWayNodeMap(lastOnewayNode(m), i);
     85                        addNodeWayMapReverse(lastOnewayNode(m), i);
     86                        addWayNodeMapReverse(firstOnewayNode(m), i);
     87                        addRemainingForward(firstOnewayNode(m), i);
     88                        addRemainingForward(lastOnewayNode(m), i);
     89                    }
     90                } else {
    6491                    addPair(w.firstNode(), i);
    6592                    addPair(w.lastNode(), i);
    6693                }
     
    6895        }
    6996
    7097        remaining = new TreeSet<Integer>();
    71         for (Integer k : waysMap.keySet()) {
    72             remaining.add(k);
    73         }
     98        remaining.addAll(waysMap.keySet());
    7499
    75100        /*
    76101         * Clean up the maps, i.e. remove nodes from roundabouts and dead ends that
    77102         * cannot be used in future. (only for performance)
    78103         */
    79         Iterator<Map.Entry<Node,TreeSet<Integer>>> it = nodesMap.entrySet().iterator();
    80         while (it.hasNext()) {
    81             Map.Entry<Node,TreeSet<Integer>> nodeLinks = it.next();
    82 
    83             if (nodeLinks.getValue().size() < 2) {
    84                 if (nodeLinks.getValue().size() != 1) throw new AssertionError();
    85 
    86                 Integer d_way = nodeLinks.getValue().iterator().next();
    87                 TreeSet<Node> d_way_nodes = waysMap.get(d_way);
    88                 d_way_nodes.remove(nodeLinks.getKey());
    89 
    90                 it.remove();
    91                 continue;
     104//        Iterator<Map.Entry<Node,TreeSet<Integer>>> it = nodesMap.entrySet().iterator();
     105//        while (it.hasNext()) {
     106//            Map.Entry<Node,TreeSet<Integer>> nodeLinks = it.next();
     107//
     108//            if (nodeLinks.getValue().size() < 2) {
     109//                if (nodeLinks.getValue().size() != 1) throw new AssertionError();
     110//
     111//                Integer d_way = nodeLinks.getValue().iterator().next();
     112//                TreeSet<Node> d_way_nodes = waysMap.get(d_way);
     113//                d_way_nodes.remove(nodeLinks.getKey());
     114//
     115//                it.remove();
     116//                continue;
     117//            }
     118//        }
    92119            }
    93         }
    94     }
    95120
    96121    private void addPair(Node n, int i) {
    97122        TreeSet<Integer> ts = nodesMap.get(n);
     
    109134        ts2.add(n);
    110135    }
    111136
     137    private void addNodeWayMap(Node n, int i) {
     138        TreeSet<Integer> ts = nodesOnewayMap.get(n);
     139        if (ts == null) {
     140            ts = new TreeSet<Integer>();
     141            nodesOnewayMap.put(n, ts);
     142        }
     143        ts.add(i);
     144    }
     145
     146    private void addWayNodeMap(Node n, int i) {
     147        TreeSet<Node> ts2 = waysOnewayMap.get(i);
     148        if (ts2 == null) {
     149            ts2 = new TreeSet<Node>();
     150            waysOnewayMap.put(i, ts2);
     151        }
     152        ts2.add(n);
     153    }
     154
     155    private void addNodeWayMapReverse(Node n, int i) {
     156        TreeSet<Integer> ts = nodesOnewayReverseMap.get(n);
     157        if (ts == null) {
     158            ts = new TreeSet<Integer>();
     159            nodesOnewayReverseMap.put(n, ts);
     160        }
     161        ts.add(i);
     162    }
     163
     164    private void addWayNodeMapReverse(Node n, int i) {
     165        TreeSet<Node> ts2 = waysOnewayReverseMap.get(i);
     166        if (ts2 == null) {
     167            ts2 = new TreeSet<Node>();
     168            waysOnewayReverseMap.put(i, ts2);
     169        }
     170        ts2.add(n);
     171    }
     172
     173    private void addRemainingForward(Node n, int i) {
     174        TreeSet<Node> ts2 = remainingOneway.get(i);
     175        if (ts2 == null) {
     176            ts2 = new TreeSet<Node>();
     177            remainingOneway.put(i, ts2);
     178        }
     179        ts2.add(n);
     180    }
     181
     182    Integer firstOneway = null;
     183    Node lastOnewayNode = null;
     184
    112185    /**
    113186     * Return a relation member that is linked to the
    114      * member 'i', but has not been popped jet.
     187     * member 'i', but has not been popped yet.
    115188     * Return null if there is no such member left.
    116189     */
    117190    public Integer popAdjacent(Integer i) {
    118         TreeSet<Node> nodes = waysMap.get(i);
     191        System.out.println ("i: " + i);
     192        if (firstOneway != null) return popOnewayAdjacent(i);
     193
     194        TreeSet<Node> nodes = new TreeSet<Node>();
     195        if (waysMap.containsKey(i)) nodes.addAll(waysMap.get(i));
    119196        for (Node n : nodes) {
    120197            TreeSet<Integer> adj = nodesMap.get(n);
    121             if (!adj.isEmpty()) {
     198            if (adj != null && !adj.isEmpty()) {
    122199                Integer j = adj.iterator().next();
    123200                done(j);
    124201                waysMap.get(j).remove(n);
    125202                return j;
    126203            }
    127204        }
     205
     206        for (Node n : nodes) {
     207            TreeSet<Integer> adj = nodesOnewayMap.get(n);
     208            if (adj != null && !adj.isEmpty()) {
     209                Integer j = adj.iterator().next();
     210                doneOneway(j);
     211                firstOneway = j;
     212                waysOnewayMap.get(j).remove(n);
     213                return j;
     214            }
     215        }
     216       
     217        firstOneway = i;
     218        return popOnewayAdjacent(i);
     219    }
     220
     221    private Integer popOnewayAdjacent(Integer i) {
     222        if (lastOnewayNode == null) { //Forward part
     223            TreeSet<Node> nodes = new TreeSet<Node>();
     224                if (waysOnewayMap.containsKey(i)) nodes.addAll(waysOnewayMap.get(i));
     225                for (Node n : nodes) {
     226                    TreeSet<Integer> adj = nodesOnewayMap.get(n);
     227                    if (adj != null && !adj.isEmpty()) {
     228                        Integer j = adj.iterator().next();
     229
     230                        TreeSet<Node> nodes1 = new TreeSet<Node>();
     231                        if (waysOnewayReverseMap.containsKey(j)) nodes1.addAll(waysOnewayReverseMap.get(j));
     232                        for (Node n1 : nodes1) {
     233                            if(nodesMap.containsKey(n1) || (nodesOnewayMap.containsKey(n1) && nodesOnewayMap.get(n1).size() > 1)) {
     234                                lastOnewayNode = n1;
     235                                i = firstOneway;
     236                                break;
     237                            }
     238                        }
     239
     240                        if (lastOnewayNode == null){
     241                            waysOnewayMap.get(j).remove(n);
     242                            doneOneway(j);
     243                            return j;
     244                        }
     245                    }
     246            }
     247        }
     248
     249        if (lastOnewayNode != null) { //Backward part
     250            TreeSet<Node> nodes = new TreeSet<Node>();
     251            if (waysOnewayReverseMap.containsKey(i)) nodes.addAll(waysOnewayReverseMap.get(i));
     252            if (waysMap.containsKey(i)) nodes.addAll(waysMap.get(i));
     253            for (Node n : nodes) {
     254                if(n == lastOnewayNode) {
     255                    firstOneway = null;
     256                    lastOnewayNode = null;
     257                    TreeSet<Integer> adj = nodesMap.get(n);
     258                    if (adj != null && !adj.isEmpty()) {
     259                        Integer j = adj.iterator().next();
     260                        waysMap.get(j).remove(n);
     261                        done(j);
     262                        return j;
     263                    }
     264
     265                    adj = nodesOnewayMap.get(n);
     266                    if (adj != null && !adj.isEmpty()) {
     267                        Integer j = adj.iterator().next();
     268                        doneOneway(j);
     269                        firstOneway = j;
     270                        waysOnewayMap.get(j).remove(n);
     271                        return j;
     272                    }
     273                }
     274
     275                TreeSet<Integer> adj = nodesOnewayReverseMap.get(n);
     276                if (adj != null && !adj.isEmpty()) {
     277                    Integer j = adj.iterator().next();
     278                    waysOnewayReverseMap.get(j).remove(n);
     279                    doneOneway(j);
     280                    return j;
     281                }
     282            }
     283        }
     284
     285        firstOneway = null;
     286        lastOnewayNode = null;
     287       
    128288        return null;
    129289    }
    130290
     
    133293     * every sortable member has been processed.
    134294     */
    135295    public Integer pop() {
    136         if (remaining.isEmpty()) return null;
     296        if (!remaining.isEmpty()){
    137297        Integer i = remaining.iterator().next();
    138298        done(i);
    139299        return i;
    140300    }
    141301
     302        if (remainingOneway.isEmpty()) return null;
     303        Integer i = remainingOneway.keySet().iterator().next();
     304        doneOneway(i);
     305        return i;
     306    }
     307
    142308    /**
    143309     * This relation member has been processed.
    144310     * Remove references in the nodesMap.
    145311     */
     312    private void doneOneway(Integer i) {
     313        TreeSet<Node> nodesForward = remainingOneway.get(i);
     314        for (Node n : nodesForward) {
     315            if(nodesOnewayMap.containsKey(n)) nodesOnewayMap.get(n).remove(i);
     316            if(nodesOnewayReverseMap.containsKey(n)) nodesOnewayReverseMap.get(n).remove(i);
     317        }
     318        remainingOneway.remove(i);
     319    }
     320
    146321    private void done(Integer i) {
    147322        remaining.remove(i);
    148323        TreeSet<Node> nodes = waysMap.get(i);
  • WayConnectionType.java

     
    3535    /** True, if the element is part of a closed loop of ways. */
    3636    public boolean isLoop;
    3737
     38    public boolean isOnewayLoopForwardPart = false;
     39    public boolean isOnewayLoopBackwardPart = false;
     40    public boolean isOnewayHead = false;
     41    public boolean isOnewayTail = false;
     42
    3843    public boolean isRoundabout = false;
    3944
    4045    public WayConnectionType(boolean linkPrev, boolean linkNext, Direction direction) {