Open johndpope opened 6 years ago
Can we step back for a second? You're trying to get the lat/lng of your current location? Or of a few cities around the world? If the former, why not use CLLocationManager
?
You're trying to get the SCNCamera
to a specific location. Are you referring to the second target in this project which is SceneKit based? The main target is ARKit which means you'll just move the phone to the position you want.
Just trying to get on the same page here.
this ticket is simply to position an item from lat lng on earth ccnode. irrespective of CCLocation Manager eg. add dot to Hong Kong.
I'll update the other ticket which specifies in more detail the geocentric point of view which will leverage CLCoreLocationManager.
found this class https://github.com/grevolution/SceneKitEarthTest/blob/eebb68885cefab784cf60ab8d2813db8c8b4f7a4/SceneKitEarthTest/ViewController.swift
but it's going from CGPoint -> lat / lng depending on how earth node is setup - we need to go the other way around.
func coordinatesFrom(point: CGPoint) -> CLLocation {
let x = Double(point.x);
let y = Double(point.y);
//NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
// lat is 90 to - 90
// long is -180 to 180
let lat : CLLocationDegrees = (y * -180) + 90
let lon : CLLocationDegrees = (x * 360) - 180
return CLLocation(latitude: lat, longitude: lon)
}
found this which successfully maps a lat / lng to a scenekit object https://stackoverflow.com/questions/10473852/convert-latitude-and-longitude-to-point-in-3d-space
https://github.com/RPasecky/ARGlobe/blob/master/ARGlobe/coordinateMarker.swift
func convertLLAtoECEF(coordinateData: coordinateData, radius: Double) {
//Thanks CodingAway https://stackoverflow.com/questions/10473852/convert-latitude-and-longitude-to-point-in-3d-space
let rad = radius //6378137.0 //Radius of the Earth (in meters)
let f = 1.0/298.257223563 // Flattening factor WGS84 Model
let longRad = (-coordinateData.longitude + 90) * .pi / 180
let latRad = (coordinateData.latitude) * .pi / 180
let cosLat = cos(latRad)
let sinLat = sin(latRad)
let FF = pow(1.0 - f, 2)
let C = 1 / sqrt(pow(cosLat, 2) + FF * pow(sinLat, 2))
let S = C * FF
self.position.x = Float((rad * C + coordinateData.altitude) * cosLat * cos(longRad))
self.position.y = Float((rad * S + coordinateData.altitude) * sinLat)
self.position.z = Float((rad * C + coordinateData.altitude) * cosLat * sin(longRad))
print("position: \(self.position)")
}
so now - I can plugin CoreLocation manager when app starts - and plot user location on scenekit earth. Then to rotate camera angle to that location.
cleaner code here - credits @dmojdehi https://github.com/johndpope/SwiftGlobe/blob/master/SwiftGlobe/SwiftGlobe.swift#L167
// code to encapsulate individual glow points
// (extend this to get different glow effects)
class GlobeGlowPoint {
var latitude = 0.0
var longitude = 0.0
// the node of this point (must be added to the scene)
fileprivate var node : SCNNode!
init(lat: Double, lon: Double) {
self.latitude = lat
self.longitude = lon
self.node = SCNNode(geometry: SCNPlane(width: kGlowPointWidth, height: kGlowPointWidth) )
self.node.geometry!.firstMaterial!.diffuse.contents = "yellowGlow-32x32.png"
// appear a little washed out in daylight...
self.node.geometry!.firstMaterial!.diffuse.intensity = 0.2
self.node.geometry!.firstMaterial!.emission.contents = "yellowGlow-32x32.png"
// but brigheter in dark areas
self.node.geometry!.firstMaterial!.emission.intensity = 0.7
self.node.castsShadow = false
// NB: our textures *center* on 0,0, so adjust by 90 degrees
let adjustedLon = lon + 90
// convert lat & lon to xyz
// Note scenekit coordinate space:
// Camera looks down the Z axis (down from +z)
// Right is +x, left is -x
// Up is +y, down is -y
let cosLat = cos(lat * Double.pi / 180.0)
let sinLat = sin(lat * Double.pi / 180.0);
let cosLon = cos(adjustedLon * Double.pi / 180.0);
let sinLon = sin(adjustedLon * Double.pi / 180.0);
let x = kGlowPointAltitude * cosLat * cosLon;
let y = kGlowPointAltitude * cosLat * sinLon;
let z = kGlowPointAltitude * sinLat;
//
let sceneKitX = -x
let sceneKitY = z
let sceneKitZ = y
//print("convered lat: \(lat) lon: \(lon) to \(sceneKitX),\(sceneKitY),\(sceneKitZ)")
let pos = SCNVector3(x: sceneKitX, y: sceneKitY, z: sceneKitZ )
self.node.position = pos
// and compute the normal pitch, yaw & roll (facing away from the globe)
//1. Pitch (the x component) is the rotation about the node's x-axis (in radians)
let pitch = -lat * Double.pi / 180.0
//2. Yaw (the y component) is the rotation about the node's y-axis (in radians)
let yaw = lon * Double.pi / 180.0
//3. Roll (the z component) is the rotation about the node's z-axis (in radians)
let roll = 0.0
self.node.eulerAngles = SCNVector3(x: pitch, y: yaw, z: roll )
}
}
currently these lines map SwiftAA into the scenekit. however, I don't believe there's any way to get scenekit camera to specific point of latitude / longitude.
this plist contains a bunch of cities with lat / lngs https://github.com/op1000/EarthTravel/blob/master/EarthTravel/Resources/AllCititesToTravel_258.plist