Changeset 3788 in josm


Ignore:
Timestamp:
Jan 13, 2011 8:46:54 PM (2 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.