This commit is contained in:
Tim Zöller 2025-12-04 13:22:23 +01:00
parent ac04dbf352
commit 1d7000d592
3 changed files with 61 additions and 6 deletions

View file

@ -150,6 +150,9 @@ public class ActivityImageService {
int trackWidth = (int) (width * 0.6);
int trackHeight = height;
// Get letterbox transformation from OSM renderer
OsmTileRenderer.LetterboxTransform letterbox = osmTileRenderer.getLastLetterboxTransform();
// Convert bounds to Web Mercator normalized coordinates (0-1)
// This matches the projection used by OSM tiles
double minX = longitudeToWebMercatorX(bounds.minLon);
@ -158,8 +161,15 @@ public class ActivityImageService {
double maxY = latitudeToWebMercatorY(bounds.minLat); // Note: minLat -> maxY (inverted)
// Calculate scale to map Web Mercator coordinates to pixels
double scaleX = trackWidth / (maxX - minX);
double scaleY = trackHeight / (maxY - minY);
// Apply letterbox scaling if available
double baseScaleX = trackWidth / (maxX - minX);
double baseScaleY = trackHeight / (maxY - minY);
double scaleX = letterbox != null ? baseScaleX * letterbox.scaleFactorX : baseScaleX;
double scaleY = letterbox != null ? baseScaleY * letterbox.scaleFactorY : baseScaleY;
int offsetX = letterbox != null ? letterbox.offsetX : 0;
int offsetY = letterbox != null ? letterbox.offsetY : 0;
// Draw track segments with privacy fade
g2d.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
@ -184,10 +194,11 @@ public class ActivityImageService {
double mercatorY2 = latitudeToWebMercatorY(lat2);
// Map Web Mercator coordinates to pixel coordinates
double x1 = (mercatorX1 - minX) * scaleX;
double y1 = (mercatorY1 - minY) * scaleY;
double x2 = (mercatorX2 - minX) * scaleX;
double y2 = (mercatorY2 - minY) * scaleY;
// Apply letterbox offset
double x1 = (mercatorX1 - minX) * scaleX + offsetX;
double y1 = (mercatorY1 - minY) * scaleY + offsetY;
double x2 = (mercatorX2 - minX) * scaleX + offsetX;
double y2 = (mercatorY2 - minY) * scaleY + offsetY;
// Calculate opacity based on distance from start/end
double distanceFromStart = cumulativeDistances[i];

View file

@ -52,6 +52,37 @@ public class OsmTileRenderer {
.build();
}
/**
* Holder for letterboxing transformation parameters.
*/
public static class LetterboxTransform {
public final int offsetX;
public final int offsetY;
public final int scaledWidth;
public final int scaledHeight;
public final double scaleFactorX;
public final double scaleFactorY;
public LetterboxTransform(int offsetX, int offsetY, int scaledWidth, int scaledHeight,
int originalWidth, int originalHeight) {
this.offsetX = offsetX;
this.offsetY = offsetY;
this.scaledWidth = scaledWidth;
this.scaledHeight = scaledHeight;
this.scaleFactorX = (double) scaledWidth / originalWidth;
this.scaleFactorY = (double) scaledHeight / originalHeight;
}
}
private LetterboxTransform lastLetterboxTransform;
/**
* Get the letterbox transformation from the last render operation.
*/
public LetterboxTransform getLastLetterboxTransform() {
return lastLetterboxTransform;
}
/**
* Render a map image with OSM tiles covering the specified geographic bounds.
*
@ -168,6 +199,12 @@ public class OsmTileRenderer {
g.drawImage(croppedMap, drawX, drawY, drawWidth, drawHeight, null);
g.dispose();
// Store letterbox transform for track rendering
lastLetterboxTransform = new LetterboxTransform(
drawX, drawY, drawWidth, drawHeight,
croppedMap.getWidth(), croppedMap.getHeight()
);
return scaledMap;
}

View file

@ -76,6 +76,13 @@ public class WeatherService {
}
JsonNode firstPoint = trackPoints.get(0);
// Check if lat/lon fields exist
if (!firstPoint.has("lat") || !firstPoint.has("lon")) {
log.debug("First track point missing lat/lon for activity {}", activity.getId());
return Optional.empty();
}
double lat = firstPoint.get("lat").asDouble();
double lon = firstPoint.get("lon").asDouble();