translating CLLocation coordinates into SCNVector3 matrics - ios

Goal: Have a AR item fixed to a location in real world based on CLLocation coordinates (LLA), and have it in the same place regardless of my orientation on viewload.
Ive been trying to convert geo LLA coordinates into an SCNVector3 matrix. The issues im having are as followed:
1) Lat1 and Long1 are based on my current coordinates from a CLLocationManager on my device. Im looking for a way to get the relative SCNVector3[x,y,z] needed by my device to and place an item at lat2 and long2's location in the real world.
2) How do I get this targeted Lat2, Long2 to be in the same place every time. I feel like the alignment of . gravityAndHeading isn't working to always orient the matrix facing true north. So though sometimes I may get the correct distance from my device location, the orientation is off.
3) I would like the values to be accurate enough to recognize something at least 2-3 meters away. even when i manually program the SCNVector3 from the same position, it seems a bit off.
Any guidance would be greatly appreciated. I've already looked at http://www.mathworks.com/help/aeroblks/llatoecefposition.html and http://www.jaimerios.com/?p=39 but it seems to return the distance but not the relative position to the phone in an SCNVector format.
import SceneKit
import ARKit
import CoreLocation
...
func latLonToECEF(_ lat1: Double,_ lon2: Double,_ alt: Double?) -> [String:Double] {
let x = 6371 * cos(lat1) * cos(long1)
let y = 6371 * cos(lat1) * sin(long1)
let z = 6371 * sin(lat1)
let lat2 = static_lat
let long2 = static_long
let x2 = 6371 * cos(lat2) * cos(long2)
let y2 = 6371 * cos(lat2) * sin(long2)
let z2 = 6371 * sin(lat2)
return ["x": (x2 - x), "y": (y2 - y), "z": (z2 - z)]
}

Related

How to calculate distance from the centering point between two eyes to the camera using ARCore + SceneKit?

I'm using ARCore + SceneKit (Swift language) to calculate the distance from the centering point between two eyes to the camera.
I determine the coordinates of the camera:
let cameraPos = sceneView.pointOfView?.position
The coordinates of the left eye and right eye:
let buffer = face.mesh.vertices
let left = buffer[LF]
let right = buffer[RT]
NOTE:
LF and RT is defined base on: https://github.com/ManuelTS/augmentedFaceMeshIndices
LF = 159 is the index that contain the Vector3 condinate of the Left eye
RT = 386 is the index that contain the Vector3 condinate of the Right eye
Compute the centering point (in SCNVector3):
let center = SCNVector3(x: (left.x - right.x) * 0.5,
y: (left.y - right.y) * 0.5,
z: (left.z - right.z) * 0.5)
Finally, I calculate the distance:
let distance = distance(start: cameraPos!, end: center)
distance is defined as:
func distance(start: SCNVector3, end: SCNVector3) -> Float {
let dx = start.x - end.x
let dy = start.y - end.y
let dz = start.z - end.z
let distance = sqrt(dx * dx + dy * dy + dz * dz)
return round(distance * 100 * 10) / 10.0
}
Runtime result is incorrect.
Actual distance: ~20 cm
In-app distance: ~3 cm
Can someone tell me where the problem lies, even another solution?
Thanks.
Assuming center is the midpoint between the eyes, then shouldn't the formula be:
Midpoint:
(x1, y1, z1) and (x2, y2, z2) is (x1+x2 )/2,(y1+y2 )/2,(z1+z2 )/2.
Edit: Taking a guess here, but...
Example: So that a projectile will actually launch from a turret with a long barrel cannon exactly where the barrel is rotated to at the time of firing, you have to calculate that position at the end of the tube as it relates to the position of the node that the barrel is attached to, otherwise the shot will not look like it came from the right spot.
Requires a little imagination, but this is your face moving around = turret is moving around. I "think" that's what's happening to your math. I don't think you are getting the right LF/RF positions because you didn't mention converting the point. The link you sent [The face mesh consists of hundreds of vertices that make up the face, and is defined relative to the center pose.] Relative to the center pose - I'm pretty sure that means you have to convert LF with relation to the center to get the real position.
// Convert position something like this:
let REAL_LF = gNodes.gameNodes.convertPosition(LF.presentation.position, from: POSE_POSITION)
convertPosition(_:to:)
Converts a position from the node’s local coordinate space to that of another node

