onekiloparsec / SwiftAA

The most comprehensive collection of accurate astronomical algorithms in (C++, Objective-C and) Swift.
http://www.onekiloparsec.dev/
MIT License
171 stars 31 forks source link

enhancement - scenekit / arkit helpers to display planet locations based off user location / JD #80

Closed johndpope closed 5 years ago

johndpope commented 6 years ago

I get that this is pushing limits of responsibility for the port - but swift + astronomy naturally leads to question - "how do I use this with iphone frameworks....."

Here's an AR app for planes - determining location / bearing of plane. Perhaps we can cherry pick some of the code / logic from @calda .

https://github.com/HTN-2017/AR-Planes

https://www.youtube.com/watch?v=dnYHQ-7wlag screen shot 2018-03-09 at 11 18 31 am

I'm looking for something as trivial as

here's my date / time / coordinate - where is the corresponding planet pluto / mars / etc.

https://github.com/HTN-2017/AR-Planes/blob/master/AR%20Planes/Model/Flight.swift


struct Flight {

    // MARK: - Properties

    let icao: String
    let callsign: String
    let longitude: Double
    let latitude: Double
    let altitude: Double
    let noseHeading: Double
    let groundVelocity: Double
    let verticalVelocity: Double

    var location: CLLocation {
        let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

        //note: CLLocation also accepts heading and speed, could be useful?
        return CLLocation(
            coordinate: coordinate,
            altitude: altitude,
            horizontalAccuracy: 1,
            verticalAccuracy: 1,
            timestamp: Date())
    }

func sceneKitCoordinate(relativeTo userLocation: CLLocation) -> SCNVector3 {
        let distance = location.distance(from: userLocation)
        let heading = userLocation.coordinate.getHeading(toPoint: location.coordinate)
        let headingRadians = heading * (.pi/180)

        let distanceScale: Double = 1/140
        let eastWestOffset = distance * sin(headingRadians) * distanceScale
        let northSouthOffset = distance * cos(headingRadians)  * distanceScale

        let altitudeScale: Double = 1/140 //1/20
        let upDownOffset = altitude * altitudeScale

        //in .gravityAndHeading, (1, 1, 1) is (east, up, south)
        return SCNVector3(eastWestOffset, upDownOffset, -northSouthOffset)
    }
johndpope commented 6 years ago

this code from AugmentedSolarSystem perhaps could be glued together https://github.com/ThumbWorks/AugmentedSolarSystem/blob/26aaa38eb18ef45fb418f85a61cfe1b5ac233cee/SolarSystem/PlanetoidGroupNode.swift

func updatePostions(to date: Date) {

        // update the planet positions
        let day = JulianDay(date)
        _ = planetoids.map { (planet, groupNode) in
            if let type = planet.type {
                let planetAA = type.init(julianDay: day)
                groupNode.updatePlanetLocation(planetAA.position())
            }
        }
}

func updatePlanetLocation(_ coords: EclipticCoordinates) {
        let latitude = Float(coords.celestialLatitude.magnitude)
        let longitude = Float(coords.celestialLongitude.magnitude)
        let latitudeInRadians = latitude * Float.pi / 180 // for some reason - not used???
        let longitudeInRadians = longitude * Float.pi / 180
        self.rotation = SCNVector4Make(0, 1, 0, longitudeInRadians)
    }
DamonChen117 commented 6 years ago

Per https://en.wikipedia.org/wiki/Ecliptic_coordinate_system

extension SwiftAA.PlanetaryBase
{
    // https://en.wikipedia.org/wiki/Ecliptic_coordinate_system
    public func position(date:Date) -> SCNVector3 {

        let julianDay = JulianDay(date)

        let l = KPCAAEclipticalElement_EclipticLongitude(julianDay.value, self.planet, self.highPrecision) * Double.pi / 180
        let b = KPCAAEclipticalElement_EclipticLatitude(julianDay.value, self.planet, self.highPrecision) * Double.pi / 180
        let r = KPCAAEclipticalElement_RadiusVector(julianDay.value, self.planet, self.highPrecision) // apply scale

        let x = r * cos(b) * cos(l)
        let y = r * cos(b) * sin(l)
        let z = r * sin(b)

        return SCNVector3Make(Float(x), Float(y), Float(z))
    }
}
johndpope commented 6 years ago

Hi @DamonChen117,

so each planet has a heliocentricEclipticCoordinates / and these are preset by the julian date in the init function. @djben built his own astronomical library which does an overlay into scenekit which you can see the positions of planets. it's almost everything I want - a step in right direction
https://github.com/DJBen/Graviton

This ticket pertains to adding scenekit stuff - need to cherry pick out how to do this.
https://github.com/DJBen/SpaceTime/issues/11

Are you using your solution? I wanted it to be adjusted to the users actual location on earth - eg. sceneKitCoordinate(relativeTo userLocation: CLLocation)

    /// The heliocentric coordinates of the Earth. That is, its apparent position on the celestial sphere, as
    /// as it would be seen by an observer at rest at the barycenter of the solar system, and referred to the
    /// instantaneous equator, ecliptic and equinox.
    /// See AA pp.217 and following.
    public var heliocentricEclipticCoordinates: EclipticCoordinates {
        get {
            let longitude = KPCAAEclipticalElement_EclipticLongitude(self.julianDay.value, self.planet, self.highPrecision)
            let latitude = KPCAAEclipticalElement_EclipticLatitude(self.julianDay.value, self.planet, self.highPrecision)
            // Using standard epoch, thus standard value for the equinox, thus the mean obliquity.
            return EclipticCoordinates(lambda: Degree(longitude), beta: Degree(latitude))
        }
    }
DamonChen117 commented 6 years ago

Hi johndpope,

so each planet has a heliocentricEclipticCoordinates / and these are preset by the julian date in the init function.

the function ignore the init date, but use it's own date arg.

Are you using your solution? I wanted it to be adjusted to the users actual location on earth - eg.

I'm building the Solar system, so I don't care about the user location on earth. But I think you can try:

  1. get xyz location of the Earth: xyzEarth
  2. get xyz location of a planet: xyzPlanet
  3. get gps location of the user: gpsUser
  4. covert gps location to xyz relative to the Earth: xyzUserRelativeToEarth
  5. xyzPlanetRelativeToUser = xyzPlanet - xyzEarth - xyzUserRelativeToEarth
onekiloparsec commented 6 years ago

the function ignore the init date,

No sure why it is necessary. One could have written :

extension SwiftAA.PlanetaryBase
{
    // https://en.wikipedia.org/wiki/Ecliptic_coordinate_system
    public func vector() -> SCNVector3 {

        let ec = self.heliocentricEclipticCoordinates
        let r = self.radiusVector        

        let x = r * cos(ec.beta) * cos(ec.lambda)
        let y = r * cos(ec.beta) * sin(ec.lambda)
        let z = r * sin(ec.beta)

        return SCNVector3Make(Float(x), Float(y), Float(z))
    }
}
onekiloparsec commented 5 years ago

Stalled. Closing.