Ticket #5109: forward_backward.patch
| File forward_backward.patch, 20.9 KB (added by , 15 years ago) |
|---|
-
MemberTableLinkedCellRenderer.java
39 39 return; 40 40 41 41 int ymax=this.getSize().height - 1; 42 int xloop = 8; 42 int xloop = 10; 43 int xowloop = 3; 43 44 int xoff = this.getSize().width / 2; 44 45 if (value.isLoop) { 45 46 xoff -= xloop / 2 - 1; … … 90 91 91 92 /* vertical lines */ 92 93 g.setColor(Color.black); 93 g.drawLine(xoff, y1, xoff, y2);94 94 if (value.isLoop) { 95 95 g.drawLine(xoff+xloop, y1, xoff+xloop, y2); 96 96 } 97 97 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 98 139 /* special icons */ 99 140 Image arrow = null; 100 141 switch (value.direction) { … … 105 146 arrow = arrowUp; 106 147 break; 107 148 } 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) { 112 150 g.drawImage(roundabout_left, xoff-6, 1, null); 113 151 } else if (value.direction == Direction.ROUNDABOUT_RIGHT) { 114 152 g.drawImage(roundabout_right, xoff-6, 1, null); 115 153 } 154 155 if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart && 156 (arrow != null)) { 157 g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null); 116 158 } 159 160 if (value.isOnewayLoopForwardPart) { 161 if ((arrow != null)) { 162 g.drawImage(arrow, xoff-xowloop-3, (y1 + y2) / 2 - 2, null); 117 163 } 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
795 795 * 796 796 * Else the direction is given as follows: 797 797 * Let the relation be a route of oneway streets, and someone travels them in the given order. 798 * Direction is FORWARD if it is leg el 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. 799 799 * 800 800 **/ 801 801 private Direction determineDirection(int ref_i,Direction ref_direction, int k) { … … 940 940 int firstGroupIdx=0; 941 941 boolean resetFirstGoupIdx=false; 942 942 943 Integer firstOnewayGroupIdx=null; 944 boolean isReversePart = false; 945 Integer lastForwardPart = null; 946 943 947 for (int i=0; i<members.size(); ++i) { 944 948 if (resetFirstGoupIdx) { 945 949 firstGroupIdx = i; … … 960 964 continue; 961 965 } 962 966 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 963 980 boolean linkPrev = (i != firstGroupIdx); 964 981 boolean linkNext; 965 982 Direction dir; 966 983 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); 968 987 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; 969 1001 } 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 971 1013 if (roundaboutType(i) != NONE) { 972 1014 dir = determineDirection(i, roundaboutType(i), i+1) != NONE ? roundaboutType(i) : NONE; 973 1015 } else { /** guess the direction and see if it fits with the next member */ … … 987 1029 988 1030 con.set(i, new WayConnectionType(linkPrev, linkNext, dir)); 989 1031 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 990 1047 if (! linkNext) { 991 1048 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; 994 1053 } else { 995 loop = determineDirection( i, dir, firstGroupIdx) == con.get(firstGroupIdx).direction;1054 loop = determineDirection(lastGroupIdx, con.get(lastGroupIdx).direction, firstGroupIdx) == con.get(firstGroupIdx).direction; 996 1055 } 997 1056 if (loop) { 998 1057 for (int j=firstGroupIdx; j <= i; ++j) { … … 1007 1066 // System.err.println(con.get(i)); 1008 1067 // } 1009 1068 } 1069 1070 private static Direction reverse(Direction dir){ 1071 if(dir == FORWARD) return BACKWARD; 1072 if(dir == BACKWARD) return FORWARD; 1073 return dir; 1010 1074 } 1075 1076 public static boolean isOneway(RelationMember m){ 1077 return m.getRole().equals("forward") || m.getRole().equals("backward"); 1078 } 1079 } -
RelationNodeMap.java
4 4 import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.NONE; 5 5 6 6 import java.util.ArrayList; 7 import java.util.Iterator;8 7 import java.util.List; 9 import java.util.Map;10 8 import java.util.TreeMap; 11 9 import java.util.TreeSet; 12 10 … … 35 33 private TreeMap<Node, TreeSet<Integer>> nodesMap; 36 34 private TreeMap<Integer, TreeSet<Node>> waysMap; 37 35 /* 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 /* 38 43 * Used to keep track of what members are done. 39 44 */ 40 45 private TreeSet<Integer> remaining; 46 private TreeMap<Integer, TreeSet<Node>> remainingOneway = new TreeMap<Integer, TreeSet<Node>>();; 41 47 42 48 /** 43 49 * All members that are incomplete or not a way 44 50 */ 45 51 private List<Integer> notSortable = new ArrayList<Integer>(); 46 52 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 47 65 RelationNodeMap(List<RelationMember> members) { 48 66 nodesMap = new TreeMap<Node, TreeSet<Integer>>(); 49 67 waysMap = new TreeMap<Integer, TreeSet<Node>>(); … … 56 74 } 57 75 else { 58 76 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()) { 60 79 for (Node nd : w.getNodes()) { 61 80 addPair(nd, i); 62 81 } 63 82 } 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 { 64 91 addPair(w.firstNode(), i); 65 92 addPair(w.lastNode(), i); 66 93 } … … 68 95 } 69 96 70 97 remaining = new TreeSet<Integer>(); 71 for (Integer k : waysMap.keySet()) { 72 remaining.add(k); 73 } 98 remaining.addAll(waysMap.keySet()); 74 99 75 100 /* 76 101 * Clean up the maps, i.e. remove nodes from roundabouts and dead ends that 77 102 * cannot be used in future. (only for performance) 78 103 */ 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 // } 92 119 } 93 }94 }95 120 96 121 private void addPair(Node n, int i) { 97 122 TreeSet<Integer> ts = nodesMap.get(n); … … 109 134 ts2.add(n); 110 135 } 111 136 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 112 185 /** 113 186 * 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. 115 188 * Return null if there is no such member left. 116 189 */ 117 190 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)); 119 196 for (Node n : nodes) { 120 197 TreeSet<Integer> adj = nodesMap.get(n); 121 if ( !adj.isEmpty()) {198 if (adj != null && !adj.isEmpty()) { 122 199 Integer j = adj.iterator().next(); 123 200 done(j); 124 201 waysMap.get(j).remove(n); 125 202 return j; 126 203 } 127 204 } 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 128 288 return null; 129 289 } 130 290 … … 133 293 * every sortable member has been processed. 134 294 */ 135 295 public Integer pop() { 136 if ( remaining.isEmpty()) return null;296 if (!remaining.isEmpty()){ 137 297 Integer i = remaining.iterator().next(); 138 298 done(i); 139 299 return i; 140 300 } 141 301 302 if (remainingOneway.isEmpty()) return null; 303 Integer i = remainingOneway.keySet().iterator().next(); 304 doneOneway(i); 305 return i; 306 } 307 142 308 /** 143 309 * This relation member has been processed. 144 310 * Remove references in the nodesMap. 145 311 */ 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 146 321 private void done(Integer i) { 147 322 remaining.remove(i); 148 323 TreeSet<Node> nodes = waysMap.get(i); -
WayConnectionType.java
35 35 /** True, if the element is part of a closed loop of ways. */ 36 36 public boolean isLoop; 37 37 38 public boolean isOnewayLoopForwardPart = false; 39 public boolean isOnewayLoopBackwardPart = false; 40 public boolean isOnewayHead = false; 41 public boolean isOnewayTail = false; 42 38 43 public boolean isRoundabout = false; 39 44 40 45 public WayConnectionType(boolean linkPrev, boolean linkNext, Direction direction) {
