MINIMAL code set for GPX line drawing
Has all the structure of the classes needed for extension to arrows/markers/whatever. However, this is just the minimal subset of those base classes required to implement the line drawing functionality with the asynchronous resampling, and fully compatible with 'current track' which is NOT resampled in any way. These files are a branch from the prior pull request, and hopefully will make everyone more comfortable about including the code. The altitude and speed displays, all the bells and whistles - that can come later if needed.
This commit is contained in:
parent
ceddb50e60
commit
9f0bcf3257
3 changed files with 7 additions and 515 deletions
|
@ -3,7 +3,6 @@ package net.osmand.plus.views;
|
|||
import android.os.AsyncTask;
|
||||
|
||||
import net.osmand.plus.GPXUtilities.WptPt;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -26,157 +25,6 @@ public abstract class AsynchronousResampler extends AsyncTask<String,Integer,Str
|
|||
}
|
||||
}
|
||||
|
||||
private WptPt createIntermediatePoint(WptPt lastPt, WptPt pt, double partial, double dist) {
|
||||
WptPt newPt = new WptPt(
|
||||
lastPt.getLatitude() + partial * (pt.getLatitude() - lastPt.getLatitude()),
|
||||
lastPt.getLongitude() + partial * (pt.getLongitude() - lastPt.getLongitude()),
|
||||
(long) (lastPt.time + partial * (pt.time - lastPt.time)),
|
||||
lastPt.ele + partial * (pt.ele - lastPt.ele),
|
||||
lastPt.speed + partial * (pt.speed - lastPt.speed),
|
||||
lastPt.hdop + partial * (pt.hdop - lastPt.hdop));
|
||||
newPt.setDistance(dist);
|
||||
return newPt;
|
||||
}
|
||||
|
||||
protected List<WptPt> resampleTrack(List<WptPt> pts, double dist) {
|
||||
|
||||
List<WptPt> newPts = new ArrayList<>();
|
||||
|
||||
int size = pts.size();
|
||||
if (size > 0) {
|
||||
WptPt lastPt = pts.get(0);
|
||||
|
||||
double segSub = 0;
|
||||
double cumDist = 0;
|
||||
for (int i = 1; i < size && !isCancelled(); i++) {
|
||||
WptPt pt = pts.get(i);
|
||||
double segLength = MapUtils.getDistance(pt.getLatitude(), pt.getLongitude(), lastPt.getLatitude(), lastPt.getLongitude());
|
||||
while (segSub < segLength) {
|
||||
double partial = segSub / segLength;
|
||||
newPts.add(createIntermediatePoint(lastPt, pt, segSub/segLength, cumDist + segLength * partial));
|
||||
segSub += dist;
|
||||
}
|
||||
segSub -= segLength;
|
||||
cumDist += segLength;
|
||||
lastPt = pt;
|
||||
}
|
||||
newPts.add(createIntermediatePoint(lastPt, lastPt, 0, cumDist));
|
||||
}
|
||||
return newPts;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class ResampleAltitude extends AsynchronousResampler {
|
||||
|
||||
private double segmentSize;
|
||||
|
||||
ResampleAltitude(Renderable.RenderableSegment rs, double segmentSize) {
|
||||
super(rs);
|
||||
this.segmentSize = segmentSize;
|
||||
}
|
||||
|
||||
@Override protected String doInBackground(String... params) {
|
||||
|
||||
// Resample track, then analyse altitudes and set colours for each point
|
||||
|
||||
culled = resampleTrack(rs.points, segmentSize);
|
||||
if (!isCancelled() && !culled.isEmpty()) {
|
||||
|
||||
int halfC = Algorithms.getRainbowColor(0.5);
|
||||
|
||||
// Calculate the absolutes of the altitude variations
|
||||
Double max = culled.get(0).ele;
|
||||
Double min = max;
|
||||
for (WptPt pt : culled) {
|
||||
max = Math.max(max, pt.ele);
|
||||
min = Math.min(min, pt.ele);
|
||||
pt.colourARGB = halfC; // default, in case there are no 'ele' in GPX
|
||||
}
|
||||
|
||||
Double elevationRange = max - min;
|
||||
if (elevationRange > 0)
|
||||
for (WptPt pt : culled)
|
||||
pt.colourARGB = Algorithms.getRainbowColor((pt.ele - min) / elevationRange);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class ResampleSpeed extends AsynchronousResampler {
|
||||
|
||||
private double segmentSize;
|
||||
|
||||
ResampleSpeed(Renderable.RenderableSegment rs, double segmentSize) {
|
||||
super(rs);
|
||||
this.segmentSize = segmentSize;
|
||||
}
|
||||
|
||||
@Override protected String doInBackground(String... params) {
|
||||
|
||||
// Resample track, then analyse speeds and set colours for each point
|
||||
|
||||
culled = resampleTrack(rs.points, segmentSize);
|
||||
if (!isCancelled() && !culled.isEmpty()) {
|
||||
|
||||
WptPt lastPt = culled.get(0);
|
||||
lastPt.speed = 0;
|
||||
|
||||
int size = culled.size();
|
||||
for (int i = 1; i < size; i++) {
|
||||
WptPt pt = culled.get(i);
|
||||
double delta = pt.time - lastPt.time;
|
||||
pt.speed = delta > 0 ? MapUtils.getDistance(pt.getLatitude(), pt.getLongitude(),
|
||||
lastPt.getLatitude(), lastPt.getLongitude()) / delta : 0;
|
||||
lastPt = pt;
|
||||
}
|
||||
|
||||
if (size > 1) {
|
||||
culled.get(0).speed = culled.get(1).speed; // fixup 1st speed
|
||||
}
|
||||
|
||||
double max = lastPt.speed;
|
||||
double min = max;
|
||||
|
||||
int halfC = Algorithms.getRainbowColor(0.5);
|
||||
|
||||
for (WptPt pt : culled) {
|
||||
max = Math.max(max, pt.speed);
|
||||
min = Math.min(min, pt.speed);
|
||||
pt.colourARGB = halfC; // default, in case there are no 'time' in GPX
|
||||
}
|
||||
double speedRange = max - min;
|
||||
if (speedRange > 0) {
|
||||
for (WptPt pt : culled)
|
||||
pt.colourARGB = Algorithms.getRainbowColor((pt.speed - min) / speedRange);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class GenericResampler extends AsynchronousResampler {
|
||||
|
||||
private double segmentSize;
|
||||
|
||||
public GenericResampler(Renderable.RenderableSegment rs, double segmentSize) {
|
||||
super(rs);
|
||||
this.segmentSize = segmentSize;
|
||||
}
|
||||
|
||||
@Override protected String doInBackground(String... params) {
|
||||
culled = resampleTrack(rs.points, segmentSize);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class RamerDouglasPeucer extends AsynchronousResampler {
|
||||
|
||||
private double epsilon;
|
||||
|
@ -228,9 +76,5 @@ public abstract class AsynchronousResampler extends AsyncTask<String,Integer,Str
|
|||
survivor[end] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -334,16 +334,10 @@ public class GPXLayer extends OsmandMapLayer implements ContextMenuLayer.IContex
|
|||
if (g.isShowCurrentTrack()) {
|
||||
ts.renders.add(new Renderable.CurrentTrack(ts.points));
|
||||
} else {
|
||||
//ts.renders.add(new Renderable.Altitude(ts.points, 10));
|
||||
ts.renders.add(new Renderable.StandardTrack(ts.points, 17.2));
|
||||
//ts.renders.add(new Renderable.Conveyor(ts.points, view, 5, 250));
|
||||
//ts.renders.add(new Renderable.Arrows(ts.points, view, 10, 250));
|
||||
//ts.renders.add(new Renderable.DistanceMarker(ts.points, 1000));
|
||||
//ts.renders.add(new Renderable.Speed(ts.points, 50));
|
||||
}
|
||||
}
|
||||
|
||||
//ts.recalculateRenderScales(view.getZoom());
|
||||
updatePaints(ts.getColor(cachedColor), g.isRoutePoints(), g.isShowCurrentTrack(), settings, tileBox);
|
||||
ts.drawRenderers(view.getZoom(), paint, canvas, tileBox);
|
||||
}
|
||||
|
|
|
@ -1,51 +1,18 @@
|
|||
package net.osmand.plus.views;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.data.RotatedTileBox;
|
||||
import net.osmand.plus.GPXUtilities.WptPt;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
|
||||
public class Renderable {
|
||||
|
||||
// This class handles the actual drawing of segment 'layers'. A segment is a piece of track
|
||||
// (i.e., a list of WptPt) which has renders attached to it. There can be any number of renders
|
||||
// layered upon each other to give multiple effects.
|
||||
|
||||
static private Timer t = null; // fires a repaint for animating segments
|
||||
static private int conveyor = 0; // single cycler for 'conveyor' style renders
|
||||
static private OsmandMapTileView view = null; // for paint refresh
|
||||
|
||||
|
||||
// If any render wants to have animation, something needs to make a one-off call to 'startScreenRefresh'
|
||||
// to setup a timer to periodically force a screen refresh/redraw
|
||||
|
||||
public static void startScreenRefresh(OsmandMapTileView v, long period) {
|
||||
view = v;
|
||||
if (t==null && v != null) {
|
||||
t = new Timer();
|
||||
t.scheduleAtFixedRate(new TimerTask() {
|
||||
public void run() {
|
||||
conveyor++;
|
||||
view.refreshMap();
|
||||
}
|
||||
}, 0, period);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static abstract class RenderableSegment {
|
||||
|
||||
public List<WptPt> points = null; // Original list of points
|
||||
|
@ -75,23 +42,7 @@ public class Renderable {
|
|||
paint.setStrokeWidth(p.getStrokeWidth());
|
||||
}
|
||||
|
||||
protected void startCuller(double newZoom) {
|
||||
if (zoom != newZoom) {
|
||||
if (culler != null) {
|
||||
culler.cancel(true);
|
||||
}
|
||||
culled.clear();
|
||||
zoom = newZoom;
|
||||
|
||||
double length = Math.pow(2.0, 17 - zoom) * segmentSize;
|
||||
culler = getCuller(length);
|
||||
culler.execute("");
|
||||
}
|
||||
}
|
||||
|
||||
protected AsynchronousResampler getCuller(double segmentSize) {
|
||||
return new AsynchronousResampler.GenericResampler(this, segmentSize);
|
||||
}
|
||||
protected abstract void startCuller(double newZoom);
|
||||
|
||||
protected void drawSingleSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {}
|
||||
|
||||
|
@ -119,7 +70,6 @@ public class Renderable {
|
|||
}
|
||||
}
|
||||
|
||||
// When the asynchronous task has finished, it calls this function to set the 'culled' list
|
||||
public void setRDP(List<WptPt> cull) {
|
||||
culled = cull;
|
||||
}
|
||||
|
@ -133,9 +83,9 @@ public class Renderable {
|
|||
QuadRect tileBounds = tileBox.getLatLonBounds();
|
||||
|
||||
WptPt lastPt = pts.get(0);
|
||||
float lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
float lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
boolean last = false;
|
||||
float lastx = 0;
|
||||
float lasty = 0;
|
||||
boolean reCalculateLastXY = true;
|
||||
|
||||
int size = pts.size();
|
||||
for (int i = 1; i < size; i++) {
|
||||
|
@ -144,10 +94,10 @@ public class Renderable {
|
|||
if (Math.min(pt.lon, lastPt.lon) < tileBounds.right && Math.max(pt.lon, lastPt.lon) > tileBounds.left
|
||||
&& Math.min(pt.lat, lastPt.lat) < tileBounds.top && Math.max(pt.lat, lastPt.lat) > tileBounds.bottom) {
|
||||
|
||||
if (!last) {
|
||||
if (reCalculateLastXY) {
|
||||
lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
last = true;
|
||||
reCalculateLastXY = false;
|
||||
}
|
||||
|
||||
float x = tileBox.getPixXFromLatLon(pt.lat, pt.lon);
|
||||
|
@ -159,7 +109,7 @@ public class Renderable {
|
|||
lasty = y;
|
||||
|
||||
} else {
|
||||
last = false;
|
||||
reCalculateLastXY = true;
|
||||
}
|
||||
lastPt = pt;
|
||||
}
|
||||
|
@ -168,8 +118,6 @@ public class Renderable {
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class StandardTrack extends RenderableSegment {
|
||||
|
||||
public StandardTrack(List<WptPt> pt, double base) {
|
||||
|
@ -198,299 +146,6 @@ public class Renderable {
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class Altitude extends RenderableSegment {
|
||||
|
||||
public Altitude(List<WptPt> pt, double segmentSize) {
|
||||
super(pt, segmentSize);
|
||||
}
|
||||
|
||||
@Override protected AsynchronousResampler getCuller(double segmentSize) {
|
||||
return new AsynchronousResampler.ResampleAltitude(this, segmentSize);
|
||||
}
|
||||
|
||||
@Override public void drawSingleSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||
|
||||
if (culled.size() > 1) {
|
||||
updateLocalPaint(p);
|
||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
|
||||
float bandWidth = paint.getStrokeWidth() * 3;
|
||||
paint.setStrokeWidth(bandWidth);
|
||||
|
||||
QuadRect tileBounds = tileBox.getLatLonBounds();
|
||||
|
||||
WptPt lastPt = culled.get(0);
|
||||
float lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
float lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
boolean last = false;
|
||||
|
||||
int size = culled.size();
|
||||
for (int i = 1; i < size; i++) {
|
||||
WptPt pt = culled.get(i);
|
||||
|
||||
if (Math.min(pt.lon, lastPt.lon) < tileBounds.right && Math.max(pt.lon, lastPt.lon) > tileBounds.left
|
||||
&& Math.min(pt.lat, lastPt.lat) < tileBounds.top && Math.max(pt.lat, lastPt.lat) > tileBounds.bottom) {
|
||||
|
||||
if (!last) {
|
||||
lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
last = true;
|
||||
}
|
||||
|
||||
float x = tileBox.getPixXFromLatLon(pt.lat, pt.lon);
|
||||
float y = tileBox.getPixYFromLatLon(pt.lat, pt.lon);
|
||||
|
||||
paint.setColor(pt.colourARGB);
|
||||
canvas.drawLine(lastx, lasty, x, y, paint);
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
|
||||
} else {
|
||||
last = false;
|
||||
}
|
||||
lastPt = pt;
|
||||
}
|
||||
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class Speed extends Altitude {
|
||||
|
||||
public Speed(List<WptPt> pt, double segmentSize) {
|
||||
super(pt, segmentSize);
|
||||
}
|
||||
|
||||
@Override protected AsynchronousResampler getCuller(double segmentSize) {
|
||||
return new AsynchronousResampler.ResampleSpeed(this, segmentSize);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class Conveyor extends RenderableSegment {
|
||||
|
||||
public Conveyor(List<WptPt> pt, OsmandMapTileView view, double segmentSize, long refreshRate) {
|
||||
super(pt, segmentSize);
|
||||
Renderable.startScreenRefresh(view, refreshRate);
|
||||
}
|
||||
|
||||
private int getComplementaryColor(int colorToInvert) {
|
||||
float[] hsv = new float[3];
|
||||
Color.RGBToHSV(Color.red(colorToInvert), Color.green(colorToInvert), Color.blue(colorToInvert), hsv);
|
||||
hsv[0] = (hsv[0] + 180) % 360;
|
||||
return Color.HSVToColor(hsv);
|
||||
}
|
||||
|
||||
@Override public void drawSingleSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||
|
||||
if (culled.size() > 1) {
|
||||
updateLocalPaint(p);
|
||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
|
||||
paint.setColor(getComplementaryColor(p.getColor()));
|
||||
|
||||
QuadRect tileBounds = tileBox.getLatLonBounds();
|
||||
|
||||
WptPt lastPt = culled.get(0);
|
||||
float lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
float lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
boolean last = false;
|
||||
|
||||
int intp = conveyor;
|
||||
|
||||
int size = culled.size();
|
||||
for (int i = 1; i < size; i++, intp--) {
|
||||
WptPt pt = culled.get(i);
|
||||
|
||||
if ((intp & 7) < 3
|
||||
&& Math.min(pt.lon, lastPt.lon) < tileBounds.right && Math.max(pt.lon, lastPt.lon) > tileBounds.left
|
||||
&& Math.min(pt.lat, lastPt.lat) < tileBounds.top && Math.max(pt.lat, lastPt.lat) > tileBounds.bottom) {
|
||||
|
||||
if (!last) {
|
||||
lastx = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
|
||||
lasty = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
|
||||
last = true;
|
||||
}
|
||||
|
||||
float x = tileBox.getPixXFromLatLon(pt.lat, pt.lon);
|
||||
float y = tileBox.getPixYFromLatLon(pt.lat, pt.lon);
|
||||
|
||||
canvas.drawLine(lastx, lasty, x, y, paint);
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
|
||||
} else {
|
||||
last = false;
|
||||
}
|
||||
lastPt = pt;
|
||||
}
|
||||
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class DistanceMarker extends RenderableSegment {
|
||||
|
||||
public DistanceMarker(List<WptPt> pt, double segmentSize) {
|
||||
super(pt, segmentSize);
|
||||
}
|
||||
|
||||
@Override public void startCuller(double zoom) {
|
||||
if (culler == null) {
|
||||
culler = new AsynchronousResampler.GenericResampler(this, segmentSize); // once only
|
||||
culler.execute("");
|
||||
}
|
||||
}
|
||||
|
||||
private String getKmLabel(double value) {
|
||||
String lab;
|
||||
lab = String.format("%d",(int)((value+0.5)/1000));
|
||||
return lab;
|
||||
}
|
||||
|
||||
@Override public void drawSingleSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||
|
||||
if (zoom > 12 && !culled.isEmpty()) {
|
||||
updateLocalPaint(p);
|
||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
|
||||
float scale = 50;
|
||||
float stroke = paint.getStrokeWidth();
|
||||
|
||||
for (int i = culled.size() - 1; --i >= 0; ) {
|
||||
|
||||
WptPt pt = culled.get(i);
|
||||
float x = tileBox.getPixXFromLatLon(pt.lat, pt.lon);
|
||||
float y = tileBox.getPixYFromLatLon(pt.lat, pt.lon);
|
||||
|
||||
paint.setTextSize(scale);
|
||||
paint.setStrokeWidth(3);
|
||||
|
||||
Rect bounds = new Rect();
|
||||
String lab = getKmLabel(pt.getDistance());
|
||||
paint.getTextBounds(lab, 0, lab.length(), bounds);
|
||||
|
||||
int rectH = bounds.height();
|
||||
int rectW = bounds.width();
|
||||
|
||||
if (x < canvas.getWidth() + rectW / 2 + scale && x > -rectW / 2 + scale
|
||||
&& y < canvas.getHeight() + rectH / 2f && y > -rectH / 2f) {
|
||||
|
||||
paint.setColor(Color.BLACK);
|
||||
paint.setStrokeWidth(stroke);
|
||||
canvas.drawPoint(x, y, paint);
|
||||
paint.setStrokeWidth(4);
|
||||
canvas.drawText(lab, x - rectW / 2 + 40, y + rectH / 2, paint);
|
||||
}
|
||||
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class Arrows extends RenderableSegment {
|
||||
|
||||
public Arrows(List<WptPt> pt, OsmandMapTileView view, double segmentSize, long refreshRate) {
|
||||
super(pt, segmentSize);
|
||||
Renderable.startScreenRefresh(view, refreshRate);
|
||||
}
|
||||
|
||||
private void drawArrows(int cachedC, Canvas canvas, RotatedTileBox tileBox, boolean internal) {
|
||||
|
||||
float scale = internal ? 0.6f : 1.0f;
|
||||
|
||||
float stroke = paint.getStrokeWidth();
|
||||
float arrowSize = 75f;
|
||||
boolean broken = true;
|
||||
int intp = cachedC; // the segment cycler
|
||||
|
||||
float clipL = -arrowSize;
|
||||
float clipB = -arrowSize;
|
||||
float clipT = canvas.getHeight() + arrowSize;
|
||||
float clipR = canvas.getWidth() + arrowSize;
|
||||
|
||||
float lastx = 0;
|
||||
float lasty = Float.NEGATIVE_INFINITY;
|
||||
|
||||
int size = culled.size();
|
||||
for (int i = 0; i < size; i++, intp--) {
|
||||
WptPt pt = culled.get(i);
|
||||
|
||||
float x = tileBox.getPixXFromLatLon(pt.lat, pt.lon);
|
||||
float y = tileBox.getPixYFromLatLon(pt.lat, pt.lon);
|
||||
|
||||
boolean nextBroken = true;
|
||||
if (Math.min(x, lastx) < clipR && Math.max(x, lastx) > clipL
|
||||
&& Math.min(y, lasty) < clipT && Math.max(y, lasty) > clipB) {
|
||||
|
||||
float segment = intp & 15;
|
||||
if (segment < 5) {
|
||||
|
||||
paint.setColor(internal ? Algorithms.getRainbowColor(((double) (i)) / ((double) size)) : Color.BLACK);
|
||||
|
||||
float segpiece = 5 - segment;
|
||||
if (segpiece > 3)
|
||||
segpiece = 3;
|
||||
|
||||
if (!broken) {
|
||||
float sw = stroke * segpiece * scale;
|
||||
paint.setStrokeWidth(sw);
|
||||
canvas.drawLine(lastx, lasty, x, y, paint);
|
||||
}
|
||||
nextBroken = false;
|
||||
|
||||
// arrowhead...
|
||||
if (segment == 0 && lasty != Float.NEGATIVE_INFINITY) {
|
||||
float sw = stroke * segpiece * scale;
|
||||
paint.setStrokeWidth(sw);
|
||||
double angle = Math.atan2(lasty - y, lastx - x);
|
||||
|
||||
float extendx = x - (float) Math.cos(angle) * arrowSize / 2;
|
||||
float extendy = y - (float) Math.sin(angle) * arrowSize / 2;
|
||||
float newx1 = extendx + (float) Math.cos(angle - 0.4) * arrowSize;
|
||||
float newy1 = extendy + (float) Math.sin(angle - 0.4) * arrowSize;
|
||||
float newx2 = extendx + (float) Math.cos(angle + 0.4) * arrowSize;
|
||||
float newy2 = extendy + (float) Math.sin(angle + 0.4) * arrowSize;
|
||||
|
||||
canvas.drawLine(extendx, extendy, x, y, paint);
|
||||
canvas.drawLine(newx1, newy1, extendx, extendy, paint);
|
||||
canvas.drawLine(newx2, newy2, extendx, extendy, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
broken = nextBroken;
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
}
|
||||
paint.setStrokeWidth(stroke);
|
||||
}
|
||||
|
||||
@Override public void drawSingleSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||
|
||||
if (zoom > 13 && !culled.isEmpty()) {
|
||||
updateLocalPaint(p);
|
||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
int cachedC = conveyor;
|
||||
drawArrows(cachedC, canvas, tileBox, false);
|
||||
drawArrows(cachedC, canvas, tileBox, true);
|
||||
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
public static class CurrentTrack extends RenderableSegment {
|
||||
|
||||
public CurrentTrack(List<WptPt> pt) {
|
||||
|
@ -510,5 +165,4 @@ public class Renderable {
|
|||
draw(points, p, canvas, tileBox);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue