Proper implementation of route colorization algorithm
This commit is contained in:
parent
acff47bf8a
commit
3da32a65cf
4 changed files with 63 additions and 69 deletions
|
@ -328,6 +328,16 @@ public class GPXUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
public void setColor(ColorizationType type, int color) {
|
||||
if (type == ColorizationType.SPEED) {
|
||||
speedColor = color;
|
||||
} else if (type == ColorizationType.ELEVATION) {
|
||||
altitudeColor = color;
|
||||
} else if (type == ColorizationType.SLOPE) {
|
||||
slopeColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
public String getBackgroundType() {
|
||||
return getExtensionsToRead().get(BACKGROUND_TYPE_EXTENSION);
|
||||
}
|
||||
|
@ -1103,6 +1113,15 @@ public class GPXUtilities {
|
|||
return trackBounds;
|
||||
}
|
||||
|
||||
public static QuadRect calculateTrackBounds(List<TrkSegment> segments) {
|
||||
QuadRect trackBounds = new QuadRect(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
|
||||
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
for (TrkSegment segment : segments) {
|
||||
updateBounds(trackBounds, segment.points, 0);
|
||||
}
|
||||
return trackBounds;
|
||||
}
|
||||
|
||||
public static void updateBounds(QuadRect trackBounds, List<WptPt> pts, int startIndex) {
|
||||
for (int i = startIndex; i < pts.size(); i++) {
|
||||
WptPt pt = pts.get(i);
|
||||
|
|
|
@ -477,7 +477,7 @@ public class RouteColorize {
|
|||
}
|
||||
|
||||
public static class RouteColorizationPoint {
|
||||
int id;
|
||||
public int id;
|
||||
public double lat;
|
||||
public double lon;
|
||||
public double val;
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
||||
public class Renderable {
|
||||
|
||||
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
|
@ -61,7 +60,6 @@ public class Renderable {
|
|||
|
||||
public List<WptPt> points = null; // Original list of points
|
||||
protected List<WptPt> culled = new ArrayList<>(); // Reduced/resampled list of points
|
||||
protected List<WptPt> oldCulled = new ArrayList<>();
|
||||
protected int pointSize;
|
||||
protected double segmentSize;
|
||||
|
||||
|
@ -89,6 +87,9 @@ public class Renderable {
|
|||
}
|
||||
paint.setColor(p.getColor());
|
||||
paint.setStrokeWidth(p.getStrokeWidth());
|
||||
if (scaleType != null) {
|
||||
paint.setAlpha(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBorderPaint(@NonNull Paint paint) {
|
||||
|
@ -117,20 +118,18 @@ public class Renderable {
|
|||
updateLocalPaint(p);
|
||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
if (scaleType != null) {
|
||||
drawGradient(getPointsForDrawingWithBorder(), p, canvas, tileBox);
|
||||
drawGradient(points, p, canvas, tileBox);
|
||||
} else {
|
||||
drawSolid(getPointsForDrawing(), p, canvas, tileBox);
|
||||
}
|
||||
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||
}
|
||||
|
||||
|
||||
public void drawSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||
if (QuadRect.trivialOverlap(tileBox.getLatLonBounds(), trackBounds)) { // is visible?
|
||||
if (tileBox.getZoomAnimation() > 0 && !Algorithms.isEmpty(culled) && scaleType != null) {
|
||||
oldCulled = new ArrayList<>(culled);
|
||||
if (scaleType == null) {
|
||||
startCuller(zoom);
|
||||
}
|
||||
startCuller(zoom);
|
||||
drawSingleSegment(zoom, p, canvas, tileBox);
|
||||
}
|
||||
}
|
||||
|
@ -143,16 +142,6 @@ public class Renderable {
|
|||
return culled.isEmpty() ? points : culled;
|
||||
}
|
||||
|
||||
public List<WptPt> getPointsForDrawingWithBorder() {
|
||||
if (!culled.isEmpty()) {
|
||||
return culled;
|
||||
} else if (!oldCulled.isEmpty()) {
|
||||
return oldCulled;
|
||||
} else {
|
||||
return points;
|
||||
}
|
||||
}
|
||||
|
||||
public void drawGeometry(Canvas canvas, RotatedTileBox tileBox, QuadRect quadRect, int arrowColor, int trackColor, float trackWidth) {
|
||||
if (geometryWay != null) {
|
||||
List<WptPt> points = getPointsForDrawing();
|
||||
|
|
|
@ -68,6 +68,8 @@ import net.osmand.render.RenderingRuleProperty;
|
|||
import net.osmand.render.RenderingRuleSearchRequest;
|
||||
import net.osmand.render.RenderingRulesStorage;
|
||||
import net.osmand.router.RouteColorize;
|
||||
import net.osmand.router.RouteColorize.ColorizationType;
|
||||
import net.osmand.router.RouteColorize.RouteColorizationPoint;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
|
@ -680,26 +682,29 @@ 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()));
|
||||
if (!selectedGpxFile.getGpxFile().hasTrkPt() || !visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
OsmandApplication app = view.getApplication();
|
||||
GPXFile gpxFile = selectedGpxFile.getGpxFile();
|
||||
List<TrkSegment> segments = selectedGpxFile.getPointsToDisplay();
|
||||
GradientScaleType scaleType = getGradientScaleType(gpxFile);
|
||||
List<RouteColorize.RouteColorizationPoint> colorsOfPoints = null;
|
||||
List<TrkSegment> segments = new ArrayList<>();
|
||||
|
||||
if (needCalculatePointsColors(segments, scaleType)) {
|
||||
if (scaleType == null) {
|
||||
segments.addAll(selectedGpxFile.getModifiablePointsToDisplay());
|
||||
} else {
|
||||
RouteColorize colorize = new RouteColorize(view.getZoom(), gpxFile, selectedGpxFile.getTrackAnalysis(app),
|
||||
scaleType.toColorizationType(), app.getSettings().getApplicationMode().getMaxSpeed());
|
||||
colorize.setPalette(getColorizationPalette(gpxFile, scaleType));
|
||||
colorsOfPoints = colorize.getResult(false);
|
||||
List<RouteColorizationPoint> colorsOfPoints = colorize.getResult(true);
|
||||
segments.addAll(createSimplifiedSegmentsFromColorizedPoints(gpxFile, colorsOfPoints, scaleType));
|
||||
}
|
||||
|
||||
int startIdx = 0;
|
||||
for (TrkSegment ts : segments) {
|
||||
String width = getTrackWidthName(gpxFile, defaultTrackWidthPref.get());
|
||||
int color = getTrackColor(gpxFile, ts.getColor(cachedColor));
|
||||
if (colorsOfPoints != null) {
|
||||
startIdx = setColorsToPoints(ts, colorsOfPoints, scaleType, startIdx);
|
||||
}
|
||||
if (ts.renderer == null && !ts.points.isEmpty()) {
|
||||
Renderable.RenderableSegment renderer;
|
||||
if (currentTrack) {
|
||||
|
@ -720,53 +725,34 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
|
|||
}
|
||||
}
|
||||
|
||||
private boolean needCalculatePointsColors(List<TrkSegment> segments, GradientScaleType scaleType) {
|
||||
if (scaleType == null) {
|
||||
return false;
|
||||
}
|
||||
RouteColorize.ColorizationType colorizationType = scaleType.toColorizationType();
|
||||
for (int segIdx = segments.size() - 1; segIdx >= 0; segIdx--) {
|
||||
List<WptPt> pts = segments.get(segIdx).points;
|
||||
if (!Algorithms.isEmpty(pts)) {
|
||||
for (int wptIdx = pts.size() - 1; wptIdx >= 0; wptIdx--) {
|
||||
WptPt pt = pts.get(wptIdx);
|
||||
if (pt.getColor(colorizationType) == 0) {
|
||||
return true;
|
||||
private List<TrkSegment> createSimplifiedSegmentsFromColorizedPoints(GPXFile gpxFile,
|
||||
List<RouteColorizationPoint> colorizationPoints,
|
||||
GradientScaleType scaleType) {
|
||||
List<TrkSegment> 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 false;
|
||||
}
|
||||
|
||||
private int setColorsToPoints(TrkSegment segment, List<RouteColorize.RouteColorizationPoint> colors, GradientScaleType scaleType, int startIdx) {
|
||||
int pointsSize = segment.points.size();
|
||||
RouteColorize.RouteColorizationPoint startColor = colors.get(startIdx);
|
||||
RouteColorize.RouteColorizationPoint endColor = colors.get(startIdx + pointsSize - 1);
|
||||
WptPt firstPoint = segment.points.get(0);
|
||||
WptPt lastPoint = segment.points.get(pointsSize - 1);
|
||||
while (!compareCoordinates(firstPoint, startColor) && compareCoordinates(lastPoint, endColor)) {
|
||||
startIdx++;
|
||||
startColor = colors.get(startIdx);
|
||||
endColor = colors.get(startIdx + pointsSize - 1);
|
||||
}
|
||||
|
||||
for (int i = startIdx; i < startIdx + pointsSize; i++) {
|
||||
WptPt currentPoint = segment.points.get(i - startIdx);
|
||||
int currentColor = colors.get(i).color;
|
||||
if (scaleType == GradientScaleType.SPEED) {
|
||||
currentPoint.speedColor = currentColor;
|
||||
} else if (scaleType == GradientScaleType.ALTITUDE) {
|
||||
currentPoint.altitudeColor = currentColor;
|
||||
} else {
|
||||
currentPoint.slopeColor = currentColor;
|
||||
}
|
||||
}
|
||||
return startIdx;
|
||||
}
|
||||
|
||||
private boolean compareCoordinates(WptPt left, RouteColorize.RouteColorizationPoint right) {
|
||||
return left.lat == right.lat && left.lon == right.lon;
|
||||
return simplifiedSegments;
|
||||
}
|
||||
|
||||
private float getTrackWidth(String width, float defaultTrackWidth) {
|
||||
|
|
Loading…
Reference in a new issue