Merge pull request #11458 from osmandapp/gradient_track_extra_tasks

Gradient track extra tasks
This commit is contained in:
Vitaliy 2021-04-18 14:52:39 +03:00 committed by GitHub
commit 2d2a951dde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 39 deletions

View file

@ -58,6 +58,7 @@ public class Renderable {
public static abstract class RenderableSegment { public static abstract class RenderableSegment {
protected static final int MIN_CULLER_ZOOM = 16; protected static final int MIN_CULLER_ZOOM = 16;
protected static final int BORDER_TYPE_ZOOM_THRESHOLD = MapTileLayer.DEFAULT_MAX_ZOOM + MapTileLayer.OVERZOOM_IN;
public List<WptPt> points = null; // Original list of points public List<WptPt> points = null; // Original list of points
protected List<WptPt> culled = new ArrayList<>(); // Reduced/resampled list of points protected List<WptPt> culled = new ArrayList<>(); // Reduced/resampled list of points
@ -70,6 +71,7 @@ public class Renderable {
protected Paint paint = null; // MUST be set by 'updateLocalPaint' before use protected Paint paint = null; // MUST be set by 'updateLocalPaint' before use
protected Paint borderPaint; protected Paint borderPaint;
protected GradientScaleType scaleType = null; protected GradientScaleType scaleType = null;
protected boolean drawBorder = false;
protected GpxGeometryWay geometryWay; protected GpxGeometryWay geometryWay;
@ -93,12 +95,10 @@ public class Renderable {
} }
} }
public void setBorderPaint(@NonNull Paint paint) { public void setGradientTrackParams(GradientScaleType gradientScaleType, @NonNull Paint borderPaint, boolean shouldDrawBorder) {
borderPaint = paint; this.scaleType = gradientScaleType;
} this.borderPaint = borderPaint;
this.drawBorder = shouldDrawBorder;
public void setGradientScaleType(GradientScaleType type) {
this.scaleType = type;
} }
public GpxGeometryWay getGeometryWay() { public GpxGeometryWay getGeometryWay() {
@ -119,8 +119,10 @@ public class Renderable {
updateLocalPaint(p); updateLocalPaint(p);
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY()); canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
if (scaleType != null) { if (scaleType != null) {
drawSolid(points, borderPaint, canvas, tileBox); if (drawBorder && zoom < BORDER_TYPE_ZOOM_THRESHOLD) {
drawGradient(points, paint, canvas, tileBox); drawSolid(points, borderPaint, canvas, tileBox);
}
drawGradient(zoom, points, paint, canvas, tileBox);
} else { } else {
drawSolid(getPointsForDrawing(), paint, canvas, tileBox); drawSolid(getPointsForDrawing(), paint, canvas, tileBox);
} }
@ -186,8 +188,9 @@ public class Renderable {
} }
} }
protected void drawGradient(List<WptPt> pts, Paint p, Canvas canvas, RotatedTileBox tileBox) { protected void drawGradient(double zoom, List<WptPt> pts, Paint p, Canvas canvas, RotatedTileBox tileBox) {
QuadRect tileBounds = tileBox.getLatLonBounds(); QuadRect tileBounds = tileBox.getLatLonBounds();
boolean drawSegmentBorder = drawBorder && zoom >= BORDER_TYPE_ZOOM_THRESHOLD;
Path path = new Path(); Path path = new Path();
boolean recalculateLastXY = true; boolean recalculateLastXY = true;
WptPt lastPt = pts.get(0); WptPt lastPt = pts.get(0);
@ -196,6 +199,9 @@ public class Renderable {
List<Integer> gradientColors = new ArrayList<>(); List<Integer> gradientColors = new ArrayList<>();
float gradientAngle = 0; float gradientAngle = 0;
List<Path> paths = new ArrayList<>();
List<LinearGradient> gradients = new ArrayList<>();
for (int i = 1; i < pts.size(); i++) { for (int i = 1; i < pts.size(); i++) {
WptPt pt = pts.get(i); WptPt pt = pts.get(i);
WptPt nextPt = i + 1 < pts.size() ? pts.get(i + 1) : null; WptPt nextPt = i + 1 < pts.size() ? pts.get(i + 1) : null;
@ -209,8 +215,8 @@ public class Renderable {
lastX = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon); lastX = tileBox.getPixXFromLatLon(lastPt.lat, lastPt.lon);
lastY = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon); lastY = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon);
if (!path.isEmpty()) { if (!path.isEmpty()) {
p.setShader(createGradient(gradientPoints, gradientColors)); paths.add(new Path(path));
canvas.drawPath(path, p); gradients.add(createGradient(gradientPoints, gradientColors));
} }
path.reset(); path.reset();
path.moveTo(lastX, lastY); path.moveTo(lastX, lastY);
@ -241,8 +247,21 @@ public class Renderable {
lastPt = pt; lastPt = pt;
} }
if (!path.isEmpty()) { if (!path.isEmpty()) {
p.setShader(createGradient(gradientPoints, gradientColors)); paths.add(new Path(path));
canvas.drawPath(path, p); gradients.add(createGradient(gradientPoints, gradientColors));
}
if (!paths.isEmpty()) {
if (drawSegmentBorder) {
canvas.drawPath(paths.get(0), borderPaint);
}
for (int i = 0; i < paths.size(); i++) {
if (drawSegmentBorder && i + 1 < paths.size()) {
canvas.drawPath(paths.get(i + 1), borderPaint);
}
p.setShader(gradients.get(i));
canvas.drawPath(paths.get(i), p);
}
} }
} }

