Update route layer

This commit is contained in:
Victor Shcherb 2016-07-29 14:29:22 +02:00
parent a681af7753
commit d2a982398b
3 changed files with 159 additions and 100 deletions

View file

@ -369,17 +369,14 @@ public class GPXLayer extends OsmandMapLayer implements ContextMenuLayer.IContex
for (SelectedGpxFile g : selectedGPXFiles) { for (SelectedGpxFile g : selectedGPXFiles) {
List<TrkSegment> segments = g.getPointsToDisplay(); List<TrkSegment> segments = g.getPointsToDisplay();
for (TrkSegment ts : segments) { for (TrkSegment ts : segments) {
if (ts.renders.isEmpty() // only do once (CODE HERE NEEDS TO BE UI INSTEAD) if (ts.renders.isEmpty() // only do once (CODE HERE NEEDS TO BE UI INSTEAD)
&& !ts.points.isEmpty()) { // hmmm. 0-point tracks happen, but.... how? && !ts.points.isEmpty()) { // hmmm. 0-point tracks happen, but.... how?
if (g.isShowCurrentTrack()) { if (g.isShowCurrentTrack()) {
ts.renders.add(new Renderable.CurrentTrack(ts.points)); ts.renders.add(new Renderable.CurrentTrack(ts.points));
} else { } else {
ts.renders.add(new Renderable.StandardTrack(ts.points, 17.2)); ts.renders.add(new Renderable.StandardTrack(ts.points, 17.2));
} }
} }
updatePaints(ts.getColor(cachedColor), g.isRoutePoints(), g.isShowCurrentTrack(), settings, tileBox); updatePaints(ts.getColor(cachedColor), g.isRoutePoints(), g.isShowCurrentTrack(), settings, tileBox);
ts.drawRenderers(view.getZoom(), paint, canvas, tileBox); ts.drawRenderers(view.getZoom(), paint, canvas, tileBox);
} }

View file

@ -1,21 +1,33 @@
package net.osmand.plus.views; package net.osmand.plus.views;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.PointF; import android.graphics.PointF;
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.os.AsyncTask;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.view.MotionEvent; 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;
import net.osmand.data.RotatedTileBox; import net.osmand.data.RotatedTileBox;
import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.render.OsmandRenderer;
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
import net.osmand.render.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage;
import net.osmand.util.MapAlgorithms; import net.osmand.util.MapAlgorithms;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -115,25 +127,28 @@ public abstract class OsmandMapLayer {
int py = ys.get(0); int py = ys.get(0);
int h = tb.getPixHeight(); int h = tb.getPixHeight();
int w = tb.getPixWidth(); 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; int cnt = 0;
boolean pin = isIn(px, py, 0, 0, w, h);
Path path = null; boolean pin = isIn(px, py, left, top, right, bottom);
for (int i = 1; i < xs.size(); i++) { for (int i = 1; i < xs.size(); i++) {
int x = xs.get(i); int x = xs.get(i);
int y = ys.get(i); int y = ys.get(i);
boolean in = isIn(x, y, 0, 0, w, h); boolean in = isIn(x, y, left, top, right, bottom);
boolean draw = false; boolean draw = false;
if (pin && in) { if (pin && in) {
draw = true; draw = true;
} else { } else {
long intersection = MapAlgorithms.calculateIntersection(x, y, long intersection = MapAlgorithms.calculateIntersection(x, y,
px, py, 0, w, h, 0); px, py, left, right, bottom, top);
if (intersection != -1) { if (intersection != -1) {
draw = true; draw = true;
} }
} }
if (draw) { if (draw) {
path = new Path();
results.add(px); results.add(px);
results.add(py); results.add(py);
results.add(x); results.add(x);
@ -323,4 +338,115 @@ public abstract class OsmandMapLayer {
} }
protected static class RenderingLineAttributes {
protected int cachedHash;
public Paint paint;
public int defaultWidth = 0;
public int defaultColor = 0;
public boolean isPaint2;
public Paint paint2;
public int defaultWidth2 = 0;
public boolean isPaint3;
public Paint paint3;
public int defaultWidth3 = 0;
public Paint shadowPaint;
public boolean isShadowPaint;
public int defaultShadowWidthExtent = 2;
public Paint paint_1;
public boolean isPaint_1;
public int defaultWidth_1 = 0;
private String renderingAttribute;
public RenderingLineAttributes(String renderingAttribute) {
this.renderingAttribute = renderingAttribute;
paint = initPaint();
paint2 = initPaint();
paint3 = initPaint();
paint_1 = initPaint();
shadowPaint = initPaint();
}
private Paint initPaint() {
Paint paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
paint.setStrokeJoin(Join.ROUND);
return paint;
}
public boolean updatePaints(OsmandMapTileView view, DrawSettings settigns, RotatedTileBox tileBox) {
OsmandApplication app = view.getApplication();
OsmandRenderer renderer = app.getResourceManager().getRenderer().getRenderer();
RenderingRulesStorage rrs = app.getRendererRegistry().getCurrentSelectedRenderer();
final boolean isNight = settigns != null && settigns.isNightMode();
int hsh = calculateHash(rrs, isNight, tileBox.getMapDensity());
if (hsh != cachedHash) {
cachedHash = hsh;
if (rrs != null) {
RenderingRuleSearchRequest req = new RenderingRuleSearchRequest(rrs);
req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, isNight);
if (req.searchRenderingAttribute(renderingAttribute)) {
RenderingContext rc = new OsmandRenderer.RenderingContext(app);
rc.setDensityValue((float) tileBox.getMapDensity());
// cachedColor = req.getIntPropertyValue(rrs.PROPS.R_COLOR);
renderer.updatePaint(req, paint, 0, false, rc);
if(paint.getColor() == 0 && defaultColor != 0) {
paint.setColor(defaultColor);
}
if (paint.getStrokeWidth() == 0 && defaultWidth != 0) {
paint.setStrokeWidth(defaultWidth);
}
isPaint2 = renderer.updatePaint(req, paint2, 1, false, rc);
if (paint2.getStrokeWidth() == 0 && defaultWidth2 != 0) {
paint2.setStrokeWidth(defaultWidth2);
}
isPaint3 = renderer.updatePaint(req, paint3, 2, false, rc);
if (paint3.getStrokeWidth() == 0 && defaultWidth3 != 0) {
paint3.setStrokeWidth(defaultWidth3);
}
isPaint_1 = renderer.updatePaint(req, paint_1, -1, false, rc);
if (paint_1.getStrokeWidth() == 0 && defaultWidth_1 != 0) {
paint_1.setStrokeWidth(defaultWidth_1);
}
isShadowPaint = req.isSpecified(rrs.PROPS.R_SHADOW_RADIUS);
if (isShadowPaint) {
ColorFilter cf = new PorterDuffColorFilter(
req.getIntPropertyValue(rrs.PROPS.R_SHADOW_COLOR), Mode.SRC_IN);
shadowPaint.setColorFilter(cf);
shadowPaint.setStrokeWidth(paint.getStrokeWidth() + defaultShadowWidthExtent
* rc.getComplexValue(req, rrs.PROPS.R_SHADOW_RADIUS));
}
} else {
System.err.println("Rendering attribute route is not found !");
paint.setStrokeWidth(defaultWidth);
}
}
return true;
}
return false;
}
private int calculateHash(Object... o) {
return Arrays.hashCode(o);
}
public void drawPath(Canvas canvas, Path path) {
if (isPaint_1) {
canvas.drawPath(path, paint_1);
}
if (isShadowPaint) {
canvas.drawPath(path, shadowPaint);
}
canvas.drawPath(path, paint);
if (isPaint2) {
canvas.drawPath(path, paint2);
}
if (isPaint3) {
canvas.drawPath(path, paint3);
}
}
}
} }

View file

@ -10,6 +10,7 @@ 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;
import net.osmand.plus.render.OsmandRenderer.RenderingContext; import net.osmand.plus.render.OsmandRenderer.RenderingContext;
@ -39,15 +40,6 @@ public class RouteLayer extends OsmandMapLayer {
private final RoutingHelper helper; private final RoutingHelper helper;
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 Paint paint;
private Paint actionPaint;
private Paint paint2;
private boolean isPaint2;
private Paint shadowPaint;
private boolean isShadowPaint;
private Paint paint_1;
private boolean isPaint_1;
private int cachedHash;
private Path path; private Path path;
@ -58,7 +50,7 @@ public class RouteLayer extends OsmandMapLayer {
private Paint paintIcon; private Paint paintIcon;
private Paint paintIconAction; private Paint paintIconAction;
private OsmandRenderer osmandRenderer; private RenderingLineAttributes attrs;
public RouteLayer(RoutingHelper helper){ public RouteLayer(RoutingHelper helper){
@ -67,20 +59,7 @@ public class RouteLayer extends OsmandMapLayer {
private void initUI() { private void initUI() {
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
paint.setStrokeJoin(Join.ROUND);
actionArrow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_action_arrow, null); actionArrow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_action_arrow, null);
actionPaint = new Paint();
actionPaint.setStyle(Style.STROKE);
actionPaint.setAntiAlias(true);
actionPaint.setStrokeCap(Cap.BUTT);
actionPaint.setStrokeJoin(Join.ROUND);
actionPaint.setStrokeWidth(7 * view.getScaleCoefficient());
actionPaint.setColor(Color.WHITE);
path = new Path(); path = new Path();
paintIcon = new Paint(); paintIcon = new Paint();
@ -89,72 +68,39 @@ public class RouteLayer extends OsmandMapLayer {
paintIcon.setColor(Color.BLACK); paintIcon.setColor(Color.BLACK);
paintIcon.setStrokeWidth(3); paintIcon.setStrokeWidth(3);
paintIconAction = new Paint(); paintIconAction = new Paint();
paintIconAction.setFilterBitmap(true); paintIconAction.setFilterBitmap(true);
paintIconAction.setAntiAlias(true); paintIconAction.setAntiAlias(true);
attrs = new RenderingLineAttributes("route");
attrs.defaultWidth = (int) (12 * view.getDensity());
attrs.defaultWidth3 = (int) (7 * view.getDensity());
attrs.defaultColor = view.getResources().getColor(R.color.nav_track);
attrs.paint3.setStrokeCap(Cap.BUTT);
attrs.paint3.setColor(Color.WHITE);
} }
@Override @Override
public void initLayer(OsmandMapTileView view) { public void initLayer(OsmandMapTileView view) {
this.view = view; this.view = view;
osmandRenderer = view.getApplication().getResourceManager().getRenderer().getRenderer();
initUI(); initUI();
} }
public void updateLayerStyle() { public void updateLayerStyle() {
cachedHash = -1; attrs.cachedHash = -1;
} }
private void updatePaints(DrawSettings nightMode, RotatedTileBox tileBox){
RenderingRulesStorage rrs = view.getApplication().getRendererRegistry().getCurrentSelectedRenderer();
final boolean isNight = nightMode != null && nightMode.isNightMode();
int hsh = calculateHash(rrs, isNight, tileBox.getMapDensity());
if (hsh != cachedHash) {
cachedHash = hsh;
// cachedColor = view.getResources().getColor(R.color.nav_track);
if (rrs != null) {
RenderingRuleSearchRequest req = new RenderingRuleSearchRequest(rrs);
req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, isNight);
if (req.searchRenderingAttribute("route")) {
RenderingContext rc = new OsmandRenderer.RenderingContext(view.getContext());
rc.setDensityValue((float) tileBox.getMapDensity());
// cachedColor = req.getIntPropertyValue(rrs.PROPS.R_COLOR);
osmandRenderer.updatePaint(req, paint, 0, false, rc);
if(paint.getStrokeWidth() == 0) {
paint.setStrokeWidth(12 * view.getDensity());
}
osmandRenderer.updatePaint(req, actionPaint, 2, false, rc);
paintIconAction.setColorFilter(new PorterDuffColorFilter(actionPaint.getColor(), Mode.MULTIPLY));
isPaint2 = osmandRenderer.updatePaint(req, paint2, 1, false, rc);
isPaint_1 = osmandRenderer.updatePaint(req, paint_1, -1, false, rc);
isShadowPaint = req.isSpecified(rrs.PROPS.R_SHADOW_RADIUS);
if(isShadowPaint) {
ColorFilter cf = new PorterDuffColorFilter(req.getIntPropertyValue(rrs.PROPS.R_SHADOW_COLOR), Mode.SRC_IN);
shadowPaint.setColorFilter(cf);
shadowPaint.setStrokeWidth(paint.getStrokeWidth() + 2 * rc.getComplexValue(req, rrs.PROPS.R_SHADOW_RADIUS));
}
} else {
System.err.println("Rendering attribute route is not found !");
paint.setStrokeWidth(12 * view.getDensity());
}
actionPaint.setStrokeWidth(7 * view.getScaleCoefficient());
}
}
}
private int calculateHash(Object... o) {
return Arrays.hashCode(o);
}
@Override @Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
path.reset(); path.reset();
if (helper.getFinalLocation() != null && helper.getRoute().isCalculated()) { if (helper.getFinalLocation() != null && helper.getRoute().isCalculated()) {
updatePaints(settings, tileBox); boolean updatePaints = attrs.updatePaints(view, settings, tileBox);
attrs.isPaint3 = false;
if(updatePaints) {
paintIconAction.setColorFilter(new PorterDuffColorFilter(attrs.paint3.getColor(), Mode.MULTIPLY));
}
if(coloredArrowUp == null) { if(coloredArrowUp == null) {
Bitmap originalArrowUp = BitmapFactory.decodeResource(view.getResources(), R.drawable.h_arrow, null); Bitmap originalArrowUp = BitmapFactory.decodeResource(view.getResources(), R.drawable.h_arrow, null);
coloredArrowUp = originalArrowUp; coloredArrowUp = originalArrowUp;
@ -200,7 +146,7 @@ public class RouteLayer extends OsmandMapLayer {
Location o = actionPoints.get(i); Location o = actionPoints.get(i);
if (o == null) { if (o == null) {
first = true; first = true;
canvas.drawPath(pth, actionPaint); canvas.drawPath(pth, attrs.paint3);
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));
@ -250,17 +196,7 @@ public class RouteLayer extends OsmandMapLayer {
ty.add(y); ty.add(y);
} }
calculatePath(tb, tx, ty, path); calculatePath(tb, tx, ty, path);
attrs.drawPath(canvas, path);
if (isPaint_1) {
canvas.drawPath(path, paint_1);
}
if (isShadowPaint) {
canvas.drawPath(path, shadowPaint);
}
canvas.drawPath(path, paint);
if (isPaint2) {
canvas.drawPath(path, paint2);
}
if (tb.getZoomAnimation() == 0) { if (tb.getZoomAnimation() == 0) {
TIntArrayList lst = new TIntArrayList(50); TIntArrayList lst = new TIntArrayList(50);
calculateSplitPaths(tb, tx, ty, lst); calculateSplitPaths(tb, tx, ty, lst);
@ -274,29 +210,29 @@ public class RouteLayer extends OsmandMapLayer {
private void drawArrowsOverPath(Canvas canvas, TIntArrayList lst, Bitmap arrow) { private void drawArrowsOverPath(Canvas canvas, TIntArrayList lst, Bitmap arrow) {
float pxStep = arrow.getHeight() * 4f; double pxStep = arrow.getHeight() * 4f;
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
float dist = 0; double dist = 0;
for (int i = 0; i < lst.size(); i += 4) { for (int i = 0; i < lst.size(); i += 4) {
int px = lst.get(i); int px = lst.get(i);
int py = lst.get(i + 1); int py = lst.get(i + 1);
int x = lst.get(i + 2); int x = lst.get(i + 2);
int y = lst.get(i + 3); int y = lst.get(i + 3);
float angleRad = (float) Math.atan2(y - py, x - px); double angleRad = Math.atan2(y - py, x - px);
float angle = (float) (angleRad * 180 / Math.PI) + 90f; double angle = (angleRad * 180 / Math.PI) + 90f;
float distSegment = (float) 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); int len = (int) (distSegment / pxStep);
if (len > 0) { if (len > 0) {
float pdx = ((x - px) / len); double pdx = ((x - px) / len);
float pdy = ((y - py) / len); double pdy = ((y - py) / len);
for (int k = 1; k <= len; k++) { for (int k = 1; k <= len; k++) {
matrix.reset(); matrix.reset();
matrix.postTranslate(0, -arrow.getHeight() / 2); matrix.postTranslate(0, -arrow.getHeight() / 2);
matrix.postRotate(angle, arrow.getWidth() / 2, 0); matrix.postRotate((float) angle, arrow.getWidth() / 2, 0);
matrix.postTranslate(px + k * pdx- arrow.getWidth() / 2 , py + pdy * k); matrix.postTranslate((float)(px + k * pdx- arrow.getWidth() / 2) , (float)(py + pdy * k));
canvas.drawBitmap(arrow, matrix, paintIcon); canvas.drawBitmap(arrow, matrix, paintIcon);
dist = 0; dist = 0;
} }
@ -304,7 +240,7 @@ public class RouteLayer extends OsmandMapLayer {
if(dist > pxStep) { if(dist > pxStep) {
matrix.reset(); matrix.reset();
matrix.postTranslate(0, -arrow.getHeight() / 2); matrix.postTranslate(0, -arrow.getHeight() / 2);
matrix.postRotate(angle, arrow.getWidth() / 2, 0); matrix.postRotate((float) angle, arrow.getWidth() / 2, 0);
matrix.postTranslate(px + (x - px) / 2 - arrow.getWidth() / 2, py + (y - py) / 2); matrix.postTranslate(px + (x - px) / 2 - arrow.getWidth() / 2, py + (y - py) / 2);
canvas.drawBitmap(arrow, matrix, paintIcon); canvas.drawBitmap(arrow, matrix, paintIcon);
dist = 0; dist = 0;