From 1d7000d59212eba6cbf31c1af5ae3ba80881bbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Z=C3=B6ller?= Date: Thu, 4 Dec 2025 13:22:23 +0100 Subject: [PATCH] Stuff --- .../fitpub/service/ActivityImageService.java | 23 +++++++++--- .../fitpub/service/OsmTileRenderer.java | 37 +++++++++++++++++++ .../fitpub/service/WeatherService.java | 7 ++++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/operaton/fitpub/service/ActivityImageService.java b/src/main/java/org/operaton/fitpub/service/ActivityImageService.java index 27a3ff4..e7c359d 100644 --- a/src/main/java/org/operaton/fitpub/service/ActivityImageService.java +++ b/src/main/java/org/operaton/fitpub/service/ActivityImageService.java @@ -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]; diff --git a/src/main/java/org/operaton/fitpub/service/OsmTileRenderer.java b/src/main/java/org/operaton/fitpub/service/OsmTileRenderer.java index c4c7aa2..b32544f 100644 --- a/src/main/java/org/operaton/fitpub/service/OsmTileRenderer.java +++ b/src/main/java/org/operaton/fitpub/service/OsmTileRenderer.java @@ -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; } diff --git a/src/main/java/org/operaton/fitpub/service/WeatherService.java b/src/main/java/org/operaton/fitpub/service/WeatherService.java index 206712d..ced9421 100644 --- a/src/main/java/org/operaton/fitpub/service/WeatherService.java +++ b/src/main/java/org/operaton/fitpub/service/WeatherService.java @@ -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();