Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom ellipsoids in Unity #465

Merged
merged 16 commits into from
Jun 28, 2024
Merged
19 changes: 19 additions & 0 deletions Editor/CesiumGeoreferenceEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal CesiumGeoreferenceOriginAuthority originAuthority
}
}

private SerializedProperty _ellipsoidOverride;
private SerializedProperty _latitude;
private SerializedProperty _longitude;
private SerializedProperty _height;
Expand All @@ -35,6 +36,7 @@ private void OnEnable()
{
this._georeference = (CesiumGeoreference)this.target;

this._ellipsoidOverride = this.serializedObject.FindProperty("_ellipsoidOverride");
this._originAuthority =
this.serializedObject.FindProperty("_originAuthority");

Expand All @@ -56,6 +58,8 @@ public override void OnInspectorGUI()
DrawInspectorButtons();
EditorGUILayout.Space(5);

this.DrawEllipsoidOverrideProperty();
EditorGUILayout.Space(5);
this.DrawScaleProperty();
EditorGUILayout.Space(5);
this.DrawOriginAuthorityProperty();
Expand Down Expand Up @@ -104,6 +108,21 @@ 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._georeference.ReloadEllipsoid();
}
}

private void DrawScaleProperty()
{
GUIContent scaleContent = new GUIContent(
Expand Down
4 changes: 2 additions & 2 deletions Runtime/CesiumCameraController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Runtime/CesiumCartographicPolygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ internal List<double2> 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.EllipsoidCenteredEllipsoidFixedToLongitudeLatitudeHeight(ecefPosition);
csciguy8 marked this conversation as resolved.
Show resolved Hide resolved

cartographicPoints.Add(cartographicPosition.xy);
}
Expand Down
110 changes: 110 additions & 0 deletions Runtime/CesiumEllipsoid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using Reinterop;
using Unity.Mathematics;
using UnityEngine;
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;


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
{
/// <summary>
/// Obtain a WGS84 ellipsoid.
/// </summary>
public static CesiumEllipsoid WGS84
{
get
{
if (_cachedWgs84 == null)
{
_cachedWgs84 = CreateInstance<CesiumEllipsoid>();
_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;
}

/// <summary>
/// Gets the maximum radius of the ellipsoid in any dimension.
/// </summary>
/// <returns>The maximum radius of the ellipsoid.</returns>
public double GetMaximumRadius()
{
return math.cmax(this.GetRadii());
}

/// <summary>
/// Gets the minimum radius of the ellipsoid in any dimension.
/// </summary>
/// <returns>The minimum radius of the ellipsoid.</returns>
public double GetMinimumRadius()
{
return math.cmin(this.GetRadii());
}

/// <summary>
/// Returns the radii of this ellipsoid.
/// </summary>
public partial double3 GetRadii();

/// <summary>
/// Sets the radii of this ellipsoid to the given values.
/// </summary>
/// <param name="newRadii">The new (x, y, z) radii of the ellipsoid.</param>
public partial void SetRadii(double3 newRadii);

/// <summary>
/// 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.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF position in meters.</param>
/// <returns>The scaled position, or null if the position is at the center of the ellipsoid.</returns>
public partial double3? ScaleToGeodeticSurface(double3 ellipsoidCenteredEllipsoidFixed);

/// <summary>
/// Computes the normal of the plane tangent to the surface of the ellipsoid at the provided
/// Ellipsoid-Centered, Ellipsoid-Fixed position.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF position in meters.</param>
/// <returns>The normal at the ECEF position</returns>
public partial double3 GeodeticSurfaceNormal(double3 ellipsoidCenteredEllipsoidFixed);

/// <summary>
/// Convert longitude, latitude, and height to Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates.
/// </summary>
/// <param name="longitudeLatitudeHeight">
/// 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.</param>
/// <returns>The ECEF coordinates in meters.</returns>
public partial double3 LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(double3 longitudeLatitudeHeight);

/// <summary>
/// Convert Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates to longitude, latitude, and height.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF coordinates in meters.</param>
/// <returns>
/// 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.
/// </returns>
public partial double3 EllipsoidCenteredEllipsoidFixedToLongitudeLatitudeHeight(double3 ellipsoidCenteredEllipsoidFixed);
}
}
11 changes: 11 additions & 0 deletions Runtime/CesiumEllipsoid.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions Runtime/CesiumFlyToController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.FromEarthCenteredEarthFixedCoordinates(
this._georeference.ellipsoid,
sourceECEF,
destinationECEF);
this._flightPathLength = math.length(sourceECEF - destinationECEF);

this._maxHeight = 0.0;
Expand Down Expand Up @@ -483,7 +486,7 @@ public void FlyToLocationLongitudeLatitudeHeight(
bool canInterruptByMoving)
{
double3 destinationECEF =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(destination);
this._georeference.ellipsoid.LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(destination);

this.FlyToLocationEarthCenteredEarthFixed(
destinationECEF,
Expand Down Expand Up @@ -522,7 +525,7 @@ public void FlyToLocationLongitudeLatitudeHeight(
z = destination.z
};
double3 destinationECEF =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(
this._georeference.ellipsoid.LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(
destinationCoordinates);

this.FlyToLocationEarthCenteredEarthFixed(
Expand Down
39 changes: 37 additions & 2 deletions Runtime/CesiumGeoreference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -106,6 +108,9 @@ public partial class CesiumGeoreference : MonoBehaviour
[NonSerialized]
private HashSet<CesiumGlobeAnchor> _globeAnchors = new HashSet<CesiumGlobeAnchor>();

[NonSerialized]
private CesiumEllipsoid _ellipsoid = null;

#endregion

/// <summary>
Expand Down Expand Up @@ -254,6 +259,23 @@ public double4x4 ecefToLocalMatrix
}
}

public CesiumEllipsoid ellipsoid
{
get
{
if (this._ellipsoid == null)
{
this._ellipsoid = this._ellipsoidOverride ?? CesiumEllipsoid.WGS84;
}

return this._ellipsoid;
}
set
{
this._ellipsoid = value;
}
}

/// <summary>
/// An event raised when the georeference changes.
/// </summary>
Expand Down Expand Up @@ -356,6 +378,19 @@ public void Initialize()
}
}

/// <summary>
/// Called when the ellipsoid override property has changed.
/// </summary>
public void ReloadEllipsoid()
{
this._ellipsoid = this._ellipsoidOverride ?? CesiumEllipsoid.WGS84;
Cesium3DTileset[] tilesets = GetComponentsInChildren<Cesium3DTileset>();
foreach(var tileset in tilesets)
{
tileset.RecreateTileset();
}
}

private void UpdateTransformations()
{
this._localToEcef = this.ComputeLocalToEarthCenteredEarthFixedTransformation();
Expand Down Expand Up @@ -424,7 +459,7 @@ private void UpdateOtherCoordinates()
if (this._originAuthority == CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight)
{
double3 ecef =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(
this.ellipsoid.LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(
new double3(this._longitude, this._latitude, this._height));
this._ecefX = ecef.x;
this._ecefY = ecef.y;
Expand All @@ -433,7 +468,7 @@ private void UpdateOtherCoordinates()
else if (this._originAuthority == CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed)
{
double3 llh =
CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(
this.ellipsoid.EllipsoidCenteredEllipsoidFixedToLongitudeLatitudeHeight(
new double3(this._ecefX, this._ecefY, this._ecefZ));
this._longitude = llh.x;
this._latitude = llh.y;
Expand Down
4 changes: 2 additions & 2 deletions Runtime/CesiumGlobeAnchor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ public double4x4 localToGlobeFixedMatrix
/// </remarks>
public double3 longitudeLatitudeHeight
{
get => CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(this.positionGlobeFixed);
get => this._georeference.ellipsoid.EllipsoidCenteredEllipsoidFixedToLongitudeLatitudeHeight(this.positionGlobeFixed);
set
{
this.positionGlobeFixed = CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(value);
this.positionGlobeFixed = this._georeference.ellipsoid.LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(value);
}
}

Expand Down
14 changes: 7 additions & 7 deletions Runtime/CesiumSimplePlanarEllipsoidCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace CesiumForUnity
{
/// <summary>
/// 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.
/// </summary>
[ReinteropNativeImplementation("CesiumForUnityNative::CesiumSimplePlanarEllipsoidCurveImpl", "CesiumSimplePlanarEllipsoidCurveImpl.h")]
[IconAttribute("Packages/com.cesium.unity/Editor/Resources/Cesium-24x24.png")]
Expand All @@ -22,10 +22,10 @@ public partial class CesiumSimplePlanarEllipsoidCurve
/// A <see cref="CesiumSimplePlanarEllipsoidCurve"/> if a curve can successfully be
/// created between the two points, or null otherwise.
/// </returns>
public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordinates(double3 sourceEcef, double3 destinationEcef)
public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordinates(CesiumEllipsoid ellipsoid, double3 sourceEcef, double3 destinationEcef)
azrogers marked this conversation as resolved.
Show resolved Hide resolved
{
CesiumSimplePlanarEllipsoidCurve curve = new CesiumSimplePlanarEllipsoidCurve();
if (!curve.CreateFromEarthCenteredEarthFixedCoordinates(sourceEcef, destinationEcef))
if (!curve.CreateFromEarthCenteredEarthFixedCoordinates(ellipsoid, sourceEcef, destinationEcef))
{
return null;
}
Expand All @@ -43,10 +43,10 @@ public static CesiumSimplePlanarEllipsoidCurve FromEarthCenteredEarthFixedCoordi
/// A <see cref="CesiumSimplePlanarEllipsoidCurve"/> if a curve can successfully be
/// created between the two points, or null otherwise.
/// </returns>
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;
}
Expand All @@ -70,8 +70,8 @@ public static CesiumSimplePlanarEllipsoidCurve FromLongituteLatitudeHeight(doubl
/// <returns>The position of the given point on this curve in Earth-Centered, Earth-Fixed coordinates.</returns>
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 CreateFromEarthCenteredEarthFixedCoordinates(CesiumEllipsoid ellipsoid, double3 sourceEcef, double3 destinationEcef);
azrogers marked this conversation as resolved.
Show resolved Hide resolved
private partial bool CreateFromLongitudeLatitudeHeight(CesiumEllipsoid ellipsoid, double3 sourceLlh, double3 destinationLlh);

private CesiumSimplePlanarEllipsoidCurve()
{
Expand Down
14 changes: 12 additions & 2 deletions Runtime/CesiumSubScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.LongitudeLatitudeHeightToEllipsoidCenteredEllipsoidFixed(new double3(
this._longitude,
this._latitude,
this._height
Expand All @@ -402,7 +412,7 @@ private void UpdateOtherCoordinates()

if (this._originAuthority == CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed)
{
double3 llh = CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(new double3(
double3 llh = this._parentGeoreference.ellipsoid.EllipsoidCenteredEllipsoidFixedToLongitudeLatitudeHeight(new double3(
this._ecefX,
this._ecefY,
this._ecefZ
Expand Down
Loading
Loading