| 156 | | if (!wayConnectionType.isOnewayLoopBackwardPart && !wayConnectionType.direction.isRoundabout()) { |
| 157 | | if (!wayConnectionType.linkPrev && !trkseg.isEmpty()) { |
| 158 | | gpxData.addTrack(new GpxTrack(trk, trkAttr)); |
| 159 | | trkAttr.clear(); |
| 160 | | trk.clear(); |
| 161 | | trkseg.clear(); |
| 162 | | trk.add(trkseg); |
| | 159 | if (!wayConnectionType.linkPrev && !trkseg.isEmpty()) { |
| | 160 | checkRoundabouts(trkseg, roundabouts); |
| | 161 | roundabouts.clear(); |
| | 162 | time = setTime(trkseg, time); |
| | 163 | gpxData.addTrack(new GpxTrack(trk, trkAttr)); |
| | 164 | trkAttr.clear(); |
| | 165 | trk.clear(); |
| | 166 | trkseg.clear(); |
| | 167 | trk.add(trkseg); |
| | 168 | } |
| | 169 | if (trkAttr.isEmpty()) { |
| | 170 | flat.get(i).getWay().referrers(Relation.class) |
| | 171 | .filter(relsFound::contains) |
| | 172 | .findFirst() |
| | 173 | .ifPresent(r -> { |
| | 174 | trkAttr.put("name", r.getName() != null ? r.getName() : Long.toString(r.getId())); |
| | 175 | trkAttr.put("desc", tr("based on osm route relation data, timestamps are synthetic")); |
| | 176 | }); |
| | 177 | GpxData.ensureUniqueName(trkAttr, names, (String) trkAttr.get("name")); |
| | 178 | } |
| | 179 | if (wayConnectionType.isOnewayLoopBackwardPart) |
| | 180 | continue; |
| | 181 | if (wayConnectionType.direction.isRoundabout()) { |
| | 182 | roundabouts.add(flat.get(i).getWay()); |
| | 183 | continue; |
| | 184 | } |
| | 185 | List<Node> ln = flat.get(i).getWay().getNodes(); |
| | 186 | if (wayConnectionType.direction == WayConnectionType.Direction.BACKWARD) |
| | 187 | Collections.reverse(ln); |
| | 188 | for (Node n: ln) { |
| | 189 | WayPoint point = OsmDataLayer.nodeToWayPoint(n, Long.MIN_VALUE); |
| | 190 | if (!trkseg.isEmpty()) { |
| | 191 | // see #24745 don't add connecting way nodes twice |
| | 192 | WayPoint last = trkseg.get(trkseg.size() - 1); |
| | 193 | if (point.getCoor().equals(last.getCoor())) |
| | 194 | continue; |
| 164 | | if (trkAttr.isEmpty()) { |
| 165 | | flat.get(i).getWay().referrers(Relation.class) |
| 166 | | .filter(relsFound::contains) |
| 167 | | .findFirst() |
| 168 | | .ifPresent(r -> { |
| 169 | | trkAttr.put("name", r.getName() != null ? r.getName() : Long.toString(r.getId())); |
| 170 | | trkAttr.put("desc", tr("based on osm route relation data, timestamps are synthetic")); |
| 171 | | }); |
| 172 | | GpxData.ensureUniqueName(trkAttr, names, (String) trkAttr.get("name")); |
| 173 | | } |
| 174 | | List<Node> ln = flat.get(i).getWay().getNodes(); |
| 175 | | if (wayConnectionType.direction == WayConnectionType.Direction.BACKWARD) |
| 176 | | Collections.reverse(ln); |
| 177 | | for (Node n: ln) { |
| 178 | | WayPoint point = OsmDataLayer.nodeToWayPoint(n, TimeUnit.SECONDS.toMillis(time)); |
| 179 | | if (!trkseg.isEmpty()) { |
| 180 | | // see #24745 don't add connecting way nodes twice |
| 181 | | WayPoint last = trkseg.get(trkseg.size() - 1); |
| 182 | | if (point.getCoor().equals(last.getCoor())) |
| 183 | | continue; |
| 184 | | } |
| 185 | | trkseg.add(point); |
| 186 | | time += 1; |
| 187 | | } |
| | 196 | trkseg.add(point); |
| | 216 | /** |
| | 217 | * Set time for the points in the given track segment and return last used value. For each point the time is incremented by 1. |
| | 218 | * @param trkseg the track segment |
| | 219 | * @param time the time value to start with |
| | 220 | * @return last used time value |
| | 221 | */ |
| | 222 | private long setTime(List<WayPoint> trkseg, long time) { |
| | 223 | for (WayPoint p : trkseg) { |
| | 224 | p.setTimeInMillis(TimeUnit.SECONDS.toMillis(time)); |
| | 225 | time++; |
| | 226 | } |
| | 227 | return time; |
| | 228 | } |
| | 229 | |
| | 230 | /** |
| | 231 | * Handle closed roundabout at beginning and/or end of track segment |
| | 232 | * @param trkseg the track segment |
| | 233 | * @param roundabouts list of roundabout ways |
| | 234 | */ |
| | 235 | private void checkRoundabouts(List<WayPoint> trkseg, List<Way> roundabouts) { |
| | 236 | for (Way roundabout : roundabouts) { |
| | 237 | checkRoundabout(trkseg, roundabout); |
| | 238 | } |
| | 239 | } |
| | 240 | |
| | 241 | /** |
| | 242 | * Check if roundabout is at the beginning and/or end of track segment and possibly add further nodes. |
| | 243 | * See #24741 |
| | 244 | * @param trkseg the track segment |
| | 245 | * @param roundabout the (closed) roundabout |
| | 246 | */ |
| | 247 | private void checkRoundabout(List<WayPoint> trkseg, Way roundabout) { |
| | 248 | if (trkseg.isEmpty()) |
| | 249 | return; |
| | 250 | LatLon first = trkseg.get(0).getCoor(); |
| | 251 | LatLon last = trkseg.get(trkseg.size() - 1).getCoor(); |
| | 252 | boolean hasFirst = roundabout.getNodes().stream().anyMatch(p -> p.getCoor().equals(first)); |
| | 253 | boolean hasLast = roundabout.getNodes().stream().anyMatch(p -> p.getCoor().equals(last)); |
| | 254 | if (hasFirst && hasLast) { |
| | 255 | // track starts and ends with the same closed roundabout and thus is a round trip, we want to add part of the circle or |
| | 256 | // just the connecting line between first and last to close the gap |
| | 257 | if (mode.contains(FROM_FIRST_MEMBER)) { |
| | 258 | trkseg.add(0, new WayPoint(trkseg.get(trkseg.size() - 1))); |
| | 259 | } else { |
| | 260 | trkseg.add(new WayPoint(trkseg.get(0))); |
| | 261 | } |
| | 262 | } else if (hasFirst || hasLast) { |
| | 263 | // a closed roundabout is before or after a gap, we want to add the full circle but we have to rotate first |
| | 264 | int pos = -1; |
| | 265 | List<Node> ln = new ArrayList<>(roundabout.getNodes()); |
| | 266 | ln.remove(0); |
| | 267 | for (int i = 0; i < ln.size(); i++) { |
| | 268 | LatLon current = roundabout.getNode(i).getCoor(); |
| | 269 | if (current.equals(first) || current.equals(last)) { |
| | 270 | pos = i; |
| | 271 | break; |
| | 272 | } |
| | 273 | } |
| | 274 | Collections.rotate(ln, -pos); |
| | 275 | ln.add(ln.get(0)); |
| | 276 | for (Node n: ln) { |
| | 277 | WayPoint point = OsmDataLayer.nodeToWayPoint(n, Long.MIN_VALUE); |
| | 278 | if (hasFirst) |
| | 279 | trkseg.add(0, point); |
| | 280 | else |
| | 281 | trkseg.add(point); |
| | 282 | } |
| | 283 | } |
| | 284 | } |
| | 285 | |