View file

@ -83,6 +83,7 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR; import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR;
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_WIDTH_ATTR; import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_WIDTH_ATTR;
@ -276,6 +277,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
} }
} }
cache.clear(); cache.clear();
removeCachedUnselectedTracks(selectedGPXFiles);
if (!selectedGPXFiles.isEmpty()) { if (!selectedGPXFiles.isEmpty()) {
drawSelectedFilesSegments(canvas, tileBox, selectedGPXFiles, settings); drawSelectedFilesSegments(canvas, tileBox, selectedGPXFiles, settings);
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY()); canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
@ -455,22 +457,23 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
private void drawDirectionArrows(Canvas canvas, RotatedTileBox tileBox, List<SelectedGpxFile> selectedGPXFiles) { private void drawDirectionArrows(Canvas canvas, RotatedTileBox tileBox, List<SelectedGpxFile> selectedGPXFiles) {
if (!tileBox.isZoomAnimated()) { if (!tileBox.isZoomAnimated()) {
QuadRect correctedQuadRect = getCorrectedQuadRect(tileBox.getLatLonBounds());
for (SelectedGpxFile selectedGpxFile : selectedGPXFiles) { for (SelectedGpxFile selectedGpxFile : selectedGPXFiles) {
boolean showArrows = isShowArrowsForTrack(selectedGpxFile.getGpxFile()); boolean showArrows = isShowArrowsForTrack(selectedGpxFile.getGpxFile());
if (showArrows) { if (!showArrows || !QuadRect.trivialOverlap(correctedQuadRect, GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay()))) {
QuadRect correctedQuadRect = getCorrectedQuadRect(tileBox.getLatLonBounds()); continue;
String width = getTrackWidthName(selectedGpxFile.getGpxFile(), defaultTrackWidthPref.get()); }
float trackWidth = getTrackWidth(width, defaultTrackWidth); String width = getTrackWidthName(selectedGpxFile.getGpxFile(), defaultTrackWidthPref.get());
int trackColor = getTrackColor(selectedGpxFile.getGpxFile(), cachedColor); float trackWidth = getTrackWidth(width, defaultTrackWidth);
int arrowColor = UiUtilities.getContrastColor(view.getApplication(), trackColor, false); int trackColor = getTrackColor(selectedGpxFile.getGpxFile(), cachedColor);
GradientScaleType scaleType = getGradientScaleType(selectedGpxFile.getGpxFile()); int arrowColor = UiUtilities.getContrastColor(view.getApplication(), trackColor, false);
List<TrkSegment> segments = scaleType != null ? GradientScaleType scaleType = getGradientScaleType(selectedGpxFile.getGpxFile());
getCachedSegments(selectedGpxFile, scaleType) : selectedGpxFile.getPointsToDisplay(); List<TrkSegment> segments = scaleType != null ?
for (TrkSegment segment : segments) { getCachedSegments(selectedGpxFile, scaleType) : selectedGpxFile.getPointsToDisplay();
if (segment.renderer instanceof Renderable.RenderableSegment) { for (TrkSegment segment : segments) {
((Renderable.RenderableSegment) segment.renderer) if (segment.renderer instanceof Renderable.RenderableSegment) {
.drawGeometry(canvas, tileBox, correctedQuadRect, arrowColor, trackColor, trackWidth); ((Renderable.RenderableSegment) segment.renderer)
} .drawGeometry(canvas, tileBox, correctedQuadRect, arrowColor, trackColor, trackWidth);
} }
} }
} }
@ -690,6 +693,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
RotatedTileBox tileBox, DrawSettings settings) { RotatedTileBox tileBox, DrawSettings settings) {
boolean visible = QuadRect.trivialOverlap(tileBox.getLatLonBounds(), GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay())); boolean visible = QuadRect.trivialOverlap(tileBox.getLatLonBounds(), GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay()));
if (!selectedGpxFile.getGpxFile().hasTrkPt() || !visible) { if (!selectedGpxFile.getGpxFile().hasTrkPt() || !visible) {
segmentsCache.remove(selectedGpxFile.getGpxFile().path);
return; return;
} }
@ -719,8 +723,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
updatePaints(color, width, selectedGpxFile.isRoutePoints(), currentTrack, settings, tileBox); updatePaints(color, width, selectedGpxFile.isRoutePoints(), currentTrack, settings, tileBox);
if (ts.renderer instanceof Renderable.RenderableSegment) { if (ts.renderer instanceof Renderable.RenderableSegment) {
Renderable.RenderableSegment renderableSegment = (Renderable.RenderableSegment) ts.renderer; Renderable.RenderableSegment renderableSegment = (Renderable.RenderableSegment) ts.renderer;
renderableSegment.setBorderPaint(borderPaint); renderableSegment.setGradientTrackParams(scaleType, borderPaint, true);
renderableSegment.setGradientScaleType(scaleType);
renderableSegment.drawSegment(view.getZoom(), paint, canvas, tileBox); renderableSegment.drawSegment(view.getZoom(), paint, canvas, tileBox);
} }
} }
@ -729,13 +732,12 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
private List<TrkSegment> getCachedSegments(SelectedGpxFile selectedGpxFile, GradientScaleType scaleType) { private List<TrkSegment> getCachedSegments(SelectedGpxFile selectedGpxFile, GradientScaleType scaleType) {
GPXFile gpxFile = selectedGpxFile.getGpxFile(); GPXFile gpxFile = selectedGpxFile.getGpxFile();
String path = gpxFile.path; String path = gpxFile.path;
long modifiedTime = gpxFile.modifiedTime;
CachedTrack cachedTrack = segmentsCache.get(path); CachedTrack cachedTrack = segmentsCache.get(path);
if (cachedTrack == null) { if (cachedTrack == null) {
cachedTrack = new CachedTrack(view.getApplication(), modifiedTime); cachedTrack = new CachedTrack(view.getApplication(), selectedGpxFile);
segmentsCache.put(path, cachedTrack); segmentsCache.put(path, cachedTrack);
} }
return cachedTrack.getCachedSegments(selectedGpxFile, view.getZoom(), scaleType, getColorizationPalette(gpxFile, scaleType)); return cachedTrack.getCachedSegments(view.getZoom(), scaleType, getColorizationPalette(gpxFile, scaleType));
} }
private float getTrackWidth(String width, float defaultTrackWidth) { private float getTrackWidth(String width, float defaultTrackWidth) {
@ -1051,6 +1053,19 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
return name.replace('_', ' '); return name.replace('_', ' ');
} }
private void removeCachedUnselectedTracks(List<SelectedGpxFile> selectedGpxFiles) {
Set<String> cachedTracksPaths = segmentsCache.keySet();
List<String> selectedTracksPaths = new ArrayList<>();
for (SelectedGpxFile gpx : selectedGpxFiles) {
selectedTracksPaths.add(gpx.getGpxFile().path);
}
for (Iterator<String> iterator = cachedTracksPaths.iterator(); iterator.hasNext();) {
if (!selectedTracksPaths.contains(iterator.next())) {
iterator.remove();
}
}
}
@Override @Override
public boolean disableSingleTap() { public boolean disableSingleTap() {
return isInTrackAppearanceMode(); return isInTrackAppearanceMode();
@ -1220,20 +1235,21 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
private OsmandApplication app; private OsmandApplication app;
private long modifiedTime; private final SelectedGpxFile selectedGpxFile;
private final Map<String, List<TrkSegment>> cache = new HashMap<>(); private final Map<String, List<TrkSegment>> cache = new HashMap<>();
public CachedTrack(@NonNull OsmandApplication app, long modifiedTime) { private long prevModifiedTime = -1;
public CachedTrack(@NonNull OsmandApplication app, @NonNull SelectedGpxFile selectedGpxFile) {
this.app = app; this.app = app;
this.modifiedTime = modifiedTime; this.selectedGpxFile = selectedGpxFile;
} }
public List<TrkSegment> getCachedSegments(@NonNull SelectedGpxFile selectedGpxFile, int zoom, public List<TrkSegment> getCachedSegments(int zoom, @NonNull GradientScaleType scaleType,
@NonNull GradientScaleType scaleType,
int[] gradientPalette) { int[] gradientPalette) {
GPXFile gpxFile = selectedGpxFile.getGpxFile(); GPXFile gpxFile = selectedGpxFile.getGpxFile();
String trackId = zoom + "_" + scaleType.toString(); String trackId = zoom + "_" + scaleType.toString();
if (modifiedTime == gpxFile.modifiedTime) { if (prevModifiedTime == gpxFile.modifiedTime) {
List<TrkSegment> segments = cache.get(trackId); List<TrkSegment> segments = cache.get(trackId);
if (segments == null) { if (segments == null) {
segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette);
@ -1242,7 +1258,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
return segments; return segments;
} else { } else {
cache.clear(); cache.clear();
modifiedTime = gpxFile.modifiedTime; prevModifiedTime = gpxFile.modifiedTime;
List<TrkSegment> segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); List<TrkSegment> segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette);
cache.put(trackId, segments); cache.put(trackId, segments);
return segments; return segments;