diff --git a/OsmAnd/src/net/osmand/plus/views/Renderable.java b/OsmAnd/src/net/osmand/plus/views/Renderable.java index dd8ba55b8a..2dbf1eb3aa 100644 --- a/OsmAnd/src/net/osmand/plus/views/Renderable.java +++ b/OsmAnd/src/net/osmand/plus/views/Renderable.java @@ -58,6 +58,7 @@ public class Renderable { public static abstract class RenderableSegment { 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 points = null; // Original list of points protected List 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 borderPaint; protected GradientScaleType scaleType = null; + protected boolean drawBorder = false; protected GpxGeometryWay geometryWay; @@ -93,12 +95,10 @@ public class Renderable { } } - public void setBorderPaint(@NonNull Paint paint) { - borderPaint = paint; - } - - public void setGradientScaleType(GradientScaleType type) { - this.scaleType = type; + public void setGradientTrackParams(GradientScaleType gradientScaleType, @NonNull Paint borderPaint, boolean shouldDrawBorder) { + this.scaleType = gradientScaleType; + this.borderPaint = borderPaint; + this.drawBorder = shouldDrawBorder; } public GpxGeometryWay getGeometryWay() { @@ -119,8 +119,10 @@ public class Renderable { updateLocalPaint(p); canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY()); if (scaleType != null) { - drawSolid(points, borderPaint, canvas, tileBox); - drawGradient(points, paint, canvas, tileBox); + if (drawBorder && zoom < BORDER_TYPE_ZOOM_THRESHOLD) { + drawSolid(points, borderPaint, canvas, tileBox); + } + drawGradient(zoom, points, paint, canvas, tileBox); } else { drawSolid(getPointsForDrawing(), paint, canvas, tileBox); } @@ -186,8 +188,9 @@ public class Renderable { } } - protected void drawGradient(List pts, Paint p, Canvas canvas, RotatedTileBox tileBox) { + protected void drawGradient(double zoom, List pts, Paint p, Canvas canvas, RotatedTileBox tileBox) { QuadRect tileBounds = tileBox.getLatLonBounds(); + boolean drawSegmentBorder = drawBorder && zoom >= BORDER_TYPE_ZOOM_THRESHOLD; Path path = new Path(); boolean recalculateLastXY = true; WptPt lastPt = pts.get(0); @@ -196,6 +199,9 @@ public class Renderable { List gradientColors = new ArrayList<>(); float gradientAngle = 0; + List paths = new ArrayList<>(); + List gradients = new ArrayList<>(); + for (int i = 1; i < pts.size(); i++) { WptPt pt = pts.get(i); 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); lastY = tileBox.getPixYFromLatLon(lastPt.lat, lastPt.lon); if (!path.isEmpty()) { - p.setShader(createGradient(gradientPoints, gradientColors)); - canvas.drawPath(path, p); + paths.add(new Path(path)); + gradients.add(createGradient(gradientPoints, gradientColors)); } path.reset(); path.moveTo(lastX, lastY); @@ -241,8 +247,21 @@ public class Renderable { lastPt = pt; } if (!path.isEmpty()) { - p.setShader(createGradient(gradientPoints, gradientColors)); - canvas.drawPath(path, p); + paths.add(new Path(path)); + 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); + } } } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java index 007e6fe700..7ce7ec3feb 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java @@ -83,6 +83,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; 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_WIDTH_ATTR; @@ -276,6 +277,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM } } cache.clear(); + removeCachedUnselectedTracks(selectedGPXFiles); if (!selectedGPXFiles.isEmpty()) { drawSelectedFilesSegments(canvas, tileBox, selectedGPXFiles, settings); 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 selectedGPXFiles) { if (!tileBox.isZoomAnimated()) { + QuadRect correctedQuadRect = getCorrectedQuadRect(tileBox.getLatLonBounds()); for (SelectedGpxFile selectedGpxFile : selectedGPXFiles) { boolean showArrows = isShowArrowsForTrack(selectedGpxFile.getGpxFile()); - if (showArrows) { - QuadRect correctedQuadRect = getCorrectedQuadRect(tileBox.getLatLonBounds()); - String width = getTrackWidthName(selectedGpxFile.getGpxFile(), defaultTrackWidthPref.get()); - float trackWidth = getTrackWidth(width, defaultTrackWidth); - int trackColor = getTrackColor(selectedGpxFile.getGpxFile(), cachedColor); - int arrowColor = UiUtilities.getContrastColor(view.getApplication(), trackColor, false); - GradientScaleType scaleType = getGradientScaleType(selectedGpxFile.getGpxFile()); - List segments = scaleType != null ? - getCachedSegments(selectedGpxFile, scaleType) : selectedGpxFile.getPointsToDisplay(); - for (TrkSegment segment : segments) { - if (segment.renderer instanceof Renderable.RenderableSegment) { - ((Renderable.RenderableSegment) segment.renderer) - .drawGeometry(canvas, tileBox, correctedQuadRect, arrowColor, trackColor, trackWidth); - } + if (!showArrows || !QuadRect.trivialOverlap(correctedQuadRect, GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay()))) { + continue; + } + String width = getTrackWidthName(selectedGpxFile.getGpxFile(), defaultTrackWidthPref.get()); + float trackWidth = getTrackWidth(width, defaultTrackWidth); + int trackColor = getTrackColor(selectedGpxFile.getGpxFile(), cachedColor); + int arrowColor = UiUtilities.getContrastColor(view.getApplication(), trackColor, false); + GradientScaleType scaleType = getGradientScaleType(selectedGpxFile.getGpxFile()); + List segments = scaleType != null ? + getCachedSegments(selectedGpxFile, scaleType) : selectedGpxFile.getPointsToDisplay(); + for (TrkSegment segment : segments) { + if (segment.renderer instanceof Renderable.RenderableSegment) { + ((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) { boolean visible = QuadRect.trivialOverlap(tileBox.getLatLonBounds(), GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay())); if (!selectedGpxFile.getGpxFile().hasTrkPt() || !visible) { + segmentsCache.remove(selectedGpxFile.getGpxFile().path); return; } @@ -719,8 +723,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM updatePaints(color, width, selectedGpxFile.isRoutePoints(), currentTrack, settings, tileBox); if (ts.renderer instanceof Renderable.RenderableSegment) { Renderable.RenderableSegment renderableSegment = (Renderable.RenderableSegment) ts.renderer; - renderableSegment.setBorderPaint(borderPaint); - renderableSegment.setGradientScaleType(scaleType); + renderableSegment.setGradientTrackParams(scaleType, borderPaint, true); renderableSegment.drawSegment(view.getZoom(), paint, canvas, tileBox); } } @@ -729,13 +732,12 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM private List getCachedSegments(SelectedGpxFile selectedGpxFile, GradientScaleType scaleType) { GPXFile gpxFile = selectedGpxFile.getGpxFile(); String path = gpxFile.path; - long modifiedTime = gpxFile.modifiedTime; CachedTrack cachedTrack = segmentsCache.get(path); if (cachedTrack == null) { - cachedTrack = new CachedTrack(view.getApplication(), modifiedTime); + cachedTrack = new CachedTrack(view.getApplication(), selectedGpxFile); 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) { @@ -1051,6 +1053,19 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM return name.replace('_', ' '); } + private void removeCachedUnselectedTracks(List selectedGpxFiles) { + Set cachedTracksPaths = segmentsCache.keySet(); + List selectedTracksPaths = new ArrayList<>(); + for (SelectedGpxFile gpx : selectedGpxFiles) { + selectedTracksPaths.add(gpx.getGpxFile().path); + } + for (Iterator iterator = cachedTracksPaths.iterator(); iterator.hasNext();) { + if (!selectedTracksPaths.contains(iterator.next())) { + iterator.remove(); + } + } + } + @Override public boolean disableSingleTap() { return isInTrackAppearanceMode(); @@ -1220,20 +1235,21 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM private OsmandApplication app; - private long modifiedTime; + private final SelectedGpxFile selectedGpxFile; private final Map> 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.modifiedTime = modifiedTime; + this.selectedGpxFile = selectedGpxFile; } - public List getCachedSegments(@NonNull SelectedGpxFile selectedGpxFile, int zoom, - @NonNull GradientScaleType scaleType, + public List getCachedSegments(int zoom, @NonNull GradientScaleType scaleType, int[] gradientPalette) { GPXFile gpxFile = selectedGpxFile.getGpxFile(); String trackId = zoom + "_" + scaleType.toString(); - if (modifiedTime == gpxFile.modifiedTime) { + if (prevModifiedTime == gpxFile.modifiedTime) { List segments = cache.get(trackId); if (segments == null) { segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); @@ -1242,7 +1258,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM return segments; } else { cache.clear(); - modifiedTime = gpxFile.modifiedTime; + prevModifiedTime = gpxFile.modifiedTime; List segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); cache.put(trackId, segments); return segments;