diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/edit/OsmMapUtils.java b/OsmAnd-java/src/main/java/net/osmand/osm/edit/OsmMapUtils.java index c4823cf9ea..a29763ee82 100644 --- a/OsmAnd-java/src/main/java/net/osmand/osm/edit/OsmMapUtils.java +++ b/OsmAnd-java/src/main/java/net/osmand/osm/edit/OsmMapUtils.java @@ -340,6 +340,30 @@ public class OsmMapUtils { } } + public static void simplifyDouglasPeucker(List nodes, int start, int end, List survivedNodes, double epsilon) { + double dmax = Double.NEGATIVE_INFINITY; + int index = -1; + + Node startPt = nodes.get(start); + Node endPt = nodes.get(end); + + for (int i = start + 1; i < end; i++) { + Node pt = nodes.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 > epsilon) { + simplifyDouglasPeucker(nodes, start, index, survivedNodes, epsilon); + simplifyDouglasPeucker(nodes, index, end, survivedNodes, epsilon); + } else { + survivedNodes.add(nodes.get(end)); + } + } + private static double orthogonalDistance(int zoom, Node nodeLineStart, Node nodeLineEnd, Node node) { LatLon p = MapUtils.getProjection(node.getLatitude(), node.getLongitude(), nodeLineStart.getLatitude(), nodeLineStart.getLongitude(), nodeLineEnd.getLatitude(), nodeLineEnd.getLongitude()); @@ -619,30 +643,6 @@ public class OsmMapUtils { return new Cell(x / area, y / area, 0, rings); } - public static void simplifyDouglasPeucker(List nodes, int start, int end, List survivedNodes, double epsilon) { - double dmax = Double.NEGATIVE_INFINITY; - int index = -1; - - Node startPt = nodes.get(start); - Node endPt = nodes.get(end); - - for (int i = start + 1; i < end; i++) { - Node pt = nodes.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 > epsilon) { - simplifyDouglasPeucker(nodes, start, index, survivedNodes, epsilon); - simplifyDouglasPeucker(nodes, index, end, survivedNodes, epsilon); - } else { - survivedNodes.add(nodes.get(end)); - } - } - private static class CellComparator implements Comparator { @Override public int compare(Cell o1, Cell o2) { diff --git a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java index 8b3494822e..d06d4077c6 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java @@ -118,8 +118,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM private MapMarkersHelper mapMarkersHelper; private GpxSelectionHelper selectedGpxHelper; - private final Map cachedModifiedTime = new HashMap<>(); - private final Map> cachedZoomedSegments = new HashMap<>(); + private final Map segmentsCache = new HashMap<>(); private List cache = new ArrayList<>(); private Map pointFileMap = new HashMap<>(); @@ -688,7 +687,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM private void drawSelectedFileSegments(SelectedGpxFile selectedGpxFile, boolean currentTrack, Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { - boolean visible = QuadRect.trivialOverlap(tileBox.getLatLonBounds(), GPXUtilities.calculateTrackBounds(selectedGpxFile.getModifiablePointsToDisplay())); + boolean visible = QuadRect.trivialOverlap(tileBox.getLatLonBounds(), GPXUtilities.calculateTrackBounds(selectedGpxFile.getPointsToDisplay())); if (!selectedGpxFile.getGpxFile().hasTrkPt() || !visible) { return; } @@ -698,7 +697,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM List segments = new ArrayList<>(); if (scaleType == null) { - segments.addAll(selectedGpxFile.getModifiablePointsToDisplay()); + segments.addAll(selectedGpxFile.getPointsToDisplay()); } else { segments.addAll(getCachedSegments(selectedGpxFile, scaleType)); } @@ -728,69 +727,14 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM private List getCachedSegments(SelectedGpxFile selectedGpxFile, GradientScaleType scaleType) { GPXFile gpxFile = selectedGpxFile.getGpxFile(); - String fileName = gpxFile.path; - String trackId = view.getZoom() + "_" + scaleType.toString() + "_" + fileName; - - if (cachedModifiedTime.get(fileName) != null && cachedModifiedTime.get(fileName) == gpxFile.modifiedTime) { - List segments = cachedZoomedSegments.get(trackId); - if (segments == null) { - segments = calculateGradientTrack(selectedGpxFile, scaleType); - cachedZoomedSegments.put(trackId, segments); - } - return segments; - } else { - if (cachedModifiedTime.get(fileName) != null) { - for (String key : cachedZoomedSegments.keySet()) { - if (key.contains("_" + fileName)) { - cachedZoomedSegments.remove(key); - } - } - } - cachedModifiedTime.put(fileName, gpxFile.modifiedTime); - List segments = calculateGradientTrack(selectedGpxFile, scaleType); - cachedZoomedSegments.put(trackId, segments); - return segments; + String path = gpxFile.path; + long modifiedTime = gpxFile.modifiedTime; + CachedTrack cachedTrack = segmentsCache.get(path); + if (cachedTrack == null) { + cachedTrack = new CachedTrack(view.getApplication(), modifiedTime); + segmentsCache.put(path, cachedTrack); } - } - - private List calculateGradientTrack(SelectedGpxFile selectedGpxFile, GradientScaleType scaleType) { - OsmandApplication app = view.getApplication(); - GPXFile gpxFile = selectedGpxFile.getGpxFile(); - RouteColorize colorize = new RouteColorize(view.getZoom(), gpxFile, selectedGpxFile.getTrackAnalysis(app), - scaleType.toColorizationType(), app.getSettings().getApplicationMode().getMaxSpeed()); - colorize.setPalette(getColorizationPalette(gpxFile, scaleType)); - List colorsOfPoints = colorize.getResult(true); - return createSimplifiedSegmentsFromColorizedPoints(selectedGpxFile.getGpxFile(), colorsOfPoints, scaleType); - } - - private List createSimplifiedSegmentsFromColorizedPoints(GPXFile gpxFile, - List colorizationPoints, - GradientScaleType scaleType) { - List simplifiedSegments = new ArrayList<>(); - ColorizationType colorizationType = scaleType.toColorizationType(); - int id = 0; - int colorPointIdx = 0; - - for (GPXUtilities.Track track : gpxFile.tracks) { - for (TrkSegment segment : track.segments) { - TrkSegment simplifiedSegment = new TrkSegment(); - simplifiedSegments.add(simplifiedSegment); - for (WptPt pt : segment.points) { - if (colorPointIdx >= colorizationPoints.size()) { - return simplifiedSegments; - } - RouteColorizationPoint colorPoint = colorizationPoints.get(colorPointIdx); - if (colorPoint.id == id) { - simplifiedSegment.points.add(pt); - pt.setColor(colorizationType, colorPoint.color); - colorPointIdx++; - } - id++; - } - } - } - - return simplifiedSegments; + return cachedTrack.getCachedSegments(selectedGpxFile, view.getZoom(), scaleType, getColorizationPalette(gpxFile, scaleType)); } private float getTrackWidth(String width, float defaultTrackWidth) { @@ -1238,4 +1182,76 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM view.getApplication().getItineraryHelper().runSynchronization(group); } } + + private static class CachedTrack { + + private OsmandApplication app; + + private long modifiedTime; + private final Map> cache = new HashMap<>(); + + public CachedTrack(@NonNull OsmandApplication app, long modifiedTime) { + this.app = app; + this.modifiedTime = modifiedTime; + } + + public List getCachedSegments(@NonNull SelectedGpxFile selectedGpxFile, int zoom, + @NonNull GradientScaleType scaleType, + int[] gradientPalette) { + GPXFile gpxFile = selectedGpxFile.getGpxFile(); + String trackId = zoom + "_" + scaleType.toString(); + if (modifiedTime == gpxFile.modifiedTime) { + List segments = cache.get(trackId); + if (segments == null) { + segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); + cache.put(trackId, segments); + } + return segments; + } else { + cache.clear(); + modifiedTime = gpxFile.modifiedTime; + List segments = calculateGradientTrack(selectedGpxFile, zoom, scaleType, gradientPalette); + cache.put(trackId, segments); + return segments; + } + } + + private List calculateGradientTrack(SelectedGpxFile selectedGpxFile, int zoom, + GradientScaleType scaleType, int[] gradientPalette) { + GPXFile gpxFile = selectedGpxFile.getGpxFile(); + RouteColorize colorize = new RouteColorize(zoom, gpxFile, selectedGpxFile.getTrackAnalysis(app), + scaleType.toColorizationType(), app.getSettings().getApplicationMode().getMaxSpeed()); + colorize.setPalette(gradientPalette); + List colorsOfPoints = colorize.getResult(true); + return createSimplifiedSegments(selectedGpxFile.getGpxFile(), colorsOfPoints, scaleType); + } + + private List createSimplifiedSegments(GPXFile gpxFile, + List colorizationPoints, + GradientScaleType scaleType) { + List simplifiedSegments = new ArrayList<>(); + ColorizationType colorizationType = scaleType.toColorizationType(); + int id = 0; + int colorPointIdx = 0; + + for (TrkSegment segment : gpxFile.getNonEmptyTrkSegments(false)) { + TrkSegment simplifiedSegment = new TrkSegment(); + simplifiedSegments.add(simplifiedSegment); + for (WptPt pt : segment.points) { + if (colorPointIdx >= colorizationPoints.size()) { + return simplifiedSegments; + } + RouteColorizationPoint colorPoint = colorizationPoints.get(colorPointIdx); + if (colorPoint.id == id) { + simplifiedSegment.points.add(pt); + pt.setColor(colorizationType, colorPoint.color); + colorPointIdx++; + } + id++; + } + } + + return simplifiedSegments; + } + } } \ No newline at end of file