diff --git a/CHANGES.md b/CHANGES.md index 16312bbd..8432d01d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,11 @@ - Fixed a bug that caused Cesium ion tokens selected on the Tokens panel to fail to save. - Fixed a bug that caused the "Select Cesium ion Token" panel to show the wrong state when the current token was not from the currently-signed-in Cesium ion account, but the signed-in account had a token named after the current Unity project. +##### Additions :tada: +- Added support for custom non-WGS84 ellipsoids. + - The ellipsoid can be changed by specifying a `CesiumEllipsoid` asset in the new "Ellipsoid Override" property of a `CesiumGeoreference`. + - New `CesiumEllipsoid` assets can be created using the menu option `Assets > Create > Cesium > Ellipsoid`. + ### v1.10.1 - 2024-06-03 This release updates [cesium-native](https://github.com/CesiumGS/cesium-native) from v0.35.0 to v0.36.0. See the [changelog](https://github.com/CesiumGS/cesium-native/blob/main/CHANGES.md) for a complete list of changes in cesium-native. diff --git a/Editor/CesiumGeoreferenceEditor.cs b/Editor/CesiumGeoreferenceEditor.cs index b216095c..1b259dc1 100644 --- a/Editor/CesiumGeoreferenceEditor.cs +++ b/Editor/CesiumGeoreferenceEditor.cs @@ -21,6 +21,7 @@ internal CesiumGeoreferenceOriginAuthority originAuthority } } + private SerializedProperty _ellipsoidOverride; private SerializedProperty _latitude; private SerializedProperty _longitude; private SerializedProperty _height; @@ -35,6 +36,7 @@ private void OnEnable() { this._georeference = (CesiumGeoreference)this.target; + this._ellipsoidOverride = this.serializedObject.FindProperty("_ellipsoidOverride"); this._originAuthority = this.serializedObject.FindProperty("_originAuthority"); @@ -56,6 +58,8 @@ public override void OnInspectorGUI() DrawInspectorButtons(); EditorGUILayout.Space(5); + this.DrawEllipsoidOverrideProperty(); + EditorGUILayout.Space(5); this.DrawScaleProperty(); EditorGUILayout.Space(5); this.DrawOriginAuthorityProperty(); @@ -104,6 +108,22 @@ private void DrawInspectorButtons() EditorGUI.EndDisabledGroup(); } + private void DrawEllipsoidOverrideProperty() + { + GUIContent ellipsoidOverrideContent = new GUIContent( + "Ellipsoid Override", + "The ellipsoid definition to use for this tileset. If this is left blank, " + + "the ellipsoid specified by the tileset is used, or WGS84 if the tileset " + + "doesn't list an ellipsoid to use."); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(this._ellipsoidOverride, ellipsoidOverrideContent); + if(EditorGUI.EndChangeCheck()) + { + this.serializedObject.ApplyModifiedProperties(); + this._georeference.ReloadEllipsoid(); + } + } + private void DrawScaleProperty() { GUIContent scaleContent = new GUIContent( diff --git a/Runtime/Cesium3DTile.cs b/Runtime/Cesium3DTile.cs index 016e280e..1aff7962 100644 --- a/Runtime/Cesium3DTile.cs +++ b/Runtime/Cesium3DTile.cs @@ -15,6 +15,7 @@ public partial class Cesium3DTile { internal double4x4 _transform; internal IntPtr _pTile; + internal IntPtr _pTileEllipsoid; internal Cesium3DTile() {} @@ -27,10 +28,10 @@ public Bounds bounds { get { - return Cesium3DTile.getBounds(this._pTile, this._transform); + return Cesium3DTile.getBounds(this._pTile, this._pTileEllipsoid, this._transform); } } - private static partial Bounds getBounds(IntPtr pTile, double4x4 ecefToLocalMatrix); + private static partial Bounds getBounds(IntPtr pTile, IntPtr pTileEllipsoid, double4x4 ecefToLocalMatrix); } } diff --git a/Runtime/CesiumCameraController.cs b/Runtime/CesiumCameraController.cs index ee419b16..bd5c5e03 100644 --- a/Runtime/CesiumCameraController.cs +++ b/Runtime/CesiumCameraController.cs @@ -622,7 +622,7 @@ private void Move(Vector3 movementInput) if (this._georeference != null) { double3 positionECEF = this._globeAnchor.positionGlobeFixed; - double3 upECEF = CesiumWgs84Ellipsoid.GeodeticSurfaceNormal(positionECEF); + double3 upECEF = this._georeference.ellipsoid.GeodeticSurfaceNormal(positionECEF); double3 upUnity = this._georeference.TransformEarthCenteredEarthFixedDirectionToUnity(upECEF); @@ -801,7 +801,7 @@ private void UpdateClippingPlanes() if (height >= this._dynamicClippingPlanesMinHeight) { - farClipPlane = height + (float)(2.0 * CesiumWgs84Ellipsoid.GetMaximumRadius()); + farClipPlane = height + (float)(2.0 * this._georeference.ellipsoid.GetMaximumRadius()); farClipPlane = Mathf.Min(farClipPlane, this._maximumFarClipPlane); float farClipRatio = farClipPlane / this._maximumNearToFarRatio; diff --git a/Runtime/CesiumCartographicPolygon.cs b/Runtime/CesiumCartographicPolygon.cs index 13305fc1..270f94e2 100644 --- a/Runtime/CesiumCartographicPolygon.cs +++ b/Runtime/CesiumCartographicPolygon.cs @@ -138,7 +138,7 @@ internal List GetCartographicPoints(Matrix4x4 worldToTileset) float3 worldPosition = knot.Transform(localToWorld).Position; float3 unityPosition = worldToTileset.MultiplyPoint3x4(worldPosition); double3 ecefPosition = georeference.TransformUnityPositionToEarthCenteredEarthFixed(unityPosition); - double3 cartographicPosition = CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(ecefPosition); + double3 cartographicPosition = georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(ecefPosition); cartographicPoints.Add(cartographicPosition.xy); } diff --git a/Runtime/CesiumEllipsoid.cs b/Runtime/CesiumEllipsoid.cs new file mode 100644 index 00000000..341a1447 --- /dev/null +++ b/Runtime/CesiumEllipsoid.cs @@ -0,0 +1,107 @@ +using Reinterop; +using Unity.Mathematics; +using UnityEngine; + + +namespace CesiumForUnity +{ + [ReinteropNativeImplementation("CesiumForUnityNative::CesiumEllipsoidImpl", "CesiumEllipsoidImpl.h")] + [IconAttribute("Packages/com.cesium.unity/Editor/Resources/Cesium-24x24.png")] + [CreateAssetMenu(menuName = "Cesium/Ellipsoid")] + public partial class CesiumEllipsoid : ScriptableObject + { + /// + /// Obtain a WGS84 ellipsoid. + /// + public static CesiumEllipsoid WGS84 + { + get + { + if (_cachedWgs84 == null) + { + _cachedWgs84 = CreateInstance(); + _cachedWgs84.name = "WGS84"; + _cachedWgs84.SetRadii(CesiumWgs84Ellipsoid.GetRadii()); + } + + return _cachedWgs84; + } + } + + private static CesiumEllipsoid _cachedWgs84; + + [SerializeField] + private double3 _radii = new double3(1.0, 1.0, 1.0); + + internal double3 radii + { + get => _radii; + set => _radii = value; + } + + /// + /// Gets the maximum radius of the ellipsoid in any dimension. + /// + /// The maximum radius of the ellipsoid. + public double GetMaximumRadius() + { + return math.cmax(this.GetRadii()); + } + + /// + /// Gets the minimum radius of the ellipsoid in any dimension. + /// + /// The minimum radius of the ellipsoid. + public double GetMinimumRadius() + { + return math.cmin(this.GetRadii()); + } + + /// + /// Returns the radii of this ellipsoid. + /// + public partial double3 GetRadii(); + + /// + /// Sets the radii of this ellipsoid to the given values. + /// + /// The new (x, y, z) radii of the ellipsoid. + public partial void SetRadii(double3 newRadii); + + /// + /// Scale the given Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) position along the geodetic surface normal + /// so that it is on the surface of the ellipsoid. If the position is at the center of the + /// ellipsoid, the result will be null. + /// + /// The ECEF position in meters. + /// The scaled position, or null if the position is at the center of the ellipsoid. + public partial double3? ScaleToGeodeticSurface(double3 ellipsoidCenteredEllipsoidFixed); + + /// + /// Computes the normal of the plane tangent to the surface of the ellipsoid at the provided + /// Ellipsoid-Centered, Ellipsoid-Fixed position. + /// + /// The ECEF position in meters. + /// The normal at the ECEF position + public partial double3 GeodeticSurfaceNormal(double3 ellipsoidCenteredEllipsoidFixed); + + /// + /// Convert longitude, latitude, and height to Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates. + /// + /// + /// The longitude (X) and latitude (Y) are in degrees. The height (Z) is in meters above the ellipsoid, + /// and should not be confused with a geoid, orthometric, or mean sea level height. + /// The ECEF coordinates in meters. + public partial double3 LongitudeLatitudeHeightToCenteredFixed(double3 longitudeLatitudeHeight); + + /// + /// Convert Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates to longitude, latitude, and height. + /// + /// The ECEF coordinates in meters. + /// + /// The longitude (X) and latitude (Y) are in degrees. The height (Z) is in meters above the ellipsoid, + /// and should not be confused with a geoid, orthometric, or mean sea level height. + /// + public partial double3 CenteredFixedToLongitudeLatitudeHeight(double3 ellipsoidCenteredEllipsoidFixed); + } +} diff --git a/Runtime/CesiumEllipsoid.cs.meta b/Runtime/CesiumEllipsoid.cs.meta new file mode 100644 index 00000000..4194a092 --- /dev/null +++ b/Runtime/CesiumEllipsoid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b804adc3b6f529547be7580b9ddc8d86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/CesiumFlyToController.cs b/Runtime/CesiumFlyToController.cs index 399842f8..51eb7c4d 100644 --- a/Runtime/CesiumFlyToController.cs +++ b/Runtime/CesiumFlyToController.cs @@ -361,7 +361,10 @@ private void ComputeFlightPath( this._destinationRotation = Quaternion.Euler(pitchAtDestination, yawAtDestination, 0.0f); this._destinationECEF = destinationECEF; - this._flightPath = CesiumSimplePlanarEllipsoidCurve.FromEarthCenteredEarthFixedCoordinates(sourceECEF, destinationECEF); + this._flightPath = CesiumSimplePlanarEllipsoidCurve.FromCenteredFixedCoordinates( + this._georeference.ellipsoid, + sourceECEF, + destinationECEF); this._flightPathLength = math.length(sourceECEF - destinationECEF); this._maxHeight = 0.0; @@ -483,7 +486,7 @@ public void FlyToLocationLongitudeLatitudeHeight( bool canInterruptByMoving) { double3 destinationECEF = - CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(destination); + this._georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(destination); this.FlyToLocationEarthCenteredEarthFixed( destinationECEF, @@ -522,7 +525,7 @@ public void FlyToLocationLongitudeLatitudeHeight( z = destination.z }; double3 destinationECEF = - CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed( + this._georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed( destinationCoordinates); this.FlyToLocationEarthCenteredEarthFixed( diff --git a/Runtime/CesiumGeoreference.cs b/Runtime/CesiumGeoreference.cs index 644b60aa..d07d5146 100644 --- a/Runtime/CesiumGeoreference.cs +++ b/Runtime/CesiumGeoreference.cs @@ -65,6 +65,8 @@ public enum CesiumGeoreferenceOriginAuthority public partial class CesiumGeoreference : MonoBehaviour { #region Fields + [SerializeField] + private CesiumEllipsoid _ellipsoidOverride = null; [SerializeField] private CesiumGeoreferenceOriginAuthority _originAuthority = CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight; @@ -106,6 +108,9 @@ public partial class CesiumGeoreference : MonoBehaviour [NonSerialized] private HashSet _globeAnchors = new HashSet(); + [NonSerialized] + private CesiumEllipsoid _ellipsoid = null; + #endregion /// @@ -254,6 +259,25 @@ public double4x4 ecefToLocalMatrix } } + public CesiumEllipsoid ellipsoid + { + get + { + if (this._ellipsoid == null) + { + // Make a copy of the ellipsoid ScriptableObject + this._ellipsoid = ScriptableObject.CreateInstance(); + this._ellipsoid.SetRadii((this._ellipsoidOverride ?? CesiumEllipsoid.WGS84).radii); + } + + return this._ellipsoid; + } + set + { + this._ellipsoid = value; + } + } + /// /// An event raised when the georeference changes. /// @@ -356,6 +380,23 @@ public void Initialize() } } + /// + /// Called when the ellipsoid override property has changed. + /// + public void ReloadEllipsoid() + { + // clear cached ellipsoid so it has to be rebuilt + this._ellipsoid = null; + this.UpdateTransformations(); + this.UpdateOtherCoordinates(); + + Cesium3DTileset[] tilesets = GetComponentsInChildren(); + foreach(var tileset in tilesets) + { + tileset.RecreateTileset(); + } + } + private void UpdateTransformations() { this._localToEcef = this.ComputeLocalToEarthCenteredEarthFixedTransformation(); @@ -424,7 +465,7 @@ private void UpdateOtherCoordinates() if (this._originAuthority == CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight) { double3 ecef = - CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed( + this.ellipsoid.LongitudeLatitudeHeightToCenteredFixed( new double3(this._longitude, this._latitude, this._height)); this._ecefX = ecef.x; this._ecefY = ecef.y; @@ -433,7 +474,7 @@ private void UpdateOtherCoordinates() else if (this._originAuthority == CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed) { double3 llh = - CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight( + this.ellipsoid.CenteredFixedToLongitudeLatitudeHeight( new double3(this._ecefX, this._ecefY, this._ecefZ)); this._longitude = llh.x; this._latitude = llh.y; diff --git a/Runtime/CesiumGlobeAnchor.cs b/Runtime/CesiumGlobeAnchor.cs index e038206f..840314ea 100644 --- a/Runtime/CesiumGlobeAnchor.cs +++ b/Runtime/CesiumGlobeAnchor.cs @@ -84,6 +84,9 @@ public partial class CesiumGlobeAnchor : MonoBehaviour, ICesiumRestartable [NonSerialized] internal CesiumGeoreference _georeference; + [NonSerialized] + internal double3? _lastEllipsoidRadii; + #endregion #region User-editable properties @@ -182,10 +185,10 @@ public double4x4 localToGlobeFixedMatrix /// public double3 longitudeLatitudeHeight { - get => CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(this.positionGlobeFixed); + get => this._georeference.ellipsoid.CenteredFixedToLongitudeLatitudeHeight(this.positionGlobeFixed); set { - this.positionGlobeFixed = CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(value); + this.positionGlobeFixed = this._georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(value); } } @@ -396,7 +399,7 @@ public void SetPositionLongitudeLatitudeHeight(double longitude, double latitude this.longitudeLatitudeHeight = new double3(longitude, latitude, height); } - + [Obsolete("Set the positionGlobeFixed property instead.")] public void SetPositionEarthCenteredEarthFixed(double x, double y, double z) { @@ -444,9 +447,16 @@ public void SetPositionEarthCenteredEarthFixed(double x, double y, double z) /// public void Sync() { + // If the ellipsoid changed since last sync, we need to update from transform since our ECEF mapping + // is going to be invalid. + bool isEllipsoidChanged = _lastEllipsoidRadii.HasValue ? + (_lastEllipsoidRadii.Value.x != _georeference.ellipsoid.radii.x || + _lastEllipsoidRadii.Value.y != _georeference.ellipsoid.radii.y || + _lastEllipsoidRadii.Value.z != _georeference.ellipsoid.radii.z) : true; + // If we don't have a local -> globe fixed matrix yet, we must update from the Transform bool updateFromTransform = !this._localToGlobeFixedMatrixIsValid; - if (!updateFromTransform && this._lastLocalsAreValid) + if (!isEllipsoidChanged && !updateFromTransform && this._lastLocalsAreValid) { // We may also need to update from the Transform if it has changed // since the last time we computed the local -> globe fixed matrix. @@ -456,7 +466,9 @@ public void Sync() this._lastLocalScale != this.transform.localScale; } - if (updateFromTransform) + _lastEllipsoidRadii = _georeference.ellipsoid.radii; + + if (isEllipsoidChanged || updateFromTransform) this.UpdateEcefFromTransform(); else this.UpdateEcef(this._localToGlobeFixedMatrix); diff --git a/Runtime/CesiumSimplePlanarEllipsoidCurve.cs b/Runtime/CesiumSimplePlanarEllipsoidCurve.cs index d4ed6ac4..22830bfa 100644 --- a/Runtime/CesiumSimplePlanarEllipsoidCurve.cs +++ b/Runtime/CesiumSimplePlanarEllipsoidCurve.cs @@ -1,4 +1,5 @@ using Reinterop; +using System; using Unity.Mathematics; using UnityEngine; @@ -6,15 +7,23 @@ namespace CesiumForUnity { /// /// Describes a curve that's a section of an ellipse that lies on a plane intersecting the center of the earth and - /// both the source and destination points on a WGS84 ellipsoid. This curve can be sampled at any point along its length. + /// both the source and destination points on an ellipsoid. This curve can be sampled at any point along its length. /// [ReinteropNativeImplementation("CesiumForUnityNative::CesiumSimplePlanarEllipsoidCurveImpl", "CesiumSimplePlanarEllipsoidCurveImpl.h")] [IconAttribute("Packages/com.cesium.unity/Editor/Resources/Cesium-24x24.png")] public partial class CesiumSimplePlanarEllipsoidCurve { + [Obsolete("Use CesiumSimplePlanarCurve.FromCenteredFixedCoordinates instead.")] + public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordinates( + CesiumEllipsoid ellipsoid, double3 sourceEcef, double3 destinationEcef) + { + return FromCenteredFixedCoordinates(ellipsoid, sourceEcef, destinationEcef); + } + + /// /// Creates a new object from a pair of - /// Earth-Centered, Earth-Fixed coordinates describing the beginning and end points of the curve. + /// Ellipsoid-Centered, Ellipsoid-Fixed coordinates describing the beginning and end points of the curve. /// /// The start point of the curve. /// The end point of the curve. @@ -22,10 +31,10 @@ public partial class CesiumSimplePlanarEllipsoidCurve /// A if a curve can successfully be /// created between the two points, or null otherwise. /// - public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordinates(double3 sourceEcef, double3 destinationEcef) + public static CesiumSimplePlanarEllipsoidCurve FromCenteredFixedCoordinates(CesiumEllipsoid ellipsoid, double3 sourceEcef, double3 destinationEcef) { CesiumSimplePlanarEllipsoidCurve curve = new CesiumSimplePlanarEllipsoidCurve(); - if (!curve.CreateFromEarthCenteredEarthFixedCoordinates(sourceEcef, destinationEcef)) + if (!curve.CreateFromCenteredFixed(ellipsoid, sourceEcef, destinationEcef)) { return null; } @@ -43,10 +52,10 @@ public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordi /// A if a curve can successfully be /// created between the two points, or null otherwise. /// - public static CesiumSimplePlanarEllipsoidCurve FromLongituteLatitudeHeight(double3 sourceLlh, double3 destinationLlh) + public static CesiumSimplePlanarEllipsoidCurve FromLongituteLatitudeHeight(CesiumEllipsoid ellipsoid, double3 sourceLlh, double3 destinationLlh) { CesiumSimplePlanarEllipsoidCurve curve = new CesiumSimplePlanarEllipsoidCurve(); - if (!curve.CreateFromLongitudeLatitudeHeight(sourceLlh, destinationLlh)) + if (!curve.CreateFromLongitudeLatitudeHeight(ellipsoid, sourceLlh, destinationLlh)) { return null; } @@ -70,8 +79,8 @@ public static CesiumSimplePlanarEllipsoidCurve FromLongituteLatitudeHeight(doubl /// The position of the given point on this curve in Earth-Centered, Earth-Fixed coordinates. public partial double3 GetPosition(double percentage, double additionalHeight = 0.0); - private partial bool CreateFromEarthCenteredEarthFixedCoordinates(double3 sourceEcef, double3 destinationEcef); - private partial bool CreateFromLongitudeLatitudeHeight(double3 sourceLlh, double3 destinationLlh); + private partial bool CreateFromCenteredFixed(CesiumEllipsoid ellipsoid, double3 sourceEcef, double3 destinationEcef); + private partial bool CreateFromLongitudeLatitudeHeight(CesiumEllipsoid ellipsoid, double3 sourceLlh, double3 destinationLlh); private CesiumSimplePlanarEllipsoidCurve() { diff --git a/Runtime/CesiumSubScene.cs b/Runtime/CesiumSubScene.cs index f4a88a3c..040be15a 100644 --- a/Runtime/CesiumSubScene.cs +++ b/Runtime/CesiumSubScene.cs @@ -387,9 +387,19 @@ private void OnDestroy() private void UpdateOtherCoordinates() { + if(this._parentGeoreference == null) + { + this.UpdateParentReference(); + + if(this._parentGeoreference == null) + { + throw new InvalidOperationException("CesiumSubScene should have been nested inside a game object with a CesiumGeoreference."); + } + } + if (this._originAuthority == CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight) { - double3 ecef = CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(new double3( + double3 ecef = this._parentGeoreference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(new double3( this._longitude, this._latitude, this._height @@ -402,7 +412,7 @@ private void UpdateOtherCoordinates() if (this._originAuthority == CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed) { - double3 llh = CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(new double3( + double3 llh = this._parentGeoreference.ellipsoid.CenteredFixedToLongitudeLatitudeHeight(new double3( this._ecefX, this._ecefY, this._ecefZ diff --git a/Runtime/ConfigureReinterop.cs b/Runtime/ConfigureReinterop.cs index 46eafc39..1722bd91 100644 --- a/Runtime/ConfigureReinterop.cs +++ b/Runtime/ConfigureReinterop.cs @@ -148,6 +148,7 @@ public void ExposeToCPP() Debug.Log("Logging"); Debug.LogWarning("Warning"); + Debug.LogError("Error"); MeshRenderer meshRenderer = new MeshRenderer(); GameObject meshGameObject = meshRenderer.gameObject; @@ -517,7 +518,13 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails CesiumGlobeAnchor globeAnchor = globeAnchors[globeAnchors.Length - 1]; globeAnchor.positionGlobeFixed = globeAnchor.positionGlobeFixed; - CesiumSimplePlanarEllipsoidCurve planarEllipsoidCurve = CesiumSimplePlanarEllipsoidCurve.FromEarthCenteredEarthFixedCoordinates(new double3(0, 0, 0), new double3(0, 0, 0)); + CesiumSimplePlanarEllipsoidCurve planarEllipsoidCurve = CesiumSimplePlanarEllipsoidCurve.FromCenteredFixedCoordinates( + CesiumEllipsoid.WGS84, + new double3(0, 0, 0), + new double3(0, 0, 0)); + CesiumEllipsoid ellipsoid = CesiumEllipsoid.WGS84; + ellipsoid.radii = new double3(0.0, 0.0, 0.0); + georeference.ellipsoid = ellipsoid; globeAnchor = go.AddComponent(); globeAnchor.detectTransformChanges = globeAnchor.detectTransformChanges; @@ -543,6 +550,7 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails Cesium3DTile tile = new Cesium3DTile(); tile._transform = new double4x4(); tile._pTile = IntPtr.Zero; + tile._pTileEllipsoid = IntPtr.Zero; Cesium3DTileInfo info; info.usesAdditiveRefinement = true; @@ -806,7 +814,7 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails primitiveFeatures = hitInfo.transform.GetComponent(); int triangleIndex = hitInfo.triangleIndex; Vector3 hitPoint = hitInfo.point; - + Vector2 textureCoordinate = new Vector2(); textureCoordinate.x = textureCoordinate.y; hitPoint = m2.MultiplyPoint3x4(hitPoint); diff --git a/Tests/Comparers.cs b/Tests/Comparers.cs index 31e0e54e..3a55a953 100644 --- a/Tests/Comparers.cs +++ b/Tests/Comparers.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Unity.Mathematics; internal class Comparers { @@ -37,6 +38,26 @@ private double RelativeToAbsoluteEpsilon(double left, double right, double relat } } + private class Double3Comparer : IEqualityComparer + { + private DoubleComparer _doubleComparer; + + public Double3Comparer(double absoluteEpsilon, double relativeEpsilon = 0.0) + { + this._doubleComparer = new DoubleComparer(absoluteEpsilon, relativeEpsilon); + } + + public bool Equals(double3 a, double3 b) + { + return _doubleComparer.Equals(a.x, b.x) && _doubleComparer.Equals(a.y, b.y) && _doubleComparer.Equals(a.z, b.z); + } + + public int GetHashCode(double3 obj) + { + throw new NotImplementedException(); + } + } + public static IEqualityComparer Double(double absoluteEpsilon) { return new DoubleComparer(absoluteEpsilon); @@ -46,4 +67,14 @@ public static IEqualityComparer Double(double absoluteEpsilon, double re { return new DoubleComparer(absoluteEpsilon, relativeEpsilon); } + + public static IEqualityComparer Double3(double absoluteEpsilon) + { + return new Double3Comparer(absoluteEpsilon); + } + + public static IEqualityComparer Double3(double absoluteEpsilon, double relativeEpsilon) + { + return new Double3Comparer(absoluteEpsilon, relativeEpsilon); + } } diff --git a/Tests/TestCesiumGlobeAnchor.cs b/Tests/TestCesiumGlobeAnchor.cs index 22c7ade5..c5eb75cf 100644 --- a/Tests/TestCesiumGlobeAnchor.cs +++ b/Tests/TestCesiumGlobeAnchor.cs @@ -237,7 +237,7 @@ public IEnumerator SettingTransformPositionAlsoUpdatesOrientation() // Modify the object's position via the Transform. goAnchored.transform.position = new Vector3(20000.0f, 3000.0f, -80000.0f); - + // The orientation should not immediately change, because the coroutine has to run first. Assert.That(goAnchored.transform.position.x, Is.EqualTo(20000.0f).Using(FloatEqualityComparer.Instance)); Assert.That(goAnchored.transform.position.y, Is.EqualTo(3000.0f).Using(FloatEqualityComparer.Instance)); @@ -256,4 +256,38 @@ public IEnumerator SettingTransformPositionAlsoUpdatesOrientation() Assert.That(goAnchored.transform.rotation.eulerAngles.y, Is.Not.EqualTo(20.0f).Using(FloatEqualityComparer.Instance)); Assert.That(goAnchored.transform.rotation.eulerAngles.z, Is.Not.EqualTo(30.0f).Using(FloatEqualityComparer.Instance)); } + + [Test] + public void GivesCorrectResultsForDifferentEllipsoids() + { + IEqualityComparer epsilon6 = Comparers.Double3(1e-6, 1e-4); + + double3 positionLlh = new double3(-20, -10, 1000.0); + + GameObject goGeoreference = new GameObject("Georeference"); + CesiumGeoreference georeference = goGeoreference.AddComponent(); + georeference.ellipsoid = CesiumEllipsoid.WGS84; + georeference.SetOriginLongitudeLatitudeHeight(positionLlh.x, positionLlh.y, positionLlh.z); + + GameObject goAnchored = new GameObject("Anchored"); + goAnchored.transform.parent = goGeoreference.transform; + goAnchored.transform.SetPositionAndRotation(new Vector3(0, 0, 0), Quaternion.identity); + + CesiumGlobeAnchor anchor = goAnchored.AddComponent(); + + // Test WGS84 first + double3 actualPosEcef = CesiumEllipsoid.WGS84.LongitudeLatitudeHeightToCenteredFixed(positionLlh); + Assert.That(anchor.positionGlobeFixed, Is.EqualTo(actualPosEcef).Using(epsilon6)); + + // Test with unit ellipsoid + CesiumEllipsoid unitEllipsoid = ScriptableObject.CreateInstance(); + unitEllipsoid.SetRadii(new double3(1.0, 1.0, 1.0)); + georeference.ellipsoid = unitEllipsoid; + georeference.SetOriginLongitudeLatitudeHeight(positionLlh.x, positionLlh.y, positionLlh.z); + + actualPosEcef = unitEllipsoid.LongitudeLatitudeHeightToCenteredFixed(positionLlh); + goAnchored.transform.SetPositionAndRotation(new Vector3(0, 0, 0), Quaternion.identity); + anchor.Sync(); + Assert.That(anchor.positionGlobeFixed, Is.EqualTo(actualPosEcef).Using(epsilon6)); + } } diff --git a/Tests/TestCesiumSimplePlanarEllipsoidCurve.cs b/Tests/TestCesiumSimplePlanarEllipsoidCurve.cs index f58cae16..f753b3c6 100644 --- a/Tests/TestCesiumSimplePlanarEllipsoidCurve.cs +++ b/Tests/TestCesiumSimplePlanarEllipsoidCurve.cs @@ -21,7 +21,7 @@ private double3 RelativeToAbsoluteEpsilon(double3 left, double3 right, double re public IEnumerator StartAndEndOfPathAreIdenticalToInput() { CesiumSimplePlanarEllipsoidCurve flightPath = - CesiumSimplePlanarEllipsoidCurve.FromEarthCenteredEarthFixedCoordinates(_philadelphiaEcef, _tokyoEcef); + CesiumSimplePlanarEllipsoidCurve.FromCenteredFixedCoordinates(CesiumEllipsoid.WGS84, _philadelphiaEcef, _tokyoEcef); Assert.IsNotNull(flightPath); double3 startPosition = flightPath.GetPosition(0.0); @@ -43,7 +43,7 @@ public IEnumerator StartAndEndOfPathAreIdenticalToInput() public IEnumerator ShouldCalculateMidpointCorrectly() { CesiumSimplePlanarEllipsoidCurve flightPath = - CesiumSimplePlanarEllipsoidCurve.FromEarthCenteredEarthFixedCoordinates(_philadelphiaEcef, _tokyoEcef); + CesiumSimplePlanarEllipsoidCurve.FromCenteredFixedCoordinates(CesiumEllipsoid.WGS84, _philadelphiaEcef, _tokyoEcef); Assert.IsNotNull(flightPath); double3 expectedResult = new double3( diff --git a/WGS84.asset b/WGS84.asset new file mode 100644 index 00000000..e2b271c5 --- /dev/null +++ b/WGS84.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b804adc3b6f529547be7580b9ddc8d86, type: 3} + m_Name: WGS84 + m_EditorClassIdentifier: + _radii: + x: 6378137 + y: 6378137 + z: 6356752.314245 diff --git a/WGS84.asset.meta b/WGS84.asset.meta new file mode 100644 index 00000000..1f3537db --- /dev/null +++ b/WGS84.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5db7b2e3ffd57a049aba6b75aa797982 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/native~/Runtime/src/CameraManager.cpp b/native~/Runtime/src/CameraManager.cpp index 586eaada..035b4cb1 100644 --- a/native~/Runtime/src/CameraManager.cpp +++ b/native~/Runtime/src/CameraManager.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ namespace CesiumForUnityNative { namespace { ViewState unityCameraToViewState( + const CesiumGeoreference& georeference, const LocalHorizontalCoordinateSystem* pCoordinateSystem, const glm::dmat4& unityWorldToTileset, Camera& camera) { @@ -71,13 +73,19 @@ ViewState unityCameraToViewState( double horizontalFOV = 2 * glm::atan(camera.aspect() * glm::tan(verticalFOV * 0.5)); + const CesiumGeospatial::Ellipsoid& ellipsoid = + georeference != nullptr + ? georeference.ellipsoid().NativeImplementation().GetEllipsoid() + : CesiumGeospatial::Ellipsoid::WGS84; + return ViewState::create( cameraPosition, glm::normalize(cameraDirection), glm::normalize(cameraUp), glm::dvec2(camera.pixelWidth(), camera.pixelHeight()), horizontalFOV, - verticalFOV); + verticalFOV, + ellipsoid); } } // namespace @@ -100,8 +108,11 @@ std::vector CameraManager::getAllCameras(const GameObject& context) { std::vector result; Camera camera = Camera::main(); if (camera != nullptr) { - result.emplace_back( - unityCameraToViewState(pCoordinateSystem, unityWorldToTileset, camera)); + result.emplace_back(unityCameraToViewState( + georeferenceComponent, + pCoordinateSystem, + unityWorldToTileset, + camera)); } #if UNITY_EDITOR @@ -111,6 +122,7 @@ std::vector CameraManager::getAllCameras(const GameObject& context) { Camera editorCamera = lastActiveEditorView.camera(); if (editorCamera != nullptr) { result.emplace_back(unityCameraToViewState( + georeferenceComponent, pCoordinateSystem, unityWorldToTileset, editorCamera)); diff --git a/native~/Runtime/src/Cesium3DTileImpl.cpp b/native~/Runtime/src/Cesium3DTileImpl.cpp index 247d337e..5cb82cd3 100644 --- a/native~/Runtime/src/Cesium3DTileImpl.cpp +++ b/native~/Runtime/src/Cesium3DTileImpl.cpp @@ -3,21 +3,27 @@ #include "UnityTransforms.h" #include +#include #include #include using namespace Cesium3DTilesSelection; using namespace CesiumGeometry; +using namespace CesiumGeospatial; namespace CesiumForUnityNative { DotNet::UnityEngine::Bounds Cesium3DTileImpl::getBounds( void* pTileVoid, + void* pTileEllipsoidVoid, const DotNet::Unity::Mathematics::double4x4& ecefToLocalMatrix) { const Tile* pTile = static_cast(pTileVoid); + const Ellipsoid* pTileEllipsoid = + static_cast(pTileEllipsoidVoid); const BoundingVolume& bv = pTile->getBoundingVolume(); - OrientedBoundingBox obb = getOrientedBoundingBoxFromBoundingVolume(bv); + OrientedBoundingBox obb = + getOrientedBoundingBoxFromBoundingVolume(bv, *pTileEllipsoid); obb = obb.transform(UnityTransforms::fromUnity(ecefToLocalMatrix)); AxisAlignedBox aabb = obb.toAxisAligned(); return DotNet::UnityEngine::Bounds::Construct( diff --git a/native~/Runtime/src/Cesium3DTileImpl.h b/native~/Runtime/src/Cesium3DTileImpl.h index 4a65326e..4d0818e3 100644 --- a/native~/Runtime/src/Cesium3DTileImpl.h +++ b/native~/Runtime/src/Cesium3DTileImpl.h @@ -14,6 +14,7 @@ class Cesium3DTileImpl { public: static DotNet::UnityEngine::Bounds getBounds( void* pTileVoid, + void* pTileEllipsoidVoid, const DotNet::Unity::Mathematics::double4x4& ecefToLocalMatrix); }; diff --git a/native~/Runtime/src/Cesium3DTilesetImpl.cpp b/native~/Runtime/src/Cesium3DTilesetImpl.cpp index 7353e5fc..186b3a07 100644 --- a/native~/Runtime/src/Cesium3DTilesetImpl.cpp +++ b/native~/Runtime/src/Cesium3DTilesetImpl.cpp @@ -1,6 +1,7 @@ #include "Cesium3DTilesetImpl.h" #include "CameraManager.h" +#include "CesiumEllipsoidImpl.h" #include "CesiumIonServerHelper.h" #include "UnityPrepareRendererResources.h" #include "UnityTileExcluderAdaptor.h" @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +267,7 @@ struct CalculateECEFCameraPosition { } glm::dvec3 operator()(const CesiumGeospatial::S2CellBoundingVolume& s2) { - return (*this)(s2.computeBoundingRegion()); + return (*this)(s2.computeBoundingRegion(ellipsoid)); } }; } // namespace @@ -325,11 +327,13 @@ void Cesium3DTilesetImpl::FocusTileset( const glm::dmat4& ecefToUnityWorld = georeferenceCrs.getEcefToLocalTransformation(); + const CesiumGeospatial::Ellipsoid& ellipsoid = + georeferenceComponent.ellipsoid().NativeImplementation().GetEllipsoid(); + const BoundingVolume& boundingVolume = this->_pTileset->getRootTile()->getBoundingVolume(); - glm::dvec3 ecefCameraPosition = std::visit( - CalculateECEFCameraPosition{CesiumGeospatial::Ellipsoid::WGS84}, - boundingVolume); + glm::dvec3 ecefCameraPosition = + std::visit(CalculateECEFCameraPosition{ellipsoid}, boundingVolume); glm::dvec3 unityCameraPosition = glm::dvec3(ecefToUnityWorld * glm::dvec4(ecefCameraPosition, 1.0)); @@ -469,6 +473,13 @@ void Cesium3DTilesetImpl::LoadTileset( options.mainThreadLoadingTimeLimit = 5.0; options.tileCacheUnloadTimeLimit = 5.0; + DotNet::CesiumForUnity::CesiumGeoreference georeferenceComponent = + tileset.gameObject() + .GetComponentInParent(); + + options.ellipsoid = + georeferenceComponent.ellipsoid().NativeImplementation().GetEllipsoid(); + TilesetContentOptions contentOptions{}; contentOptions.generateMissingNormalsSmooth = tileset.generateSmoothNormals(); diff --git a/native~/Runtime/src/CesiumBingMapsRasterOverlayImpl.cpp b/native~/Runtime/src/CesiumBingMapsRasterOverlayImpl.cpp index 436cc15f..e56ba926 100644 --- a/native~/Runtime/src/CesiumBingMapsRasterOverlayImpl.cpp +++ b/native~/Runtime/src/CesiumBingMapsRasterOverlayImpl.cpp @@ -81,7 +81,7 @@ void CesiumBingMapsRasterOverlayImpl::AddToTileset( overlay.bingMapsKey().ToStlString(), mapStyle, "", - CesiumGeospatial::Ellipsoid::WGS84, + pTileset->getEllipsoid(), options); pTileset->getOverlays().add(this->_pOverlay); diff --git a/native~/Runtime/src/CesiumEllipsoidFunctions.cpp b/native~/Runtime/src/CesiumEllipsoidFunctions.cpp new file mode 100644 index 00000000..c419435e --- /dev/null +++ b/native~/Runtime/src/CesiumEllipsoidFunctions.cpp @@ -0,0 +1,70 @@ +#include "CesiumEllipsoidFunctions.h" + +#include + +using namespace DotNet::Unity::Mathematics; +using namespace CesiumGeospatial; +using namespace CesiumUtility; + +double3 CesiumEllipsoidFunctions::GetRadii( + const CesiumGeospatial::Ellipsoid& ellipsoid) { + const glm::dvec3& radii = ellipsoid.getRadii(); + return double3{radii.x, radii.y, radii.z}; +} + +std::optional CesiumEllipsoidFunctions::ScaleToGeodeticSurface( + const CesiumGeospatial::Ellipsoid& ellipsoid, + double3 earthCenteredEarthFixed) { + auto result = ellipsoid.scaleToGeodeticSurface(glm::dvec3( + earthCenteredEarthFixed.x, + earthCenteredEarthFixed.y, + earthCenteredEarthFixed.z)); + if (result) { + return double3{result->x, result->y, result->z}; + } + + return std::nullopt; +} + +DotNet::Unity::Mathematics::double3 +CesiumEllipsoidFunctions::GeodeticSurfaceNormal( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 earthCenteredEarthFixed) { + glm::dvec3 result = ellipsoid.geodeticSurfaceNormal(glm::dvec3( + earthCenteredEarthFixed.x, + earthCenteredEarthFixed.y, + earthCenteredEarthFixed.z)); + + return double3{result.x, result.y, result.z}; +} + +DotNet::Unity::Mathematics::double3 +CesiumEllipsoidFunctions::LongitudeLatitudeHeightToCenteredFixed( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 longitudeLatitudeHeight) { + glm::dvec3 cartesian = + ellipsoid.cartographicToCartesian(Cartographic::fromDegrees( + longitudeLatitudeHeight.x, + longitudeLatitudeHeight.y, + longitudeLatitudeHeight.z)); + return double3{cartesian.x, cartesian.y, cartesian.z}; +} + +DotNet::Unity::Mathematics::double3 +CesiumEllipsoidFunctions::CenteredFixedToLongitudeLatitudeHeight( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 earthCenteredEarthFixed) { + std::optional result = + ellipsoid.cartesianToCartographic(glm::dvec3( + earthCenteredEarthFixed.x, + earthCenteredEarthFixed.y, + earthCenteredEarthFixed.z)); + if (result) { + return double3{ + Math::radiansToDegrees(result->longitude), + Math::radiansToDegrees(result->latitude), + result->height}; + } else { + return double3{0.0, 0.0, 0.0}; + } +} diff --git a/native~/Runtime/src/CesiumEllipsoidFunctions.h b/native~/Runtime/src/CesiumEllipsoidFunctions.h new file mode 100644 index 00000000..9cb19daf --- /dev/null +++ b/native~/Runtime/src/CesiumEllipsoidFunctions.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +#include + +class CesiumEllipsoidFunctions { +public: + static DotNet::Unity::Mathematics::double3 + GetRadii(const CesiumGeospatial::Ellipsoid& ellipsoid); + static std::optional + ScaleToGeodeticSurface( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 earthCenteredEarthFixed); + static DotNet::Unity::Mathematics::double3 GeodeticSurfaceNormal( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 earthCenteredEarthFixed); + static DotNet::Unity::Mathematics::double3 + LongitudeLatitudeHeightToCenteredFixed( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 longitudeLatitudeHeight); + static DotNet::Unity::Mathematics::double3 + CenteredFixedToLongitudeLatitudeHeight( + const CesiumGeospatial::Ellipsoid& ellipsoid, + DotNet::Unity::Mathematics::double3 earthCenteredEarthFixed); +}; diff --git a/native~/Runtime/src/CesiumEllipsoidImpl.cpp b/native~/Runtime/src/CesiumEllipsoidImpl.cpp new file mode 100644 index 00000000..e19a78f1 --- /dev/null +++ b/native~/Runtime/src/CesiumEllipsoidImpl.cpp @@ -0,0 +1,91 @@ +#include "CesiumEllipsoidImpl.h" + +#include "CesiumEllipsoidFunctions.h" + +#include +#include +#include +#include +#include + +#include + +using namespace DotNet::Unity::Mathematics; +using namespace DotNet::CesiumForUnity; + +static constexpr double MinRadiiValue = std::numeric_limits::epsilon(); + +CesiumForUnityNative::CesiumEllipsoidImpl::CesiumEllipsoidImpl( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid) + : _ellipsoid(1.0, 1.0, 1.0) { + this->SetRadii(unityEllipsoid, unityEllipsoid.radii()); +} + +CesiumForUnityNative::CesiumEllipsoidImpl::~CesiumEllipsoidImpl() {} + +DotNet::Unity::Mathematics::double3 +CesiumForUnityNative::CesiumEllipsoidImpl::GetRadii( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid) { + return CesiumEllipsoidFunctions::GetRadii(this->_ellipsoid); +} + +void CesiumForUnityNative::CesiumEllipsoidImpl::SetRadii( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& newRadii) { + if (newRadii.x < MinRadiiValue || newRadii.y < MinRadiiValue || + newRadii.z < MinRadiiValue) { + DotNet::UnityEngine::Debug::LogError( + DotNet::System::String("Ellipsoid radii must be greater than 0 - " + "clamping to minimum value to avoid crashes.")); + } + + double3 clampedRadii = double3::Construct( + std::max(newRadii.x, MinRadiiValue), + std::max(newRadii.y, MinRadiiValue), + std::max(newRadii.z, MinRadiiValue)); + + this->_ellipsoid = CesiumGeospatial::Ellipsoid( + clampedRadii.x, + clampedRadii.y, + clampedRadii.z); + unityEllipsoid.radii(clampedRadii); +} + +std::optional +CesiumForUnityNative::CesiumEllipsoidImpl::ScaleToGeodeticSurface( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed) { + return CesiumEllipsoidFunctions::ScaleToGeodeticSurface( + this->_ellipsoid, + ellipsoidCenteredEllipsoidFixed); +} + +DotNet::Unity::Mathematics::double3 +CesiumForUnityNative::CesiumEllipsoidImpl::GeodeticSurfaceNormal( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed) { + return CesiumEllipsoidFunctions::GeodeticSurfaceNormal( + this->_ellipsoid, + ellipsoidCenteredEllipsoidFixed); +} + +DotNet::Unity::Mathematics::double3 CesiumForUnityNative::CesiumEllipsoidImpl:: + LongitudeLatitudeHeightToCenteredFixed( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& longitudeLatitudeHeight) { + return CesiumEllipsoidFunctions::LongitudeLatitudeHeightToCenteredFixed( + this->_ellipsoid, + longitudeLatitudeHeight); +} + +DotNet::Unity::Mathematics::double3 CesiumForUnityNative::CesiumEllipsoidImpl:: + CenteredFixedToLongitudeLatitudeHeight( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed) { + return CesiumEllipsoidFunctions::CenteredFixedToLongitudeLatitudeHeight( + this->_ellipsoid, + ellipsoidCenteredEllipsoidFixed); +} diff --git a/native~/Runtime/src/CesiumEllipsoidImpl.h b/native~/Runtime/src/CesiumEllipsoidImpl.h new file mode 100644 index 00000000..6240b184 --- /dev/null +++ b/native~/Runtime/src/CesiumEllipsoidImpl.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +#include + +#include + +namespace DotNet::CesiumForUnity { +class CesiumEllipsoid; +} // namespace DotNet::CesiumForUnity + +namespace CesiumForUnityNative { + +class CesiumEllipsoidImpl { +public: + CesiumEllipsoidImpl( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid); + ~CesiumEllipsoidImpl(); + + DotNet::Unity::Mathematics::double3 + GetRadii(const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid); + + void SetRadii( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& newRadii); + + std::optional ScaleToGeodeticSurface( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed); + + DotNet::Unity::Mathematics::double3 GeodeticSurfaceNormal( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed); + + DotNet::Unity::Mathematics::double3 LongitudeLatitudeHeightToCenteredFixed( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& longitudeLatitudeHeight); + + DotNet::Unity::Mathematics::double3 CenteredFixedToLongitudeLatitudeHeight( + const DotNet::CesiumForUnity::CesiumEllipsoid& unityEllipsoid, + const DotNet::Unity::Mathematics::double3& + ellipsoidCenteredEllipsoidFixed); + + const CesiumGeospatial::Ellipsoid& GetEllipsoid() const { + return this->_ellipsoid; + } + +private: + CesiumGeospatial::Ellipsoid _ellipsoid; +}; + +} // namespace CesiumForUnityNative diff --git a/native~/Runtime/src/CesiumGeoreferenceImpl.cpp b/native~/Runtime/src/CesiumGeoreferenceImpl.cpp index 842b157b..192fb80e 100644 --- a/native~/Runtime/src/CesiumGeoreferenceImpl.cpp +++ b/native~/Runtime/src/CesiumGeoreferenceImpl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,8 @@ LocalHorizontalCoordinateSystem createCoordinateSystem( LocalDirection::East, LocalDirection::Up, LocalDirection::North, - 1.0 / georeference.scale()); + 1.0 / georeference.scale(), + georeference.ellipsoid().NativeImplementation().GetEllipsoid()); } else { return LocalHorizontalCoordinateSystem( glm::dvec3( @@ -44,7 +46,8 @@ LocalHorizontalCoordinateSystem createCoordinateSystem( LocalDirection::East, LocalDirection::Up, LocalDirection::North, - 1.0 / georeference.scale()); + 1.0 / georeference.scale(), + georeference.ellipsoid().NativeImplementation().GetEllipsoid()); } } diff --git a/native~/Runtime/src/CesiumGlobeAnchorImpl.cpp b/native~/Runtime/src/CesiumGlobeAnchorImpl.cpp index ca9f80da..101a0995 100644 --- a/native~/Runtime/src/CesiumGlobeAnchorImpl.cpp +++ b/native~/Runtime/src/CesiumGlobeAnchorImpl.cpp @@ -1,11 +1,13 @@ #include "CesiumGlobeAnchorImpl.h" +#include "CesiumEllipsoidImpl.h" #include "UnityTransforms.h" #include #include #include +#include #include #include #include @@ -24,6 +26,16 @@ namespace CesiumForUnityNative { namespace { +const CesiumGeospatial::Ellipsoid& +getAnchorEllipsoid(const ::DotNet::CesiumForUnity::CesiumGlobeAnchor& anchor) { + + anchor.UpdateGeoreferenceIfNecessary(); + return anchor._georeference() + .ellipsoid() + .NativeImplementation() + .GetEllipsoid(); +} + GlobeAnchor createOrUpdateNativeGlobeAnchorFromEcef( const ::DotNet::CesiumForUnity::CesiumGlobeAnchor& anchor, const ::DotNet::Unity::Mathematics::double4x4& newLocalToGlobeFixedMatrix) { @@ -37,7 +49,8 @@ GlobeAnchor createOrUpdateNativeGlobeAnchorFromEcef( UnityTransforms::fromUnity(anchor._localToGlobeFixedMatrix())); cppAnchor.setAnchorToFixedTransform( UnityTransforms::fromUnity(newLocalToGlobeFixedMatrix), - anchor.adjustOrientationForGlobeWhenMoving()); + anchor.adjustOrientationForGlobeWhenMoving(), + getAnchorEllipsoid(anchor)); return cppAnchor; } } @@ -61,7 +74,8 @@ GlobeAnchor createOrUpdateNativeGlobeAnchorFromLocal( cppAnchor.setAnchorToLocalTransform( local, newModelToLocal, - anchor.adjustOrientationForGlobeWhenMoving()); + anchor.adjustOrientationForGlobeWhenMoving(), + getAnchorEllipsoid(anchor)); return cppAnchor; } } @@ -105,7 +119,9 @@ void updateAnchorFromCpp( } } -LocalHorizontalCoordinateSystem createEastUpNorth(const GlobeAnchor& anchor) { +LocalHorizontalCoordinateSystem createEastUpNorth( + const GlobeAnchor& anchor, + const CesiumGeospatial::Ellipsoid& ellipsoid) { glm::dvec3 ecefPosition; Transforms::computeTranslationRotationScaleFromMatrix( anchor.getAnchorToFixedTransform(), @@ -118,7 +134,8 @@ LocalHorizontalCoordinateSystem createEastUpNorth(const GlobeAnchor& anchor) { LocalDirection::East, LocalDirection::Up, LocalDirection::North, - 1.0); + 1.0, + ellipsoid); } } // namespace @@ -154,7 +171,8 @@ CesiumGlobeAnchorImpl::GetLocalToEastUpNorthRotation( GlobeAnchor cppAnchor( UnityTransforms::fromUnity(anchor._localToGlobeFixedMatrix())); - LocalHorizontalCoordinateSystem eastUpNorth = createEastUpNorth(cppAnchor); + LocalHorizontalCoordinateSystem eastUpNorth = + createEastUpNorth(cppAnchor, getAnchorEllipsoid(anchor)); glm::dmat4 modelToEastUpNorth = cppAnchor.getAnchorToLocalTransform(eastUpNorth); @@ -174,7 +192,10 @@ void CesiumGlobeAnchorImpl::SetLocalToEastUpNorthRotation( GlobeAnchor cppAnchor( UnityTransforms::fromUnity(anchor._localToGlobeFixedMatrix())); - LocalHorizontalCoordinateSystem eastUpNorth = createEastUpNorth(cppAnchor); + const CesiumGeospatial::Ellipsoid& ellipsoid = getAnchorEllipsoid(anchor); + + LocalHorizontalCoordinateSystem eastUpNorth = + createEastUpNorth(cppAnchor, ellipsoid); glm::dmat4 modelToEastUpNorth = cppAnchor.getAnchorToLocalTransform(eastUpNorth); @@ -196,7 +217,8 @@ void CesiumGlobeAnchorImpl::SetLocalToEastUpNorthRotation( cppAnchor.setAnchorToLocalTransform( eastUpNorth, newModelToEastUpNorth, - false); + false, + ellipsoid); updateAnchorFromCpp(anchor, cppAnchor); } diff --git a/native~/Runtime/src/CesiumPolygonRasterOverlayImpl.cpp b/native~/Runtime/src/CesiumPolygonRasterOverlayImpl.cpp index cf8a704a..b82fabcf 100644 --- a/native~/Runtime/src/CesiumPolygonRasterOverlayImpl.cpp +++ b/native~/Runtime/src/CesiumPolygonRasterOverlayImpl.cpp @@ -99,12 +99,14 @@ void CesiumPolygonRasterOverlayImpl::AddToTileset( nativePolygons.emplace_back(std::move(nativePolygon)); } + const CesiumGeospatial::Ellipsoid& ellipsoid = pTileset->getEllipsoid(); + this->_pOverlay = new RasterizedPolygonsOverlay( overlay.materialKey().ToStlString(), nativePolygons, overlay.invertSelection(), - CesiumGeospatial::Ellipsoid::WGS84, - CesiumGeospatial::GeographicProjection(), + ellipsoid, + CesiumGeospatial::GeographicProjection(ellipsoid), options); pTileset->getOverlays().add(this->_pOverlay); diff --git a/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.cpp b/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.cpp index d2e6b606..116668df 100644 --- a/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.cpp +++ b/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.cpp @@ -14,14 +14,14 @@ CesiumSimplePlanarEllipsoidCurveImpl::CesiumSimplePlanarEllipsoidCurveImpl( CesiumSimplePlanarEllipsoidCurveImpl::~CesiumSimplePlanarEllipsoidCurveImpl() {} -bool CesiumSimplePlanarEllipsoidCurveImpl:: - CreateFromEarthCenteredEarthFixedCoordinates( - const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path, - const DotNet::Unity::Mathematics::double3 sourceEcef, - const DotNet::Unity::Mathematics::double3 destinationEcef) { +bool CesiumSimplePlanarEllipsoidCurveImpl::CreateFromCenteredFixed( + const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path, + const DotNet::CesiumForUnity::CesiumEllipsoid& ellipsoid, + const DotNet::Unity::Mathematics::double3 sourceEcef, + const DotNet::Unity::Mathematics::double3 destinationEcef) { this->_curve = SimplePlanarEllipsoidCurve::fromEarthCenteredEarthFixedCoordinates( - Ellipsoid::WGS84, + ellipsoid.NativeImplementation().GetEllipsoid(), glm::dvec3(sourceEcef.x, sourceEcef.y, sourceEcef.z), glm::dvec3(destinationEcef.x, destinationEcef.y, destinationEcef.z)); @@ -30,10 +30,11 @@ bool CesiumSimplePlanarEllipsoidCurveImpl:: bool CesiumSimplePlanarEllipsoidCurveImpl::CreateFromLongitudeLatitudeHeight( const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path, + const DotNet::CesiumForUnity::CesiumEllipsoid& ellipsoid, const DotNet::Unity::Mathematics::double3 sourceLlh, const DotNet::Unity::Mathematics::double3 destinationLlh) { this->_curve = SimplePlanarEllipsoidCurve::fromLongitudeLatitudeHeight( - Ellipsoid::WGS84, + ellipsoid.NativeImplementation().GetEllipsoid(), Cartographic(sourceLlh.x, sourceLlh.y, sourceLlh.z), Cartographic(destinationLlh.x, destinationLlh.y, destinationLlh.z)); diff --git a/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.h b/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.h index 8663c82b..a6c543d2 100644 --- a/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.h +++ b/native~/Runtime/src/CesiumSimplePlanarEllipsoidCurveImpl.h @@ -2,6 +2,7 @@ #include +#include #include #include @@ -22,13 +23,15 @@ class CesiumSimplePlanarEllipsoidCurveImpl { const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path); ~CesiumSimplePlanarEllipsoidCurveImpl(); - bool CreateFromEarthCenteredEarthFixedCoordinates( + bool CreateFromCenteredFixed( const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path, + const DotNet::CesiumForUnity::CesiumEllipsoid& ellipsoid, const DotNet::Unity::Mathematics::double3 sourceEcef, const DotNet::Unity::Mathematics::double3 destinationEcef); bool CreateFromLongitudeLatitudeHeight( const DotNet::CesiumForUnity::CesiumSimplePlanarEllipsoidCurve& path, + const DotNet::CesiumForUnity::CesiumEllipsoid& ellipsoid, const DotNet::Unity::Mathematics::double3 sourceLlh, const DotNet::Unity::Mathematics::double3 destinationLlh); diff --git a/native~/Runtime/src/CesiumWebMapTileServiceRasterOverlayImpl.cpp b/native~/Runtime/src/CesiumWebMapTileServiceRasterOverlayImpl.cpp index dd2e7f4b..88a99548 100644 --- a/native~/Runtime/src/CesiumWebMapTileServiceRasterOverlayImpl.cpp +++ b/native~/Runtime/src/CesiumWebMapTileServiceRasterOverlayImpl.cpp @@ -51,6 +51,8 @@ void CesiumWebMapTileServiceRasterOverlayImpl::AddToTileset( return; } + const CesiumGeospatial::Ellipsoid& ellipsoid = pTileset->getEllipsoid(); + WebMapTileServiceRasterOverlayOptions wmtsOptions; wmtsOptions.format = overlay.format().ToStlString(); wmtsOptions.layer = overlay.layer().ToStlString(); @@ -68,9 +70,9 @@ void CesiumWebMapTileServiceRasterOverlayImpl::AddToTileset( if (overlay.projection() == CesiumWebMapTileServiceRasterOverlayProjection::Geographic) { - wmtsOptions.projection = CesiumGeospatial::GeographicProjection(); + wmtsOptions.projection = CesiumGeospatial::GeographicProjection(ellipsoid); } else { - wmtsOptions.projection = CesiumGeospatial::WebMercatorProjection(); + wmtsOptions.projection = CesiumGeospatial::WebMercatorProjection(ellipsoid); } if (overlay.specifyTilingScheme()) { diff --git a/native~/Runtime/src/CesiumWgs84EllipsoidImpl.cpp b/native~/Runtime/src/CesiumWgs84EllipsoidImpl.cpp index f06aef3a..52781b3d 100644 --- a/native~/Runtime/src/CesiumWgs84EllipsoidImpl.cpp +++ b/native~/Runtime/src/CesiumWgs84EllipsoidImpl.cpp @@ -1,5 +1,7 @@ #include "CesiumWgs84EllipsoidImpl.h" +#include "CesiumEllipsoidFunctions.h" + #include #include @@ -11,64 +13,37 @@ using namespace DotNet::Unity::Mathematics; namespace CesiumForUnityNative { double3 CesiumWgs84EllipsoidImpl::GetRadii() { - const glm::dvec3 radii = Ellipsoid::WGS84.getRadii(); - return double3{radii.x, radii.y, radii.z}; + return CesiumEllipsoidFunctions::GetRadii(Ellipsoid::WGS84); } std::optional CesiumWgs84EllipsoidImpl::ScaleToGeodeticSurface( double3 earthCenteredEarthFixed) { - const glm::dvec3 cartesian( - earthCenteredEarthFixed.x, - earthCenteredEarthFixed.y, - earthCenteredEarthFixed.z); - - auto result = Ellipsoid::WGS84.scaleToGeodeticSurface(cartesian); - if (result) { - return double3{result->x, result->y, result->z}; - } - - return std::nullopt; + return CesiumEllipsoidFunctions::ScaleToGeodeticSurface( + Ellipsoid::WGS84, + earthCenteredEarthFixed); } double3 CesiumWgs84EllipsoidImpl::GeodeticSurfaceNormal( double3 earthCenteredEarthFixed) { - const glm::dvec3 cartesian( - earthCenteredEarthFixed.x, - earthCenteredEarthFixed.y, - earthCenteredEarthFixed.z); - - glm::dvec3 result = Ellipsoid::WGS84.geodeticSurfaceNormal(cartesian); - - return double3{result.x, result.y, result.z}; + return CesiumEllipsoidFunctions::GeodeticSurfaceNormal( + Ellipsoid::WGS84, + earthCenteredEarthFixed); } double3 CesiumWgs84EllipsoidImpl::LongitudeLatitudeHeightToEarthCenteredEarthFixed( double3 longitudeLatitudeHeight) { - glm::dvec3 cartesian = - Ellipsoid::WGS84.cartographicToCartesian(Cartographic::fromDegrees( - longitudeLatitudeHeight.x, - longitudeLatitudeHeight.y, - longitudeLatitudeHeight.z)); - return double3{cartesian.x, cartesian.y, cartesian.z}; + return CesiumEllipsoidFunctions::LongitudeLatitudeHeightToCenteredFixed( + Ellipsoid::WGS84, + longitudeLatitudeHeight); } double3 CesiumWgs84EllipsoidImpl::EarthCenteredEarthFixedToLongitudeLatitudeHeight( double3 earthCenteredEarthFixed) { - std::optional result = - Ellipsoid::WGS84.cartesianToCartographic(glm::dvec3( - earthCenteredEarthFixed.x, - earthCenteredEarthFixed.y, - earthCenteredEarthFixed.z)); - if (result) { - return double3{ - Math::radiansToDegrees(result->longitude), - Math::radiansToDegrees(result->latitude), - result->height}; - } else { - return double3{0.0, 0.0, 0.0}; - } + return CesiumEllipsoidFunctions::CenteredFixedToLongitudeLatitudeHeight( + Ellipsoid::WGS84, + earthCenteredEarthFixed); } } // namespace CesiumForUnityNative diff --git a/native~/Runtime/src/UnityTileExcluderAdaptor.cpp b/native~/Runtime/src/UnityTileExcluderAdaptor.cpp index 8d544bc9..2e361d4b 100644 --- a/native~/Runtime/src/UnityTileExcluderAdaptor.cpp +++ b/native~/Runtime/src/UnityTileExcluderAdaptor.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -64,7 +66,14 @@ bool UnityTileExcluderAdaptor::shouldExclude( return false; } + const CesiumGeospatial::Ellipsoid ellipsoid = + _georeference.ellipsoid().NativeImplementation().GetEllipsoid(); + this->_tile._pTile(const_cast(&tile)); + // it's ok for us to pass by pointer since it will only be valid for this call + // anyways + this->_tile._pTileEllipsoid( + const_cast(&ellipsoid)); return this->_excluder.ShouldExclude(this->_tile); } diff --git a/native~/extern/cesium-native b/native~/extern/cesium-native index b647e633..dbc8e118 160000 --- a/native~/extern/cesium-native +++ b/native~/extern/cesium-native @@ -1 +1 @@ -Subproject commit b647e633b69be4e6936db9cee3fefdd7c7e95e12 +Subproject commit dbc8e118581e3ee2eee00fc8fec001fa60e3b8b6