Changeset 3788 in josm for trunk/src/org/openstreetmap/josm


Ignore:
Timestamp:
2011-01-13T20:46:54+01:00 (13 years ago)
Author:
bastiK
Message:

see #5109 (patch by Petr Dlouhý) - take forward/backward roles for route relations into account (sorting and connectivity column in relation editor). This is still in development and has known limitations.

Opened 7 months ago

Last modified 102 minutes ago
[patch] relation analysis

Location:
trunk/src/org/openstreetmap/josm/gui/dialogs/relation
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java

    r3083 r3788  
    22package org.openstreetmap.josm.gui.dialogs.relation;
    33
     4import java.awt.BasicStroke;
    45import java.awt.Color;
    56import java.awt.Component;
    67import java.awt.Graphics;
     8import java.awt.Graphics2D;
    79import java.awt.Image;
    810
     
    4042
    4143        int ymax=this.getSize().height - 1;
    42         int xloop = 8;
     44        int xloop = 10;
     45        int xowloop = 0;
     46        if(value.isOnewayLoopForwardPart) xowloop = -3;
     47        if(value.isOnewayLoopBackwardPart) xowloop = 3;
     48       
    4349        int xoff = this.getSize().width / 2;
    4450        if (value.isLoop) {
     
    5258        if (value.linkPrev) {
    5359            g.setColor(Color.black);
    54             g.fillRect(xoff - 1, 0, 3, 1);
     60            if(value.isOnewayHead)
     61                g.fillRect(xoff - 1, 0, 3, 1);
     62            else
     63                g.fillRect(xoff - 1 + xowloop, 0, 3, 1);
    5564            y1 = 0;
    5665        } else {
     
    6473            else {
    6574                g.setColor(Color.red);
    66                 g.drawRect(xoff-1, p - 1 - w, w, w);
     75                if(value.isOnewayHead)
     76                    g.drawRect(xoff-1, p - 3 - w, w, w);
     77                else
     78                    g.drawRect(xoff-1 + xowloop, p - 1 - w, w, w);
    6779                y1 = p;
    6880            }
     
    7183        if (value.linkNext) {
    7284            g.setColor(Color.black);
    73             g.fillRect(xoff - 1, ymax, 3, 1);
     85            if(value.isOnewayTail)
     86                g.fillRect(xoff - 1, ymax, 3, 1);
     87            else
     88                g.fillRect(xoff - 1 + xowloop, ymax, 3, 1);
    7489            y2 = ymax;
    7590        } else {
     
    8499            else {
    85100                g.setColor(Color.red);
    86                 g.drawRect(xoff-1, ymax - p + 1, w, w);
     101                if(value.isOnewayTail)
     102                    g.drawRect(xoff-1, ymax - p + 3, w, w);
     103                else
     104                    g.drawRect(xoff-1 + xowloop, ymax - p + 1, w, w);
    87105                y2 = ymax - p;
    88106            }
     
    91109        /* vertical lines */
    92110        g.setColor(Color.black);
    93         g.drawLine(xoff, y1, xoff, y2);
    94111        if (value.isLoop) {
    95112            g.drawLine(xoff+xloop, y1, xoff+xloop, y2);
    96113        }
    97114
     115        if (value.isOnewayHead) {
     116            setDotted(g);
     117            y1 = 7;
     118
     119            int xValues [] = {xoff - xowloop + 1, xoff - xowloop + 1, xoff};
     120            int yValues [] = {ymax, y1+1, 1};
     121            g.drawPolyline(xValues, yValues, 3);
     122            unsetDotted(g);
     123            g.drawLine(xoff + xowloop, y1+1, xoff, 1);
     124        }
     125
     126        if(value.isOnewayTail){
     127            setDotted(g);
     128            y2 = ymax - 7;
     129
     130            int xValues [] = {xoff+1, xoff - xowloop + 1, xoff - xowloop + 1};
     131            int yValues [] = {ymax-1, y2, y1};
     132            g.drawPolyline(xValues, yValues, 3);
     133            unsetDotted(g);
     134            g.drawLine(xoff + xowloop, y2, xoff, ymax-1);
     135        }
     136
     137        if ((value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) && !value.isOnewayTail && !value.isOnewayHead) {
     138            setDotted(g);
     139            g.drawLine(xoff - xowloop+1, y1, xoff - xowloop+1, y2 + 1);
     140            unsetDotted(g);
     141        }
     142
     143        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart){
     144            g.drawLine(xoff, y1, xoff, y2);
     145        }
     146       
     147        g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2);
     148     
    98149        /* special icons */
    99150        Image arrow = null;
     
    106157            break;
    107158        }
    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) {
     159        if (value.direction == Direction.ROUNDABOUT_LEFT) {
    112160            g.drawImage(roundabout_left, xoff-6, 1, null);
    113161        } else if (value.direction == Direction.ROUNDABOUT_RIGHT) {
    114162            g.drawImage(roundabout_right, xoff-6, 1, null);
    115163        }
     164
     165        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart &&
     166                (arrow != null)) {
     167            g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
     168        }
     169
     170        if (value.isOnewayLoopBackwardPart && value.isOnewayLoopForwardPart) {
     171            if(arrow == arrowDown)
     172                arrow = arrowUp;
     173            else if (arrow == arrowUp)
     174                arrow = arrowDown;
     175        }
     176
     177        if ((arrow != null)) {
     178            g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null);
     179        }
     180    }
     181
     182    private void setDotted(Graphics g) {
     183        ((Graphics2D)g).setStroke(new BasicStroke(
     184              1f,
     185              BasicStroke.CAP_BUTT,
     186              BasicStroke.CAP_BUTT,
     187              5f,
     188              new float[] {1f, 2f},
     189              0f));
     190    }
     191
     192    private void unsetDotted(Graphics g) {
     193        ((Graphics2D)g).setStroke(new BasicStroke());
    116194    }
    117195}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java

    r3712 r3788  
    22package org.openstreetmap.josm.gui.dialogs.relation;
    33
    4 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.BACKWARD;
    5 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.FORWARD;
    6 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.NONE;
    7 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.ROUNDABOUT_LEFT;
    8 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.ROUNDABOUT_RIGHT;
     4import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.*;
    95
    106import java.util.ArrayList;
     
    5753    private CopyOnWriteArrayList<IMemberModelListener> listeners;
    5854    private OsmDataLayer layer;
     55
     56    private final int UNCONNECTED = Integer.MIN_VALUE;
    5957
    6058    /**
     
    787785    }
    788786
     787    private Direction determineDirection(int ref_i, Direction ref_direction, int k) {
     788        return determineDirection(ref_i, ref_direction, k, false);
     789    }
    789790    /**
    790791     * Determines the direction of way k with respect to the way ref_i.
     
    796797     * Else the direction is given as follows:
    797798     * 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.
     799     * Direction is FORWARD if it is legal and BACKWARD if it is illegal to do so for the given way.
    799800     *
    800801     **/
    801     private Direction determineDirection(int ref_i,Direction ref_direction, int k) {
     802    private Direction determineDirection(int ref_i, final Direction ref_direction, int k, boolean reversed) {
    802803        if (ref_i < 0 || k < 0 || ref_i >= members.size() || k >= members.size())
    803804            return NONE;
     
    805806            return NONE;
    806807
    807         RelationMember m_ref = members.get(ref_i);
    808         RelationMember m = members.get(k);
     808        final RelationMember m_ref = members.get(ref_i);
     809        final RelationMember m = members.get(k);
    809810        Way way_ref = null;
    810811        Way way = null;
     
    847848                    if (n == nn)
    848849                        return roundaboutType(k);
     850                }
     851            } else if(isOneway(m)) {
     852                if (n == RelationNodeMap.firstOnewayNode(m) && !reversed) {
     853                    if(isBackward(m))
     854                        return BACKWARD;
     855                    else
     856                        return FORWARD;
     857                }
     858                if (n == RelationNodeMap.lastOnewayNode(m) && reversed) {
     859                    if(isBackward(m))
     860                        return FORWARD;
     861                    else
     862                        return BACKWARD;
    849863                }
    850864            } else {
     
    932946    public void updateLinks() {
    933947        connectionType = null;
    934         ArrayList<WayConnectionType> con = new ArrayList<WayConnectionType>();
     948        final List<WayConnectionType> con = new ArrayList<WayConnectionType>();
    935949
    936950        for (int i=0; i<members.size(); ++i) {
     
    939953
    940954        int firstGroupIdx=0;
    941         boolean resetFirstGoupIdx=false;
     955
     956        lastForwardWay = UNCONNECTED;
     957        lastBackwardWay = UNCONNECTED;
     958        onewayBeginning = false;
     959        WayConnectionType lastWct = null;
    942960
    943961        for (int i=0; i<members.size(); ++i) {
    944             if (resetFirstGoupIdx) {
    945                 firstGroupIdx = i;
    946                 resetFirstGoupIdx = false;
    947             }
    948 
    949             RelationMember m = members.get(i);
     962            final RelationMember m = members.get(i);
    950963            if (! m.isWay()) {
    951964                con.set(i, new WayConnectionType());
    952                 resetFirstGoupIdx = true;
     965                firstGroupIdx = i;
    953966                continue;
    954967            }
    955968
    956             Way w = m.getWay();
     969            final Way w = m.getWay();
    957970            if (w == null || w.isIncomplete()) {
    958971                con.set(i, new WayConnectionType());
    959                 resetFirstGoupIdx = true;
     972                firstGroupIdx = i;
    960973                continue;
    961974            }
    962 
    963             boolean linkPrev = (i != firstGroupIdx);
    964             boolean linkNext;
    965             Direction dir;
    966             if (linkPrev) {
    967                 dir = determineDirection(i-1, con.get(i-1).direction, i);
    968                 linkNext = (determineDirection(i, dir, i+1) != NONE);
    969             }
    970             else {
    971                 if (roundaboutType(i) != NONE) {
    972                     dir = determineDirection(i, roundaboutType(i), i+1) != NONE ? roundaboutType(i) : NONE;
    973                 } else { /** guess the direction and see if it fits with the next member */
    974                     dir = determineDirection(i, FORWARD, i+1) != NONE ? FORWARD : NONE;
    975                     if (dir == NONE) {
    976                         dir = determineDirection(i, BACKWARD, i+1) != NONE ? BACKWARD : NONE;
    977                     }
     975         
     976            WayConnectionType wct = new WayConnectionType(false);
     977            wct.linkPrev = i>0 && con.get(i-1) != null && con.get(i-1).isValid();
     978            wct.direction = NONE;
     979
     980            if(isOneway(m)){
     981                if(lastWct != null && lastWct.isOnewayTail)
     982                    wct.isOnewayHead = true;
     983                if(lastBackwardWay == UNCONNECTED && lastForwardWay == UNCONNECTED){ //Beginning of new oneway
     984                    wct.isOnewayHead = true;
     985                    lastForwardWay = i-1;
     986                    lastBackwardWay = i;
     987                    onewayBeginning = true;
    978988                }
    979                 linkNext = (dir != NONE);
    980                 if (dir == NONE) {
    981                     if (roundaboutType(i) != NONE) {
    982                         dir = roundaboutType(i);
    983                     }
     989            }           
     990
     991            if (wct.linkPrev) {
     992                if(lastBackwardWay != UNCONNECTED && lastForwardWay != UNCONNECTED) {
     993                    wct = determineOnewayConnectionType(con, m, i, wct);
     994                    if(!wct.linkPrev)
     995                        firstGroupIdx = i;
    984996                }
    985997
    986             }
    987 
    988             con.set(i, new WayConnectionType(linkPrev, linkNext, dir));
    989 
    990             if (! linkNext) {
    991                 boolean loop;
    992                 if (i == firstGroupIdx) {
    993                     loop = determineDirection(i, FORWARD, i) == FORWARD;
    994                 } else {
    995                     loop = determineDirection(i, dir, firstGroupIdx) == con.get(firstGroupIdx).direction;
     998                if(!isOneway(m)) {
     999                    wct.direction = determineDirection(i-1, lastWct.direction, i);
     1000                    wct.linkPrev = (wct.direction != NONE);
     1001                }                   
     1002            }
     1003           
     1004            if (!wct.linkPrev) {
     1005                wct.direction = determineDirectionOfFirst(i, m);
     1006                if(isOneway(m)){
     1007                    wct.isOnewayLoopForwardPart = true;
     1008                    lastForwardWay = i;
    9961009                }
    997                 if (loop) {
    998                     for (int j=firstGroupIdx; j <= i; ++j) {
    999                         con.get(j).isLoop = true;
    1000                     }
    1001                 }
    1002                 resetFirstGoupIdx = true;
    1003             }
    1004         }
     1010            }
     1011
     1012            wct.linkNext = false;
     1013            if(lastWct != null)
     1014                lastWct.linkNext = wct.linkPrev;
     1015            con.set(i, wct);
     1016            lastWct = wct;
     1017
     1018            if(!wct.linkPrev) {
     1019                if(i > 0) makeLoopIfNeeded(con, i-1, firstGroupIdx);
     1020                firstGroupIdx = i;
     1021            }
     1022        }
     1023        makeLoopIfNeeded(con, members.size()-1, firstGroupIdx);
    10051024        connectionType = con;
    10061025        //        for (int i=0; i<con.size(); ++i) {
     
    10081027        //        }
    10091028    }
     1029
     1030//    private static void unconnectPreviousLink(List<WayConnectionType> con, int beg, boolean backward){
     1031//        int i = beg;
     1032//        while(true){
     1033//            WayConnectionType t = con.get(i--);
     1034//            t.isOnewayOppositeConnected = false;
     1035//            if(backward && t.isOnewayLoopBackwardPart) break;
     1036//            if(!backward && t.isOnewayLoopForwardPart) break;
     1037//        }
     1038//    }
     1039
     1040    private static Direction reverse(final Direction dir){
     1041        if(dir == FORWARD) return BACKWARD;
     1042        if(dir == BACKWARD) return FORWARD;
     1043        return dir;
     1044    }
     1045
     1046    private static boolean isBackward(final RelationMember member){
     1047        return member.getRole().equals("backward");
     1048    }
     1049
     1050    private static boolean isForward(final RelationMember member){
     1051        return member.getRole().equals("forward");
     1052    }
     1053   
     1054    public static boolean isOneway(final RelationMember member){
     1055        return isForward(member) || isBackward(member);
     1056    }
     1057
     1058    private void makeLoopIfNeeded(final List<WayConnectionType> con, final int i, final int firstGroupIdx) {
     1059        boolean loop;
     1060        if (i == firstGroupIdx) { //is primitive loop
     1061            loop = determineDirection(i, FORWARD, i) == FORWARD;
     1062        } else {
     1063            loop = determineDirection(i, con.get(i).direction, firstGroupIdx) == con.get(firstGroupIdx).direction;
     1064        }
     1065        if (loop) {
     1066            for (int j=firstGroupIdx; j <= i; ++j) {
     1067                con.get(j).isLoop = true;
     1068            }
     1069        }
     1070    }
     1071
     1072    private Direction determineDirectionOfFirst(final int i, final RelationMember m) {
     1073        if (roundaboutType(i) != NONE) {
     1074            return roundaboutType(i);
     1075        }
     1076       
     1077        if (isOneway(m)){
     1078            if(isBackward(m)) return BACKWARD;
     1079            else return FORWARD;
     1080        } else { /** guess the direction and see if it fits with the next member */
     1081            if(determineDirection(i, FORWARD, i+1) != NONE) return FORWARD;
     1082            if(determineDirection(i, BACKWARD, i+1) != NONE) return BACKWARD;
     1083        }
     1084        return NONE;
     1085    }
     1086
     1087    int lastForwardWay, lastBackwardWay;
     1088    boolean onewayBeginning;
     1089    private WayConnectionType determineOnewayConnectionType(final List<WayConnectionType> con,
     1090            RelationMember m, int i, final WayConnectionType wct) {
     1091        Direction dirFW = determineDirection(lastForwardWay, con.get(lastForwardWay).direction, i);
     1092        Direction dirBW = NONE;
     1093        if(onewayBeginning) {
     1094            if(lastBackwardWay != i)
     1095                dirBW = determineDirection(lastBackwardWay, reverse(con.get(lastBackwardWay).direction), i, true);
     1096            if(dirBW != NONE)
     1097                onewayBeginning = false;
     1098        } else
     1099            dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
     1100
     1101        if(isOneway(m)) {
     1102            if(dirBW != NONE){
     1103                wct.direction = dirBW;
     1104                lastBackwardWay = i;
     1105                wct.isOnewayLoopBackwardPart = true;
     1106            }
     1107            if(dirFW != NONE){
     1108                wct.direction = dirFW;
     1109                lastForwardWay = i;
     1110                wct.isOnewayLoopForwardPart = true;
     1111            }
     1112            if(dirFW == NONE && dirBW == NONE) { //Not connected to previous
     1113//                        unconnectPreviousLink(con, i, true);
     1114//                        unconnectPreviousLink(con, i, false);
     1115                wct.linkPrev = false;
     1116                if(isOneway(m)){
     1117                    wct.isOnewayHead = true;
     1118                    lastForwardWay = i-1;
     1119                    lastBackwardWay = i;
     1120                } else {
     1121                    lastForwardWay = UNCONNECTED;
     1122                    lastBackwardWay = UNCONNECTED;
     1123                }
     1124                onewayBeginning = true;
     1125            }
     1126
     1127            if(dirFW != NONE && dirBW != NONE) { //End of oneway loop
     1128                if(i+1<members.size() && determineDirection(i, dirFW, i+1) != NONE) {
     1129                    wct.isOnewayLoopBackwardPart = false;
     1130                    dirBW = NONE;
     1131                    wct.direction = dirFW;
     1132                } else {
     1133                    wct.isOnewayLoopForwardPart = false;
     1134                    dirFW = NONE;
     1135                    wct.direction = dirBW;
     1136                }
     1137
     1138                wct.isOnewayTail = true;
     1139            }
     1140
     1141        } else {
     1142            lastForwardWay = UNCONNECTED;
     1143            lastBackwardWay = UNCONNECTED;
     1144            if(dirFW == NONE || dirBW == NONE)
     1145                wct.linkPrev = false;
     1146        }
     1147        return wct;
     1148    }
    10101149}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java

    r3095 r3788  
    55
    66import java.util.ArrayList;
    7 import java.util.Iterator;
    87import java.util.List;
    98import java.util.Map;
     9import java.util.Set;
    1010import java.util.TreeMap;
    1111import java.util.TreeSet;
     
    3030 */
    3131public class RelationNodeMap {
     32    private class NodesWays{
     33        public Map<Node, Set<Integer>> nodes = new TreeMap<Node, Set<Integer>>();
     34        public Map<Integer, Set<Node>> ways = new TreeMap<Integer, Set<Node>>();
     35        public boolean oneWay;
     36        public NodesWays(boolean oneWay){
     37            this.oneWay = oneWay;
     38        }
     39    }
     40
    3241    /*
    3342     * the maps. (Need TreeMap for efficiency.)
    3443     */
    35     private TreeMap<Node, TreeSet<Integer>> nodesMap;
    36     private TreeMap<Integer, TreeSet<Node>> waysMap;
     44    private NodesWays map = new NodesWays(false);
     45    /*
     46     * Maps for oneways (forward/backward roles)
     47     */
     48
     49    private NodesWays onewayMap = new NodesWays(true);
     50    private NodesWays onewayReverseMap = new NodesWays(true);
    3751    /*
    3852     * Used to keep track of what members are done.
    3953     */
    40     private TreeSet<Integer> remaining;
     54    private Set<Integer> remaining;
     55    private Map<Integer, Set<Node>> remainingOneway = new TreeMap<Integer, Set<Node>>();;
    4156
    4257    /**
     
    4560    private List<Integer> notSortable = new ArrayList<Integer>();
    4661
     62    public static Node firstOnewayNode(RelationMember m){
     63        if(!m.isWay()) return null;
     64        if(m.getRole().equals("backward")) return m.getWay().lastNode();
     65        return m.getWay().firstNode();
     66    }
     67
     68    public static Node lastOnewayNode(RelationMember m){
     69        if(!m.isWay()) return null;
     70        if(m.getRole().equals("backward")) return m.getWay().firstNode();
     71        return m.getWay().lastNode();
     72    }
     73
    4774    RelationNodeMap(List<RelationMember> members) {
    48         nodesMap = new TreeMap<Node, TreeSet<Integer>>();
    49         waysMap = new TreeMap<Integer, TreeSet<Node>>();
     75        map.nodes = new TreeMap<Node, Set<Integer>>();
     76        map.ways = new TreeMap<Integer, Set<Node>>();
    5077
    5178        for (int i = 0; i < members.size(); ++i) {
    5279            RelationMember m = members.get(i);
    53             if (m.getMember().isIncomplete() || !m.isWay())
    54             {
     80            if (m.getMember().isIncomplete() || !m.isWay()) {
    5581                notSortable.add(i);
    56             }
    57             else {
    58                 Way w = m.getWay();
    59                 if (MemberTableModel.roundaboutType(w) != NONE) {
    60                     for (Node nd : w.getNodes()) {
    61                         addPair(nd, i);
    62                     }
    63                 } else {
    64                     addPair(w.firstNode(), i);
    65                     addPair(w.lastNode(), i);
    66                 }
     82                continue;
     83            }
     84
     85            Way w = m.getWay();
     86            if ((MemberTableModel.roundaboutType(w) != NONE)) {
     87                for (Node nd : w.getNodes()) {
     88                    addPair(nd, i);
     89                }
     90            } else if(MemberTableModel.isOneway(m)) {
     91                addNodeWayMap(firstOnewayNode(m), i);
     92                addWayNodeMap(lastOnewayNode(m), i);
     93                addNodeWayMapReverse(lastOnewayNode(m), i);
     94                addWayNodeMapReverse(firstOnewayNode(m), i);
     95                addRemainingForward(firstOnewayNode(m), i);
     96                addRemainingForward(lastOnewayNode(m), i);
     97            } else {
     98                addPair(w.firstNode(), i);
     99                addPair(w.lastNode(), i);
    67100            }
    68101        }
    69102
    70103        remaining = new TreeSet<Integer>();
    71         for (Integer k : waysMap.keySet()) {
    72             remaining.add(k);
    73         }
     104        remaining.addAll(map.ways.keySet());
    74105
    75106        /*
     
    77108         * cannot be used in future. (only for performance)
    78109         */
    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;
    92             }
    93         }
    94     }
     110//        Iterator<Map.Entry<Node,TreeSet<Integer>>> it = map.nodes.entrySet().iterator();
     111//        while (it.hasNext()) {
     112//            Map.Entry<Node,TreeSet<Integer>> nodeLinks = it.next();
     113//
     114//            if (nodeLinks.getValue().size() < 2) {
     115//                if (nodeLinks.getValue().size() != 1) throw new AssertionError();
     116//
     117//                Integer d_way = nodeLinks.getValue().iterator().next();
     118//                TreeSet<Node> d_way_nodes = map.ways.get(d_way);
     119//                d_way_nodes.remove(nodeLinks.getKey());
     120//
     121//                it.remove();
     122//                continue;
     123//            }
     124//        }
     125            }
    95126
    96127    private void addPair(Node n, int i) {
    97         TreeSet<Integer> ts = nodesMap.get(n);
     128        Set<Integer> ts = map.nodes.get(n);
    98129        if (ts == null) {
    99130            ts = new TreeSet<Integer>();
    100             nodesMap.put(n, ts);
     131            map.nodes.put(n, ts);
    101132        }
    102133        ts.add(i);
    103134
    104         TreeSet<Node> ts2 = waysMap.get(i);
     135        Set<Node> ts2 = map.ways.get(i);
    105136        if (ts2 == null) {
    106137            ts2 = new TreeSet<Node>();
    107             waysMap.put(i, ts2);
     138            map.ways.put(i, ts2);
    108139        }
    109140        ts2.add(n);
    110141    }
    111142
     143    private void addNodeWayMap(Node n, int i) {
     144        Set<Integer> ts = onewayMap.nodes.get(n);
     145        if (ts == null) {
     146            ts = new TreeSet<Integer>();
     147            onewayMap.nodes.put(n, ts);
     148        }
     149        ts.add(i);
     150    }
     151
     152    private void addWayNodeMap(Node n, int i) {
     153        Set<Node> ts2 = onewayMap.ways.get(i);
     154        if (ts2 == null) {
     155            ts2 = new TreeSet<Node>();
     156            onewayMap.ways.put(i, ts2);
     157        }
     158        ts2.add(n);
     159    }
     160
     161    private void addNodeWayMapReverse(Node n, int i) {
     162        Set<Integer> ts = onewayReverseMap.nodes.get(n);
     163        if (ts == null) {
     164            ts = new TreeSet<Integer>();
     165            onewayReverseMap.nodes.put(n, ts);
     166        }
     167        ts.add(i);
     168    }
     169
     170    private void addWayNodeMapReverse(Node n, int i) {
     171        Set<Node> ts2 = onewayReverseMap.ways.get(i);
     172        if (ts2 == null) {
     173            ts2 = new TreeSet<Node>();
     174            onewayReverseMap.ways.put(i, ts2);
     175        }
     176        ts2.add(n);
     177    }
     178
     179    private void addRemainingForward(Node n, int i) {
     180        Set<Node> ts2 = remainingOneway.get(i);
     181        if (ts2 == null) {
     182            ts2 = new TreeSet<Node>();
     183            remainingOneway.put(i, ts2);
     184        }
     185        ts2.add(n);
     186    }
     187
     188    Integer firstOneway = null;
     189    Node lastOnewayNode = null;
     190    Node firstCircular = null;
     191
    112192    /**
    113193     * Return a relation member that is linked to the
    114      * member 'i', but has not been popped jet.
     194     * member 'i', but has not been popped yet.
    115195     * Return null if there is no such member left.
    116196     */
    117     public Integer popAdjacent(Integer i) {
    118         TreeSet<Node> nodes = waysMap.get(i);
    119         for (Node n : nodes) {
    120             TreeSet<Integer> adj = nodesMap.get(n);
    121             if (!adj.isEmpty()) {
    122                 Integer j = adj.iterator().next();
    123                 done(j);
    124                 waysMap.get(j).remove(n);
    125                 return j;
    126             }
    127         }
     197    public Integer popAdjacent(Integer way) {
     198        if (lastOnewayNode != null) return popBackwardOnewayPart(way);
     199        if (firstOneway != null) return popForwardOnewayPart(way);
     200
     201        if (map.ways.containsKey(way)){
     202            for (Node n : map.ways.get(way)) {
     203                Integer i = deleteAndGetAdjacentNode(map, n);
     204                if(i != null) return i;
     205
     206                Integer j = deleteAndGetAdjacentNode(onewayMap, n);
     207                if(j != null) {
     208                    firstOneway = j;
     209                    return j;
     210                }
     211            }
     212        }
     213       
     214        firstOneway = way;
     215        return popForwardOnewayPart(way);
     216    }
     217
     218    private Integer popForwardOnewayPart(Integer way) {
     219        if(onewayMap.ways.containsKey(way)) {
     220            for (Node n : onewayMap.ways.get(way)) {
     221                Integer i = findAdjacentWay(onewayMap, n);
     222                if(i == null) continue;
     223
     224                lastOnewayNode = processBackwardIfEndOfLoopReached(i);
     225                if(lastOnewayNode != null){
     226                    return popBackwardOnewayPart(firstOneway);
     227                }
     228
     229                deleteWayNode(onewayMap, i, n);
     230                return i;
     231            }
     232        }
     233       
     234        firstOneway = null;
    128235        return null;
     236    }
     237
     238    private Node processBackwardIfEndOfLoopReached(Integer way) { //find if we didn't reach end of the loop (and process backward part)
     239        if (onewayReverseMap.ways.containsKey(way)) {
     240            for (Node n : onewayReverseMap.ways.get(way)) {
     241                if((map.nodes.containsKey(n))
     242                        || (onewayMap.nodes.containsKey(n) && onewayMap.nodes.get(n).size() > 1)) {
     243                    return n;
     244                }
     245                if(firstCircular != null && firstCircular == n) {
     246                    return firstCircular;
     247                }
     248            }
     249        }
     250        return null;
     251    }
     252   
     253    private Integer popBackwardOnewayPart(int way){
     254        if (lastOnewayNode != null) {
     255            TreeSet<Node> nodes = new TreeSet<Node>();
     256            if (onewayReverseMap.ways.containsKey(way)) nodes.addAll(onewayReverseMap.ways.get(way));
     257            if (map.ways.containsKey(way)) nodes.addAll(map.ways.get(way));
     258            for (Node n : nodes) {
     259                if(n == lastOnewayNode) { //if oneway part ends
     260                    firstOneway = null;
     261                    lastOnewayNode = null;
     262                    Integer j = deleteAndGetAdjacentNode(map, n);
     263                    if(j != null) return j;
     264
     265                    Integer k = deleteAndGetAdjacentNode(onewayMap, n);
     266                    if(k != null) {
     267                        firstOneway = k;
     268                        return k;
     269                    }
     270                }
     271
     272                Integer j = deleteAndGetAdjacentNode(onewayReverseMap, n);
     273                if(j != null) return j;
     274            }
     275        }
     276
     277        firstOneway = null;
     278        lastOnewayNode = null;
     279       
     280        return null;
     281    }
     282
     283    /**
     284     * find next node in nw NodeWays structure, if the node is found delete and return it
     285     * @param nw
     286     * @param n
     287     * @return node next to n
     288     */
     289    private Integer deleteAndGetAdjacentNode(NodesWays nw, Node n){
     290        Integer j = findAdjacentWay(nw, n);
     291        if(j == null) return null;
     292        deleteWayNode(nw, j, n);
     293        return j;
     294    }
     295
     296    private Integer findAdjacentWay(NodesWays nw, Node n) {
     297        Set<Integer> adj = nw.nodes.get(n);
     298        if (adj == null || adj.isEmpty()) return null;
     299        Integer j = adj.iterator().next();
     300        return j;
     301    }
     302
     303    private void deleteWayNode(NodesWays nw, Integer way, Node n){
     304        if(nw.oneWay)
     305            doneOneway(way);
     306        else
     307            done(way);
     308        nw.ways.get(way).remove(n);
    129309    }
    130310
     
    134314     */
    135315    public Integer pop() {
    136         if (remaining.isEmpty()) return null;
    137         Integer i = remaining.iterator().next();
    138         done(i);
     316        if (!remaining.isEmpty()){
     317            Integer i = remaining.iterator().next();
     318            done(i);
     319            return i;
     320        }
     321
     322        if (remainingOneway.isEmpty()) return null;
     323        for(Integer i :remainingOneway.keySet()){ //find oneway, whic is connected to more than one way (is between two oneway loops)
     324            for(Node n : onewayReverseMap.ways.get(i)){
     325                if(onewayReverseMap.nodes.containsKey(n) && onewayReverseMap.nodes.get(n).size() > 1) {
     326                    doneOneway(i);
     327                    firstCircular = n;
     328                    return i;
     329                }
     330            }
     331        }
     332
     333        Integer i = remainingOneway.keySet().iterator().next();
     334        doneOneway(i);
    139335        return i;
    140336    }
     
    142338    /**
    143339     * This relation member has been processed.
    144      * Remove references in the nodesMap.
    145      */
     340     * Remove references in the map.nodes.
     341     */
     342    private void doneOneway(Integer i) {
     343        Set<Node> nodesForward = remainingOneway.get(i);
     344        for (Node n : nodesForward) {
     345            if(onewayMap.nodes.containsKey(n)) onewayMap.nodes.get(n).remove(i);
     346            if(onewayReverseMap.nodes.containsKey(n)) onewayReverseMap.nodes.get(n).remove(i);
     347        }
     348        remainingOneway.remove(i);
     349    }
     350
    146351    private void done(Integer i) {
    147352        remaining.remove(i);
    148         TreeSet<Node> nodes = waysMap.get(i);
     353        Set<Node> nodes = map.ways.get(i);
    149354        for (Node n : nodes) {
    150             boolean result = nodesMap.get(n).remove(i);
     355            boolean result = map.nodes.get(n).remove(i);
    151356            if (!result) throw new AssertionError();
    152357        }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/WayConnectionType.java

    r3083 r3788  
    1111
    1212    /** True, if linked to the previous / next member.  */
    13     public final boolean linkPrev;
    14     public final boolean linkNext;
     13    public boolean linkPrev;
     14    public boolean linkNext;
    1515
    1616    /**
     
    2323     * direction has the value NONE.
    2424     */
    25     public final Direction direction;
     25    public Direction direction;
    2626
    2727    public enum Direction {
     
    3636    public boolean isLoop;
    3737
    38     public boolean isRoundabout = false;
     38    public boolean isOnewayLoopForwardPart = false;
     39    public boolean isOnewayLoopBackwardPart = false;
     40    public boolean isOnewayHead = false;
     41    public boolean isOnewayTail = false;
     42//    public boolean isOnewayOppositeConnected = true;
    3943
    4044    public WayConnectionType(boolean linkPrev, boolean linkNext, Direction direction) {
     
    4448        this.direction = direction;
    4549        invalid = false;
     50    }
     51
     52    public WayConnectionType(boolean invalid){
     53        this.invalid = invalid;
    4654    }
    4755
     
    6169    @Override
    6270    public String toString() {
    63         return "[P "+linkPrev+" ;N "+linkNext+" ;D "+direction+" ;L "+isLoop+"]";
     71        return "[P "+linkPrev+" ;N "+linkNext+" ;D "+direction+" ;L "+isLoop+
     72                " ;FP " + isOnewayLoopForwardPart+";BP " + isOnewayLoopBackwardPart+
     73                ";OH " + isOnewayHead+";OT " + isOnewayTail+"]";
    6474    }
    6575
Note: See TracChangeset for help on using the changeset viewer.