Skip to content

Colossal.Atmosphere.TopocentricCoordinates

Assembly:
Namespace: Colossal.Atmosphere

Type: struct

Base: System.ValueType

Summary:
Represents topocentric angular coordinates of a direction on/above the local horizon. Stores azimuth and altitude in radians (double). Provides conversions to a local 3D direction (Unity.Mathematics.float3), quantization utilities, and human-readable formatting (degrees and compass cardinal). Useful for atmosphere, sun/moon/sky positioning and related modding tasks in Cities: Skylines 2.


Fields

  • public double azimuth
    Horizon azimuth in radians. Convention used by ToLocalCoordinates: this value is passed as the phi angle (longitude-like around the local vertical).

  • public double altitude
    Altitude (elevation) above the horizon in radians. Used to compute theta = π/2 - altitude for conversion to a local direction vector.

  • private static readonly string[] kCardinals
    Array of 9 strings: { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "N" } used to map degrees to an approximate cardinal direction (rounding every 45°). The extra "N" at the end makes indexing safe for rounding to 8 segments.

Properties

  • None.

Constructors

  • public TopocentricCoordinates()
    Default value-type constructor. For structs this is the implicit parameterless constructor which initializes azimuth and altitude to 0.0. Typically you set azimuth/altitude explicitly after construction.

Methods

  • private float Remap(float value, float from1, float to1, float from2, float to2)
    Linear remap helper: returns a value mapped from the input range [from1,to1] to the output range [from2,to2]. Used internally to compute a normalized "planetTime" value.

  • public float3 ToLocalCoordinates(out float planetTime)
    Converts this topocentric pair (azimuth, altitude) into a local direction vector (float3) and also outputs a normalized planetTime. Implementation notes:

  • Computes theta = π/2 - altitude.
  • planetTime = saturate(Remap((float)theta, -1.5f, 0f, 1.5f, 1f)), clamped to [0,1] via math.saturate.
  • Returns ConvertToLocalCoordinates((float)theta, (float)azimuth).
  • Returned float3 uses Unity coordinate convention: x = sin(theta)sin(phi), y = cos(theta), z = sin(theta)cos(phi).
  • planetTime is derived from theta and is used by the calling system to drive time-of-day or blending related to object position relative to the planet.

  • public static float3 ConvertToLocalCoordinates(float theta, float phi)
    Static helper that converts spherical angles (theta measured from local vertical, phi azimuth) to a normalized direction vector:

  • x = sin(theta) * sin(phi)
  • y = cos(theta)
  • z = sin(theta) * cos(phi) Useful when you already have theta/phi in floats.

  • public void Quantize(double resolutionRadians)
    Snaps azimuth and altitude to the nearest multiple of resolutionRadians using math.round. Useful for reducing precision/noise or for deterministic sampling/grid alignment.

  • private static string DegreesToCardinal(double degrees)
    Converts degrees to one of the cardinal strings in kCardinals by rounding (degrees % 360 / 45) and indexing the array.

  • private static string FormatAzimuth(double azimuth)
    Formats azimuth as a string showing the stored radian value, its degree equivalent, and the closest cardinal direction. Example output: "0.785... (45° - NE)".

  • private static string FormatAltitude(double altitude)
    Formats altitude as a string showing the stored radian value and its degree equivalent.

  • public override string ToString()
    Returns a string combining formatted azimuth and altitude, e.g.: "(azimuth: (° - ), altitude: (°))"

Usage Example

// Create and initialize
Colossal.Atmosphere.TopocentricCoordinates topo = new Colossal.Atmosphere.TopocentricCoordinates();
topo.azimuth = math.radians(135.0);   // 135° -> SE direction in radians
topo.altitude = math.radians(30.0);   // 30° above horizon

// Convert to local direction and get planetTime
float planetTime;
Unity.Mathematics.float3 localDir = topo.ToLocalCoordinates(out planetTime);

// localDir is a normalized direction in local coordinates (x,y,z).
// planetTime is a normalized value derived from theta used by atmosphere/time systems.

// Quantize to a resolution (e.g., snap to 1 degree)
topo.Quantize(math.radians(1.0));

// Debug string
UnityEngine.Debug.Log(topo.ToString());

{{ Additional notes: - Units: azimuth and altitude are stored in radians. Use math.radians/ math.degrees to convert when needed. - Coordinate conventions: altitude is measured above the horizon; conversion uses theta = π/2 − altitude (theta measured from local up vector). - planetTime calculation: maps theta from [-1.5, 0] -> [1.5, 1] then saturates to [0,1]; this mapping is specific to how the calling atmosphere/planet code blends states and may be tuned for the engine's needs. - Cardinal mapping uses simple 45° sectors and rounding; edge cases (negative degrees) rely on the behavior of % and round but are generally fine for typical azimuth values within [0,360). }}