diff --git a/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java b/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java index 694493c8d8..08e5ea8251 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/GeneralRouter.java @@ -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); diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RouteResultPreparation.java b/OsmAnd-java/src/main/java/net/osmand/router/RouteResultPreparation.java index 1b2849912f..ee618358fc 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RouteResultPreparation.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RouteResultPreparation.java @@ -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 prepareResult(RoutingContext ctx, FinalRouteSegment finalSegment) throws IOException { List 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 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 originalWay = new ArrayList(); + List routeWay = new ArrayList(); + 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 routeWay, List 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 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 prepareResult(RoutingContext ctx, List result) throws IOException { validateAllPointsConnected(result); diff --git a/OsmAnd-java/src/main/java/net/osmand/router/VehicleRouter.java b/OsmAnd-java/src/main/java/net/osmand/router/VehicleRouter.java index c49ac1a6b8..c2b5f5f970 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/VehicleRouter.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/VehicleRouter.java @@ -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 params); + + } \ No newline at end of file diff --git a/OsmAnd-java/src/main/java/net/osmand/util/MapAlgorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/MapAlgorithms.java index 7efce5145d..fbb0ec4ec0 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/MapAlgorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/MapAlgorithms.java @@ -291,8 +291,8 @@ public class MapAlgorithms { return true; } - public static boolean containsPoint(Collection polyNodes, double latitude, double longitude){ - return countIntersections(polyNodes, latitude, longitude) % 2 == 1; + public static boolean containsPoint(Collection polyNodes, double latitude, double longitude) { + return countIntersections(polyNodes, latitude, longitude) % 2 == 1; } /**