Fix road creation mechanism
This commit is contained in:
parent
5f638bcc27
commit
5905a465d7
8 changed files with 41 additions and 577 deletions
|
@ -9,7 +9,6 @@ import java.util.List;
|
|||
|
||||
import net.osmand.Algoritms;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.router.BinaryRoutePlanner;
|
||||
import net.osmand.router.RoutingConfiguration;
|
||||
import net.osmand.swing.DataExtractionSettings;
|
||||
import net.osmand.swing.NativeSwingRendering;
|
||||
|
@ -31,7 +30,7 @@ public class JUnitRouteTest {
|
|||
}
|
||||
// test without native because it is not present on the server
|
||||
// lib = NativeSwingRendering.getDefaultFromSettings();
|
||||
BinaryRoutePlanner.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
RouteResultPreparation.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
String obfdir = System.getenv("OBF_DIR");
|
||||
if(Algoritms.isEmpty(obfdir)){
|
||||
obfdir = DataExtractionSettings.getSettings().getBinaryFilesDir();
|
||||
|
|
|
@ -41,12 +41,12 @@ public class RouterTestsSuite {
|
|||
Parameters p = new Parameters();
|
||||
String routingXmlFile = null;
|
||||
String obfDirectory = null;
|
||||
BinaryRoutePlanner.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = false;
|
||||
RouteResultPreparation.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = false;
|
||||
for (String a : args) {
|
||||
if (a.startsWith("-routingXmlPath=")) {
|
||||
routingXmlFile = a.substring("-routingXmlPath=".length());
|
||||
} else if (a.startsWith("-verbose")) {
|
||||
BinaryRoutePlanner.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
RouteResultPreparation.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
} else if (a.startsWith("-obfDir=")) {
|
||||
obfDirectory = a.substring("-obfDir=".length());
|
||||
} else if (a.startsWith("-testDir=")) {
|
||||
|
|
|
@ -744,7 +744,7 @@ public class IndexCreator {
|
|||
// creator.setIndexMap(true);
|
||||
// creator.setIndexAddress(true);
|
||||
// creator.setIndexPOI(true);
|
||||
// creator.setInde xTransport(true);
|
||||
// creator.setIndexTransport(true);
|
||||
creator.setIndexRouting(true);
|
||||
|
||||
// creator.deleteDatabaseIndexes = false;
|
||||
|
@ -755,8 +755,9 @@ public class IndexCreator {
|
|||
MapRenderingTypes rt = MapRenderingTypes.getDefault();
|
||||
MapZooms zooms = MapZooms.getDefault(); // MapZooms.parseZooms("15-");
|
||||
|
||||
String file = "/home/victor/projects/OsmAnd/temp/map.osm";
|
||||
// String file = "/home/victor/projects/OsmAnd/temp/map.osm";
|
||||
// String file = "/home/victor/projects/OsmAnd/temp/belgium.osm.pbf";
|
||||
String file = "/home/victor/projects/OsmAnd/temp/poland.osm.pbf";
|
||||
int st = file.lastIndexOf('/');
|
||||
int e = file.indexOf('.', st);
|
||||
creator.setNodesDBFile(new File("/home/victor/projects/OsmAnd/data/osm-gen/"+file.substring(st, e) + ".tmp.odb"));
|
||||
|
|
|
@ -614,6 +614,7 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
return main;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void getAdjacentRoads(GeneralizedCluster gcluster, GeneralizedWay gw, int i, Collection<GeneralizedWay> collection){
|
||||
gcluster = getCluster(gw, i, gcluster);
|
||||
Object o = gcluster.map.get(gw.getLocation(i));
|
||||
|
@ -628,10 +629,12 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public int countAdjacentRoads(GeneralizedCluster gcluster, GeneralizedWay gw, int i){
|
||||
gcluster = getCluster(gw, i, gcluster);
|
||||
Object o = gcluster.map.get(gw.getLocation(i));
|
||||
if (o instanceof LinkedList) {
|
||||
|
||||
Iterator it = ((LinkedList) o).iterator();
|
||||
int cnt = 0;
|
||||
while (it.hasNext()) {
|
||||
|
@ -701,12 +704,14 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
System.err.println(gw.id + " empty ? ");
|
||||
continue;
|
||||
}
|
||||
Node prev = convertBaseToNode(gw.getLocation(0));
|
||||
nodes.add(prev);
|
||||
long prev = 0;
|
||||
for (int i = 0; i < gw.size(); i++) {
|
||||
Node c = convertBaseToNode(gw.getLocation(i));
|
||||
prev = c;
|
||||
nodes.add(c);
|
||||
long loc = gw.getLocation(i);
|
||||
if(loc != prev) {
|
||||
Node c = convertBaseToNode(loc);
|
||||
prev = loc;
|
||||
nodes.add(c);
|
||||
}
|
||||
}
|
||||
outTypes.clear();
|
||||
outTypes.add(gw.mainType);
|
||||
|
@ -809,8 +814,7 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
}
|
||||
}
|
||||
|
||||
private int checkDistanceToLine(GeneralizedWay line, int start, boolean directionPlus,
|
||||
int px, int py, double distThreshold) {
|
||||
public int checkDistanceToLine(GeneralizedWay line, int start, boolean directionPlus, int px, int py, double distThreshold) {
|
||||
int j = start;
|
||||
int next = directionPlus ? j + 1 : j - 1;
|
||||
while (next >= 0 && next < line.size()) {
|
||||
|
@ -824,68 +828,6 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
return -1;
|
||||
}
|
||||
|
||||
private void removeLineDuplication(Collection<GeneralizedCluster> clusters) {
|
||||
for(GeneralizedCluster cluster : clusters) {
|
||||
ArrayList<GeneralizedWay> copy = new ArrayList<GeneralizedWay>(cluster.ways);
|
||||
for(GeneralizedWay gw : copy) {
|
||||
// already deleted
|
||||
if(!cluster.ways.contains(gw)){
|
||||
continue;
|
||||
}
|
||||
if(gw.size() > 2) {
|
||||
float p = DOUGLAS_PEUKER_DISTANCE / 3;
|
||||
for (GeneralizedWay gn : copy) {
|
||||
int kmin = checkDistanceToLine(gn, 0, true, gw.px.get(0),
|
||||
gw.py.get(0), p);
|
||||
int knext = kmin;
|
||||
boolean dir = true;
|
||||
if(kmin >= 0) {
|
||||
knext = checkDistanceToLine(gn, kmin, dir, gw.px.get(1),
|
||||
gw.py.get(1), p);
|
||||
if(knext < 0) {
|
||||
dir = false;
|
||||
knext = checkDistanceToLine(gn, kmin, dir, gw.px.get(1),
|
||||
gw.py.get(1), p);
|
||||
}
|
||||
}
|
||||
if(knext > 0){
|
||||
int prevk = kmin;
|
||||
while (gw.size() > 1) {
|
||||
prevk = checkDistanceToLine(gn, prevk, dir, gw.px.get(1),
|
||||
gw.py.get(1), p);
|
||||
if(prevk < 0){
|
||||
break;
|
||||
}
|
||||
removePointFromWayAndReplace(cluster, gw, 1, gn.px.get(prevk), gn.py.get(prevk));
|
||||
}
|
||||
removePointFromWayAndReplace(cluster, gw, 0, gn.px.get(kmin), gn.py.get(kmin));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removePointFromWayAndReplace(GeneralizedCluster cluster, GeneralizedWay gw, int i, int x31, int y31) {
|
||||
GeneralizedCluster gcluster = getCluster(gw, i, cluster);
|
||||
Object o = gcluster.map.get(gw.getLocation(i));
|
||||
if (o instanceof LinkedList) {
|
||||
Iterator it = ((LinkedList) o).iterator();
|
||||
while (it.hasNext()) {
|
||||
GeneralizedWay next = (GeneralizedWay) it.next();
|
||||
replacePointWithAnotherPoint(gcluster, gw, x31, y31, i, next);
|
||||
}
|
||||
} else if (o instanceof GeneralizedWay) {
|
||||
replacePointWithAnotherPoint(gcluster, gw, x31, y31, i, (GeneralizedWay) o);
|
||||
}
|
||||
gcluster.removeWayFromLocation(gw, i);
|
||||
gw.px.removeAt(i);
|
||||
gw.py.removeAt(i);
|
||||
}
|
||||
|
||||
|
||||
private void processRoundabouts(Collection<GeneralizedCluster> clusters) {
|
||||
for(GeneralizedCluster cluster : clusters) {
|
||||
ArrayList<GeneralizedWay> copy = new ArrayList<GeneralizedWay>(cluster.ways);
|
||||
|
@ -899,7 +841,6 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void removeSmall2RoadsConnectors(Collection<GeneralizedCluster> clusters) {
|
||||
for(GeneralizedCluster cluster : clusters) {
|
||||
|
@ -948,6 +889,7 @@ public class IndexRouteCreator extends AbstractIndexPartCreator {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void removeWayAndSubstituteWithPoint(GeneralizedWay gw, GeneralizedCluster gcluster) {
|
||||
// calculate center location
|
||||
long pxc = 0;
|
||||
|
|
|
@ -59,11 +59,11 @@
|
|||
|
||||
<!-- filter does not work for renderingConstant - the last one will be used, but better use separate depends Rendering style -->
|
||||
<!-- roadColors="Modified Mapnik" -->
|
||||
<renderingConstant name="motorwayRoadColor" value="#809bff"/>
|
||||
<renderingConstant name="trunkRoadColor" value="#FF8095"/>
|
||||
<renderingConstant name="primaryRoadColor" value="#FFAA80"/>
|
||||
<renderingConstant name="secondaryRoadColor" value="#ffd080"/>
|
||||
<renderingConstant name="tertiaryRoadColor" value="#ffff80"/>
|
||||
<renderingConstant name="motorwayRoadColor" value="#55809bff"/>
|
||||
<renderingConstant name="trunkRoadColor" value="#55FF8095"/>
|
||||
<renderingConstant name="primaryRoadColor" value="#55FFAA80"/>
|
||||
<renderingConstant name="secondaryRoadColor" value="#55ffd080"/>
|
||||
<renderingConstant name="tertiaryRoadColor" value="#55ffff80"/>
|
||||
<!-- roadColors="Road atlas style" -->
|
||||
<!--
|
||||
<renderingConstant name="motorwayRoadColor" value="#809bff"/>
|
||||
|
|
|
@ -3,10 +3,7 @@ package net.osmand.router;
|
|||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -21,7 +18,6 @@ import org.apache.commons.logging.Log;
|
|||
|
||||
public class BinaryRoutePlanner {
|
||||
|
||||
public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
private final int REVERSE_WAY_RESTRICTION_ONLY = 1024;
|
||||
/*private*/ final int STANDARD_ROAD_IN_QUEUE_OVERHEAD = 220;
|
||||
/*private */final int STANDARD_ROAD_VISITED_OVERHEAD = 150;
|
||||
|
@ -29,7 +25,6 @@ public class BinaryRoutePlanner {
|
|||
protected static final Log log = LogUtil.getLog(BinaryRoutePlanner.class);
|
||||
|
||||
private static final int ROUTE_POINTS = 11;
|
||||
private static final float TURN_DEGREE_MIN = 45;
|
||||
private static final boolean TRACE_ROUTING = false;
|
||||
|
||||
|
||||
|
@ -41,12 +36,6 @@ public class BinaryRoutePlanner {
|
|||
// return measuredDist(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
private static double measuredDist(int x1, int y1, int x2, int y2) {
|
||||
return MapUtils.getDistance(MapUtils.get31LatitudeY(y1), MapUtils.get31LongitudeX(x1),
|
||||
MapUtils.get31LatitudeY(y2), MapUtils.get31LongitudeX(x2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public RouteSegment findRouteSegment(double lat, double lon, RoutingContext ctx) throws IOException {
|
||||
int px = MapUtils.get31TileNumberX(lon);
|
||||
|
@ -149,7 +138,7 @@ public class BinaryRoutePlanner {
|
|||
}
|
||||
}
|
||||
ctx.unloadAllData();
|
||||
printResults(ctx, start, end, results);
|
||||
new RouteResultPreparation().printResults(ctx, start, end, results);
|
||||
return results;
|
||||
}
|
||||
return searchRoute(ctx, start, end, leftSideNavigation);
|
||||
|
@ -169,7 +158,7 @@ public class BinaryRoutePlanner {
|
|||
}
|
||||
List<RouteSegmentResult> result = searchRouteInternalPrepare(ctx, start, end, leftSideNavigation);
|
||||
if(result != null) {
|
||||
printResults(ctx, start, end, result);
|
||||
new RouteResultPreparation().printResults(ctx, start, end, result);
|
||||
}
|
||||
if (RoutingContext.SHOW_GC_SIZE) {
|
||||
int sz = ctx.global.size;
|
||||
|
@ -190,7 +179,7 @@ public class BinaryRoutePlanner {
|
|||
// Split into 2 methods to let GC work in between
|
||||
FinalRouteSegment finalRouteSegment = searchRouteInternal(ctx, start, end, leftSideNavigation);
|
||||
// 4. Route is found : collect all segments and prepare result
|
||||
return prepareResult(ctx, finalRouteSegment, leftSideNavigation);
|
||||
return new RouteResultPreparation().prepareResult(ctx, finalRouteSegment, leftSideNavigation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -805,482 +794,6 @@ public class BinaryRoutePlanner {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to prepare final result
|
||||
*/
|
||||
private List<RouteSegmentResult> prepareResult(RoutingContext ctx, FinalRouteSegment finalSegment,boolean leftside) {
|
||||
List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>();
|
||||
|
||||
if (finalSegment != null) {
|
||||
ctx.routingTime = finalSegment.distanceFromStart;
|
||||
println("Routing calculated time distance " + finalSegment.distanceFromStart);
|
||||
// Get results from opposite direction roads
|
||||
RouteSegment segment = finalSegment.reverseWaySearch ? finalSegment : finalSegment.opposite.getParentRoute();
|
||||
int parentSegmentStart = finalSegment.reverseWaySearch ? finalSegment.opposite.getSegmentStart() : finalSegment.opposite.getParentSegmentEnd();
|
||||
|
||||
if(segment != null) {
|
||||
// println(segment.road +" 1->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart);
|
||||
}
|
||||
while (segment != null) {
|
||||
RouteSegmentResult res = new RouteSegmentResult(segment.road, parentSegmentStart, segment.getSegmentStart());
|
||||
parentSegmentStart = segment.getParentSegmentEnd();
|
||||
segment = segment.getParentRoute();
|
||||
if (res.getStartPointIndex() != res.getEndPointIndex()) {
|
||||
result.add(res);
|
||||
}
|
||||
}
|
||||
// reverse it just to attach good direction roads
|
||||
Collections.reverse(result);
|
||||
|
||||
segment = finalSegment.reverseWaySearch ? finalSegment.opposite.getParentRoute() : finalSegment;
|
||||
int parentSegmentEnd = finalSegment.reverseWaySearch ? finalSegment.opposite.getParentSegmentEnd() : finalSegment.opposite.getSegmentStart();
|
||||
|
||||
if(segment != null) {
|
||||
// println(segment.road +" 2->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart);
|
||||
}
|
||||
while (segment != null) {
|
||||
RouteSegmentResult res = new RouteSegmentResult(segment.road, segment.getSegmentStart(), parentSegmentEnd);
|
||||
parentSegmentEnd = segment.getParentSegmentEnd();
|
||||
segment = segment.getParentRoute();
|
||||
// happens in smart recalculation
|
||||
if (res.getStartPointIndex() != res.getEndPointIndex()) {
|
||||
result.add(res);
|
||||
}
|
||||
}
|
||||
Collections.reverse(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// calculate time
|
||||
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();
|
||||
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 split = false;
|
||||
// split if needed
|
||||
for (RouteSegmentResult rs : attachedRoutes) {
|
||||
double diff = MapUtils.degreesDiff(before + 180, rs.getBearingBegin());
|
||||
if (Math.abs(diff) <= TURN_DEGREE_MIN) {
|
||||
split = true;
|
||||
} else if (!straight && Math.abs(diff) < 100) {
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
if (split) {
|
||||
int endPointIndex = rr.getEndPointIndex();
|
||||
RouteSegmentResult splitted = new RouteSegmentResult(rr.getObject(), next, endPointIndex);
|
||||
rr.setSegmentTime((float) distOnRoadToPass);
|
||||
rr.setSegmentSpeed((float) speed);
|
||||
rr.setDistance((float) distance);
|
||||
rr.setEndPointIndex(next);
|
||||
|
||||
result.add(i + 1, splitted);
|
||||
// switch current segment to the splitted
|
||||
rr = splitted;
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
addTurnInfo(leftside, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void printResults(RoutingContext ctx, RouteSegment start, RouteSegment end, List<RouteSegmentResult> result) {
|
||||
float completeTime = 0;
|
||||
float completeDistance = 0;
|
||||
for(RouteSegmentResult r : result) {
|
||||
completeTime += r.getSegmentTime();
|
||||
completeDistance += r.getDistance();
|
||||
}
|
||||
|
||||
println("ROUTE : ");
|
||||
double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.getSegmentStart()));
|
||||
double startLon = MapUtils.get31LongitudeX(start.road.getPoint31XTile(start.getSegmentStart()));
|
||||
double endLat = MapUtils.get31LatitudeY(end.road.getPoint31YTile(end.getSegmentStart()));
|
||||
double endLon = MapUtils.get31LongitudeX(end.road.getPoint31XTile(end.getSegmentStart()));
|
||||
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.getObject().getMaximumSpeed();
|
||||
// if(ms > 0) {
|
||||
// additional.append("maxspeed = \"").append(ms * 3.6f).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 void addTurnInfo(boolean leftside, List<RouteSegmentResult> result) {
|
||||
int prevSegment = -1;
|
||||
float dist = 0;
|
||||
int next = 1;
|
||||
for (int i = 0; i <= result.size(); i = next) {
|
||||
TurnType t = null;
|
||||
next = i + 1;
|
||||
if (i < result.size()) {
|
||||
t = getTurnInfo(result, i, leftside);
|
||||
// justify turn
|
||||
if(t != null && i < result.size() - 1) {
|
||||
boolean tl = TurnType.TL.equals(t.getValue());
|
||||
boolean tr = TurnType.TR.equals(t.getValue());
|
||||
if(tl || tr) {
|
||||
TurnType tnext = getTurnInfo(result, i + 1, leftside);
|
||||
if(tnext != null && result.get(i).getDistance() < 35) {
|
||||
if(tl && TurnType.TL.equals(tnext.getValue()) ) {
|
||||
next = i + 2;
|
||||
t = TurnType.valueOf(TurnType.TU, false);
|
||||
} else if(tr && TurnType.TR.equals(tnext.getValue()) ) {
|
||||
next = i + 2;
|
||||
t = TurnType.valueOf(TurnType.TU, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.get(i).setTurnType(t);
|
||||
}
|
||||
if (t != null || i == result.size()) {
|
||||
if (prevSegment >= 0) {
|
||||
String turn = result.get(prevSegment).getTurnType().toString();
|
||||
if (result.get(prevSegment).getTurnType().getLanes() != null) {
|
||||
turn += Arrays.toString(result.get(prevSegment).getTurnType().getLanes());
|
||||
}
|
||||
result.get(prevSegment).setDescription(turn + String.format(" and go %.2f meters", dist));
|
||||
if(result.get(prevSegment).getTurnType().isSkipToSpeak()) {
|
||||
result.get(prevSegment).setDescription(result.get(prevSegment).getDescription() +" (*)");
|
||||
}
|
||||
}
|
||||
prevSegment = i;
|
||||
dist = 0;
|
||||
}
|
||||
if (i < result.size()) {
|
||||
dist += result.get(i).getDistance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_SPEAK_PRIORITY = 5;
|
||||
private int highwaySpeakPriority(String highway) {
|
||||
if(highway == null || highway.endsWith("track") || highway.endsWith("services") || highway.endsWith("service")
|
||||
|| highway.endsWith("path")) {
|
||||
return MAX_SPEAK_PRIORITY;
|
||||
}
|
||||
if (highway.endsWith("_link") || highway.endsWith("unclassified") || highway.endsWith("road")
|
||||
|| highway.endsWith("living_street") || highway.endsWith("residential") ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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 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 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 long getPoint(RouteDataObject road, int pointInd) {
|
||||
return (((long) road.getPoint31XTile(pointInd)) << 31) + (long) road.getPoint31YTile(pointInd);
|
||||
}
|
||||
|
||||
|
||||
private void attachRoadSegments(RoutingContext ctx, List<RouteSegmentResult> result, int routeInd, int pointInd, boolean plus) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
RouteSegment routeSegment = ctx.loadRouteSegment(road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd), ctx.config.memoryLimitation);
|
||||
// try to attach all segments except with current id
|
||||
while (routeSegment != null) {
|
||||
if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) {
|
||||
RouteDataObject addRoad = routeSegment.road;
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
routeSegment = routeSegment.next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*public */static int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
|
||||
double o2DistanceFromStart, double o2DistanceToEnd, double heuristicCoefficient ) {
|
||||
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
|
||||
|
@ -1369,7 +882,7 @@ public class BinaryRoutePlanner {
|
|||
|
||||
}
|
||||
|
||||
private class FinalRouteSegment extends RouteSegment {
|
||||
class FinalRouteSegment extends RouteSegment {
|
||||
|
||||
boolean reverseWaySearch;
|
||||
RouteSegment opposite;
|
||||
|
|
|
@ -159,8 +159,6 @@ public class RouteResultPreparation {
|
|||
} else if (toAdd.getEndPointIndex() == previous.getStartPointIndex() && reverse) {
|
||||
previous.setStartPointIndex(toAdd.getStartPointIndex());
|
||||
return true;
|
||||
} else {
|
||||
throw new IllegalStateException("Roads could not be combined");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -11,9 +11,9 @@ import net.osmand.osm.MapUtils;
|
|||
|
||||
public class RouteSegmentResult {
|
||||
private final RouteDataObject object;
|
||||
private final int startPointIndex;
|
||||
private int startPointIndex;
|
||||
private int endPointIndex;
|
||||
private final List<RouteSegmentResult>[] attachedRoutes;
|
||||
private List<RouteSegmentResult>[] attachedRoutes;
|
||||
private float segmentTime;
|
||||
private float speed;
|
||||
private float distance;
|
||||
|
@ -21,11 +21,16 @@ public class RouteSegmentResult {
|
|||
// this make not possible to make turns in between segment result for now
|
||||
private TurnType turnType;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
public RouteSegmentResult(RouteDataObject object, int startPointIndex, int endPointIndex) {
|
||||
this.object = object;
|
||||
this.startPointIndex = startPointIndex;
|
||||
this.endPointIndex = endPointIndex;
|
||||
updateCapacity();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void updateCapacity() {
|
||||
int capacity = Math.abs(endPointIndex - startPointIndex) + 1;
|
||||
this.attachedRoutes = new List[capacity];
|
||||
}
|
||||
|
@ -109,6 +114,12 @@ public class RouteSegmentResult {
|
|||
|
||||
public void setEndPointIndex(int endPointIndex) {
|
||||
this.endPointIndex = endPointIndex;
|
||||
updateCapacity();
|
||||
}
|
||||
|
||||
public void setStartPointIndex(int startPointIndex) {
|
||||
this.startPointIndex = startPointIndex;
|
||||
updateCapacity();
|
||||
}
|
||||
|
||||
public float getSegmentSpeed() {
|
||||
|
|
Loading…
Reference in a new issue