All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.earth.worldwind.util.SunPosition.kt Maven / Gradle / Ivy

package earth.worldwind.util

import earth.worldwind.geom.Angle
import earth.worldwind.geom.Angle.Companion.degrees
import earth.worldwind.geom.Angle.Companion.radians
import earth.worldwind.geom.Location
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import kotlin.math.*

/**
 * Provides utilities for determining the Sun geographic and celestial location.
 */
object SunPosition {
    class CelestialLocation(val declination: Angle, val rightAscension: Angle)

    /**
     * Computes the geographic location of the sun for a given date
     * @param instant Input instant
     * @return the geographic location
     */
    fun getAsGeographicLocation(instant: Instant) = celestialToGeographic(getAsCelestialLocation(instant), instant)

    /**
     * Computes the celestial location of the sun for a given julianDate
     * @param instant Input instant
     * @return the celestial location
     */
    fun getAsCelestialLocation(instant: Instant): CelestialLocation {
        val julianDate = computeJulianDate(instant)

        //number of days (positive or negative) since Greenwich noon, Terrestrial Time, on 1 January 2000 (J2000.0)
        val numDays = julianDate - 2451545
        val meanLongitude = Angle.normalizeAngle360(280.460 + 0.9856474 * numDays)
        val meanAnomaly = Angle.toRadians(Angle.normalizeAngle360(357.528 + 0.9856003 * numDays))
        val eclipticLongitude = meanLongitude + 1.915 * sin(meanAnomaly) + 0.02 * sin(2 * meanAnomaly)
        val eclipticLongitudeRad = Angle.toRadians(eclipticLongitude)
        val obliquityOfTheEcliptic = Angle.toRadians(23.439 - 0.0000004 * numDays)
        val declination = asin(sin(obliquityOfTheEcliptic) * sin(eclipticLongitudeRad)).radians
        var rightAscension = atan(cos(obliquityOfTheEcliptic) * tan(eclipticLongitudeRad)).radians
        if (eclipticLongitude >= 90 && eclipticLongitude < 270) rightAscension += Angle.POS180
        return CelestialLocation(declination, rightAscension.normalize360())
    }

    /**
     * Converts from celestial coordinates (declination and right ascension) to geographic coordinates
     * (latitude, longitude) for a given julian date
     * @param celestialLocation Celestial location
     * @param instant Input instant
     * @return the geographic location
     */
    fun celestialToGeographic(celestialLocation: CelestialLocation, instant: Instant): Location {
        val julianDate = computeJulianDate(instant)

        //number of days (positive or negative) since Greenwich noon, Terrestrial Time, on 1 January 2000 (J2000.0)
        val numDays = julianDate - 2451545

        //Greenwich Mean Sidereal Time
        val GMST = Angle.normalizeAngle360(280.46061837 + 360.98564736629 * numDays)

        //Greenwich Hour Angle
        val GHA = Angle.normalizeAngle360(GMST - celestialLocation.rightAscension.inDegrees)

        val longitude = (-GHA).degrees.normalizeLongitude()

        return Location(celestialLocation.declination, longitude)
    }

    /**
     * Computes the julian date from a javascript date object
     * @param instant Input instant
     * @return the julian date
     */
    fun computeJulianDate(instant: Instant): Double {
        val date = instant.toLocalDateTime(TimeZone.UTC)
        var year = date.year
        var month = date.monthNumber + 1
        val day = date.dayOfMonth
        val hour = date.hour
        val minute = date.minute
        val second = date.second
        val dayFraction = (hour + minute / 60.0 + second / 3600.0) / 24.0
        if (month <= 2) {
            year -= 1
            month += 12
        }
        val a = floor(year / 100.0)
        val b = 2 - a + floor(a / 4.0)
        val JD0h = floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524.5
        return JD0h + dayFraction
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy