private TurnType processRoundaboutTurn( List<RouteSegmentResult> result, int i, boolean leftSide, RouteSegmentResult prev, RouteSegmentResult rr) { int exit = 1; RouteSegmentResult last = rr; for (int j = i; j < result.size(); j++) { RouteSegmentResult rnext = result.get(j); last = rnext; if (rnext.getObject().roundabout()) { boolean plus = rnext.getStartPointIndex() < rnext.getEndPointIndex(); int k = rnext.getStartPointIndex(); if (j == i) { k = plus ? k + 1 : k - 1; } while (k != rnext.getEndPointIndex()) { if (rnext.getAttachedRoutes(k).size() > 0) { exit++; } k = plus ? k + 1 : k - 1; } } else { break; } } // combine all roundabouts TurnType t = TurnType.valueOf("EXIT" + exit, leftSide); t.setTurnAngle((float) MapUtils.degreesDiff(last.getBearingBegin(), prev.getBearingEnd())); return t; }
private void addRouteSegmentToResult( List<RouteSegmentResult> result, RouteSegmentResult res, boolean reverse) { if (res.getStartPointIndex() != res.getEndPointIndex()) { if (result.size() > 0) { RouteSegmentResult last = result.get(result.size() - 1); if (last.getObject().id == res.getObject().id) { if (combineTwoSegmentResult(res, last, reverse)) { return; } } } result.add(res); } }
private String getLanesString(RouteSegmentResult segment) { final int[] lns = segment.getTurnType().getLanes(); if (lns != null) { String s = ""; for (int h = 0; h < lns.length; h++) { if (h > 0) { s += "|"; } if (lns[h] % 2 == 1) { s += "+"; } int pt = TurnType.getPrimaryTurn(lns[h]); if (pt == 0) { pt = 1; } s += TurnType.valueOf(pt, false).toXmlString(); int st = TurnType.getSecondaryTurn(lns[h]); if (st != 0) { s += "," + TurnType.valueOf(st, false).toXmlString(); } int tt = TurnType.getTertiaryTurn(lns[h]); if (tt != 0) { s += "," + TurnType.valueOf(tt, false).toXmlString(); } } s += ""; return s; } return null; }
private TurnType getTurnInfo(List<RouteSegmentResult> result, int i, boolean leftSide) { if (i == 0) { return TurnType.valueOf(TurnType.C, false); } RouteSegmentResult prev = result.get(i - 1); if (prev.getObject().roundabout()) { // already analyzed! return null; } RouteSegmentResult rr = result.get(i); if (rr.getObject().roundabout()) { return processRoundaboutTurn(result, i, leftSide, prev, rr); } TurnType t = null; if (prev != null) { boolean noAttachedRoads = rr.getAttachedRoutes(rr.getStartPointIndex()).size() == 0; // add description about turn double mpi = MapUtils.degreesDiff(prev.getBearingEnd(), rr.getBearingBegin()); if (noAttachedRoads) { // TODO VICTOR : look at the comment inside direction route // double begin = rr.getObject().directionRoute(rr.getStartPointIndex(), // rr.getStartPointIndex() < // rr.getEndPointIndex(), 25); // mpi = MapUtils.degreesDiff(prev.getBearingEnd(), begin); } if (mpi >= TURN_DEGREE_MIN) { if (mpi < 60) { t = TurnType.valueOf(TurnType.TSLL, leftSide); } else if (mpi < 120) { t = TurnType.valueOf(TurnType.TL, leftSide); } else if (mpi < 135 || leftSide) { t = TurnType.valueOf(TurnType.TSHL, leftSide); } else { t = TurnType.valueOf(TurnType.TU, leftSide); } } else if (mpi < -TURN_DEGREE_MIN) { if (mpi > -60) { t = TurnType.valueOf(TurnType.TSLR, leftSide); } else if (mpi > -120) { t = TurnType.valueOf(TurnType.TR, leftSide); } else if (mpi > -135 || !leftSide) { t = TurnType.valueOf(TurnType.TSHR, leftSide); } else { t = TurnType.valueOf(TurnType.TU, leftSide); } } else { t = attachKeepLeftInfoAndLanes(leftSide, prev, rr, t); } if (t != null) { t.setTurnAngle((float) -mpi); } } return t; }
private void validateAllPointsConnected(List<RouteSegmentResult> result) { for (int i = 1; i < result.size(); i++) { RouteSegmentResult rr = result.get(i); RouteSegmentResult pr = result.get(i - 1); double d = MapUtils.getDistance( pr.getPoint(pr.getEndPointIndex()), rr.getPoint(rr.getStartPointIndex())); if (d > 0) { System.err.println( "Points are not connected : " + pr.getObject() + "(" + pr.getEndPointIndex() + ") -> " + rr.getObject() + "(" + rr.getStartPointIndex() + ") " + d + " meters"); } } }
private List<RouteSegmentResult> prepareResult( RoutingContext ctx, RouteSegment start, RouteSegment end, long startNanoTime, RouteSegment finalDirectRoute, RouteSegment finalReverseRoute) { List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>(); RouteSegment segment = finalReverseRoute; int parentSegmentStart = segment == null ? 0 : segment.segmentEnd; while (segment != null) { RouteSegmentResult res = new RouteSegmentResult(); res.object = segment.road; res.endPointIndex = segment.segmentStart; res.startPointIndex = parentSegmentStart; parentSegmentStart = segment.parentSegmentEnd; segment = segment.parentRoute; // reverse start and end point for start if needed // rely that point.segmentStart <= point.segmentEnd for end, start if (segment == null && res.startPointIndex >= res.endPointIndex && res.endPointIndex < res.object.getPointsLength() - 1) { res.endPointIndex++; } // do not add segments consists from 1 point if (res.startPointIndex != res.endPointIndex) { result.add(res); } res.startPoint = convertPoint(res.object, res.startPointIndex); res.endPoint = convertPoint(res.object, res.endPointIndex); } Collections.reverse(result); segment = finalDirectRoute; int parentSegmentEnd = segment == null ? 0 : segment.segmentEnd; while (segment != null) { RouteSegmentResult res = new RouteSegmentResult(); res.object = segment.road; res.endPointIndex = parentSegmentEnd; res.startPointIndex = segment.segmentStart; parentSegmentEnd = segment.parentSegmentEnd; segment = segment.parentRoute; // reverse start and end point for start if needed // rely that point.segmentStart <= point.segmentEnd for end, start if (segment == null && res.startPointIndex < res.endPointIndex) { res.startPointIndex++; } // do not add segments consists from 1 point if (res.startPointIndex != res.endPointIndex) { result.add(res); } res.startPoint = convertPoint(res.object, res.startPointIndex); res.endPoint = convertPoint(res.object, res.endPointIndex); } Collections.reverse(result); if (PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST) { System.out.println("ROUTE : "); double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.segmentEnd)); double startLon = MapUtils.get31LongitudeX(start.road.getPoint31XTile(start.segmentEnd)); double endLat = MapUtils.get31LatitudeY(end.road.getPoint31YTile(end.segmentStart)); double endLon = MapUtils.get31LongitudeX(end.road.getPoint31XTile(end.segmentEnd)); System.out.println( MessageFormat.format( "<test regions=\"\" description=\"\" best_percent=\"\" vehicle=\"\" \n" + " start_lat=\"{0}\" start_lon=\"{1}\" target_lat=\"{2}\" target_lon=\"{3}\">", startLat + "", startLon + "", endLat + "", endLon + "")); for (RouteSegmentResult res : result) { // (res.object.getId() >> 1) System.out.println( MessageFormat.format( "\t<segment id=\"{0}\" start=\"{1}\" end=\"{2}\" name=\"{3}\"/>", (res.object.getId() >> 1) + "", res.startPointIndex, res.endPointIndex, (res.object.getName() + "").replace(MapRenderingTypes.REF_CHAR, ' '))); } System.out.println("</test>"); } ctx.timeToCalculate = (System.nanoTime() - startNanoTime); log.info( "Time to calculate : " + ctx.timeToCalculate / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6 + ", loaded tiles : " + ctx.loadedTiles.size() + ", visited segments " + ctx.visitedSegments); return result; }
private void attachRoadSegments( RoutingContext ctx, List<RouteSegmentResult> result, int routeInd, int pointInd, boolean plus) throws IOException { RouteSegmentResult rr = result.get(routeInd); RouteDataObject road = rr.getObject(); long nextL = pointInd < road.getPointsLength() - 1 ? getPoint(road, pointInd + 1) : 0; long prevL = pointInd > 0 ? getPoint(road, pointInd - 1) : 0; // attach additional roads to represent more information about the route RouteSegmentResult previousResult = null; // by default make same as this road id long previousRoadId = road.getId(); if (pointInd == rr.getStartPointIndex() && routeInd > 0) { previousResult = result.get(routeInd - 1); previousRoadId = previousResult.getObject().getId(); if (previousRoadId != road.getId()) { if (previousResult.getStartPointIndex() < previousResult.getEndPointIndex() && previousResult.getEndPointIndex() < previousResult.getObject().getPointsLength() - 1) { rr.attachRoute( pointInd, new RouteSegmentResult( previousResult.getObject(), previousResult.getEndPointIndex(), previousResult.getObject().getPointsLength() - 1)); } else if (previousResult.getStartPointIndex() > previousResult.getEndPointIndex() && previousResult.getEndPointIndex() > 0) { rr.attachRoute( pointInd, new RouteSegmentResult( previousResult.getObject(), previousResult.getEndPointIndex(), 0)); } } } Iterator<RouteSegment> it; if (rr.getPreAttachedRoutes(pointInd) != null) { final RouteSegmentResult[] list = rr.getPreAttachedRoutes(pointInd); it = new Iterator<BinaryRoutePlanner.RouteSegment>() { int i = 0; @Override public boolean hasNext() { return i < list.length; } @Override public RouteSegment next() { RouteSegmentResult r = list[i++]; return new RouteSegment(r.getObject(), r.getStartPointIndex()); } @Override public void remove() {} }; } else { RouteSegment rt = ctx.loadRouteSegment( road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation); it = rt.getIterator(); } // try to attach all segments except with current id while (it.hasNext()) { RouteSegment routeSegment = it.next(); if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) { RouteDataObject addRoad = routeSegment.road; checkAndInitRouteRegion(ctx, addRoad); // TODO restrictions can be considered as well int oneWay = ctx.getRouter().isOneWay(addRoad); if (oneWay >= 0 && routeSegment.getSegmentStart() < addRoad.getPointsLength() - 1) { long pointL = getPoint(addRoad, routeSegment.getSegmentStart() + 1); if (pointL != nextL && pointL != prevL) { // if way contains same segment (nodes) as different way (do not attach it) rr.attachRoute( pointInd, new RouteSegmentResult( addRoad, routeSegment.getSegmentStart(), addRoad.getPointsLength() - 1)); } } if (oneWay <= 0 && routeSegment.getSegmentStart() > 0) { long pointL = getPoint(addRoad, routeSegment.getSegmentStart() - 1); // if way contains same segment (nodes) as different way (do not attach it) if (pointL != nextL && pointL != prevL) { rr.attachRoute( pointInd, new RouteSegmentResult(addRoad, routeSegment.getSegmentStart(), 0)); } } } } }
private TurnType attachKeepLeftInfoAndLanes( boolean leftSide, RouteSegmentResult prev, RouteSegmentResult rr, TurnType t) { // keep left/right int[] lanes = null; boolean kl = false; boolean kr = false; List<RouteSegmentResult> attachedRoutes = rr.getAttachedRoutes(rr.getStartPointIndex()); int ls = prev.getObject().getLanes(); if (ls >= 0 && prev.getObject().getOneway() == 0) { ls = (ls + 1) / 2; } int left = 0; int right = 0; boolean speak = false; int speakPriority = Math.max( highwaySpeakPriority(prev.getObject().getHighway()), highwaySpeakPriority(rr.getObject().getHighway())); if (attachedRoutes != null) { for (RouteSegmentResult rs : attachedRoutes) { double ex = MapUtils.degreesDiff(rs.getBearingBegin(), rr.getBearingBegin()); double mpi = Math.abs(MapUtils.degreesDiff(prev.getBearingEnd(), rs.getBearingBegin())); int rsSpeakPriority = highwaySpeakPriority(rs.getObject().getHighway()); if (rsSpeakPriority != MAX_SPEAK_PRIORITY || speakPriority == MAX_SPEAK_PRIORITY) { if ((ex < TURN_DEGREE_MIN || mpi < TURN_DEGREE_MIN) && ex >= 0) { kl = true; int lns = rs.getObject().getLanes(); if (rs.getObject().getOneway() == 0) { lns = (lns + 1) / 2; } if (lns > 0) { right += lns; } speak = speak || rsSpeakPriority <= speakPriority; } else if ((ex > -TURN_DEGREE_MIN || mpi < TURN_DEGREE_MIN) && ex <= 0) { kr = true; int lns = rs.getObject().getLanes(); if (rs.getObject().getOneway() == 0) { lns = (lns + 1) / 2; } if (lns > 0) { left += lns; } speak = speak || rsSpeakPriority <= speakPriority; } } } } if (kr && left == 0) { left = 1; } else if (kl && right == 0) { right = 1; } int current = rr.getObject().getLanes(); if (rr.getObject().getOneway() == 0) { current = (current + 1) / 2; } if (current <= 0) { current = 1; } if (ls >= 0 /*&& current + left + right >= ls*/) { lanes = new int[current + left + right]; ls = current + left + right; for (int it = 0; it < ls; it++) { if (it < left || it >= left + current) { lanes[it] = 0; } else { lanes[it] = 1; } } // sometimes links are if ((current <= left + right) && (left > 1 || right > 1)) { speak = true; } } if (kl) { t = TurnType.valueOf(TurnType.KL, leftSide); t.setSkipToSpeak(!speak); } else if (kr) { t = TurnType.valueOf(TurnType.KR, leftSide); t.setSkipToSpeak(!speak); } if (t != null && lanes != null) { t.setLanes(lanes); } return t; }
private void calculateTimeSpeedAndAttachRoadSegments( RoutingContext ctx, List<RouteSegmentResult> result) throws IOException { for (int i = 0; i < result.size(); i++) { if (ctx.checkIfMemoryLimitCritical(ctx.config.memoryLimitation)) { ctx.unloadUnusedTiles(ctx.config.memoryLimitation); } RouteSegmentResult rr = result.get(i); RouteDataObject road = rr.getObject(); checkAndInitRouteRegion(ctx, road); double distOnRoadToPass = 0; double speed = ctx.getRouter().defineSpeed(road); if (speed == 0) { speed = ctx.getRouter().getMinDefaultSpeed(); } boolean plus = rr.getStartPointIndex() < rr.getEndPointIndex(); int next; double distance = 0; for (int j = rr.getStartPointIndex(); j != rr.getEndPointIndex(); j = next) { next = plus ? j + 1 : j - 1; if (j == rr.getStartPointIndex()) { attachRoadSegments(ctx, result, i, j, plus); } if (next != rr.getEndPointIndex()) { attachRoadSegments(ctx, result, i, next, plus); } double d = measuredDist( road.getPoint31XTile(j), road.getPoint31YTile(j), road.getPoint31XTile(next), road.getPoint31YTile(next)); distance += d; double obstacle = ctx.getRouter().defineObstacle(road, j); if (obstacle < 0) { obstacle = 0; } distOnRoadToPass += d / speed + obstacle; List<RouteSegmentResult> attachedRoutes = rr.getAttachedRoutes(next); if (next != rr.getEndPointIndex() && !rr.getObject().roundabout() && attachedRoutes != null) { float before = rr.getBearing(next, !plus); float after = rr.getBearing(next, plus); boolean straight = Math.abs(MapUtils.degreesDiff(before + 180, after)) < TURN_DEGREE_MIN; boolean isSplit = false; // split if needed for (RouteSegmentResult rs : attachedRoutes) { double diff = MapUtils.degreesDiff(before + 180, rs.getBearingBegin()); if (Math.abs(diff) <= TURN_DEGREE_MIN) { isSplit = true; } else if (!straight && Math.abs(diff) < 100) { isSplit = true; } } if (isSplit) { int endPointIndex = rr.getEndPointIndex(); RouteSegmentResult split = new RouteSegmentResult(rr.getObject(), next, endPointIndex); split.copyPreattachedRoutes(rr, Math.abs(next - rr.getStartPointIndex())); rr.setSegmentTime((float) distOnRoadToPass); rr.setSegmentSpeed((float) speed); rr.setDistance((float) distance); rr.setEndPointIndex(next); result.add(i + 1, split); i++; // switch current segment to the splitted rr = split; distOnRoadToPass = 0; distance = 0; } } } // last point turn time can be added // if(i + 1 < result.size()) { distOnRoadToPass += ctx.getRouter().calculateTurnTime(); } rr.setSegmentTime((float) distOnRoadToPass); rr.setSegmentSpeed((float) speed); rr.setDistance((float) distance); } }
void printResults(RoutingContext ctx, LatLon start, LatLon end, List<RouteSegmentResult> result) { float completeTime = 0; float completeDistance = 0; for (RouteSegmentResult r : result) { completeTime += r.getSegmentTime(); completeDistance += r.getDistance(); } println("ROUTE : "); double startLat = start.getLatitude(); double startLon = start.getLongitude(); double endLat = end.getLatitude(); double endLon = end.getLongitude(); StringBuilder add = new StringBuilder(); add.append("loadedTiles = \"").append(ctx.loadedTiles).append("\" "); add.append("visitedSegments = \"").append(ctx.visitedSegments).append("\" "); add.append("complete_distance = \"").append(completeDistance).append("\" "); add.append("complete_time = \"").append(completeTime).append("\" "); add.append("routing_time = \"").append(ctx.routingTime).append("\" "); println( MessageFormat.format( "<test regions=\"\" description=\"\" best_percent=\"\" vehicle=\"{4}\" \n" + " start_lat=\"{0}\" start_lon=\"{1}\" target_lat=\"{2}\" target_lon=\"{3}\" {5} >", startLat + "", startLon + "", endLat + "", endLon + "", ctx.config.routerName, add.toString())); if (PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST) { for (RouteSegmentResult res : result) { String name = res.getObject().getName(); String ref = res.getObject().getRef(); if (name == null) { name = ""; } if (ref != null) { name += " (" + ref + ") "; } StringBuilder additional = new StringBuilder(); additional.append("time = \"").append(res.getSegmentTime()).append("\" "); additional.append("name = \"").append(name).append("\" "); // float ms = res.getSegmentSpeed(); float ms = res.getObject().getMaximumSpeed(); if (ms > 0) { additional .append("maxspeed = \"") .append(ms * 3.6f) .append("\" ") .append(res.getObject().getHighway()) .append(" "); } additional.append("distance = \"").append(res.getDistance()).append("\" "); if (res.getTurnType() != null) { additional.append("turn = \"").append(res.getTurnType()).append("\" "); additional .append("turn_angle = \"") .append(res.getTurnType().getTurnAngle()) .append("\" "); if (res.getTurnType().getLanes() != null) { additional .append("lanes = \"") .append(Arrays.toString(res.getTurnType().getLanes())) .append("\" "); } } additional.append("start_bearing = \"").append(res.getBearingBegin()).append("\" "); additional.append("end_bearing = \"").append(res.getBearingEnd()).append("\" "); additional.append("description = \"").append(res.getDescription()).append("\" "); println( MessageFormat.format( "\t<segment id=\"{0}\" start=\"{1}\" end=\"{2}\" {3}/>", (res.getObject().getId()) + "", res.getStartPointIndex() + "", res.getEndPointIndex() + "", additional.toString())); } } println("</test>"); }
private boolean combineTwoSegmentResult( RouteSegmentResult toAdd, RouteSegmentResult previous, boolean reverse) { boolean ld = previous.getEndPointIndex() > previous.getStartPointIndex(); boolean rd = toAdd.getEndPointIndex() > toAdd.getStartPointIndex(); if (rd == ld) { if (toAdd.getStartPointIndex() == previous.getEndPointIndex() && !reverse) { previous.setEndPointIndex(toAdd.getEndPointIndex()); return true; } else if (toAdd.getEndPointIndex() == previous.getStartPointIndex() && reverse) { previous.setStartPointIndex(toAdd.getStartPointIndex()); return true; } } return false; }