Programmatically move in the direction camera is facing

I'm trying to move a user position marker in the direction the camera is facing. Kind of like you would control a character in a game.
Since camera in MapKit is aligned north, I thought for moving forward I'd add some latitude degrees and then rotate the resulting point on camera angle.
I have some converters from meters to how many degrees is that:
class Converter {
fileprivate static let earthRadius = 6378000.0 // meter
class func latitudeDegrees(fromMeter meter: Double) -> Double {
return meter / earthRadius * (180 / Double.pi)
}
class func longitudeDegress(fromMeter meter: Double, latitude: Double) -> Double {
return meter / earthRadius * (180 / Double.pi) / cos(latitude * Double.pi / 180)
}
}
So for moving forward, my code looks like this:
let latitudeDelta = Converter.latitudeDegrees(fromMeter: speed)
let y = userLocation.latitude + latitudeDelta
let x = userLocation.longitude
let a = -self.mapView.camera.heading * Double.pi / 180
self.userLocation = CLLocationCoordinate2D(latitude: x*sin(a) + y*cos(a), longitude:x*cos(a) - y*sin(a))
I've tried different approaches, and none seem to work. Is there something fundamentally wrong? Could it be that I also need to consider Earth curvature in the calculations?
After some more struggling, I found out that this problem is called "Direct Geodesic Problem". Here I found all the formulas I needed, but in the end used a great C library.

Rotation angles from Quaternion

I have a 3D scene in which in the imaginary sphere I position few objects, now I want to rotate them within device motion.
I use spherical coordinate system and calculate position in sphere like below:
x = ρ * sin⁡ϕ * cos⁡θ
y = ρ * sin⁡ϕ * sin⁡θ
z = ρ * cos⁡ϕ.
Also, I use angles (from 0 to 2_M_PI) for performing rotation horizontally (in z-x)
As result all works perfect until I want to use Quaternion from motion matrix.
I can extract values like pitch, yaw, roll
GLKQuaternion quat = GLKQuaternionMakeWithMatrix4(motionMatrix);
CGFloat adjRoll = atan2(2 * (quat.y * quat.w - quat.x * quat.z), 1 - 2 * quat.y * quat.y - 2 * quat.z * quat.z);
CGFloat adjPitch = atan2(2 * (quat.x * quat.w + quat.y * quat.z), 1 - 2 * quat.x * quat.x - 2 * quat.z * quat.z);
CGFloat adjYaw = asin(2 * quat.x * quat.y + 2 * quat.w * quat.z);
or try also
CMAttitude *currentAttitude = [MotionDataProvider sharedProvider].attitude; //from CoreMotion
CGFloat roll = currentAttitude.roll;
CGFloat pitch = currentAttitude.pitch;
CGFloat yaw = currentAttitude.yaw;
*the values that i got is different for this methods
The problem is that pitch, yaw, roll is not applicable in this format to my scheme.
How can I convert pitch, yaw, roll or quaternion or motionMatrix to required angles in x-z for my rotation model? Am I on correct way of things doing, or I missed some milestone point?
How to get rotation around y axis from received rotation matrix/quaternion from CoreMotion, converting current z and x to 0, so displayed object can be rotated only around y axis?
I use iOS, by the way, but guess this is not important here.

How to show heading direction from Current location to other location on map in ios?

