[5630] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
| 2 | package org.openstreetmap.josm.gui.dialogs.relation.sort;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.BACKWARD;
|
---|
| 5 | import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.FORWARD;
|
---|
| 6 | import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.NONE;
|
---|
| 7 |
|
---|
| 8 | import java.util.ArrayList;
|
---|
| 9 | import java.util.List;
|
---|
| 10 |
|
---|
| 11 | import org.openstreetmap.josm.data.osm.Node;
|
---|
| 12 | import org.openstreetmap.josm.data.osm.RelationMember;
|
---|
| 13 | import org.openstreetmap.josm.data.osm.Way;
|
---|
| 14 | import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
|
---|
| 15 |
|
---|
| 16 | public class WayConnectionTypeCalculator {
|
---|
| 17 |
|
---|
[6286] | 18 | private static final int UNCONNECTED = Integer.MIN_VALUE;
|
---|
[5630] | 19 |
|
---|
| 20 | private List<RelationMember> members;
|
---|
| 21 |
|
---|
| 22 | /**
|
---|
| 23 | * refresh the cache of member WayConnectionTypes
|
---|
| 24 | */
|
---|
| 25 | public List<WayConnectionType> updateLinks(List<RelationMember> members) {
|
---|
| 26 | this.members = members;
|
---|
[7005] | 27 | final List<WayConnectionType> con = new ArrayList<>();
|
---|
[5630] | 28 |
|
---|
[8510] | 29 | for (int i = 0; i < members.size(); ++i) {
|
---|
[5630] | 30 | con.add(null);
|
---|
| 31 | }
|
---|
| 32 |
|
---|
[8510] | 33 | firstGroupIdx = 0;
|
---|
[5630] | 34 |
|
---|
| 35 | lastForwardWay = UNCONNECTED;
|
---|
| 36 | lastBackwardWay = UNCONNECTED;
|
---|
| 37 | onewayBeginning = false;
|
---|
| 38 | WayConnectionType lastWct = null;
|
---|
| 39 |
|
---|
[8510] | 40 | for (int i = 0; i < members.size(); ++i) {
|
---|
[5630] | 41 | final RelationMember m = members.get(i);
|
---|
| 42 | if (!m.isWay() || m.getWay() == null || m.getWay().isIncomplete()) {
|
---|
[6289] | 43 | if (i > 0) {
|
---|
[5630] | 44 | makeLoopIfNeeded(con, i-1);
|
---|
| 45 | }
|
---|
| 46 | con.set(i, new WayConnectionType());
|
---|
| 47 | firstGroupIdx = i;
|
---|
| 48 | continue;
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | WayConnectionType wct = new WayConnectionType(false);
|
---|
[8510] | 52 | wct.linkPrev = i > 0 && con.get(i-1) != null && con.get(i-1).isValid();
|
---|
[5630] | 53 | wct.direction = NONE;
|
---|
| 54 |
|
---|
[8510] | 55 | if (RelationSortUtils.isOneway(m)) {
|
---|
[6289] | 56 | if (lastWct != null && lastWct.isOnewayTail) {
|
---|
[5630] | 57 | wct.isOnewayHead = true;
|
---|
| 58 | }
|
---|
[8510] | 59 | if (lastBackwardWay == UNCONNECTED && lastForwardWay == UNCONNECTED) { //Beginning of new oneway
|
---|
[5630] | 60 | wct.isOnewayHead = true;
|
---|
| 61 | lastForwardWay = i-1;
|
---|
| 62 | lastBackwardWay = i-1;
|
---|
| 63 | onewayBeginning = true;
|
---|
| 64 | }
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | if (wct.linkPrev) {
|
---|
[6289] | 68 | if (lastBackwardWay != UNCONNECTED && lastForwardWay != UNCONNECTED) {
|
---|
[8406] | 69 | determineOnewayConnectionType(con, m, i, wct);
|
---|
[6289] | 70 | if (!wct.linkPrev) {
|
---|
[5630] | 71 | firstGroupIdx = i;
|
---|
| 72 | }
|
---|
| 73 | }
|
---|
| 74 |
|
---|
[6289] | 75 | if (!RelationSortUtils.isOneway(m)) {
|
---|
[5630] | 76 | wct.direction = determineDirection(i-1, lastWct.direction, i);
|
---|
| 77 | wct.linkPrev = (wct.direction != NONE);
|
---|
| 78 | }
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | if (!wct.linkPrev) {
|
---|
| 82 | wct.direction = determineDirectionOfFirst(i, m);
|
---|
[8510] | 83 | if (RelationSortUtils.isOneway(m)) {
|
---|
[5630] | 84 | wct.isOnewayLoopForwardPart = true;
|
---|
| 85 | lastForwardWay = i;
|
---|
| 86 | }
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | wct.linkNext = false;
|
---|
[6289] | 90 | if (lastWct != null) {
|
---|
[5630] | 91 | lastWct.linkNext = wct.linkPrev;
|
---|
| 92 | }
|
---|
| 93 | con.set(i, wct);
|
---|
| 94 | lastWct = wct;
|
---|
| 95 |
|
---|
[6289] | 96 | if (!wct.linkPrev) {
|
---|
| 97 | if (i > 0) {
|
---|
[5630] | 98 | makeLoopIfNeeded(con, i-1);
|
---|
| 99 | }
|
---|
| 100 | firstGroupIdx = i;
|
---|
| 101 | }
|
---|
| 102 | }
|
---|
| 103 | makeLoopIfNeeded(con, members.size()-1);
|
---|
| 104 |
|
---|
| 105 | return con;
|
---|
| 106 | }
|
---|
| 107 |
|
---|
[8285] | 108 | private int firstGroupIdx;
|
---|
[5630] | 109 | private void makeLoopIfNeeded(final List<WayConnectionType> con, final int i) {
|
---|
| 110 | boolean loop;
|
---|
| 111 | if (i == firstGroupIdx) { //is primitive loop
|
---|
| 112 | loop = determineDirection(i, FORWARD, i) == FORWARD;
|
---|
| 113 | } else {
|
---|
| 114 | loop = determineDirection(i, con.get(i).direction, firstGroupIdx) == con.get(firstGroupIdx).direction;
|
---|
| 115 | }
|
---|
| 116 | if (loop) {
|
---|
[8510] | 117 | for (int j = firstGroupIdx; j <= i; ++j) {
|
---|
[5630] | 118 | con.get(j).isLoop = true;
|
---|
| 119 | }
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | private Direction determineDirectionOfFirst(final int i, final RelationMember m) {
|
---|
| 124 | Direction result = RelationSortUtils.roundaboutType(m);
|
---|
| 125 | if (result != NONE)
|
---|
| 126 | return result;
|
---|
| 127 |
|
---|
[8510] | 128 | if (RelationSortUtils.isOneway(m)) {
|
---|
[6289] | 129 | if (RelationSortUtils.isBackward(m)) return BACKWARD;
|
---|
[5630] | 130 | else return FORWARD;
|
---|
| 131 | } else { /** guess the direction and see if it fits with the next member */
|
---|
[6289] | 132 | if (determineDirection(i, FORWARD, i+1) != NONE) return FORWARD;
|
---|
| 133 | if (determineDirection(i, BACKWARD, i+1) != NONE) return BACKWARD;
|
---|
[5630] | 134 | }
|
---|
| 135 | return NONE;
|
---|
| 136 | }
|
---|
| 137 |
|
---|
[8285] | 138 | private int lastForwardWay;
|
---|
| 139 | private int lastBackwardWay;
|
---|
| 140 | private boolean onewayBeginning;
|
---|
[8406] | 141 |
|
---|
| 142 | private void determineOnewayConnectionType(final List<WayConnectionType> con,
|
---|
[5630] | 143 | RelationMember m, int i, final WayConnectionType wct) {
|
---|
| 144 | Direction dirFW = determineDirection(lastForwardWay, con.get(lastForwardWay).direction, i);
|
---|
| 145 | Direction dirBW = NONE;
|
---|
[6289] | 146 | if (onewayBeginning) {
|
---|
| 147 | if (lastBackwardWay < 0) {
|
---|
[5630] | 148 | dirBW = determineDirection(firstGroupIdx, reverse(con.get(firstGroupIdx).direction), i, true);
|
---|
| 149 | } else {
|
---|
| 150 | dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
|
---|
| 151 | }
|
---|
| 152 |
|
---|
[6289] | 153 | if (dirBW != NONE) {
|
---|
[5630] | 154 | onewayBeginning = false;
|
---|
| 155 | }
|
---|
| 156 | } else {
|
---|
| 157 | dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
|
---|
| 158 | }
|
---|
| 159 |
|
---|
[6289] | 160 | if (RelationSortUtils.isOneway(m)) {
|
---|
[8510] | 161 | if (dirBW != NONE) {
|
---|
[5630] | 162 | wct.direction = dirBW;
|
---|
| 163 | lastBackwardWay = i;
|
---|
| 164 | wct.isOnewayLoopBackwardPart = true;
|
---|
| 165 | }
|
---|
[8510] | 166 | if (dirFW != NONE) {
|
---|
[5630] | 167 | wct.direction = dirFW;
|
---|
| 168 | lastForwardWay = i;
|
---|
| 169 | wct.isOnewayLoopForwardPart = true;
|
---|
| 170 | }
|
---|
[6296] | 171 | // Not connected to previous
|
---|
| 172 | if (dirFW == NONE && dirBW == NONE) {
|
---|
[5630] | 173 | wct.linkPrev = false;
|
---|
[6296] | 174 | if (RelationSortUtils.isOneway(m)) {
|
---|
[5630] | 175 | wct.isOnewayHead = true;
|
---|
| 176 | lastForwardWay = i-1;
|
---|
| 177 | lastBackwardWay = i-1;
|
---|
| 178 | } else {
|
---|
| 179 | lastForwardWay = UNCONNECTED;
|
---|
| 180 | lastBackwardWay = UNCONNECTED;
|
---|
| 181 | }
|
---|
| 182 | onewayBeginning = true;
|
---|
| 183 | }
|
---|
| 184 |
|
---|
[6289] | 185 | if (dirFW != NONE && dirBW != NONE) { //End of oneway loop
|
---|
[8510] | 186 | if (i+1 < members.size() && determineDirection(i, dirFW, i+1) != NONE) {
|
---|
[5630] | 187 | wct.isOnewayLoopBackwardPart = false;
|
---|
| 188 | wct.direction = dirFW;
|
---|
| 189 | } else {
|
---|
| 190 | wct.isOnewayLoopForwardPart = false;
|
---|
| 191 | wct.direction = dirBW;
|
---|
| 192 | }
|
---|
| 193 |
|
---|
| 194 | wct.isOnewayTail = true;
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | } else {
|
---|
| 198 | lastForwardWay = UNCONNECTED;
|
---|
| 199 | lastBackwardWay = UNCONNECTED;
|
---|
[6289] | 200 | if (dirFW == NONE || dirBW == NONE) {
|
---|
[5630] | 201 | wct.linkPrev = false;
|
---|
| 202 | }
|
---|
| 203 | }
|
---|
| 204 | }
|
---|
| 205 |
|
---|
[8510] | 206 | private static Direction reverse(final Direction dir) {
|
---|
[6289] | 207 | if (dir == FORWARD) return BACKWARD;
|
---|
| 208 | if (dir == BACKWARD) return FORWARD;
|
---|
[5630] | 209 | return dir;
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | private Direction determineDirection(int ref_i, Direction ref_direction, int k) {
|
---|
| 213 | return determineDirection(ref_i, ref_direction, k, false);
|
---|
| 214 | }
|
---|
| 215 | /**
|
---|
| 216 | * Determines the direction of way k with respect to the way ref_i.
|
---|
| 217 | * The way ref_i is assumed to have the direction ref_direction and
|
---|
| 218 | * to be the predecessor of k.
|
---|
| 219 | *
|
---|
| 220 | * If both ways are not linked in any way, NONE is returned.
|
---|
| 221 | *
|
---|
| 222 | * Else the direction is given as follows:
|
---|
| 223 | * Let the relation be a route of oneway streets, and someone travels them in the given order.
|
---|
| 224 | * Direction is FORWARD if it is legal and BACKWARD if it is illegal to do so for the given way.
|
---|
| 225 | *
|
---|
| 226 | **/
|
---|
| 227 | private Direction determineDirection(int ref_i, final Direction ref_direction, int k, boolean reversed) {
|
---|
| 228 | if (ref_i < 0 || k < 0 || ref_i >= members.size() || k >= members.size())
|
---|
| 229 | return NONE;
|
---|
| 230 | if (ref_direction == NONE)
|
---|
| 231 | return NONE;
|
---|
| 232 |
|
---|
| 233 | final RelationMember m_ref = members.get(ref_i);
|
---|
| 234 | final RelationMember m = members.get(k);
|
---|
| 235 | Way way_ref = null;
|
---|
| 236 | Way way = null;
|
---|
| 237 |
|
---|
| 238 | if (m_ref.isWay()) {
|
---|
| 239 | way_ref = m_ref.getWay();
|
---|
| 240 | }
|
---|
| 241 | if (m.isWay()) {
|
---|
| 242 | way = m.getWay();
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 | if (way_ref == null || way == null)
|
---|
| 246 | return NONE;
|
---|
| 247 |
|
---|
| 248 | /** the list of nodes the way k can dock to */
|
---|
[8510] | 249 | List<Node> refNodes = new ArrayList<>();
|
---|
[5630] | 250 |
|
---|
| 251 | switch (ref_direction) {
|
---|
| 252 | case FORWARD:
|
---|
| 253 | refNodes.add(way_ref.lastNode());
|
---|
| 254 | break;
|
---|
| 255 | case BACKWARD:
|
---|
| 256 | refNodes.add(way_ref.firstNode());
|
---|
| 257 | break;
|
---|
| 258 | case ROUNDABOUT_LEFT:
|
---|
| 259 | case ROUNDABOUT_RIGHT:
|
---|
| 260 | refNodes = way_ref.getNodes();
|
---|
| 261 | break;
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | for (Node n : refNodes) {
|
---|
| 265 | if (n == null) {
|
---|
| 266 | continue;
|
---|
| 267 | }
|
---|
| 268 | if (RelationSortUtils.roundaboutType(members.get(k)) != NONE) {
|
---|
| 269 | for (Node nn : way.getNodes()) {
|
---|
| 270 | if (n == nn)
|
---|
| 271 | return RelationSortUtils.roundaboutType(members.get(k));
|
---|
| 272 | }
|
---|
[6289] | 273 | } else if (RelationSortUtils.isOneway(m)) {
|
---|
[5630] | 274 | if (n == RelationNodeMap.firstOnewayNode(m) && !reversed) {
|
---|
[6289] | 275 | if (RelationSortUtils.isBackward(m))
|
---|
[5630] | 276 | return BACKWARD;
|
---|
| 277 | else
|
---|
| 278 | return FORWARD;
|
---|
| 279 | }
|
---|
| 280 | if (n == RelationNodeMap.lastOnewayNode(m) && reversed) {
|
---|
[6289] | 281 | if (RelationSortUtils.isBackward(m))
|
---|
[5630] | 282 | return FORWARD;
|
---|
| 283 | else
|
---|
| 284 | return BACKWARD;
|
---|
| 285 | }
|
---|
| 286 | } else {
|
---|
| 287 | if (n == way.firstNode())
|
---|
| 288 | return FORWARD;
|
---|
| 289 | if (n == way.lastNode())
|
---|
| 290 | return BACKWARD;
|
---|
| 291 | }
|
---|
| 292 | }
|
---|
| 293 | return NONE;
|
---|
| 294 | }
|
---|
| 295 | }
|
---|