From cdd5d4fa0227b36778778b1dd6579ca4ac545ae6 Mon Sep 17 00:00:00 2001 From: absences <49706424+absences@users.noreply.github.com> Date: Mon, 25 May 2026 16:25:52 +0800 Subject: [PATCH] Added horizontal world wrap (Date Line wrap) normalization for tile position calculation in the Unity space The issue of tiles being wrongly determined as being out of the field of view and thus not being displayed when crossing the boundary line has been resolved. --- .../BaseModule/Utilities/Conversions.cs | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Runtime/Mapbox/BaseModule/Utilities/Conversions.cs b/Runtime/Mapbox/BaseModule/Utilities/Conversions.cs index 20ae5b1c3..9519d51a5 100644 --- a/Runtime/Mapbox/BaseModule/Utilities/Conversions.cs +++ b/Runtime/Mapbox/BaseModule/Utilities/Conversions.cs @@ -132,16 +132,15 @@ public static Vector3 LatitudeLongitudeToWorldPosition(LatitudeLongitude latLong { return LatitudeLongitudeToWorldPosition(latLong.Latitude, latLong.Longitude, refPoint, scale); } - - - - /// - /// Convert a simple string to a latitude longitude. - /// Expects format: latitude, longitude - /// - /// The lat/lon as Vector2d. - /// string. - public static LatitudeLongitude StringToLatLon(string s) + + + /// + /// Convert a simple string to a latitude longitude. + /// Expects format: latitude, longitude + /// + /// The lat/lon as Vector2d. + /// string. + public static LatitudeLongitude StringToLatLon(string s) { var latLonSplit = s.Split(','); if (latLonSplit.Length != 2) @@ -219,7 +218,9 @@ public static RectD TileBoundsInWebMercator(CanonicalTileId canonicalTileId) public static Vector3 TileTopLeftInUnitySpace(CanonicalTileId unwrappedTileId, Vector2d worldCenter, float scale) { var res = InitialResolution / PowerTable2[unwrappedTileId.Z]; - var minX = (float)(((unwrappedTileId.X * TileSize) * res - OriginShift) - worldCenter.x) / scale; + var xMeters = (unwrappedTileId.X * TileSize) * res - OriginShift; + xMeters = WrapWorldX(xMeters, worldCenter.x); + var minX = (float)((xMeters - worldCenter.x) / scale); var minY = (float)((-((unwrappedTileId.Y * TileSize * res) - OriginShift)) - worldCenter.y) / scale; return new Vector3(minX, 0, minY); } @@ -239,6 +240,13 @@ public static RectD TileBoundsInUnitySpace(CanonicalTileId unwrappedTileId, Vect (unwrappedTileId.X + 1) * TileSize, (unwrappedTileId.Y + 1) * TileSize, unwrappedTileId.Z); + var centerX = (min.x + max.x) * 0.5; + var shift = Math.Round((centerX - worldCenter.x) / (OriginShift * 2.0)) * (OriginShift * 2.0); + if (shift != 0.0) + { + min.x -= shift; + max.x -= shift; + } return new RectD((min - worldCenter)/scale, (max - min)/scale); } @@ -256,6 +264,13 @@ public static float TileEdgeSizeInMercator(CanonicalTileId unwrappedTileId) return (40075017f / PowerTable2[unwrappedTileId.Z]); } + private static double WrapWorldX(double x, double worldCenterX) + { + var worldWidth = OriginShift * 2.0; + var shift = Math.Round((x - worldCenterX) / worldWidth) * worldWidth; + return x - shift; + } + public static RectD TileBoundsInUnitySpace(UnwrappedTileId unwrappedTileId, Vector2d worldCenter, float scale) { var min = PixelsToMeters( @@ -266,6 +281,13 @@ public static RectD TileBoundsInUnitySpace(UnwrappedTileId unwrappedTileId, Vect (unwrappedTileId.X + 1) * TileSize, (unwrappedTileId.Y + 1) * TileSize, unwrappedTileId.Z); + var centerX = (min.x + max.x) * 0.5; + var shift = Math.Round((centerX - worldCenter.x) / (OriginShift * 2.0)) * (OriginShift * 2.0); + if (shift != 0.0) + { + min.x -= shift; + max.x -= shift; + } return new RectD((min - worldCenter)/scale, (max - min)/scale); }