I have a requirement where i have to show the heading direction towards any location on map from user current location. Let say if we have 4 location annotation on map apart from current location and i want to show heading towards any of the location after tapping on it.
How can we achieve it. I have gone trough Map API documentation & Locaiotn API, I found that we get the heading value in the delegate method which provided by API when we called the startupdatingheading method. I not getting idea how can we externally get the heading data between two locations.
Please help me out.
Thanks in advance.
This will calculate the initial bearing to get from lat1,lon1 to lat2,lon2 on a straight line.
double lat1=48.0; // source latitude, example data
double lon1=17.0; // source longitude
double lat2=49.0; // destination latitude
double lon2=18.0; // destination longitude
double lat1Rad = lat1 * M_PI / 180;
double lat2Rad = lat2 * M_PI / 180;
double dLon = (lon2 - lon1) * M_PI / 180;
double y = sin(dLon) * cos(lat2Rad);
double x = cos(lat1Rad) * sin(lat2Rad) - sin(lat1Rad) * cos(lat2Rad) * cos(dLon);
double bearingRad = atan2(y, x);
// this is the bearing from source to destination in degrees, normalized to 0..360
double bearing = fmod((bearingRad * 180 / M_PI + 360),360);
Swift version:
func getHeading(fromLoc: CLLocationCoordinate2D, toLoc: CLLocationCoordinate2D) -> Double {
let lat1Rad = fromLoc.latitude * Double.pi / 180
let lat2Rad = toLoc.latitude * Double.pi / 180
let dLon = (toLoc.longitude - fromLoc.longitude) * Double.pi / 180
let y = sin(dLon) * cos(lat2Rad)
let x = cos(lat1Rad) * sin(lat2Rad) - sin(lat1Rad) * cos(lat2Rad) * cos(dLon)
let bearingRad = atan2(y, x)
// this is the bearing from/to in degrees, normalized to 0..360
return fmod((bearingRad * 180 / Double.pi + 360),360);
}

Get distance between 2 latitude & longitude in iOS6+

I want to calculate the distance between 2 lat & long. I am able to calculate the distance as below
CLLocation *currentLoc = [[CLLocation alloc] initWithLatitude:-24.4132995 longitude:121.0790024];
CLLocation *restaurnatLoc = [[CLLocation alloc] initWithLatitude:-32.8310013 longitude:150.1390075];
CLLocationDistance meters = [restaurnatLoc distanceFromLocation:currentLoc];
NSLog(#"Distance between 2 geo cordinates: %.2f Meters",meters);
Now I want to get the direction from currentLocation to restaurnatLoc. For this I have below code
double DegreesToRadians(double degrees) {return degrees * M_PI / 180;};
double RadiansToDegrees(double radians) {return radians * 180/M_PI;};
-(double) bearingToLocationFromCoordinate:(CLLocation*)fromLoc toCoordinate:(CLLocation*)toLoc
{
double lat1 = DegreesToRadians(fromLoc.coordinate.latitude);
double lon1 = DegreesToRadians(fromLoc.coordinate.longitude);
double lat2 = DegreesToRadians(toLoc.coordinate.latitude);
double lon2 = DegreesToRadians(toLoc.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
return RadiansToDegrees(radiansBearing);
}
It returns bearing = 114.975752 Now how can I decide whether restaurant is in North,South,West,East,NW,NE,SW,SE from my current location ?
I get 1 solution from this link Direction based off of 2 Lat,Long points But if I consider this solution , then I have doubt on bearing 114 from my location(red circle) to restaurant (green circle) as shown below. Correct me if I am wrong.
As current location is "Western Australia" & restaurant location is "Sydney" as shown in Google Maps.
Can any body tell me whats going wrong here ? Thanks.
///////////////////////////// Update /////////////////////////////
My compass diagram is wrong. Here is the correct diagram all thanks to AlexWien
Now I am getting the correct output
your compass rose is totally wrong. have you ever looked at a compass? open the iphone compass app and look where 90Degrees is located. It is east, not west like in your graphic.
geographical direction is measured clockwise!
so 114 deg is east, which matches you expectation

Resources