Add support for polygon routing

This commit is contained in:
Victor Shcherb 2018-07-31 21:41:38 +02:00
parent 9f67d84440
commit ac3163c64c
4 changed files with 130 additions and 3 deletions

View file

@ -68,7 +68,8 @@ public class GeneralRouter implements VehicleRouter {
ROUTING_OBSTACLES("obstacle"),
ONEWAY("oneway"),
PENALTY_TRANSITION("penalty_transition"),
OBSTACLE_SRTM_ALT_SPEED("obstacle_srtm_alt_speed");
OBSTACLE_SRTM_ALT_SPEED("obstacle_srtm_alt_speed"),
AREA("area");
public final String nm;
RouteDataObjectAttribute(String name) {
nm = name;
@ -344,6 +345,11 @@ public class GeneralRouter implements VehicleRouter {
return getObjContext(RouteDataObjectAttribute.ONEWAY).evaluateInt(road, 0);
}
@Override
public boolean isArea(RouteDataObject road) {
return getObjContext(RouteDataObjectAttribute.AREA).evaluateInt(road, 0) == 1;
}
@Override
public float getPenaltyTransition(RouteDataObject road) {
return getObjContext(RouteDataObjectAttribute.PENALTY_TRANSITION).evaluateInt(road, 0);

View file

@ -24,6 +24,7 @@ import net.osmand.router.BinaryRoutePlanner.RouteSegment;
import net.osmand.router.GeneralRouter.GeneralRouterProfile;
import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode;
import net.osmand.util.Algorithms;
import net.osmand.util.MapAlgorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
@ -40,9 +41,121 @@ public class RouteResultPreparation {
*/
List<RouteSegmentResult> prepareResult(RoutingContext ctx, FinalRouteSegment finalSegment) throws IOException {
List<RouteSegmentResult> result = convertFinalSegmentToResults(ctx, finalSegment);
combineWayPointsForAreaRouting(ctx, result);
prepareResult(ctx, result);
return result;
}
private static class CombineAreaRoutePoint {
int x31;
int y31;
int originalIndex;
}
private void combineWayPointsForAreaRouting(RoutingContext ctx, List<RouteSegmentResult> result) {
for(int i = 0; i < result.size(); i++) {
RouteSegmentResult rsr = result.get(i);
RouteDataObject obj = rsr.getObject();
boolean area = false;
if(obj.getPoint31XTile(0) == obj.getPoint31XTile(obj.getPointsLength() - 1) &&
obj.getPoint31YTile(0) == obj.getPoint31YTile(obj.getPointsLength() - 1)) {
area = true;
}
if(!area || !ctx.getRouter().isArea(obj)) {
continue;
}
List<CombineAreaRoutePoint> originalWay = new ArrayList<CombineAreaRoutePoint>();
List<CombineAreaRoutePoint> routeWay = new ArrayList<CombineAreaRoutePoint>();
for(int j = 0; j < obj.getPointsLength(); j++) {
CombineAreaRoutePoint pnt = new CombineAreaRoutePoint();
pnt.x31 = obj.getPoint31XTile(j);
pnt.y31 = obj.getPoint31YTile(j);
pnt.originalIndex = j;
originalWay.add(pnt);
if(j >= rsr.getStartPointIndex() && j <= rsr.getEndPointIndex()) {
routeWay.add(pnt);
} else if(j <= rsr.getStartPointIndex() && j >= rsr.getEndPointIndex()) {
routeWay.add(0, pnt);
}
}
int originalSize = routeWay.size();
simplifyAreaRouteWay(routeWay, originalWay);
int newsize = routeWay.size();
if (routeWay.size() != originalSize) {
RouteDataObject nobj = new RouteDataObject(obj);
nobj.pointsX = new int[newsize];
nobj.pointsY = new int[newsize];
for (int k = 0; k < newsize; k++) {
nobj.pointsX[k] = routeWay.get(k).x31;
nobj.pointsY[k] = routeWay.get(k).y31;
}
// in future point names might be used
nobj.restrictions = null;
nobj.restrictionsVia = null;
nobj.pointTypes = null;
nobj.pointNames = null;
nobj.pointNameTypes = null;
RouteSegmentResult nrsr = new RouteSegmentResult(nobj, 0, newsize - 1);
result.set(i, nrsr);
}
}
}
private void simplifyAreaRouteWay(List<CombineAreaRoutePoint> routeWay, List<CombineAreaRoutePoint> originalWay) {
boolean changed = true;
while (changed) {
changed = false;
int connectStart = -1;
int connectLen = 0;
double dist = 0;
int length = routeWay.size() - 1;
while (length > 0 && connectLen == 0) {
for (int i = 0; i < routeWay.size() - length; i++) {
CombineAreaRoutePoint p = routeWay.get(i);
CombineAreaRoutePoint n = routeWay.get(i + length);
if (segmentLineBelongsToPolygon(p, n, originalWay)) {
double ndist = BinaryRoutePlanner.squareRootDist(p.x31, p.y31, n.x31, n.y31);
if (ndist > dist) {
ndist = dist;
connectStart = i;
connectLen = length;
}
}
}
length--;
}
while (connectLen > 1) {
routeWay.remove(connectStart + 1);
connectLen--;
changed = true;
}
}
}
private boolean segmentLineBelongsToPolygon(CombineAreaRoutePoint p, CombineAreaRoutePoint n,
List<CombineAreaRoutePoint> originalWay) {
int intersections = 0;
int mx = p.x31 / 2 + n.x31 / 2;
int my = p.y31 / 2 + n.y31 / 2;
for(int i = 1; i < originalWay.size(); i++) {
CombineAreaRoutePoint p2 = originalWay.get(i -1);
CombineAreaRoutePoint n2 = originalWay.get(i);
if(p.originalIndex != i && p.originalIndex != i - 1) {
if(n.originalIndex != i && n.originalIndex != i - 1) {
if(MapAlgorithms.linesIntersect(p.x31, p.y31, n.x31, n.y31, p2.x31, p2.y31, n2.x31, n2.y31)) {
return false;
}
}
}
int fx = MapAlgorithms.ray_intersect_x(p2.x31, p2.y31, n2.x31, n2.y31, my);
if (Integer.MIN_VALUE != fx && mx >= fx) {
intersections++;
}
}
return intersections % 2 == 1;
}
List<RouteSegmentResult> prepareResult(RoutingContext ctx, List<RouteSegmentResult> result) throws IOException {
validateAllPointsConnected(result);

View file

@ -76,6 +76,12 @@ public interface VehicleRouter {
*/
public boolean restrictionsAware();
/**
* @param obj
* @return if road supports area routing
*/
public boolean isArea(RouteDataObject obj);
/**
* Calculate turn time
*/
@ -85,5 +91,7 @@ public interface VehicleRouter {
public VehicleRouter build(Map<String, String> params);
}

View file

@ -291,8 +291,8 @@ public class MapAlgorithms {
return true;
}
public static boolean containsPoint(Collection<Node> polyNodes, double latitude, double longitude){
return countIntersections(polyNodes, latitude, longitude) % 2 == 1;
public static boolean containsPoint(Collection<Node> polyNodes, double latitude, double longitude) {
return countIntersections(polyNodes, latitude, longitude) % 2 == 1;
}
/**