Fix #3225 - fix moving arrows
This commit is contained in:
parent
6a0a5f1dd2
commit
d77ff5290d
3 changed files with 115 additions and 104 deletions
|
@ -638,6 +638,13 @@ public class RouteCalculationResult {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRouteDistanceToFinish(int posFromCurrentIndex) {
|
||||||
|
if(listDistance != null && currentRoute + posFromCurrentIndex < listDistance.length){
|
||||||
|
return listDistance[currentRoute + posFromCurrentIndex];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public RouteSegmentResult getCurrentSegmentResult() {
|
public RouteSegmentResult getCurrentSegmentResult() {
|
||||||
int cs = currentRoute > 0 ? currentRoute - 1 : 0;
|
int cs = currentRoute > 0 ? currentRoute - 1 : 0;
|
||||||
if(cs < segments.size()) {
|
if(cs < segments.size()) {
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
package net.osmand.plus.views;
|
package net.osmand.plus.views;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import gnu.trove.list.array.TIntArrayList;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.ColorFilter;
|
import java.util.ArrayList;
|
||||||
import android.graphics.Paint;
|
import java.util.Arrays;
|
||||||
import android.graphics.Path;
|
import java.util.List;
|
||||||
import android.graphics.PointF;
|
import java.util.Map;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
|
||||||
import android.graphics.Paint.Cap;
|
|
||||||
import android.graphics.Paint.Join;
|
|
||||||
import android.graphics.Paint.Style;
|
|
||||||
import android.graphics.PorterDuff.Mode;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.QuadTree;
|
import net.osmand.data.QuadTree;
|
||||||
|
@ -26,13 +19,20 @@ import net.osmand.plus.render.OsmandRenderer.RenderingContext;
|
||||||
import net.osmand.render.RenderingRuleSearchRequest;
|
import net.osmand.render.RenderingRuleSearchRequest;
|
||||||
import net.osmand.render.RenderingRulesStorage;
|
import net.osmand.render.RenderingRulesStorage;
|
||||||
import net.osmand.util.MapAlgorithms;
|
import net.osmand.util.MapAlgorithms;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import java.util.ArrayList;
|
import android.graphics.Color;
|
||||||
import java.util.Arrays;
|
import android.graphics.ColorFilter;
|
||||||
import java.util.List;
|
import android.graphics.Paint;
|
||||||
import java.util.Map;
|
import android.graphics.Paint.Cap;
|
||||||
|
import android.graphics.Paint.Join;
|
||||||
import gnu.trove.list.array.TIntArrayList;
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.PorterDuff.Mode;
|
||||||
|
import android.graphics.PorterDuffColorFilter;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
public abstract class OsmandMapLayer {
|
public abstract class OsmandMapLayer {
|
||||||
|
|
||||||
|
@ -118,49 +118,11 @@ public abstract class OsmandMapLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isIn(int x, int y, int lx, int ty, int rx, int by) {
|
protected boolean isIn(int x, int y, int lx, int ty, int rx, int by) {
|
||||||
return x >= lx && x <= rx && y >= ty && y <= by;
|
return x >= lx && x <= rx && y >= ty && y <= by;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int calculateSplitPaths(RotatedTileBox tb, TIntArrayList xs, TIntArrayList ys,
|
|
||||||
TIntArrayList results) {
|
|
||||||
int px = xs.get(0);
|
|
||||||
int py = ys.get(0);
|
|
||||||
int h = tb.getPixHeight();
|
|
||||||
int w = tb.getPixWidth();
|
|
||||||
int left = -w / 4;
|
|
||||||
int right = w + w / 4;
|
|
||||||
int top = - h/4;
|
|
||||||
int bottom = h + h/4;
|
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
boolean pin = isIn(px, py, left, top, right, bottom);
|
|
||||||
for (int i = 1; i < xs.size(); i++) {
|
|
||||||
int x = xs.get(i);
|
|
||||||
int y = ys.get(i);
|
|
||||||
boolean in = isIn(x, y, left, top, right, bottom);
|
|
||||||
boolean draw = false;
|
|
||||||
if (pin && in) {
|
|
||||||
draw = true;
|
|
||||||
} else {
|
|
||||||
long intersection = MapAlgorithms.calculateIntersection(x, y,
|
|
||||||
px, py, left, right, bottom, top);
|
|
||||||
if (intersection != -1) {
|
|
||||||
draw = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (draw) {
|
|
||||||
results.add(px);
|
|
||||||
results.add(py);
|
|
||||||
results.add(x);
|
|
||||||
results.add(y);
|
|
||||||
}
|
|
||||||
pin = in;
|
|
||||||
px = x;
|
|
||||||
py = y;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int calculatePath(RotatedTileBox tb, TIntArrayList xs, TIntArrayList ys, Path path) {
|
public int calculatePath(RotatedTileBox tb, TIntArrayList xs, TIntArrayList ys, Path path) {
|
||||||
boolean start = false;
|
boolean start = false;
|
||||||
|
|
|
@ -1,33 +1,26 @@
|
||||||
package net.osmand.plus.views;
|
package net.osmand.plus.views;
|
||||||
|
|
||||||
|
import gnu.trove.list.array.TByteArrayList;
|
||||||
import gnu.trove.list.array.TIntArrayList;
|
import gnu.trove.list.array.TIntArrayList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.render.OsmandRenderer;
|
|
||||||
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
|
|
||||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||||
import net.osmand.plus.routing.RoutingHelper;
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
import net.osmand.render.RenderingRuleSearchRequest;
|
import net.osmand.util.MapUtils;
|
||||||
import net.osmand.render.RenderingRulesStorage;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.ColorFilter;
|
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Cap;
|
import android.graphics.Paint.Cap;
|
||||||
import android.graphics.Paint.Join;
|
|
||||||
import android.graphics.Paint.Style;
|
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.PorterDuff.Mode;
|
import android.graphics.PorterDuff.Mode;
|
||||||
|
@ -35,11 +28,15 @@ import android.graphics.PorterDuffColorFilter;
|
||||||
|
|
||||||
public class RouteLayer extends OsmandMapLayer {
|
public class RouteLayer extends OsmandMapLayer {
|
||||||
|
|
||||||
|
private static final float EPSILON_IN_DPI = 4;
|
||||||
|
|
||||||
private OsmandMapTileView view;
|
private OsmandMapTileView view;
|
||||||
|
|
||||||
private final RoutingHelper helper;
|
private final RoutingHelper helper;
|
||||||
|
// keep array lists created
|
||||||
private List<Location> points = new ArrayList<Location>();
|
private List<Location> points = new ArrayList<Location>();
|
||||||
private List<Location> actionPoints = new ArrayList<Location>();
|
private List<Location> actionPoints = new ArrayList<Location>();
|
||||||
|
private TByteArrayList simplifyPoints = new TByteArrayList();
|
||||||
|
|
||||||
private Path path;
|
private Path path;
|
||||||
|
|
||||||
|
@ -181,10 +178,41 @@ public class RouteLayer extends OsmandMapLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cullRamerDouglasPeucker(TByteArrayList survivor, List<Location> points,
|
||||||
|
int start, int end, double epsillon) {
|
||||||
|
double dmax = Double.NEGATIVE_INFINITY;
|
||||||
|
int index = -1;
|
||||||
|
Location startPt = points.get(start);
|
||||||
|
Location endPt = points.get(end);
|
||||||
|
|
||||||
private void drawSegment(RotatedTileBox tb, Canvas canvas) {
|
for (int i = start + 1; i < end; i++) {
|
||||||
if (points.size() > 0) {
|
Location pt = points.get(i);
|
||||||
|
double d = MapUtils.getOrthogonalDistance(pt.getLatitude(), pt.getLongitude(),
|
||||||
|
startPt.getLatitude(), startPt.getLongitude(), endPt.getLatitude(), endPt.getLongitude());
|
||||||
|
if (d > dmax) {
|
||||||
|
dmax = d;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dmax > epsillon) {
|
||||||
|
cullRamerDouglasPeucker(survivor, points, start, index, epsillon);
|
||||||
|
cullRamerDouglasPeucker(survivor, points, index, end, epsillon);
|
||||||
|
} else {
|
||||||
|
survivor.set(end, (byte) 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawSegment(List<Location> points, RotatedTileBox tb, Canvas canvas, int distToFinish) {
|
||||||
|
if (points.size() > 1) {
|
||||||
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
|
double distInPix = (tb.getDistance(0, 0, tb.getPixWidth(), 0) / tb.getPixWidth());
|
||||||
|
double cullDistance = (distInPix * (EPSILON_IN_DPI * Math.max(1, tb.getDensity())));
|
||||||
|
double distPixToFinish = distInPix * distToFinish;
|
||||||
|
simplifyPoints.resetQuick();
|
||||||
|
simplifyPoints.fill(0, points.size(), (byte) 0);
|
||||||
|
simplifyPoints.set(0, (byte) 1);
|
||||||
|
cullRamerDouglasPeucker(simplifyPoints, points, 0, points.size() - 1, cullDistance);
|
||||||
try {
|
try {
|
||||||
TIntArrayList tx = new TIntArrayList();
|
TIntArrayList tx = new TIntArrayList();
|
||||||
TIntArrayList ty = new TIntArrayList();
|
TIntArrayList ty = new TIntArrayList();
|
||||||
|
@ -192,15 +220,17 @@ public class RouteLayer extends OsmandMapLayer {
|
||||||
Location o = points.get(i);
|
Location o = points.get(i);
|
||||||
int x = (int) tb.getPixXFromLatLon(o.getLatitude(), o.getLongitude());
|
int x = (int) tb.getPixXFromLatLon(o.getLatitude(), o.getLongitude());
|
||||||
int y = (int) tb.getPixYFromLatLon(o.getLatitude(), o.getLongitude());
|
int y = (int) tb.getPixYFromLatLon(o.getLatitude(), o.getLongitude());
|
||||||
tx.add(x);
|
if(simplifyPoints.get(i) > 0) {
|
||||||
ty.add(y);
|
tx.add(x);
|
||||||
|
ty.add(y);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatePath(tb, tx, ty, path);
|
calculatePath(tb, tx, ty, path);
|
||||||
attrs.drawPath(canvas, path);
|
attrs.drawPath(canvas, path);
|
||||||
if (tb.getZoomAnimation() == 0) {
|
if (tb.getZoomAnimation() == 0) {
|
||||||
TIntArrayList lst = new TIntArrayList(50);
|
drawArrowsOverPath(canvas, tb, tx, ty, coloredArrowUp, distPixToFinish);
|
||||||
calculateSplitPaths(tb, tx, ty, lst);
|
|
||||||
drawArrowsOverPath(canvas, lst, coloredArrowUp);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
|
@ -209,44 +239,53 @@ public class RouteLayer extends OsmandMapLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void drawArrowsOverPath(Canvas canvas, TIntArrayList lst, Bitmap arrow) {
|
|
||||||
|
|
||||||
|
private void drawArrowsOverPath(Canvas canvas, RotatedTileBox tb, TIntArrayList tx, TIntArrayList ty, Bitmap arrow, double distPixToFinish) {
|
||||||
|
int h = tb.getPixHeight();
|
||||||
|
int w = tb.getPixWidth();
|
||||||
|
int left = -w / 4;
|
||||||
|
int right = w + w / 4;
|
||||||
|
int top = - h/4;
|
||||||
|
int bottom = h + h/4;
|
||||||
|
|
||||||
double pxStep = arrow.getHeight() * 4f;
|
double pxStep = arrow.getHeight() * 4f;
|
||||||
Matrix matrix = new Matrix();
|
Matrix matrix = new Matrix();
|
||||||
double dist = 0;
|
double dist = 0;
|
||||||
for (int i = 0; i < lst.size(); i += 4) {
|
if(distPixToFinish != 0) {
|
||||||
int px = lst.get(i);
|
dist = distPixToFinish - pxStep * ((int) (distPixToFinish / pxStep)); // dist < 1
|
||||||
int py = lst.get(i + 1);
|
}
|
||||||
int x = lst.get(i + 2);
|
|
||||||
int y = lst.get(i + 3);
|
for (int i = tx.size() - 2; i >= 0; i --) {
|
||||||
|
int px = tx.get(i);
|
||||||
|
int py = ty.get(i);
|
||||||
|
int x = tx.get(i + 1);
|
||||||
|
int y = ty.get(i + 1);
|
||||||
double angleRad = Math.atan2(y - py, x - px);
|
double angleRad = Math.atan2(y - py, x - px);
|
||||||
double angle = (angleRad * 180 / Math.PI) + 90f;
|
double angle = (angleRad * 180 / Math.PI) + 90f;
|
||||||
double distSegment = Math.sqrt((y - py) * (y - py) + (x - px) * (x - px));
|
double distSegment = Math.sqrt((y - py) * (y - py) + (x - px) * (x - px));
|
||||||
if(distSegment == 0) {
|
if(distSegment == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int len = (int) (distSegment / pxStep);
|
if(dist >= pxStep) {
|
||||||
if (len > 0) {
|
dist = 0; // unnecessary but double check to avoid errors
|
||||||
double pdx = ((x - px) / len);
|
}
|
||||||
double pdy = ((y - py) / len);
|
double percent = 1 - (pxStep - dist) / distSegment;
|
||||||
for (int k = 1; k <= len; k++) {
|
dist += distSegment;
|
||||||
|
while(dist >= pxStep) {
|
||||||
|
double pdx = (x - px) * percent;
|
||||||
|
double pdy = (y - py) * percent;
|
||||||
|
if (isIn((int)(px + pdx), (int) (py + pdy), left, top, right, bottom)) {
|
||||||
|
float icony = (float) (py + pdy);
|
||||||
|
float iconx = (float) (px + pdx - arrow.getWidth() / 2);
|
||||||
matrix.reset();
|
matrix.reset();
|
||||||
matrix.postTranslate(0, -arrow.getHeight() / 2);
|
matrix.postTranslate(0, -arrow.getHeight() / 2);
|
||||||
matrix.postRotate((float) angle, arrow.getWidth() / 2, 0);
|
matrix.postRotate((float) angle, arrow.getWidth() / 2, 0);
|
||||||
matrix.postTranslate((float)(px + k * pdx- arrow.getWidth() / 2) , (float)(py + pdy * k));
|
matrix.postTranslate(iconx, icony);
|
||||||
canvas.drawBitmap(arrow, matrix, paintIcon);
|
canvas.drawBitmap(arrow, matrix, paintIcon);
|
||||||
dist = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(dist > pxStep) {
|
|
||||||
matrix.reset();
|
|
||||||
matrix.postTranslate(0, -arrow.getHeight() / 2);
|
|
||||||
matrix.postRotate((float) angle, arrow.getWidth() / 2, 0);
|
|
||||||
matrix.postTranslate(px + (x - px) / 2 - arrow.getWidth() / 2, py + (y - py) / 2);
|
|
||||||
canvas.drawBitmap(arrow, matrix, paintIcon);
|
|
||||||
dist = 0;
|
|
||||||
} else {
|
|
||||||
dist += distSegment;
|
|
||||||
}
|
}
|
||||||
|
dist -= pxStep;
|
||||||
|
percent -= pxStep / distSegment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,12 +306,14 @@ public class RouteLayer extends OsmandMapLayer {
|
||||||
int cd = helper.getRoute().getCurrentRoute();
|
int cd = helper.getRoute().getCurrentRoute();
|
||||||
List<RouteDirectionInfo> rd = helper.getRouteDirections();
|
List<RouteDirectionInfo> rd = helper.getRouteDirections();
|
||||||
Iterator<RouteDirectionInfo> it = rd.iterator();
|
Iterator<RouteDirectionInfo> it = rd.iterator();
|
||||||
|
int distToFinish = 0;
|
||||||
for (int i = 0; i < routeNodes.size(); i++) {
|
for (int i = 0; i < routeNodes.size(); i++) {
|
||||||
Location ls = routeNodes.get(i);
|
Location ls = routeNodes.get(i);
|
||||||
|
int dd = helper.getRoute().getRouteDistanceToFinish(i);
|
||||||
if (leftLongitude <= ls.getLongitude() && ls.getLongitude() <= rightLongitude && bottomLatitude <= ls.getLatitude()
|
if (leftLongitude <= ls.getLongitude() && ls.getLongitude() <= rightLongitude && bottomLatitude <= ls.getLatitude()
|
||||||
&& ls.getLatitude() <= topLatitude) {
|
&& ls.getLatitude() <= topLatitude) {
|
||||||
points.add(ls);
|
points.add(ls);
|
||||||
|
distToFinish = dd;
|
||||||
if (!previousVisible) {
|
if (!previousVisible) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
points.add(0, routeNodes.get(i - 1));
|
points.add(0, routeNodes.get(i - 1));
|
||||||
|
@ -283,12 +324,13 @@ public class RouteLayer extends OsmandMapLayer {
|
||||||
previousVisible = true;
|
previousVisible = true;
|
||||||
} else if (previousVisible) {
|
} else if (previousVisible) {
|
||||||
points.add(ls);
|
points.add(ls);
|
||||||
drawSegment(tb, canvas);
|
distToFinish = dd;
|
||||||
|
drawSegment(points, tb, canvas, distToFinish);
|
||||||
previousVisible = false;
|
previousVisible = false;
|
||||||
points.clear();
|
points.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawSegment(tb, canvas);
|
drawSegment(points, tb, canvas, distToFinish);
|
||||||
if (tb.getZoom() >= 14) {
|
if (tb.getZoom() >= 14) {
|
||||||
calculateActionPoints(topLatitude, leftLongitude, bottomLatitude, rightLongitude, lastProjection,
|
calculateActionPoints(topLatitude, leftLongitude, bottomLatitude, rightLongitude, lastProjection,
|
||||||
routeNodes, cd, it, tb.getZoom());
|
routeNodes, cd, it, tb.getZoom());
|
||||||
|
|
Loading…
Reference in a new issue