Merge branch 'master' of ssh://github.com/osmandapp/Osmand
|
@ -18,6 +18,7 @@ public class RenderingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int renderedState = 0;
|
||||||
// FIELDS OF THAT CLASS ARE USED IN C++
|
// FIELDS OF THAT CLASS ARE USED IN C++
|
||||||
public boolean interrupted = false;
|
public boolean interrupted = false;
|
||||||
public boolean nightMode = false;
|
public boolean nightMode = false;
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class BinaryMapDataObject {
|
||||||
this.coordinates = coordinates;
|
this.coordinates = coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getName(){
|
public String getName(){
|
||||||
if(objectNames == null){
|
if(objectNames == null){
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -1541,6 +1541,10 @@ public class BinaryMapIndexReader {
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getZoom() {
|
||||||
|
return zoom;
|
||||||
|
}
|
||||||
|
|
||||||
public void clearSearchResults(){
|
public void clearSearchResults(){
|
||||||
// recreate whole list to allow GC collect old data
|
// recreate whole list to allow GC collect old data
|
||||||
searchResults = new ArrayList<T>();
|
searchResults = new ArrayList<T>();
|
||||||
|
@ -1598,6 +1602,10 @@ public class BinaryMapIndexReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRegisteredRule(int id) {
|
||||||
|
return decodingRules.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
public void initMapEncodingRule(int type, int id, String tag, String val) {
|
public void initMapEncodingRule(int type, int id, String tag, String val) {
|
||||||
if(!encodingRules.containsKey(tag)){
|
if(!encodingRules.containsKey(tag)){
|
||||||
encodingRules.put(tag, new HashMap<String, Integer>());
|
encodingRules.put(tag, new HashMap<String, Integer>());
|
||||||
|
@ -2070,7 +2078,7 @@ public class BinaryMapIndexReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<RouteSubregion> searchRouteIndexTree(SearchRequest<RouteDataObject> req, List<RouteSubregion> list) throws IOException {
|
public List<RouteSubregion> searchRouteIndexTree(SearchRequest<?> req, List<RouteSubregion> list) throws IOException {
|
||||||
req.numberOfVisitedObjects = 0;
|
req.numberOfVisitedObjects = 0;
|
||||||
req.numberOfAcceptedObjects = 0;
|
req.numberOfAcceptedObjects = 0;
|
||||||
req.numberOfAcceptedSubtrees = 0;
|
req.numberOfAcceptedSubtrees = 0;
|
||||||
|
|
|
@ -674,7 +674,7 @@ public class BinaryMapRouteReaderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initRouteTypesIfNeeded(SearchRequest<RouteDataObject> req, List<RouteSubregion> list) throws IOException {
|
public void initRouteTypesIfNeeded(SearchRequest<?> req, List<RouteSubregion> list) throws IOException {
|
||||||
for (RouteSubregion rs : list) {
|
for (RouteSubregion rs : list) {
|
||||||
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
||||||
initRouteRegion(rs.routeReg);
|
initRouteRegion(rs.routeReg);
|
||||||
|
@ -736,7 +736,7 @@ public class BinaryMapRouteReaderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RouteSubregion> searchRouteRegionTree(SearchRequest<RouteDataObject> req, List<RouteSubregion> list,
|
public List<RouteSubregion> searchRouteRegionTree(SearchRequest<?> req, List<RouteSubregion> list,
|
||||||
List<RouteSubregion> toLoad) throws IOException {
|
List<RouteSubregion> toLoad) throws IOException {
|
||||||
for (RouteSubregion rs : list) {
|
for (RouteSubregion rs : list) {
|
||||||
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
||||||
|
|
|
@ -61,6 +61,10 @@ public class RouteDataObject {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TIntObjectHashMap<String> getNames() {
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRef(){
|
public String getRef(){
|
||||||
if(names != null ) {
|
if(names != null ) {
|
||||||
return names.get(region.refTypeRule);
|
return names.get(region.refTypeRule);
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class BinaryRoutePlanner {
|
||||||
graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD;
|
graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD;
|
||||||
|
|
||||||
if(TRACE_ROUTING){
|
if(TRACE_ROUTING){
|
||||||
printRoad(">", segment);
|
printRoad(">", segment, !forwardSearch);
|
||||||
}
|
}
|
||||||
if(segment instanceof FinalRouteSegment) {
|
if(segment instanceof FinalRouteSegment) {
|
||||||
if(RoutingContext.SHOW_GC_SIZE){
|
if(RoutingContext.SHOW_GC_SIZE){
|
||||||
|
@ -136,9 +136,9 @@ public class BinaryRoutePlanner {
|
||||||
}
|
}
|
||||||
if (ctx.planRouteIn2Directions()) {
|
if (ctx.planRouteIn2Directions()) {
|
||||||
forwardSearch = (nonHeuristicSegmentsComparator.compare(graphDirectSegments.peek(), graphReverseSegments.peek()) < 0);
|
forwardSearch = (nonHeuristicSegmentsComparator.compare(graphDirectSegments.peek(), graphReverseSegments.peek()) < 0);
|
||||||
if (graphDirectSegments.size() * 1.3 > graphReverseSegments.size()) {
|
if (graphDirectSegments.size() * 2 > graphReverseSegments.size()) {
|
||||||
forwardSearch = false;
|
forwardSearch = false;
|
||||||
} else if (graphDirectSegments.size() < 1.3 * graphReverseSegments.size()) {
|
} else if (graphDirectSegments.size() < 2 * graphReverseSegments.size()) {
|
||||||
forwardSearch = true;
|
forwardSearch = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,14 +236,18 @@ public class BinaryRoutePlanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void printRoad(String prefix, RouteSegment segment) {
|
private void printRoad(String prefix, RouteSegment segment, Boolean reverseWaySearch) {
|
||||||
String pr;
|
String pr;
|
||||||
if(segment.parentRoute != null){
|
if(segment.parentRoute != null){
|
||||||
pr = " pend="+segment.parentSegmentEnd +" parent=" + segment.parentRoute.road;
|
pr = " pend="+segment.parentSegmentEnd +" parent=" + segment.parentRoute.road;
|
||||||
} else {
|
} else {
|
||||||
pr = "";
|
pr = "";
|
||||||
}
|
}
|
||||||
println(prefix +"" + segment.road + " dir="+segment.getDirectionAssigned()+" ind=" + segment.getSegmentStart() +
|
String p = "";
|
||||||
|
if(reverseWaySearch != null) {
|
||||||
|
p = (reverseWaySearch?"B" : "F");
|
||||||
|
}
|
||||||
|
println(p+prefix +"" + segment.road + " dir="+segment.getDirectionAssigned()+" ind=" + segment.getSegmentStart() +
|
||||||
" ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
|
" ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +308,7 @@ public class BinaryRoutePlanner {
|
||||||
final RouteDataObject road = segment.road;
|
final RouteDataObject road = segment.road;
|
||||||
boolean initDirectionAllowed = checkIfInitialMovementAllowedOnSegment(ctx, reverseWaySearch, visitedSegments, segment, road);
|
boolean initDirectionAllowed = checkIfInitialMovementAllowedOnSegment(ctx, reverseWaySearch, visitedSegments, segment, road);
|
||||||
if(TEST_SPECIFIC && road.getId() == TEST_ID ) {
|
if(TEST_SPECIFIC && road.getId() == TEST_ID ) {
|
||||||
printRoad(" ! " + +segment.distanceFromStart + " ", segment);
|
printRoad(" ! " + +segment.distanceFromStart + " ", segment, reverseWaySearch);
|
||||||
}
|
}
|
||||||
boolean directionAllowed = initDirectionAllowed;
|
boolean directionAllowed = initDirectionAllowed;
|
||||||
if(!directionAllowed) {
|
if(!directionAllowed) {
|
||||||
|
@ -367,15 +371,23 @@ public class BinaryRoutePlanner {
|
||||||
// long nt = System.nanoTime();
|
// long nt = System.nanoTime();
|
||||||
// float devDistance = ctx.precalculatedRouteDirection.getDeviationDistance(x, y);
|
// float devDistance = ctx.precalculatedRouteDirection.getDeviationDistance(x, y);
|
||||||
// // 1. linear method
|
// // 1. linear method
|
||||||
// // segmentDist = segmentDist * (1 + ctx.precalculatedRouteDirection.getDeviationDistance(x, y) / ctx.config.DEVIATION_RADIUS);
|
// segmentDist = segmentDist * (1 + devDistance / ctx.config.DEVIATION_RADIUS);
|
||||||
// // 2. exponential method
|
// // 2. exponential method
|
||||||
// segmentDist = segmentDist * (float) Math.pow(1.5, devDistance / 500);
|
// segmentDist = segmentDist * (float) Math.pow(1.5, devDistance / 500);
|
||||||
|
// 3. next by method
|
||||||
|
// segmentDist = devDistance ;
|
||||||
// ctx.timeNanoToCalcDeviation += (System.nanoTime() - nt);
|
// ctx.timeNanoToCalcDeviation += (System.nanoTime() - nt);
|
||||||
}
|
}
|
||||||
// could be expensive calculation
|
// could be expensive calculation
|
||||||
// 3. get intersected ways
|
// 3. get intersected ways
|
||||||
final RouteSegment roadNext = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
|
final RouteSegment roadNext = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
|
||||||
float distStartObstacles = segment.distanceFromStart + calculateTimeWithObstacles(ctx, road, segmentDist , obstaclesTime);
|
float distStartObstacles = segment.distanceFromStart + calculateTimeWithObstacles(ctx, road, segmentDist , obstaclesTime);
|
||||||
|
if(ctx.precalculatedRouteDirection != null && ctx.precalculatedRouteDirection.isFollowNext()) {
|
||||||
|
// reset to f
|
||||||
|
// distStartObstacles = 0;
|
||||||
|
// more precise but slower
|
||||||
|
distStartObstacles = ctx.precalculatedRouteDirection.getDeviationDistance(x, y) / ctx.getRouter().getMaxDefaultSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
// We don't check if there are outgoing connections
|
// We don't check if there are outgoing connections
|
||||||
previous = processIntersections(ctx, graphSegments, visitedSegments, distStartObstacles,
|
previous = processIntersections(ctx, graphSegments, visitedSegments, distStartObstacles,
|
||||||
|
@ -433,7 +445,7 @@ public class BinaryRoutePlanner {
|
||||||
frs.opposite = opposite;
|
frs.opposite = opposite;
|
||||||
graphSegments.add(frs);
|
graphSegments.add(frs);
|
||||||
if(TRACE_ROUTING){
|
if(TRACE_ROUTING){
|
||||||
printRoad(" >> Final segment : ", frs);
|
printRoad(" >> Final segment : ", frs, reverseWaySearch);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -553,7 +565,7 @@ public class BinaryRoutePlanner {
|
||||||
|
|
||||||
|
|
||||||
private RouteSegment processIntersections(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments,
|
private RouteSegment processIntersections(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments,
|
||||||
TLongObjectHashMap<RouteSegment> visitedSegments, float distFromStart, RouteSegment segment,
|
TLongObjectHashMap<RouteSegment> visitedSegments, float distFromStart, RouteSegment segment,
|
||||||
short segmentPoint, RouteSegment inputNext, boolean reverseWaySearch, boolean doNotAddIntersections,
|
short segmentPoint, RouteSegment inputNext, boolean reverseWaySearch, boolean doNotAddIntersections,
|
||||||
boolean[] processFurther) {
|
boolean[] processFurther) {
|
||||||
boolean thereAreRestrictions ;
|
boolean thereAreRestrictions ;
|
||||||
|
@ -634,7 +646,7 @@ public class BinaryRoutePlanner {
|
||||||
printRoad(" !? distFromStart=" + +distFromStart + " from " + segment.getRoad().getId() +
|
printRoad(" !? distFromStart=" + +distFromStart + " from " + segment.getRoad().getId() +
|
||||||
" dir=" + segment.getDirectionAssigned() +
|
" dir=" + segment.getDirectionAssigned() +
|
||||||
" distToEnd=" + distanceToEnd +
|
" distToEnd=" + distanceToEnd +
|
||||||
" segmentPoint="+ segmentPoint + " -- ", next);
|
" segmentPoint="+ segmentPoint + " -- ", next, true);
|
||||||
}
|
}
|
||||||
if (!visitedSegments.containsKey(calculateRoutePointId(next, next.isPositive()))) {
|
if (!visitedSegments.containsKey(calculateRoutePointId(next, next.isPositive()))) {
|
||||||
if (next.getParentRoute() == null
|
if (next.getParentRoute() == null
|
||||||
|
@ -643,7 +655,7 @@ public class BinaryRoutePlanner {
|
||||||
next.distanceFromStart = distFromStart;
|
next.distanceFromStart = distFromStart;
|
||||||
next.distanceToEnd = distanceToEnd;
|
next.distanceToEnd = distanceToEnd;
|
||||||
if (TRACE_ROUTING) {
|
if (TRACE_ROUTING) {
|
||||||
printRoad(" >>", next);
|
printRoad(" >>", next, null);
|
||||||
}
|
}
|
||||||
// put additional information to recover whole route after
|
// put additional information to recover whole route after
|
||||||
next.setParentRoute(segment);
|
next.setParentRoute(segment);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.QuadPoint;
|
import net.osmand.data.QuadPoint;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.QuadTree;
|
import net.osmand.data.QuadTree;
|
||||||
|
@ -18,6 +19,7 @@ public class PrecalculatedRouteDirection {
|
||||||
private float minSpeed;
|
private float minSpeed;
|
||||||
private float maxSpeed;
|
private float maxSpeed;
|
||||||
private float[] tms;
|
private float[] tms;
|
||||||
|
private boolean followNext;
|
||||||
private static final int SHIFT = (1 << (31 - 17));
|
private static final int SHIFT = (1 << (31 - 17));
|
||||||
private static final int[] SHIFTS = new int[]{1 << (31 - 15), 1 << (31 - 13), 1 << (31 - 12),
|
private static final int[] SHIFTS = new int[]{1 << (31 - 15), 1 << (31 - 13), 1 << (31 - 12),
|
||||||
1 << (31 - 11), 1 << (31 - 7)};
|
1 << (31 - 11), 1 << (31 - 7)};
|
||||||
|
@ -42,6 +44,11 @@ public class PrecalculatedRouteDirection {
|
||||||
init(ls);
|
init(ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PrecalculatedRouteDirection(LatLon[] ls, float maxSpeed) {
|
||||||
|
this.maxSpeed = maxSpeed;
|
||||||
|
init(ls);
|
||||||
|
}
|
||||||
|
|
||||||
private PrecalculatedRouteDirection(PrecalculatedRouteDirection parent, int s1, int s2) {
|
private PrecalculatedRouteDirection(PrecalculatedRouteDirection parent, int s1, int s2) {
|
||||||
this.minSpeed = parent.minSpeed;
|
this.minSpeed = parent.minSpeed;
|
||||||
this.maxSpeed = parent.maxSpeed;
|
this.maxSpeed = parent.maxSpeed;
|
||||||
|
@ -81,6 +88,10 @@ public class PrecalculatedRouteDirection {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PrecalculatedRouteDirection build(LatLon[] ls, float maxSpeed){
|
||||||
|
return new PrecalculatedRouteDirection(ls, maxSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void init(List<RouteSegmentResult> ls) {
|
private void init(List<RouteSegmentResult> ls) {
|
||||||
TIntArrayList px = new TIntArrayList();
|
TIntArrayList px = new TIntArrayList();
|
||||||
|
@ -105,6 +116,19 @@ public class PrecalculatedRouteDirection {
|
||||||
init(px, py, speedSegments);
|
init(px, py, speedSegments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void init(LatLon[] ls) {
|
||||||
|
TIntArrayList px = new TIntArrayList();
|
||||||
|
TIntArrayList py = new TIntArrayList();
|
||||||
|
List<Float> speedSegments = new ArrayList<Float>();
|
||||||
|
for (LatLon s : ls) {
|
||||||
|
float routeSpd = maxSpeed; // (s.getDistance() / s.getRoutingTime())
|
||||||
|
px.add(MapUtils.get31TileNumberX(s.getLongitude()));
|
||||||
|
py.add(MapUtils.get31TileNumberY(s.getLatitude()));
|
||||||
|
speedSegments.add(routeSpd);
|
||||||
|
}
|
||||||
|
init(px, py, speedSegments);
|
||||||
|
}
|
||||||
|
|
||||||
private void init(TIntArrayList px, TIntArrayList py, List<Float> speedSegments) {
|
private void init(TIntArrayList px, TIntArrayList py, List<Float> speedSegments) {
|
||||||
float totaltm = 0;
|
float totaltm = 0;
|
||||||
List<Float> times = new ArrayList<Float>();
|
List<Float> times = new ArrayList<Float>();
|
||||||
|
@ -217,6 +241,15 @@ public class PrecalculatedRouteDirection {
|
||||||
return ((long) x31) << 32l + ((long)y31);
|
return ((long) x31) << 32l + ((long)y31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFollowNext(boolean followNext) {
|
||||||
|
this.followNext = followNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFollowNext() {
|
||||||
|
return followNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public PrecalculatedRouteDirection adopt(RoutingContext ctx) {
|
public PrecalculatedRouteDirection adopt(RoutingContext ctx) {
|
||||||
int ind1 = getIndex(ctx.startX, ctx.startY);
|
int ind1 = getIndex(ctx.startX, ctx.startY);
|
||||||
int ind2 = getIndex(ctx.targetX, ctx.targetY);
|
int ind2 = getIndex(ctx.targetX, ctx.targetY);
|
||||||
|
@ -235,6 +268,7 @@ public class PrecalculatedRouteDirection {
|
||||||
// routeDirection.startY31 = ctx.startY;
|
// routeDirection.startY31 = ctx.startY;
|
||||||
routeDirection.endPoint = calc(ctx.targetX, ctx.targetX);
|
routeDirection.endPoint = calc(ctx.targetX, ctx.targetX);
|
||||||
routeDirection.endFinishTime = (float) BinaryRoutePlanner.squareRootDist(pointsX[ind2], pointsY[ind2], ctx.targetX, ctx.targetY) / maxSpeed;
|
routeDirection.endFinishTime = (float) BinaryRoutePlanner.squareRootDist(pointsX[ind2], pointsY[ind2], ctx.targetX, ctx.targetY) / maxSpeed;
|
||||||
|
routeDirection.followNext = followNext;
|
||||||
|
|
||||||
// routeDirection.endX31 = ctx.targetX;
|
// routeDirection.endX31 = ctx.targetX;
|
||||||
// routeDirection.endY31 = ctx.targetY;
|
// routeDirection.endY31 = ctx.targetY;
|
||||||
|
|
|
@ -84,13 +84,17 @@ public class RoutePlannerFrontEnd {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates) throws IOException, InterruptedException {
|
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates) throws IOException, InterruptedException {
|
||||||
|
return searchRoute(ctx, start, end, intermediates, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates,
|
||||||
|
PrecalculatedRouteDirection routeDirection) throws IOException, InterruptedException {
|
||||||
if(ctx.calculationProgress == null) {
|
if(ctx.calculationProgress == null) {
|
||||||
ctx.calculationProgress = new RouteCalculationProgress();
|
ctx.calculationProgress = new RouteCalculationProgress();
|
||||||
}
|
}
|
||||||
boolean intermediatesEmpty = intermediates == null || intermediates.isEmpty();
|
boolean intermediatesEmpty = intermediates == null || intermediates.isEmpty();
|
||||||
PrecalculatedRouteDirection routeDirection = null;
|
|
||||||
double maxDistance = MapUtils.getDistance(start, end);
|
double maxDistance = MapUtils.getDistance(start, end);
|
||||||
if(!intermediatesEmpty) {
|
if(!intermediatesEmpty) {
|
||||||
LatLon b = start;
|
LatLon b = start;
|
||||||
|
@ -99,7 +103,8 @@ public class RoutePlannerFrontEnd {
|
||||||
b = l;
|
b = l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ctx.calculationMode == RouteCalculationMode.COMPLEX && maxDistance > Math.max(ctx.config.DEVIATION_RADIUS * 4, 30000)) {
|
if(ctx.calculationMode == RouteCalculationMode.COMPLEX && routeDirection == null
|
||||||
|
&& maxDistance > Math.max(ctx.config.DEVIATION_RADIUS * 4, 30000)) {
|
||||||
RoutingContext nctx = buildRoutingContext(ctx.config, ctx.nativeLib, ctx.getMaps(), RouteCalculationMode.BASE);
|
RoutingContext nctx = buildRoutingContext(ctx.config, ctx.nativeLib, ctx.getMaps(), RouteCalculationMode.BASE);
|
||||||
nctx.calculationProgress = ctx.calculationProgress ;
|
nctx.calculationProgress = ctx.calculationProgress ;
|
||||||
List<RouteSegmentResult> ls = searchRoute(nctx, start, end, intermediates);
|
List<RouteSegmentResult> ls = searchRoute(nctx, start, end, intermediates);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.osmand.binary.BinaryMapIndexReader;
|
import net.osmand.binary.BinaryMapIndexReader;
|
||||||
|
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment;
|
import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment;
|
||||||
|
@ -295,11 +296,30 @@ public class RouteResultPreparation {
|
||||||
additional.append("description = \"").append(res.getDescription()).append("\" ");
|
additional.append("description = \"").append(res.getDescription()).append("\" ");
|
||||||
println(MessageFormat.format("\t<segment id=\"{0}\" start=\"{1}\" end=\"{2}\" {3}/>", (res.getObject().getId()) + "",
|
println(MessageFormat.format("\t<segment id=\"{0}\" start=\"{1}\" end=\"{2}\" {3}/>", (res.getObject().getId()) + "",
|
||||||
res.getStartPointIndex() + "", res.getEndPointIndex() + "", additional.toString()));
|
res.getStartPointIndex() + "", res.getEndPointIndex() + "", additional.toString()));
|
||||||
|
printAdditionalPointInfo(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("</test>");
|
println("</test>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printAdditionalPointInfo(RouteSegmentResult res) {
|
||||||
|
boolean plus = res.getStartPointIndex() < res.getEndPointIndex();
|
||||||
|
for(int k = res.getStartPointIndex(); k != res.getEndPointIndex(); ) {
|
||||||
|
int[] tp = res.getObject().getPointTypes(k);
|
||||||
|
if(tp != null) {
|
||||||
|
for(int t = 0; t < tp.length; t++) {
|
||||||
|
RouteTypeRule rr = res.getObject().region.quickGetEncodingRule(tp[t]);
|
||||||
|
println("\t<point tag=\""+rr.getTag()+"\"" + " value=\""+rr.getValue()+"\"/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(plus) {
|
||||||
|
k++;
|
||||||
|
} else {
|
||||||
|
k--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void addTurnInfo(boolean leftside, List<RouteSegmentResult> result) {
|
private void addTurnInfo(boolean leftside, List<RouteSegmentResult> result) {
|
||||||
int prevSegment = -1;
|
int prevSegment = -1;
|
||||||
|
|
BIN
OsmAnd/res/drawable-hdpi/ic_action_truck_dark.png
Normal file
After Width: | Height: | Size: 859 B |
BIN
OsmAnd/res/drawable-hdpi/ic_action_truck_light.png
Normal file
After Width: | Height: | Size: 998 B |
BIN
OsmAnd/res/drawable-hdpi/ic_truck.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
OsmAnd/res/drawable-mdpi/ic_action_truck_dark.png
Normal file
After Width: | Height: | Size: 528 B |
BIN
OsmAnd/res/drawable-mdpi/ic_action_truck_light.png
Normal file
After Width: | Height: | Size: 649 B |
BIN
OsmAnd/res/drawable-mdpi/ic_truck.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
OsmAnd/res/drawable-xhdpi/ic_action_truck_dark.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAnd/res/drawable-xhdpi/ic_action_truck_light.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
OsmAnd/res/drawable-xhdpi/ic_truck.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
|
@ -9,6 +9,15 @@
|
||||||
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
|
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
|
||||||
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
|
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
|
||||||
-->
|
-->
|
||||||
|
<string name="android_19_location_disabled">Since KitKat version you can\'t download and update map in previous storage location (%s). Do you want to change to allowed one and copy all files there?
|
||||||
|
\n Note : old files will stay untouched.
|
||||||
|
\n Note : it will not be possible to share files between OsmAnd and OsmAnd+. </string>
|
||||||
|
<string name="application_dir_change_warning2">OsmAnd could try to move the data to new destination. Do you want it?</string>
|
||||||
|
<string name="copying_osmand_one_file_descr">Copying file (%s) to new destination...</string>
|
||||||
|
<string name="copying_osmand_files_descr">Copying OsmAnd files to new destination (%s)</string>
|
||||||
|
<string name="copying_osmand_files">Copying OsmAnd files</string>
|
||||||
|
<string name="calculate_osmand_route_gpx">Calculate OsmAnd offline route</string>
|
||||||
|
<string name="app_mode_truck">Truck</string>
|
||||||
<string name="guidance_preferences_descr">Navigation preferences</string>
|
<string name="guidance_preferences_descr">Navigation preferences</string>
|
||||||
<string name="routing_preferences_descr">Routing preferences</string>
|
<string name="routing_preferences_descr">Routing preferences</string>
|
||||||
<string name="speech_rate_descr">Specify speech rate for TTS</string>
|
<string name="speech_rate_descr">Specify speech rate for TTS</string>
|
||||||
|
@ -1250,7 +1259,7 @@ Afghanistan, Albania, Algeria, Andorra, Angola, Anguilla, Antigua and Barbuda, A
|
||||||
<string name="osmand_routing_experimental">OsmAnd offline navigation is an experimental feature and it does not work for distances of more than about 20 km.\n\nNavigation service is temporarily switched to online CloudMade.</string>
|
<string name="osmand_routing_experimental">OsmAnd offline navigation is an experimental feature and it does not work for distances of more than about 20 km.\n\nNavigation service is temporarily switched to online CloudMade.</string>
|
||||||
<string name="specified_dir_doesnt_exist">Can not find specified directory.</string>
|
<string name="specified_dir_doesnt_exist">Can not find specified directory.</string>
|
||||||
<string name="application_dir">Storage directory</string>
|
<string name="application_dir">Storage directory</string>
|
||||||
<string name="application_dir_change_warning">Changing the storage directory will not move or delete the data. This must be performed separately and outside OsmAnd. Continue anyway?</string>
|
|
||||||
<string name="osmand_net_previously_installed">A previous OsmAnd version is installed. All offline data will be supported by the new application. But Favorite points should be exported in the old application and later imported by the new one.</string>
|
<string name="osmand_net_previously_installed">A previous OsmAnd version is installed. All offline data will be supported by the new application. But Favorite points should be exported in the old application and later imported by the new one.</string>
|
||||||
<string name="build_installed">Build {0} successfully installed ({1}).</string>
|
<string name="build_installed">Build {0} successfully installed ({1}).</string>
|
||||||
<string name="downloading_build">Downloading build…</string>
|
<string name="downloading_build">Downloading build…</string>
|
||||||
|
|
|
@ -45,6 +45,10 @@ public class ApplicationMode {
|
||||||
carLocation().parent(CAR).
|
carLocation().parent(CAR).
|
||||||
icon(R.drawable.ic_motorcycle, R.drawable.ic_action_motorcycle_light, R.drawable.ic_action_motorcycle_dark).reg();
|
icon(R.drawable.ic_motorcycle, R.drawable.ic_action_motorcycle_light, R.drawable.ic_action_motorcycle_dark).reg();
|
||||||
|
|
||||||
|
public static final ApplicationMode TRUCK = create(R.string.app_mode_truck, "truck").speed(15.3f, 40).
|
||||||
|
carLocation().parent(CAR).
|
||||||
|
icon(R.drawable.ic_truck, R.drawable.ic_action_truck_light, R.drawable.ic_action_truck_dark).reg();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ApplicationMode[] exceptPedestrian = new ApplicationMode[] { DEFAULT, CAR, BICYCLE, BOAT, AIRCRAFT };
|
ApplicationMode[] exceptPedestrian = new ApplicationMode[] { DEFAULT, CAR, BICYCLE, BOAT, AIRCRAFT };
|
||||||
ApplicationMode[] exceptAirBoat = new ApplicationMode[] { DEFAULT, CAR, BICYCLE};
|
ApplicationMode[] exceptAirBoat = new ApplicationMode[] { DEFAULT, CAR, BICYCLE};
|
||||||
|
|
|
@ -8,8 +8,8 @@ import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.access.AccessibleToast;
|
import net.osmand.access.AccessibleToast;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.routing.RouteProvider;
|
|
||||||
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
||||||
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
|
||||||
import net.osmand.plus.routing.RoutingHelper;
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
|
@ -72,8 +72,11 @@ public class OsmAndLocationSimulation {
|
||||||
new CallbackWithObject<GPXUtilities.GPXFile>() {
|
new CallbackWithObject<GPXUtilities.GPXFile>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean processResult(GPXUtilities.GPXFile result) {
|
public boolean processResult(GPXUtilities.GPXFile result) {
|
||||||
GPXRouteParams prms = new RouteProvider.GPXRouteParams(result, false, ch
|
GPXRouteParamsBuilder builder = GPXRouteParams.GPXRouteParamsBuilder.newBuilder(result, app.getSettings());
|
||||||
.isChecked(), app.getSettings());
|
if(ch.isChecked()){
|
||||||
|
builder.announceWaypoints();
|
||||||
|
}
|
||||||
|
GPXRouteParams prms = builder.build();
|
||||||
startAnimationThread(app.getRoutingHelper(), ma, prms.getPoints(), true,
|
startAnimationThread(app.getRoutingHelper(), ma, prms.getPoints(), true,
|
||||||
speedup.getProgress() + 1);
|
speedup.getProgress() + 1);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -651,7 +651,7 @@ public class OsmandSettings {
|
||||||
|
|
||||||
public float getSettingsZoomScale(float density){
|
public float getSettingsZoomScale(float density){
|
||||||
// by default scale between [0, 1[ density (because of lots map complains)
|
// by default scale between [0, 1[ density (because of lots map complains)
|
||||||
return MAP_ZOOM_SCALE_BY_DENSITY.get() + (float)Math.min(Math.sqrt(Math.max(0, density - 1)), 1);
|
return MAP_ZOOM_SCALE_BY_DENSITY.get() + (float)Math.sqrt(Math.max(0, density - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -739,6 +739,7 @@ public class OsmandSettings {
|
||||||
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache();
|
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache();
|
||||||
|
|
||||||
public final OsmandPreference<Boolean> SPEAK_GPX_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache();
|
public final OsmandPreference<Boolean> SPEAK_GPX_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache();
|
||||||
|
public final OsmandPreference<Boolean> CALC_GPX_ROUTE = new BooleanPreference("calc_gpx_route", false).makeGlobal().cache();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -992,8 +993,22 @@ public class OsmandSettings {
|
||||||
public static final String EXTERNAL_STORAGE_DIR = "external_storage_dir"; //$NON-NLS-1$
|
public static final String EXTERNAL_STORAGE_DIR = "external_storage_dir"; //$NON-NLS-1$
|
||||||
|
|
||||||
public File getExternalStorageDirectory() {
|
public File getExternalStorageDirectory() {
|
||||||
return new File(settingsAPI.getString(globalPreferences,EXTERNAL_STORAGE_DIR,
|
String defaultLocation = ctx.getExternalServiceAPI().getExternalStorageDirectory();
|
||||||
ctx.getExternalServiceAPI().getExternalStorageDirectory()));
|
if(Build.VERSION.SDK_INT >= VERSION_DEFAULTLOCATION_CHANGED && !new File(defaultLocation, IndexConstants.APP_DIR).exists()) {
|
||||||
|
defaultLocation += "/Android/data/" + ctx.getPackageName();
|
||||||
|
}
|
||||||
|
return new File(settingsAPI.getString(globalPreferences, EXTERNAL_STORAGE_DIR,
|
||||||
|
defaultLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int VERSION_DEFAULTLOCATION_CHANGED = 19;
|
||||||
|
|
||||||
|
public String getDefaultExternalStorageLocation() {
|
||||||
|
String defaultLocation = ctx.getExternalServiceAPI().getExternalStorageDirectory();
|
||||||
|
if(Build.VERSION.SDK_INT >= VERSION_DEFAULTLOCATION_CHANGED) {
|
||||||
|
defaultLocation += "/Android/data/" + ctx.getPackageName();
|
||||||
|
}
|
||||||
|
return defaultLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setExternalStorageDirectory(String externalStorageDir) {
|
public boolean setExternalStorageDirectory(String externalStorageDir) {
|
||||||
|
|
|
@ -11,6 +11,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import net.osmand.IndexConstants;
|
||||||
|
import net.osmand.access.AccessibleAlertBuilder;
|
||||||
import net.osmand.access.AccessibleToast;
|
import net.osmand.access.AccessibleToast;
|
||||||
import net.osmand.plus.ClientContext;
|
import net.osmand.plus.ClientContext;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
@ -18,6 +20,7 @@ import net.osmand.plus.OsmandPlugin;
|
||||||
import net.osmand.plus.OsmandSettings;
|
import net.osmand.plus.OsmandSettings;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
|
import net.osmand.plus.activities.SettingsGeneralActivity.MoveFilesToDifferentDirectory;
|
||||||
import net.osmand.plus.base.BasicProgressAsyncTask;
|
import net.osmand.plus.base.BasicProgressAsyncTask;
|
||||||
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
|
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
|
||||||
import net.osmand.plus.download.DownloadActivityType;
|
import net.osmand.plus.download.DownloadActivityType;
|
||||||
|
@ -36,6 +39,7 @@ import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask.Status;
|
import android.os.AsyncTask.Status;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
@ -89,6 +93,7 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
|
||||||
private TextView progressPercent;
|
private TextView progressPercent;
|
||||||
private ImageView cancel;
|
private ImageView cancel;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -162,7 +167,10 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
|
||||||
DownloadIndexAdapter adapter = new DownloadIndexAdapter(this, list);
|
DownloadIndexAdapter adapter = new DownloadIndexAdapter(this, list);
|
||||||
setListAdapter(adapter);
|
setListAdapter(adapter);
|
||||||
if(getMyApplication().getResourceManager().getIndexFileNames().isEmpty()) {
|
if(getMyApplication().getResourceManager().getIndexFileNames().isEmpty()) {
|
||||||
boolean showedDialog = SuggestExternalDirectoryDialog.showDialog(this, null, null);
|
boolean showedDialog = false;
|
||||||
|
if(Build.VERSION.SDK_INT < OsmandSettings.VERSION_DEFAULTLOCATION_CHANGED) {
|
||||||
|
SuggestExternalDirectoryDialog.showDialog(this, null, null);
|
||||||
|
}
|
||||||
if(!showedDialog) {
|
if(!showedDialog) {
|
||||||
showDialogOfFreeDownloadsIfNeeded();
|
showDialogOfFreeDownloadsIfNeeded();
|
||||||
}
|
}
|
||||||
|
@ -182,7 +190,39 @@ public class DownloadIndexActivity extends OsmandExpandableListActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if(Build.VERSION.SDK_INT >= OsmandSettings.VERSION_DEFAULTLOCATION_CHANGED) {
|
||||||
|
if(!settings.getExternalStorageDirectory().getAbsolutePath().equals(settings.getDefaultExternalStorageLocation())) {
|
||||||
|
AccessibleAlertBuilder ab = new AccessibleAlertBuilder(this);
|
||||||
|
ab.setMessage(getString(R.string.android_19_location_disabled, settings.getExternalStorageDirectory()));
|
||||||
|
ab.setPositiveButton(R.string.default_buttons_yes, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
copyFilesForAndroid19();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ab.setNegativeButton(R.string.default_buttons_cancel, null);
|
||||||
|
ab.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFilesForAndroid19() {
|
||||||
|
final String newLoc = settings.getDefaultExternalStorageLocation();
|
||||||
|
MoveFilesToDifferentDirectory task =
|
||||||
|
new MoveFilesToDifferentDirectory(DownloadIndexActivity.this,
|
||||||
|
new File(settings.getExternalStorageDirectory(), IndexConstants.APP_DIR),
|
||||||
|
new File(newLoc, IndexConstants.APP_DIR)) {
|
||||||
|
protected Boolean doInBackground(Void[] params) {
|
||||||
|
Boolean result = super.doInBackground(params);
|
||||||
|
if(result) {
|
||||||
|
settings.setExternalStorageDirectory(newLoc);
|
||||||
|
getMyApplication().getResourceManager().resetStoreDirectory();
|
||||||
|
getMyApplication().getResourceManager().reloadIndexes(progress) ;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
task.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -367,10 +367,10 @@ public class MapActivity extends AccessibleActivity {
|
||||||
|
|
||||||
public void changeZoom(int stp){
|
public void changeZoom(int stp){
|
||||||
// delta = Math.round(delta * OsmandMapTileView.ZOOM_DELTA) * OsmandMapTileView.ZOOM_DELTA_1;
|
// delta = Math.round(delta * OsmandMapTileView.ZOOM_DELTA) * OsmandMapTileView.ZOOM_DELTA_1;
|
||||||
boolean changeLocation = true;
|
boolean changeLocation = false;
|
||||||
if (settings.AUTO_ZOOM_MAP.get() == AutoZoomMap.NONE) {
|
// if (settings.AUTO_ZOOM_MAP.get() == AutoZoomMap.NONE) {
|
||||||
changeLocation = false;
|
// changeLocation = false;
|
||||||
}
|
// }
|
||||||
final int newZoom = mapView.getZoom() + stp;
|
final int newZoom = mapView.getZoom() + stp;
|
||||||
mapView.getAnimatedDraggingThread().startZooming(newZoom, changeLocation);
|
mapView.getAnimatedDraggingThread().startZooming(newZoom, changeLocation);
|
||||||
if (app.accessibilityEnabled())
|
if (app.accessibilityEnabled())
|
||||||
|
|
|
@ -4,30 +4,27 @@ package net.osmand.plus.activities;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.widget.ScrollView;
|
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandPlugin;
|
import net.osmand.plus.OsmandPlugin;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.rastermaps.SettingsRasterMapsActivity;
|
|
||||||
import net.osmand.util.Algorithms;
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class SettingsActivity extends SettingsBaseActivity {
|
public class SettingsActivity extends SettingsBaseActivity {
|
||||||
|
|
|
@ -2,23 +2,32 @@ package net.osmand.plus.activities;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.IProgress;
|
import net.osmand.IProgress;
|
||||||
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.access.AccessibleToast;
|
import net.osmand.access.AccessibleToast;
|
||||||
import net.osmand.plus.ApplicationMode;
|
import net.osmand.plus.ApplicationMode;
|
||||||
import net.osmand.plus.ClientContext;
|
import net.osmand.plus.ClientContext;
|
||||||
import net.osmand.plus.OsmandSettings;
|
import net.osmand.plus.OsmandSettings;
|
||||||
import net.osmand.plus.OsmandSettings.DrivingRegion;
|
import net.osmand.plus.OsmandSettings.DrivingRegion;
|
||||||
import net.osmand.plus.OsmandSettings.MetricsConstants;
|
import net.osmand.plus.OsmandSettings.MetricsConstants;
|
||||||
|
import net.osmand.plus.ProgressDialogImplementation;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
|
import net.osmand.plus.base.SuggestExternalDirectoryDialog;
|
||||||
import net.osmand.plus.render.NativeOsmandLibrary;
|
import net.osmand.plus.render.NativeOsmandLibrary;
|
||||||
import net.osmand.plus.voice.CommandPlayer;
|
import net.osmand.plus.voice.CommandPlayer;
|
||||||
import net.osmand.render.RenderingRulesStorage;
|
import net.osmand.render.RenderingRulesStorage;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -101,12 +110,12 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
showOtherDialog();
|
showOtherDialog();
|
||||||
}
|
}
|
||||||
}, new Runnable() {
|
}, new CallbackWithObject<String>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public boolean processResult(String result) {
|
||||||
Toast.makeText(SettingsGeneralActivity.this, getString(R.string.application_dir_change_warning),
|
warnAboutChangingStorage(result);
|
||||||
Toast.LENGTH_LONG).show();
|
return true;
|
||||||
reloadIndexes();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
|
@ -265,6 +274,97 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MoveFilesToDifferentDirectory extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
|
||||||
|
private File to;
|
||||||
|
private Context ctx;
|
||||||
|
private File from;
|
||||||
|
protected ProgressDialogImplementation progress;
|
||||||
|
private Runnable runOnSuccess;
|
||||||
|
|
||||||
|
public MoveFilesToDifferentDirectory(Context ctx, File from, File to) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunOnSuccess(Runnable runOnSuccess) {
|
||||||
|
this.runOnSuccess = runOnSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
progress = ProgressDialogImplementation.createProgressDialog(
|
||||||
|
ctx, ctx.getString(R.string.copying_osmand_files),
|
||||||
|
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
|
||||||
|
ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
if(result != null && result.booleanValue() && runOnSuccess != null) {
|
||||||
|
runOnSuccess.run();
|
||||||
|
}
|
||||||
|
if(progress.getDialog().isShowing()) {
|
||||||
|
progress.getDialog().dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void movingFiles(File f, File t, int depth) throws IOException {
|
||||||
|
if(depth <= 2) {
|
||||||
|
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
|
||||||
|
}
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
t.mkdirs();
|
||||||
|
File[] lf = f.listFiles();
|
||||||
|
if (lf != null) {
|
||||||
|
for (int i = 0; i < lf.length; i++) {
|
||||||
|
if (lf[i] != null) {
|
||||||
|
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.delete();
|
||||||
|
} else if (f.isFile()) {
|
||||||
|
if(t.exists()) {
|
||||||
|
Algorithms.removeAllFiles(t);
|
||||||
|
}
|
||||||
|
boolean rnm = false;
|
||||||
|
try {
|
||||||
|
rnm = f.renameTo(t);
|
||||||
|
} catch(RuntimeException e) {
|
||||||
|
}
|
||||||
|
if (!rnm) {
|
||||||
|
FileInputStream fin = new FileInputStream(f);
|
||||||
|
FileOutputStream fout = new FileOutputStream(t);
|
||||||
|
try {
|
||||||
|
Algorithms.streamCopy(fin, fout);
|
||||||
|
} finally {
|
||||||
|
fin.close();
|
||||||
|
fout.close();
|
||||||
|
}
|
||||||
|
f.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(depth <= 2) {
|
||||||
|
progress.finishTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
to.mkdirs();
|
||||||
|
try {
|
||||||
|
movingFiles(from, to, 0);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(ctx, R.string.input_output_error, Toast.LENGTH_LONG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void warnAboutChangingStorage(final String newValue) {
|
private void warnAboutChangingStorage(final String newValue) {
|
||||||
final String newDir = newValue != null ? newValue.trim() : newValue;
|
final String newDir = newValue != null ? newValue.trim() : newValue;
|
||||||
File path = new File(newDir);
|
File path = new File(newDir);
|
||||||
|
@ -273,23 +373,43 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
|
||||||
AccessibleToast.makeText(this, R.string.specified_dir_doesnt_exist, Toast.LENGTH_LONG).show();
|
AccessibleToast.makeText(this, R.string.specified_dir_doesnt_exist, Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder builder = new AlertDialog.Builder(this);
|
Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(getString(R.string.application_dir_change_warning));
|
builder.setMessage(getString(R.string.application_dir_change_warning2));
|
||||||
builder.setPositiveButton(R.string.default_buttons_yes, new OnClickListener() {
|
builder.setPositiveButton(R.string.default_buttons_yes, new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
// edit the preference
|
MoveFilesToDifferentDirectory task =
|
||||||
settings.setExternalStorageDirectory(newDir);
|
new MoveFilesToDifferentDirectory(SettingsGeneralActivity.this,
|
||||||
getMyApplication().getResourceManager().resetStoreDirectory();
|
new File(settings.getExternalStorageDirectory(), IndexConstants.APP_DIR), new File(newDir,
|
||||||
reloadIndexes();
|
IndexConstants.APP_DIR));
|
||||||
updateApplicationDirTextAndSummary();
|
task.setRunOnSuccess(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateSettingsToNewDir(newDir);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
task.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNeutralButton(R.string.default_buttons_no, new OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
updateSettingsToNewDir(newDir);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(R.string.default_buttons_cancel, null);
|
builder.setNegativeButton(R.string.default_buttons_cancel, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSettingsToNewDir(final String newDir) {
|
||||||
|
// edit the preference
|
||||||
|
settings.setExternalStorageDirectory(newDir);
|
||||||
|
getMyApplication().getResourceManager().resetStoreDirectory();
|
||||||
|
reloadIndexes();
|
||||||
|
updateApplicationDirTextAndSummary();
|
||||||
|
}
|
||||||
|
|
||||||
public void reloadIndexes() {
|
public void reloadIndexes() {
|
||||||
setSupportProgressBarIndeterminateVisibility(true);
|
setSupportProgressBarIndeterminateVisibility(true);
|
||||||
final CharSequence oldTitle = getSupportActionBar().getTitle();
|
final CharSequence oldTitle = getSupportActionBar().getTitle();
|
||||||
|
|
|
@ -233,7 +233,7 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
|
||||||
if (MORE_VALUE.equals(newValue)) {
|
if (MORE_VALUE.equals(newValue)) {
|
||||||
// listPref.set(oldValue); // revert the change..
|
// listPref.set(oldValue); // revert the change..
|
||||||
final Intent intent = new Intent(this, DownloadIndexActivity.class);
|
final Intent intent = new Intent(this, DownloadIndexActivity.class);
|
||||||
intent.putExtra(DownloadIndexActivity.FILTER_KEY, "voice");
|
intent.putExtra(DownloadIndexActivity.FILTER_KEY, getString(R.string.voice));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else {
|
} else {
|
||||||
super.onPreferenceChange(preference, newValue);
|
super.onPreferenceChange(preference, newValue);
|
||||||
|
|
|
@ -19,6 +19,7 @@ import net.osmand.plus.TargetPointsHelper;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
||||||
import net.osmand.plus.routing.RouteProvider.RouteService;
|
import net.osmand.plus.routing.RouteProvider.RouteService;
|
||||||
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
|
@ -66,10 +67,11 @@ public class NavigateAction {
|
||||||
public boolean navigateUsingGPX(final ApplicationMode appMode, final LatLon endForRouting,
|
public boolean navigateUsingGPX(final ApplicationMode appMode, final LatLon endForRouting,
|
||||||
final GPXFile result) {
|
final GPXFile result) {
|
||||||
Builder builder = new AlertDialog.Builder(mapActivity);
|
Builder builder = new AlertDialog.Builder(mapActivity);
|
||||||
final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get()};
|
final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get(), settings.CALC_GPX_ROUTE.get()};
|
||||||
builder.setMultiChoiceItems(new String[] { getString(R.string.gpx_option_reverse_route),
|
builder.setMultiChoiceItems(new String[] { getString(R.string.gpx_option_reverse_route),
|
||||||
getString(R.string.gpx_option_destination_point), getString(R.string.gpx_option_from_start_point),
|
getString(R.string.gpx_option_destination_point), getString(R.string.gpx_option_from_start_point),
|
||||||
getString(R.string.announce_gpx_waypoints) }, props,
|
getString(R.string.announce_gpx_waypoints),
|
||||||
|
getString(R.string.calculate_osmand_route_gpx)}, props,
|
||||||
new OnMultiChoiceClickListener() {
|
new OnMultiChoiceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
||||||
|
@ -83,9 +85,20 @@ public class NavigateAction {
|
||||||
boolean passWholeWay = props[2];
|
boolean passWholeWay = props[2];
|
||||||
boolean useDestination = props[1];
|
boolean useDestination = props[1];
|
||||||
boolean announceGpxWpt = props[3];
|
boolean announceGpxWpt = props[3];
|
||||||
|
boolean calculateOsmAndRoute = props[4];
|
||||||
settings.SPEAK_GPX_WPT.set(announceGpxWpt);
|
settings.SPEAK_GPX_WPT.set(announceGpxWpt);
|
||||||
GPXRouteParams gpxRoute = new GPXRouteParams(result, reverse, announceGpxWpt, settings);
|
settings.CALC_GPX_ROUTE.set(calculateOsmAndRoute);
|
||||||
|
GPXRouteParamsBuilder bld = GPXRouteParamsBuilder.newBuilder(result, settings);
|
||||||
|
if(reverse) {
|
||||||
|
bld.reverse();
|
||||||
|
}
|
||||||
|
if(announceGpxWpt) {
|
||||||
|
bld.announceWaypoints();
|
||||||
|
}
|
||||||
|
if(calculateOsmAndRoute) {
|
||||||
|
bld.calculateOsmAndRoute();
|
||||||
|
}
|
||||||
|
GPXRouteParams gpxRoute = bld.build();
|
||||||
Location loc = getLastKnownLocation();
|
Location loc = getLastKnownLocation();
|
||||||
if(passWholeWay && loc != null){
|
if(passWholeWay && loc != null){
|
||||||
gpxRoute.setStartPoint(loc);
|
gpxRoute.setStartPoint(loc);
|
||||||
|
|
|
@ -16,6 +16,7 @@ import net.osmand.plus.R;
|
||||||
import net.osmand.plus.TargetPointsHelper;
|
import net.osmand.plus.TargetPointsHelper;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
|
||||||
|
import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -123,14 +124,26 @@ public class FailSafeFuntions {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(GPXFile result) {
|
protected void onPostExecute(GPXFile result) {
|
||||||
final GPXRouteParams gpxRoute = result == null ? null : new GPXRouteParams(result, false,
|
final GPXRouteParams gpxRoute;
|
||||||
settings.SPEAK_GPX_WPT.get(), settings);
|
if (result != null) {
|
||||||
|
GPXRouteParamsBuilder builder = GPXRouteParamsBuilder.newBuilder(result, settings);
|
||||||
|
if (settings.SPEAK_GPX_WPT.get()) {
|
||||||
|
builder.announceWaypoints();
|
||||||
|
}
|
||||||
|
if(settings.CALC_GPX_ROUTE.get()) {
|
||||||
|
builder.calculateOsmAndRoute();
|
||||||
|
}
|
||||||
|
gpxRoute = builder.build();
|
||||||
|
} else {
|
||||||
|
gpxRoute = null;
|
||||||
|
}
|
||||||
LatLon endPoint = pointToNavigate != null ? pointToNavigate : gpxRoute.getLastPoint();
|
LatLon endPoint = pointToNavigate != null ? pointToNavigate : gpxRoute.getLastPoint();
|
||||||
net.osmand.Location startPoint = gpxRoute == null ? null : gpxRoute.getStartPointForRoute();
|
net.osmand.Location startPoint = gpxRoute == null ? null : gpxRoute.getStartPointForRoute();
|
||||||
if (endPoint == null) {
|
if (endPoint == null) {
|
||||||
notRestoreRoutingMode(ma, app);
|
notRestoreRoutingMode(ma, app);
|
||||||
} else {
|
} else {
|
||||||
ma.followRoute(settings.getApplicationMode(), endPoint, targetPoints.getIntermediatePoints(), startPoint, gpxRoute);
|
ma.followRoute(settings.getApplicationMode(), endPoint,
|
||||||
|
targetPoints.getIntermediatePoints(), startPoint, gpxRoute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.io.InputStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ public class SuggestExternalDirectoryDialog {
|
||||||
|
|
||||||
|
|
||||||
public static boolean showDialog(Activity a, final DialogInterface.OnClickListener otherListener,
|
public static boolean showDialog(Activity a, final DialogInterface.OnClickListener otherListener,
|
||||||
final Runnable reloadListener){
|
final CallbackWithObject<String> selector){
|
||||||
final boolean showOther = otherListener != null;
|
final boolean showOther = otherListener != null;
|
||||||
final OsmandApplication app = (OsmandApplication) a.getApplication();
|
final OsmandApplication app = (OsmandApplication) a.getApplication();
|
||||||
Builder bld = new AlertDialog.Builder(a);
|
Builder bld = new AlertDialog.Builder(a);
|
||||||
|
@ -46,10 +47,11 @@ public class SuggestExternalDirectoryDialog {
|
||||||
otherListener.onClick(dialog, which);
|
otherListener.onClick(dialog, which);
|
||||||
} else {
|
} else {
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
app.getSettings().setExternalStorageDirectory(extMounts[which]);
|
if(selector != null) {
|
||||||
app.getResourceManager().resetStoreDirectory();
|
selector.processResult(extMounts[which]);
|
||||||
if(reloadListener != null) {
|
} else {
|
||||||
reloadListener.run();
|
app.getSettings().setExternalStorageDirectory(extMounts[which]);
|
||||||
|
app.getResourceManager().resetStoreDirectory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
|
@ -182,7 +183,7 @@ public class DownloadOsmandIndexesHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String reparseDate(Context ctx, String date) {
|
protected static String reparseDate(Context ctx, String date) {
|
||||||
try {
|
try {
|
||||||
Date d = simpleDateFormat.parse(date);
|
Date d = simpleDateFormat.parse(date);
|
||||||
return AndroidUtils.formatDate(ctx, d.getTime());
|
return AndroidUtils.formatDate(ctx, d.getTime());
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
|
@ -218,7 +219,9 @@ public class IndexItem implements Comparable<IndexItem> {
|
||||||
entry.zipStream = zipStream;
|
entry.zipStream = zipStream;
|
||||||
entry.unzipFolder = unzipDir;
|
entry.unzipFolder = unzipDir;
|
||||||
try {
|
try {
|
||||||
Date d = DateFormat.getDateFormat((Context) ctx).parse(date);
|
final java.text.DateFormat format = DateFormat.getDateFormat((Context) ctx);
|
||||||
|
format.setTimeZone(TimeZone.getTimeZone("GMT+01:00"));
|
||||||
|
Date d = format.parse(date);
|
||||||
entry.dateModified = d.getTime();
|
entry.dateModified = d.getTime();
|
||||||
} catch (ParseException e1) {
|
} catch (ParseException e1) {
|
||||||
log.error("ParseException", e1);
|
log.error("ParseException", e1);
|
||||||
|
|
|
@ -301,7 +301,13 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
||||||
OsmBaseStorage st = new OsmBaseStorage();
|
OsmBaseStorage st = new OsmBaseStorage();
|
||||||
st.parseOSM(new ByteArrayInputStream(res.getBytes("UTF-8")), null, null, true); //$NON-NLS-1$
|
st.parseOSM(new ByteArrayInputStream(res.getBytes("UTF-8")), null, null, true); //$NON-NLS-1$
|
||||||
EntityId id = new Entity.EntityId(EntityType.NODE, nodeId);
|
EntityId id = new Entity.EntityId(EntityType.NODE, nodeId);
|
||||||
// Node entity = (Node) st.getRegisteredEntities().get(id);
|
Node entity = (Node) st.getRegisteredEntities().get(id);
|
||||||
|
// merge non existing tags
|
||||||
|
for(String rtag : entity.getTagKeySet()) {
|
||||||
|
if(!n.getTagKeySet().contains(rtag)) {
|
||||||
|
n.putTag(rtag, entity.getTag(rtag));
|
||||||
|
}
|
||||||
|
}
|
||||||
entityInfo = st.getRegisteredEntityInfo().get(id);
|
entityInfo = st.getRegisteredEntityInfo().get(id);
|
||||||
return entityInfo;
|
return entityInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package net.osmand.plus.render;
|
package net.osmand.plus.render;
|
||||||
|
|
||||||
|
|
||||||
|
import gnu.trove.iterator.TIntObjectIterator;
|
||||||
import gnu.trove.list.TLongList;
|
import gnu.trove.list.TLongList;
|
||||||
import gnu.trove.list.array.TIntArrayList;
|
import gnu.trove.list.array.TIntArrayList;
|
||||||
import gnu.trove.list.array.TLongArrayList;
|
import gnu.trove.list.array.TLongArrayList;
|
||||||
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
import gnu.trove.set.TLongSet;
|
import gnu.trove.set.TLongSet;
|
||||||
import gnu.trove.set.hash.TLongHashSet;
|
import gnu.trove.set.hash.TLongHashSet;
|
||||||
|
|
||||||
|
@ -20,18 +22,19 @@ import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import net.osmand.IProgress;
|
import net.osmand.IProgress;
|
||||||
|
import net.osmand.ResultMatcher;
|
||||||
import net.osmand.NativeLibrary.NativeSearchResult;
|
import net.osmand.NativeLibrary.NativeSearchResult;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.ResultMatcher;
|
|
||||||
import net.osmand.access.AccessibleToast;
|
import net.osmand.access.AccessibleToast;
|
||||||
import net.osmand.binary.BinaryMapDataObject;
|
import net.osmand.binary.BinaryMapDataObject;
|
||||||
import net.osmand.binary.BinaryMapIndexReader;
|
import net.osmand.binary.BinaryMapIndexReader;
|
||||||
|
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||||
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
|
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
|
||||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||||
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
|
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
|
||||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||||
import net.osmand.binary.RouteDataObject;
|
|
||||||
import net.osmand.data.QuadPointDouble;
|
import net.osmand.data.QuadPointDouble;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
@ -66,10 +69,10 @@ public class MapRenderRepositories {
|
||||||
// It is needed to not draw object twice if user have map index that intersects by boundaries
|
// It is needed to not draw object twice if user have map index that intersects by boundaries
|
||||||
public static boolean checkForDuplicateObjectIds = true;
|
public static boolean checkForDuplicateObjectIds = true;
|
||||||
|
|
||||||
|
|
||||||
private final static Log log = PlatformUtil.getLog(MapRenderRepositories.class);
|
private final static Log log = PlatformUtil.getLog(MapRenderRepositories.class);
|
||||||
private final OsmandApplication context;
|
private final OsmandApplication context;
|
||||||
private final static int BASEMAP_ZOOM = 11;
|
private final static int zoomOnlyForBasemaps = 11;
|
||||||
|
static int zoomForBaseRouteRendering = 14;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
private Map<String, BinaryMapIndexReader> files = new ConcurrentHashMap<String, BinaryMapIndexReader>();
|
private Map<String, BinaryMapIndexReader> files = new ConcurrentHashMap<String, BinaryMapIndexReader>();
|
||||||
private Set<String> nativeFiles = new HashSet<String>();
|
private Set<String> nativeFiles = new HashSet<String>();
|
||||||
|
@ -91,6 +94,8 @@ public class MapRenderRepositories {
|
||||||
private RotatedTileBox prevBmpLocation = null;
|
private RotatedTileBox prevBmpLocation = null;
|
||||||
// already rendered bitmap
|
// already rendered bitmap
|
||||||
private Bitmap prevBmp;
|
private Bitmap prevBmp;
|
||||||
|
// to track necessity of map download (1 (if basemap) + 2 (if normal map)
|
||||||
|
private int previousRenderedState;
|
||||||
|
|
||||||
// location of rendered bitmap
|
// location of rendered bitmap
|
||||||
private RotatedTileBox bmpLocation = null;
|
private RotatedTileBox bmpLocation = null;
|
||||||
|
@ -98,6 +103,7 @@ public class MapRenderRepositories {
|
||||||
private Bitmap bmp;
|
private Bitmap bmp;
|
||||||
// Field used in C++
|
// Field used in C++
|
||||||
private boolean interrupted = false;
|
private boolean interrupted = false;
|
||||||
|
private int renderedState = 0; // (1 (if basemap) + 2 (if normal map)
|
||||||
private RenderingContext currentRenderingContext;
|
private RenderingContext currentRenderingContext;
|
||||||
private SearchRequest<BinaryMapDataObject> searchRequest;
|
private SearchRequest<BinaryMapDataObject> searchRequest;
|
||||||
private OsmandSettings prefs;
|
private OsmandSettings prefs;
|
||||||
|
@ -252,7 +258,7 @@ public class MapRenderRepositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeSearchResult resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, renderingReq,
|
NativeSearchResult resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, renderingReq,
|
||||||
checkForDuplicateObjectIds, this, /*context.getString(R.string.switch_to_raster_map_to_see)*/ "");
|
checkForDuplicateObjectIds, this, "");
|
||||||
if (checkWhetherInterrupted()) {
|
if (checkWhetherInterrupted()) {
|
||||||
resultHandler.deleteNativeResult();
|
resultHandler.deleteNativeResult();
|
||||||
return false;
|
return false;
|
||||||
|
@ -268,6 +274,77 @@ public class MapRenderRepositories {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void readRouteDataAsMapObjects(SearchRequest<BinaryMapDataObject> sr, BinaryMapIndexReader c,
|
||||||
|
final ArrayList<BinaryMapDataObject> tempResult, final TLongSet ids) {
|
||||||
|
final boolean basemap = c.isBasemap();
|
||||||
|
try {
|
||||||
|
for (RouteRegion reg : c.getRoutingIndexes()) {
|
||||||
|
List<RouteSubregion> parent = sr.getZoom() < 15 ? reg.getBaseSubregions() : reg.getSubregions();
|
||||||
|
List<RouteSubregion> searchRouteIndexTree = c.searchRouteIndexTree(sr, parent);
|
||||||
|
final MapIndex nmi = new MapIndex();
|
||||||
|
c.loadRouteIndexData(searchRouteIndexTree, new ResultMatcher<RouteDataObject>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean publish(RouteDataObject r) {
|
||||||
|
if (basemap) {
|
||||||
|
renderedState |= 1;
|
||||||
|
} else {
|
||||||
|
renderedState |= 2;
|
||||||
|
}
|
||||||
|
if (checkForDuplicateObjectIds && !basemap) {
|
||||||
|
if (ids.contains(r.getId()) && r.getId() > 0) {
|
||||||
|
// do not add object twice
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ids.add(r.getId());
|
||||||
|
}
|
||||||
|
int[] coordinantes = new int[r.getPointsLength() * 2];
|
||||||
|
int[] roTypes = r.getTypes();
|
||||||
|
for(int k = 0; k < roTypes.length; k++) {
|
||||||
|
int type = roTypes[k];
|
||||||
|
registerMissingType(nmi, r, type);
|
||||||
|
}
|
||||||
|
for(int k = 0; k < coordinantes.length/2; k++ ) {
|
||||||
|
coordinantes[2 * k] = r.getPoint31XTile(k);
|
||||||
|
coordinantes[2 * k + 1] = r.getPoint31YTile(k);
|
||||||
|
}
|
||||||
|
BinaryMapDataObject mo = new BinaryMapDataObject(coordinantes, roTypes, new int[0][], r.getId());
|
||||||
|
TIntObjectHashMap<String> names = r.getNames();
|
||||||
|
if(names != null) {
|
||||||
|
TIntObjectIterator<String> it = names.iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
it.advance();
|
||||||
|
registerMissingType(nmi, r, it.key());
|
||||||
|
mo.putObjectName(it.key(), it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mo.setMapIndex(nmi);
|
||||||
|
tempResult.add(mo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerMissingType(final MapIndex nmi, RouteDataObject r, int type) {
|
||||||
|
if (!nmi.isRegisteredRule(type)) {
|
||||||
|
RouteTypeRule rr = r.region.quickGetEncodingRule(type);
|
||||||
|
String tag = rr.getTag();
|
||||||
|
int additional = ("highway".equals(tag) || "route".equals(tag) || "railway".equals(tag)
|
||||||
|
|| "aeroway".equals(tag) || "aerialway".equals(tag)) ? 0 : 1;
|
||||||
|
nmi.initMapEncodingRule(additional, type, rr.getTag(), rr.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return !interrupted;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.debug("Search failed " + c.getRegionNames(), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean loadVectorData(QuadRect dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq) {
|
private boolean loadVectorData(QuadRect dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq) {
|
||||||
double cBottomLatitude = dataBox.bottom;
|
double cBottomLatitude = dataBox.bottom;
|
||||||
double cTopLatitude = dataBox.top;
|
double cTopLatitude = dataBox.top;
|
||||||
|
@ -277,18 +354,102 @@ public class MapRenderRepositories {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
System.gc(); // to clear previous objects
|
System.gc(); // to clear previous objects
|
||||||
int count = 0;
|
|
||||||
ArrayList<BinaryMapDataObject> tempResult = new ArrayList<BinaryMapDataObject>();
|
ArrayList<BinaryMapDataObject> tempResult = new ArrayList<BinaryMapDataObject>();
|
||||||
ArrayList<BinaryMapDataObject> basemapResult = new ArrayList<BinaryMapDataObject>();
|
ArrayList<BinaryMapDataObject> basemapResult = new ArrayList<BinaryMapDataObject>();
|
||||||
TLongSet ids = new TLongHashSet();
|
|
||||||
|
int[] count = new int[]{0};
|
||||||
|
boolean[] ocean = new boolean[]{false};
|
||||||
|
boolean[] land = new boolean[]{false};
|
||||||
List<BinaryMapDataObject> coastLines = new ArrayList<BinaryMapDataObject>();
|
List<BinaryMapDataObject> coastLines = new ArrayList<BinaryMapDataObject>();
|
||||||
List<BinaryMapDataObject> basemapCoastLines = new ArrayList<BinaryMapDataObject>();
|
List<BinaryMapDataObject> basemapCoastLines = new ArrayList<BinaryMapDataObject>();
|
||||||
int leftX = MapUtils.get31TileNumberX(cLeftLongitude);
|
int leftX = MapUtils.get31TileNumberX(cLeftLongitude);
|
||||||
int rightX = MapUtils.get31TileNumberX(cRightLongitude);
|
int rightX = MapUtils.get31TileNumberX(cRightLongitude);
|
||||||
int bottomY = MapUtils.get31TileNumberY(cBottomLatitude);
|
int bottomY = MapUtils.get31TileNumberY(cBottomLatitude);
|
||||||
int topY = MapUtils.get31TileNumberY(cTopLatitude);
|
int topY = MapUtils.get31TileNumberY(cTopLatitude);
|
||||||
BinaryMapIndexReader.SearchFilter searchFilter = new BinaryMapIndexReader.SearchFilter() {
|
TLongSet ids = new TLongHashSet();
|
||||||
|
MapIndex mi = readMapObjectsForRendering(zoom, renderingReq, tempResult, basemapResult, ids, count, ocean,
|
||||||
|
land, coastLines, basemapCoastLines, leftX, rightX, bottomY, topY);
|
||||||
|
int renderRouteDataFile = 0;
|
||||||
|
if (renderingReq.searchRenderingAttribute("showRoadMapsAttribute")) {
|
||||||
|
renderRouteDataFile = renderingReq.getIntPropertyValue(renderingReq.ALL.R_ATTR_INT_VALUE);
|
||||||
|
}
|
||||||
|
if (checkWhetherInterrupted()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (renderRouteDataFile >= 0 && zoom >= zoomOnlyForBasemaps ) {
|
||||||
|
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, null);
|
||||||
|
for (BinaryMapIndexReader c : files.values()) {
|
||||||
|
// false positive case when we have 2 sep maps Country-roads & Country
|
||||||
|
if(c.getMapIndexes().size() == 0 || renderRouteDataFile == 1) {
|
||||||
|
readRouteDataAsMapObjects(searchRequest, c, tempResult, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info(String.format("Route objects %s", tempResult.size() +""));
|
||||||
|
}
|
||||||
|
|
||||||
|
String coastlineTime = "";
|
||||||
|
boolean addBasemapCoastlines = true;
|
||||||
|
boolean emptyData = zoom > zoomOnlyForBasemaps && tempResult.isEmpty() && coastLines.isEmpty();
|
||||||
|
boolean basemapMissing = zoom <= zoomOnlyForBasemaps && basemapCoastLines.isEmpty() && mi == null;
|
||||||
|
boolean detailedLandData = zoom >= zoomForBaseRouteRendering && tempResult.size() > 0 && renderRouteDataFile < 0;
|
||||||
|
if (!coastLines.isEmpty()) {
|
||||||
|
long ms = System.currentTimeMillis();
|
||||||
|
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
|
||||||
|
basemapCoastLines.isEmpty(), true, tempResult);
|
||||||
|
addBasemapCoastlines = (!coastlinesWereAdded && !detailedLandData) || zoom <= zoomOnlyForBasemaps;
|
||||||
|
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
|
||||||
|
} else {
|
||||||
|
addBasemapCoastlines = !detailedLandData;
|
||||||
|
}
|
||||||
|
if (addBasemapCoastlines) {
|
||||||
|
long ms = System.currentTimeMillis();
|
||||||
|
boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom,
|
||||||
|
true, true, tempResult);
|
||||||
|
addBasemapCoastlines = !coastlinesWereAdded;
|
||||||
|
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
|
||||||
|
}
|
||||||
|
if (addBasemapCoastlines && mi != null) {
|
||||||
|
BinaryMapDataObject o = new BinaryMapDataObject(new int[]{leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX,
|
||||||
|
topY}, new int[]{ocean[0] && !land[0] ? mi.coastlineEncodingType : (mi.landEncodingType)}, null, -1);
|
||||||
|
o.setMapIndex(mi);
|
||||||
|
tempResult.add(o);
|
||||||
|
}
|
||||||
|
if (emptyData || basemapMissing) {
|
||||||
|
// message
|
||||||
|
MapIndex mapIndex;
|
||||||
|
if (!tempResult.isEmpty()) {
|
||||||
|
mapIndex = tempResult.get(0).getMapIndex();
|
||||||
|
} else {
|
||||||
|
mapIndex = new MapIndex();
|
||||||
|
mapIndex.initMapEncodingRule(0, 1, "natural", "coastline");
|
||||||
|
mapIndex.initMapEncodingRule(0, 2, "name", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (zoom <= zoomOnlyForBasemaps || emptyData) {
|
||||||
|
tempResult.addAll(basemapResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (count[0] > 0) {
|
||||||
|
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
|
||||||
|
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom));
|
||||||
|
log.info(String.format("Searching: %s ms %s (%s results found)", System.currentTimeMillis() - now, coastlineTime, count[0])); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cObjects = tempResult;
|
||||||
|
cObjectsBox = dataBox;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private MapIndex readMapObjectsForRendering(final int zoom, final RenderingRuleSearchRequest renderingReq,
|
||||||
|
ArrayList<BinaryMapDataObject> tempResult, ArrayList<BinaryMapDataObject> basemapResult,
|
||||||
|
TLongSet ids, int[] count, boolean[] ocean, boolean[] land, List<BinaryMapDataObject> coastLines,
|
||||||
|
List<BinaryMapDataObject> basemapCoastLines, int leftX, int rightX, int bottomY, int topY) {
|
||||||
|
BinaryMapIndexReader.SearchFilter searchFilter = new BinaryMapIndexReader.SearchFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(TIntArrayList types, BinaryMapIndexReader.MapIndex root) {
|
public boolean accept(TIntArrayList types, BinaryMapIndexReader.MapIndex root) {
|
||||||
for (int j = 0; j < types.size(); j++) {
|
for (int j = 0; j < types.size(); j++) {
|
||||||
|
@ -318,11 +479,10 @@ public class MapRenderRepositories {
|
||||||
if (zoom > 16) {
|
if (zoom > 16) {
|
||||||
searchFilter = null;
|
searchFilter = null;
|
||||||
}
|
}
|
||||||
boolean ocean = false;
|
|
||||||
boolean land = false;
|
|
||||||
MapIndex mi = null;
|
MapIndex mi = null;
|
||||||
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
|
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
|
||||||
for (BinaryMapIndexReader c : files.values()) {
|
for (BinaryMapIndexReader c : files.values()) {
|
||||||
|
boolean basemap = c.isBasemap();
|
||||||
searchRequest.clearSearchResults();
|
searchRequest.clearSearchResults();
|
||||||
List<BinaryMapDataObject> res;
|
List<BinaryMapDataObject> res;
|
||||||
try {
|
try {
|
||||||
|
@ -331,99 +491,52 @@ public class MapRenderRepositories {
|
||||||
res = new ArrayList<BinaryMapDataObject>();
|
res = new ArrayList<BinaryMapDataObject>();
|
||||||
log.debug("Search failed " + c.getRegionNames(), e); //$NON-NLS-1$
|
log.debug("Search failed " + c.getRegionNames(), e); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
if(res.size() > 0) {
|
||||||
|
if(basemap) {
|
||||||
|
renderedState |= 1;
|
||||||
|
} else {
|
||||||
|
renderedState |= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (BinaryMapDataObject r : res) {
|
for (BinaryMapDataObject r : res) {
|
||||||
if (checkForDuplicateObjectIds) {
|
if (checkForDuplicateObjectIds && !basemap) {
|
||||||
if (ids.contains(r.getId()) && r.getId() > 0) {
|
if (ids.contains(r.getId()) && r.getId() > 0) {
|
||||||
// do not add object twice
|
// do not add object twice
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ids.add(r.getId());
|
ids.add(r.getId());
|
||||||
}
|
}
|
||||||
count++;
|
count[0]++;
|
||||||
|
|
||||||
if (r.containsType(r.getMapIndex().coastlineEncodingType)) {
|
if (r.containsType(r.getMapIndex().coastlineEncodingType)) {
|
||||||
if (c.isBasemap()) {
|
if (basemap) {
|
||||||
basemapCoastLines.add(r);
|
basemapCoastLines.add(r);
|
||||||
} else {
|
} else {
|
||||||
coastLines.add(r);
|
coastLines.add(r);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// do not mess coastline and other types
|
// do not mess coastline and other types
|
||||||
if (c.isBasemap()) {
|
if (basemap) {
|
||||||
basemapResult.add(r);
|
basemapResult.add(r);
|
||||||
} else {
|
} else {
|
||||||
tempResult.add(r);
|
tempResult.add(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (checkWhetherInterrupted()) {
|
if (checkWhetherInterrupted()) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchRequest.isOcean()) {
|
if (searchRequest.isOcean()) {
|
||||||
mi = c.getMapIndexes().get(0);
|
mi = c.getMapIndexes().get(0);
|
||||||
ocean = true;
|
ocean[0] = true;
|
||||||
}
|
}
|
||||||
if (searchRequest.isLand()) {
|
if (searchRequest.isLand()) {
|
||||||
mi = c.getMapIndexes().get(0);
|
mi = c.getMapIndexes().get(0);
|
||||||
land = true;
|
land[0] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return mi;
|
||||||
String coastlineTime = "";
|
|
||||||
boolean addBasemapCoastlines = true;
|
|
||||||
boolean emptyData = zoom > BASEMAP_ZOOM && tempResult.isEmpty() && coastLines.isEmpty();
|
|
||||||
boolean basemapMissing = zoom <= BASEMAP_ZOOM && basemapCoastLines.isEmpty() && mi == null;
|
|
||||||
boolean detailedLandData = zoom >= 14 && tempResult.size() > 0;
|
|
||||||
if (!coastLines.isEmpty()) {
|
|
||||||
long ms = System.currentTimeMillis();
|
|
||||||
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
|
|
||||||
basemapCoastLines.isEmpty(), true, tempResult);
|
|
||||||
addBasemapCoastlines = (!coastlinesWereAdded && !detailedLandData) || zoom <= BASEMAP_ZOOM;
|
|
||||||
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
|
|
||||||
} else {
|
|
||||||
addBasemapCoastlines = !detailedLandData;
|
|
||||||
}
|
|
||||||
if (addBasemapCoastlines) {
|
|
||||||
long ms = System.currentTimeMillis();
|
|
||||||
boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom,
|
|
||||||
true, true, tempResult);
|
|
||||||
addBasemapCoastlines = !coastlinesWereAdded;
|
|
||||||
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
|
|
||||||
}
|
|
||||||
if (addBasemapCoastlines && mi != null) {
|
|
||||||
BinaryMapDataObject o = new BinaryMapDataObject(new int[]{leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX,
|
|
||||||
topY}, new int[]{ocean && !land ? mi.coastlineEncodingType : (mi.landEncodingType)}, null, -1);
|
|
||||||
o.setMapIndex(mi);
|
|
||||||
tempResult.add(o);
|
|
||||||
}
|
|
||||||
if (emptyData || basemapMissing) {
|
|
||||||
// message
|
|
||||||
MapIndex mapIndex;
|
|
||||||
if (!tempResult.isEmpty()) {
|
|
||||||
mapIndex = tempResult.get(0).getMapIndex();
|
|
||||||
} else {
|
|
||||||
mapIndex = new MapIndex();
|
|
||||||
mapIndex.initMapEncodingRule(0, 1, "natural", "coastline");
|
|
||||||
mapIndex.initMapEncodingRule(0, 2, "name", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (zoom <= BASEMAP_ZOOM || emptyData) {
|
|
||||||
tempResult.addAll(basemapResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
|
|
||||||
cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom));
|
|
||||||
log.info(String.format("Searching: %s ms %s (%s results found)", System.currentTimeMillis() - now, coastlineTime, count)); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
cObjects = tempResult;
|
|
||||||
cObjectsBox = dataBox;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateLatLonBox(QuadRect box) {
|
private void validateLatLonBox(QuadRect box) {
|
||||||
|
@ -442,60 +555,13 @@ public class MapRenderRepositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// only single thread to read !
|
|
||||||
public synchronized boolean checkIfMapIsEmpty(int leftX, int rightX, int topY, int bottomY, int zoom){
|
|
||||||
final boolean[] empty = new boolean[] {true};
|
|
||||||
SearchRequest<BinaryMapDataObject> searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom,
|
|
||||||
null, new ResultMatcher<BinaryMapDataObject>() {
|
|
||||||
@Override
|
|
||||||
public boolean publish(BinaryMapDataObject object) {
|
|
||||||
empty[0] = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public boolean isLastMapRenderedEmpty(boolean checkBaseMap){
|
||||||
public boolean isCancelled() {
|
if(checkBaseMap) {
|
||||||
return !empty[0];
|
return prevBmp != null && previousRenderedState == 0;
|
||||||
}
|
} else {
|
||||||
});
|
return prevBmp != null && previousRenderedState == 1;
|
||||||
SearchRequest<RouteDataObject> searchRouteRequest = BinaryMapIndexReader.buildSearchRouteRequest(leftX, rightX, topY, bottomY,
|
|
||||||
new ResultMatcher<RouteDataObject>() {
|
|
||||||
@Override
|
|
||||||
public boolean publish(RouteDataObject object) {
|
|
||||||
empty[0] = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return !empty[0];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (BinaryMapIndexReader c : files.values()) {
|
|
||||||
if (!c.isBasemap()) {
|
|
||||||
try {
|
|
||||||
c.searchMapIndex(searchRequest);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// lots of FalsePositive cases
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!empty[0]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (RouteRegion r : c.getRoutingIndexes()) {
|
|
||||||
try {
|
|
||||||
List<RouteSubregion> regs = c.searchRouteIndexTree(searchRouteRequest, r.getSubregions());
|
|
||||||
if(!regs.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// lots of FalsePositive cases
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return empty[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void loadMap(RotatedTileBox tileRect, List<IMapDownloaderCallback> notifyList) {
|
public synchronized void loadMap(RotatedTileBox tileRect, List<IMapDownloaderCallback> notifyList) {
|
||||||
|
@ -539,10 +605,10 @@ public class MapRenderRepositories {
|
||||||
// prevent editing
|
// prevent editing
|
||||||
requestedBox = new RotatedTileBox(tileRect);
|
requestedBox = new RotatedTileBox(tileRect);
|
||||||
|
|
||||||
|
|
||||||
// calculate data box
|
// calculate data box
|
||||||
QuadRect dataBox = requestedBox.getLatLonBounds();
|
QuadRect dataBox = requestedBox.getLatLonBounds();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right
|
if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right
|
||||||
|| cObjectsBox.bottom < dataBox.bottom || (nativeLib != null) == (cNativeObjects == null)) {
|
|| cObjectsBox.bottom < dataBox.bottom || (nativeLib != null) == (cNativeObjects == null)) {
|
||||||
// increase data box in order for rotate
|
// increase data box in order for rotate
|
||||||
|
@ -556,6 +622,7 @@ public class MapRenderRepositories {
|
||||||
dataBox.bottom -= hi;
|
dataBox.bottom -= hi;
|
||||||
}
|
}
|
||||||
validateLatLonBox(dataBox);
|
validateLatLonBox(dataBox);
|
||||||
|
renderedState = 0;
|
||||||
boolean loaded;
|
boolean loaded;
|
||||||
if(nativeLib != null) {
|
if(nativeLib != null) {
|
||||||
cObjects = new LinkedList<BinaryMapDataObject>();
|
cObjects = new LinkedList<BinaryMapDataObject>();
|
||||||
|
@ -618,6 +685,7 @@ public class MapRenderRepositories {
|
||||||
Bitmap reuse = prevBmp;
|
Bitmap reuse = prevBmp;
|
||||||
this.prevBmp = this.bmp;
|
this.prevBmp = this.bmp;
|
||||||
this.prevBmpLocation = this.bmpLocation;
|
this.prevBmpLocation = this.bmpLocation;
|
||||||
|
this.previousRenderedState = renderedState;
|
||||||
if (reuse != null && reuse.getWidth() == currentRenderingContext.width && reuse.getHeight() == currentRenderingContext.height) {
|
if (reuse != null && reuse.getWidth() == currentRenderingContext.width && reuse.getHeight() == currentRenderingContext.height) {
|
||||||
bmp = reuse;
|
bmp = reuse;
|
||||||
bmp.eraseColor(currentRenderingContext.defaultColor);
|
bmp.eraseColor(currentRenderingContext.defaultColor);
|
||||||
|
@ -726,6 +794,7 @@ public class MapRenderRepositories {
|
||||||
cObjectsBox = new QuadRect();
|
cObjectsBox = new QuadRect();
|
||||||
|
|
||||||
requestedBox = prevBmpLocation = null;
|
requestedBox = prevBmpLocation = null;
|
||||||
|
previousRenderedState = 0;
|
||||||
// Do not clear main bitmap to not cause a screen refresh
|
// Do not clear main bitmap to not cause a screen refresh
|
||||||
// prevBmp = null;
|
// prevBmp = null;
|
||||||
// bmp = null;
|
// bmp = null;
|
||||||
|
|
|
@ -3,6 +3,7 @@ package net.osmand.plus.routing;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
@ -48,6 +49,7 @@ import net.osmand.router.GeneralRouter;
|
||||||
import net.osmand.router.GeneralRouter.GeneralRouterProfile;
|
import net.osmand.router.GeneralRouter.GeneralRouterProfile;
|
||||||
import net.osmand.router.GeneralRouter.RoutingParameter;
|
import net.osmand.router.GeneralRouter.RoutingParameter;
|
||||||
import net.osmand.router.GeneralRouter.RoutingParameterType;
|
import net.osmand.router.GeneralRouter.RoutingParameterType;
|
||||||
|
import net.osmand.router.PrecalculatedRouteDirection;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd;
|
import net.osmand.router.RoutePlannerFrontEnd;
|
||||||
import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode;
|
import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode;
|
||||||
import net.osmand.router.RouteSegmentResult;
|
import net.osmand.router.RouteSegmentResult;
|
||||||
|
@ -115,9 +117,9 @@ public class RouteProvider {
|
||||||
List<Location> points = new ArrayList<Location>();
|
List<Location> points = new ArrayList<Location>();
|
||||||
List<RouteDirectionInfo> directions;
|
List<RouteDirectionInfo> directions;
|
||||||
DataTileManager<WptPt> wpt;
|
DataTileManager<WptPt> wpt;
|
||||||
|
boolean calculateOsmAndRoute = false;
|
||||||
|
|
||||||
public GPXRouteParams(GPXFile file, boolean reverse, boolean announceWaypoints, OsmandSettings settings){
|
private GPXRouteParams(){
|
||||||
prepareEverything(file, reverse, announceWaypoints, settings.DRIVING_REGION.get().leftHandDriving);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStartPoint(Location startPoint) {
|
public void setStartPoint(Location startPoint) {
|
||||||
|
@ -144,6 +146,45 @@ public class RouteProvider {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class GPXRouteParamsBuilder {
|
||||||
|
|
||||||
|
private GPXRouteParams obj = new GPXRouteParams();
|
||||||
|
private GPXFile file;
|
||||||
|
private boolean leftHandDriving;
|
||||||
|
private boolean reverse;
|
||||||
|
private boolean announceWaypoints;
|
||||||
|
private GPXRouteParamsBuilder(GPXFile f, OsmandSettings settings) {
|
||||||
|
this.file = f;
|
||||||
|
leftHandDriving = settings.DRIVING_REGION.get().leftHandDriving;
|
||||||
|
// obj = new GPXRouteParams(file, reverse, announceWaypoints, settings)
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPXRouteParamsBuilder reverse() {
|
||||||
|
this.reverse = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPXRouteParamsBuilder announceWaypoints() {
|
||||||
|
this.announceWaypoints = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPXRouteParamsBuilder calculateOsmAndRoute() {
|
||||||
|
obj.calculateOsmAndRoute = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GPXRouteParamsBuilder newBuilder(GPXFile f, OsmandSettings settings) {
|
||||||
|
return new GPXRouteParamsBuilder(f, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPXRouteParams build(){
|
||||||
|
obj.prepareEverything(file, reverse, announceWaypoints, leftHandDriving);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareEverything(GPXFile file, boolean reverse, boolean announceWaypoints, boolean leftSide){
|
private void prepareEverything(GPXFile file, boolean reverse, boolean announceWaypoints, boolean leftSide){
|
||||||
if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){
|
if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){
|
||||||
directions = parseCloudmadeRoute(points, file, OSMAND_ROUTER.equals(file.author), leftSide, 10);
|
directions = parseCloudmadeRoute(points, file, OSMAND_ROUTER.equals(file.author), leftSide, 10);
|
||||||
|
@ -210,7 +251,10 @@ public class RouteProvider {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
RouteCalculationResult res;
|
RouteCalculationResult res;
|
||||||
if(params.gpxRoute != null && !params.gpxRoute.points.isEmpty()){
|
boolean calcGPXRoute = params.gpxRoute != null && !params.gpxRoute.points.isEmpty();
|
||||||
|
if (params.type == RouteService.OSMAND || (calcGPXRoute && params.gpxRoute.calculateOsmAndRoute)) {
|
||||||
|
res = findVectorMapsRoute(params, calcGPXRoute);
|
||||||
|
} else if(calcGPXRoute){
|
||||||
res = calculateGpxRoute(params);
|
res = calculateGpxRoute(params);
|
||||||
} else if (params.type == RouteService.YOURS) {
|
} else if (params.type == RouteService.YOURS) {
|
||||||
res = findYOURSRoute(params);
|
res = findYOURSRoute(params);
|
||||||
|
@ -218,8 +262,6 @@ public class RouteProvider {
|
||||||
res = findORSRoute(params);
|
res = findORSRoute(params);
|
||||||
} else if (params.type == RouteService.OSRM) {
|
} else if (params.type == RouteService.OSRM) {
|
||||||
res = findOSRMRoute(params);
|
res = findOSRMRoute(params);
|
||||||
} else if (params.type == RouteService.OSMAND) {
|
|
||||||
res = findVectorMapsRoute(params);
|
|
||||||
} else if (params.type == RouteService.BROUTER) {
|
} else if (params.type == RouteService.BROUTER) {
|
||||||
res = findBROUTERRoute(params);
|
res = findBROUTERRoute(params);
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,45 +288,20 @@ public class RouteProvider {
|
||||||
private RouteCalculationResult calculateGpxRoute(RouteCalculationParams pars) {
|
private RouteCalculationResult calculateGpxRoute(RouteCalculationParams pars) {
|
||||||
RouteCalculationResult res;
|
RouteCalculationResult res;
|
||||||
// get the closest point to start and to end
|
// get the closest point to start and to end
|
||||||
float minDist = Integer.MAX_VALUE;
|
|
||||||
int startI = 0;
|
|
||||||
GPXRouteParams params = pars.gpxRoute;
|
GPXRouteParams params = pars.gpxRoute;
|
||||||
List<Location> gpxRoute = params.points;
|
List<Location> gpxRoute = params.points;
|
||||||
int endI = gpxRoute.size();
|
int[] startI = new int[]{0};
|
||||||
if (pars.start != null) {
|
int[] endI = new int[]{gpxRoute.size()};
|
||||||
for (int i = 0; i < gpxRoute.size(); i++) {
|
ArrayList<Location> sublist = findGpxLocations(pars, startI, endI);
|
||||||
float d = gpxRoute.get(i).distanceTo(pars.start);
|
|
||||||
if (d < minDist) {
|
|
||||||
startI = i;
|
|
||||||
minDist = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pars.start = gpxRoute.get(0);
|
|
||||||
}
|
|
||||||
Location l = new Location("temp"); //$NON-NLS-1$
|
|
||||||
l.setLatitude(pars.end.getLatitude());
|
|
||||||
l.setLongitude(pars.end.getLongitude());
|
|
||||||
minDist = Integer.MAX_VALUE;
|
|
||||||
// get in reverse order taking into account ways with cycle
|
|
||||||
for (int i = gpxRoute.size() - 1; i >= startI; i--) {
|
|
||||||
float d = gpxRoute.get(i).distanceTo(l);
|
|
||||||
if (d < minDist) {
|
|
||||||
endI = i + 1;
|
|
||||||
// slightly modify to allow last point to be added
|
|
||||||
minDist = d - 40;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ArrayList<Location> sublist = new ArrayList<Location>(gpxRoute.subList(startI, endI));
|
|
||||||
pars.intermediates = null;
|
pars.intermediates = null;
|
||||||
if(params.directions == null){
|
if(params.directions == null){
|
||||||
res = new RouteCalculationResult(sublist, null, pars, params.wpt);
|
res = new RouteCalculationResult(sublist, null, pars, params.wpt);
|
||||||
} else {
|
} else {
|
||||||
List<RouteDirectionInfo> subdirections = new ArrayList<RouteDirectionInfo>();
|
List<RouteDirectionInfo> subdirections = new ArrayList<RouteDirectionInfo>();
|
||||||
for (RouteDirectionInfo info : params.directions) {
|
for (RouteDirectionInfo info : params.directions) {
|
||||||
if(info.routePointOffset >= startI && info.routePointOffset < endI){
|
if(info.routePointOffset >= startI[0] && info.routePointOffset < endI[0]){
|
||||||
RouteDirectionInfo ch = new RouteDirectionInfo(info.getAverageSpeed(), info.getTurnType());
|
RouteDirectionInfo ch = new RouteDirectionInfo(info.getAverageSpeed(), info.getTurnType());
|
||||||
ch.routePointOffset = info.routePointOffset - startI;
|
ch.routePointOffset = info.routePointOffset - startI[0];
|
||||||
ch.setDescriptionRoute(info.getDescriptionRoute());
|
ch.setDescriptionRoute(info.getDescriptionRoute());
|
||||||
|
|
||||||
// recalculate
|
// recalculate
|
||||||
|
@ -298,6 +315,49 @@ public class RouteProvider {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private ArrayList<Location> findGpxLocations(RouteCalculationParams pars, int[] startI, int[] endI) {
|
||||||
|
GPXRouteParams params = pars.gpxRoute;
|
||||||
|
List<Location> gpxRoute = params.points;
|
||||||
|
float minDist = Integer.MAX_VALUE;
|
||||||
|
int start = 0;
|
||||||
|
int end = gpxRoute.size();
|
||||||
|
if (pars.start != null) {
|
||||||
|
for (int i = 0; i < gpxRoute.size(); i++) {
|
||||||
|
float d = gpxRoute.get(i).distanceTo(pars.start);
|
||||||
|
if (d < minDist) {
|
||||||
|
start = i;
|
||||||
|
minDist = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pars.start = gpxRoute.get(0);
|
||||||
|
}
|
||||||
|
Location l = new Location("temp"); //$NON-NLS-1$
|
||||||
|
l.setLatitude(pars.end.getLatitude());
|
||||||
|
l.setLongitude(pars.end.getLongitude());
|
||||||
|
minDist = Integer.MAX_VALUE;
|
||||||
|
// get in reverse order taking into account ways with cycle
|
||||||
|
for (int i = gpxRoute.size() - 1; i >= start; i--) {
|
||||||
|
float d = gpxRoute.get(i).distanceTo(l);
|
||||||
|
if (d < minDist) {
|
||||||
|
end = i + 1;
|
||||||
|
// slightly modify to allow last point to be added
|
||||||
|
minDist = d - 40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArrayList<Location> sublist = new ArrayList<Location>(gpxRoute.subList(start, end));
|
||||||
|
if(startI != null) {
|
||||||
|
startI[0] = start;
|
||||||
|
}
|
||||||
|
if(endI != null) {
|
||||||
|
endI[0] = end;
|
||||||
|
}
|
||||||
|
return sublist;
|
||||||
|
}
|
||||||
|
|
||||||
protected String getString(ClientContext ctx, int resId){
|
protected String getString(ClientContext ctx, int resId){
|
||||||
if(ctx == null){
|
if(ctx == null){
|
||||||
return ""; //$NON-NLS-1$
|
return ""; //$NON-NLS-1$
|
||||||
|
@ -370,10 +430,63 @@ public class RouteProvider {
|
||||||
return new RouteCalculationResult(res, null, params, null);
|
return new RouteCalculationResult(res, null, params, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params) throws IOException {
|
protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params, boolean calcGPXRoute) throws IOException {
|
||||||
BinaryMapIndexReader[] files = params.ctx.getTodoAPI().getRoutingMapFiles();
|
BinaryMapIndexReader[] files = params.ctx.getTodoAPI().getRoutingMapFiles();
|
||||||
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(false);
|
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(false);
|
||||||
OsmandSettings settings = params.ctx.getSettings();
|
OsmandSettings settings = params.ctx.getSettings();
|
||||||
|
|
||||||
|
GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode);
|
||||||
|
if(generalRouter == null) {
|
||||||
|
return applicationModeNotSupported(params);
|
||||||
|
}
|
||||||
|
RoutingConfiguration cf = initOsmAndRoutingConfig(params, settings, generalRouter);
|
||||||
|
if(cf == null){
|
||||||
|
return applicationModeNotSupported(params);
|
||||||
|
}
|
||||||
|
PrecalculatedRouteDirection precalculated = null;
|
||||||
|
if(calcGPXRoute) {
|
||||||
|
ArrayList<Location> sublist = findGpxLocations(params, null, null);
|
||||||
|
LatLon[] latLon = new LatLon[sublist.size()];
|
||||||
|
for(int k = 0; k < latLon.length; k ++) {
|
||||||
|
latLon[k] = new LatLon(sublist.get(k).getLatitude(), sublist.get(k).getLongitude());
|
||||||
|
}
|
||||||
|
precalculated = PrecalculatedRouteDirection.build(latLon, generalRouter.getMaxDefaultSpeed());
|
||||||
|
precalculated.setFollowNext(true);
|
||||||
|
//cf.planRoadDirection = 1;
|
||||||
|
}
|
||||||
|
// BUILD context
|
||||||
|
RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
|
||||||
|
RouteCalculationMode.NORMAL);
|
||||||
|
|
||||||
|
RoutingContext complexCtx = null;
|
||||||
|
boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get()
|
||||||
|
&& precalculated == null;
|
||||||
|
if(complex) {
|
||||||
|
complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
|
||||||
|
RouteCalculationMode.COMPLEX);
|
||||||
|
complexCtx.calculationProgress = params.calculationProgress;
|
||||||
|
complexCtx.leftSideNavigation = params.leftSide;
|
||||||
|
}
|
||||||
|
ctx.leftSideNavigation = params.leftSide;
|
||||||
|
ctx.calculationProgress = params.calculationProgress;
|
||||||
|
if(params.previousToRecalculate != null) {
|
||||||
|
// not used any more
|
||||||
|
// ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute();
|
||||||
|
}
|
||||||
|
LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude());
|
||||||
|
LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude());
|
||||||
|
List<LatLon> inters = new ArrayList<LatLon>();
|
||||||
|
if (params.intermediates != null) {
|
||||||
|
inters = new ArrayList<LatLon>(params.intermediates);
|
||||||
|
}
|
||||||
|
return calcOfflineRouteImpl(params, router, ctx, complexCtx, st, en, inters, precalculated);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private RoutingConfiguration initOsmAndRoutingConfig(final RouteCalculationParams params, OsmandSettings settings,
|
||||||
|
GeneralRouter generalRouter) throws IOException, FileNotFoundException {
|
||||||
File routingXml = params.ctx.getAppPath(IndexConstants.ROUTING_XML_FILE);
|
File routingXml = params.ctx.getAppPath(IndexConstants.ROUTING_XML_FILE);
|
||||||
RoutingConfiguration.Builder config ;
|
RoutingConfiguration.Builder config ;
|
||||||
if (routingXml.exists() && routingXml.canRead()) {
|
if (routingXml.exists() && routingXml.canRead()) {
|
||||||
|
@ -393,12 +506,9 @@ public class RouteProvider {
|
||||||
} else if(params.mode.isDerivedRoutingFrom(ApplicationMode.CAR)){
|
} else if(params.mode.isDerivedRoutingFrom(ApplicationMode.CAR)){
|
||||||
p = GeneralRouterProfile.CAR;
|
p = GeneralRouterProfile.CAR;
|
||||||
} else {
|
} else {
|
||||||
return applicationModeNotSupported(params);
|
return null;
|
||||||
}
|
|
||||||
GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode);
|
|
||||||
if(generalRouter == null) {
|
|
||||||
return applicationModeNotSupported(params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> paramsR = new LinkedHashMap<String, String>();
|
Map<String, String> paramsR = new LinkedHashMap<String, String>();
|
||||||
for(Map.Entry<String, RoutingParameter> e : generalRouter.getParameters().entrySet()){
|
for(Map.Entry<String, RoutingParameter> e : generalRouter.getParameters().entrySet()){
|
||||||
String key = e.getKey();
|
String key = e.getKey();
|
||||||
|
@ -427,32 +537,20 @@ public class RouteProvider {
|
||||||
RoutingConfiguration cf = config.build(p.name().toLowerCase(), params.start.hasBearing() ?
|
RoutingConfiguration cf = config.build(p.name().toLowerCase(), params.start.hasBearing() ?
|
||||||
params.start.getBearing() / 180d * Math.PI : null,
|
params.start.getBearing() / 180d * Math.PI : null,
|
||||||
memoryLimit, paramsR);
|
memoryLimit, paramsR);
|
||||||
boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get();
|
return cf;
|
||||||
RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
|
}
|
||||||
RouteCalculationMode.NORMAL);
|
|
||||||
RoutingContext complexCtx = null;
|
|
||||||
if(complex) {
|
|
||||||
complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files,
|
|
||||||
RouteCalculationMode.COMPLEX);
|
private RouteCalculationResult calcOfflineRouteImpl(final RouteCalculationParams params,
|
||||||
complexCtx.calculationProgress = params.calculationProgress;
|
RoutePlannerFrontEnd router, RoutingContext ctx, RoutingContext complexCtx, LatLon st, LatLon en,
|
||||||
}
|
List<LatLon> inters, PrecalculatedRouteDirection precalculated) throws IOException {
|
||||||
ctx.leftSideNavigation = params.leftSide;
|
|
||||||
ctx.calculationProgress = params.calculationProgress;
|
|
||||||
if(params.previousToRecalculate != null) {
|
|
||||||
// not used any more
|
|
||||||
// ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute();
|
|
||||||
}
|
|
||||||
LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude());
|
|
||||||
LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude());
|
|
||||||
List<LatLon> inters = new ArrayList<LatLon>();
|
|
||||||
if (params.intermediates != null) {
|
|
||||||
inters = new ArrayList<LatLon>(params.intermediates);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
List<RouteSegmentResult> result ;
|
List<RouteSegmentResult> result ;
|
||||||
if(complexCtx != null) {
|
if(complexCtx != null) {
|
||||||
try {
|
try {
|
||||||
result = router.searchRoute(complexCtx, st, en, inters);
|
result = router.searchRoute(complexCtx, st, en, inters, precalculated);
|
||||||
// discard ctx and replace with calculated
|
// discard ctx and replace with calculated
|
||||||
ctx = complexCtx;
|
ctx = complexCtx;
|
||||||
} catch(final RuntimeException e) {
|
} catch(final RuntimeException e) {
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class DownloadedRegionsLayer extends OsmandMapLayer {
|
||||||
int right = MapUtils.get31TileNumberX(tileBox.getRightBottomLatLon().getLongitude());
|
int right = MapUtils.get31TileNumberX(tileBox.getRightBottomLatLon().getLongitude());
|
||||||
int top = MapUtils.get31TileNumberY(tileBox.getLeftTopLatLon().getLatitude());
|
int top = MapUtils.get31TileNumberY(tileBox.getLeftTopLatLon().getLatitude());
|
||||||
int bottom = MapUtils.get31TileNumberY(tileBox.getRightBottomLatLon().getLatitude());
|
int bottom = MapUtils.get31TileNumberY(tileBox.getRightBottomLatLon().getLatitude());
|
||||||
final boolean empty = rm.getRenderer().checkIfMapIsEmpty(left, right, top, bottom, tileBox.getZoom());
|
final boolean empty = rm.getRenderer().isLastMapRenderedEmpty(false);
|
||||||
noMapsPresent = empty;
|
noMapsPresent = empty;
|
||||||
if (!empty && tileBox.getZoom() >= ZOOM_TO_SHOW_MAP_NAMES) {
|
if (!empty && tileBox.getZoom() >= ZOOM_TO_SHOW_MAP_NAMES) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
|
@ -393,7 +393,7 @@ public class MapControlsLayer extends OsmandMapLayer {
|
||||||
final AlertDialog.Builder bld = new AlertDialog.Builder(view.getContext());
|
final AlertDialog.Builder bld = new AlertDialog.Builder(view.getContext());
|
||||||
float scale = view.getZoomScale();
|
float scale = view.getZoomScale();
|
||||||
int p = (int) ((scale > 0 ? 1 : -1) * Math.round(scale * scale * 100)) + 100;
|
int p = (int) ((scale > 0 ? 1 : -1) * Math.round(scale * scale * 100)) + 100;
|
||||||
final TIntArrayList tlist = new TIntArrayList(new int[] { 75, 100, 150, 200, 300, 400 });
|
final TIntArrayList tlist = new TIntArrayList(new int[] { 75, 100, 150, 200, 300, 400, 500 });
|
||||||
final List<String> values = new ArrayList<String>();
|
final List<String> values = new ArrayList<String>();
|
||||||
int i = -1;
|
int i = -1;
|
||||||
for (int k = 0; k <= tlist.size(); k++) {
|
for (int k = 0; k <= tlist.size(); k++) {
|
||||||
|
|