Oculus rift, quaternion and euler, how to increase range - math

I have access to rotation degrees from oculus. Quanterion to Euler, Euler to degrees.
Range of pitch, roll and yaw is from -90 to 90. Is there any way to increase range -180 to 180? I know that can't use arcus functions, because it has ranges from -pi/2 to pi/2

double a = ts.HeadPose.ThePose.Orientation.x;
double b = ts.HeadPose.ThePose.Orientation.y;
double c = ts.HeadPose.ThePose.Orientation.z;
double d = ts.HeadPose.ThePose.Orientation.w;
double kat_x = atan2(2 * (a*b + c*d), 1 - 2 * (b*b + c*c));
kat_x = (kat_x * 180) / 3.1415;
double kat_y = asin(2 * (a*c - d*b));
kat_y = (kat_y * 180) / 3.1415;
double kat_z = atan2(2 * (a*d + b*c), 1 - 2 * (c*c + d*d));
kat_z = (kat_z * 180) / 3.1415;
Ok now it's working. Instead of using atan i needed to use atan2

Related

Convert Lat/Long to X,Y position within a Bounding Box

I have a bounding box of:
Left -122.27671
Bottom 37.80445
Right -122.26673
Top 37.81449
It could also be converted into NE Lat/Long and SW Lat/Long
Within that bounding box, I'd like to find the X,Y position of a specific Lat/Long. This would be using the Mercator projection.
I've seen answers that find the X,Y of a position on a world map using Mercator, but not within a specific lat/lon.
Any help appreciated!
UPDATE
Put this together from another question I saw. Can anyone validate if this seems legit?
map_width = 1240
map_height = 1279
map_lon_left = -122.296916
map_lon_right = -122.243380
map_lon_delta = map_lon_right - map_lon_left
map_lat_bottom = 37.782368
map_lat_bottom_degree = map_lat_bottom * Math::PI / 180
def convert_geo_to_pixel(lat, long)
x = (long - map_lon_left) * (map_width / map_lon_delta)
lat = lat * Math::PI / 180
world_map_width = ((map_width / map_lon_delta) * 360) / (2 * Math::PI)
map_offset_y = (world_map_width / 2 * Math.log((1 + Math.sin(map_lat_bottom_degree)) / (1 - Math.sin(map_lat_bottom_degree))))
y = map_height - ((world_map_width / 2 * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat)))) - map_offset_y)
return [x, y]
end
Found a better solution that I've test and validated. Posting this for anyone else who might find it useful. It's written in Ruby but easy to convert to any other language
#north = to_radians(37.81449)
#south = to_radians(37.80445)
#east = to_radians(-122.26673)
#west = to_radians(-122.27671)
# Coordinates above are a subsection of Oakland, CA
#map_width = map_width
#map_height = map_height
def location_to_pixel(lat:, lon:)
lat = to_radians(lat)
lon = to_radians(lon)
ymin = mercator_y(#south)
ymax = mercator_y(#north)
x_factor = #map_width/(#east - #west)
y_factor = #map_height/(ymax - ymin)
y = mercator_y(lat);
x = (lon - #west) * x_factor
y = (ymax - y) * y_factor
[x, y]
end
def to_radians(deg)
deg * Math::PI/180
end
def mercator_y(lat)
Math.log(
Math.tan(lat/2 + Math::PI/4)
)
end
Let's s is shift of map in world space, bottom latitude in radians B, top latitude T. (I assume y=0 is bottom)
C * Sin(B) = 0 + s
C * Sin(T) = map_height + s
=>
C = map_height / (Sin(T) - Sin(B))
s = C * Sin(B)
y = C * Sin(Lat) - s =
C * Sin(Lat) - C * Sin(B) =
C * (Sin(Lat) - Sin(B)) =
map_height * (Sin(Lat) - Sin(B) / (Sin(T) - Sin(B))
// note - resembles linear interpolation is sine space

Tesselation of the circle in OpenGL

I'm having trouble understanding the math behind this function. I would like to hear the logic behind the formulas (especially what is this tangential and radial factor) written here to create points which later (when it send the vec3 array to a function) form a circle in OpenGL.
void doTesselate(const Arc& arc, int slices, std::vector<glm::vec3>& vertices)
{
double dang = (arc.endAngle() - arc.startAngle()) * Deg2Rad;
double radius = arc.radius();
double angIncr = dang / slices;
double tangetial_factor = tan(angIncr);
double radial_factor = 1 - cos(angIncr);
double startAngle = arc.startAngle() * Deg2Rad;
const glm::vec3& center = arc.center();
double x = center.x - radius * cos(startAngle);
double y = center.y - radius * sin(startAngle);
++slices;
for (int ii = 0; ii < slices; ii++) {
vertices.push_back(glm::vec3(x, y, center.z));
double tx = center.y - y;
double ty = x - center.x;
x += tx * tangetial_factor;
y += ty * tangetial_factor;
double rx = center.x - x;
double ry = center.y - y;
x += rx * radial_factor;
y += ry * radial_factor;
}
}
The idea is the following:
Starting from the current point, you go a bit in tangential direction and then back towards the center.
The vector (tx, ty) is the tangent at the current point with length equal to the radius. In order to get to the new angle, you have to move tan(angle) * radius along the tangent. radius is already incorporated in the tangent vector and tan(angle) is the tangetial_factor (you get that directly from tangent's definition).
After that, (rx, ry) is the vector towards the center. This vector has the length l:
cos(angle) = radius / l
l = radius / cos(angle)
We need to find a multiple m of this vector, such that the corrected point lies on the circle with the given radius again. If we just inspect the lengths, then we want to find:
target distance = current distance - m * length of (rx, ry)
radius = radius / cos(angle) - m * radius / cos(angle)
1 = (1 - m) / cos(angle)
cos(angle) = 1 - m
1 - cos(angle) = m
And this multiple is exactly the radial_factor (the amount which you need to move towards the center to get onto the circle).

How can i map both angles (theta and phi) of the spherical coordinates to 360 degrees

to get the spherical coordinates (theta, phi and alpha) i use this code:
double phi_rad = atan2f(z,sqrt((x*x)+(y*y)));
double theta_rad = atan2f(y, x);
double r = sqrt((x*x)+(y*y)+(z*z));
And to map theta to 0-360 degrees i use this code:
double theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);
But how can i map phi to 0-360 degrees? I tryed the same principle as i used for theta_deg but it dont work really fine.
If phi is your azimuthal angle (0 to 2π) and theta is your polar angle (0 to π), you can do:
double phi_rad = atan2(y,x);
double theta_rad = acos(z);
Then you can just convert from radians to degrees using the standard:
double rad2deg(double rad)
{
return rad * 180.0 / M_PI;
}

Incorrect conversion from quaternions to euler angles and back

I am converting angles-axis representation to Euler angles. I decided to check and make sure that the Euler angles I got from the conversion would lead back to the original axis-angle. I print out the values, but they do not match! I have read http://forum.onlineconversion.com/showthread.php?t=5408 and http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles as well as similar conversion questions on this website.
In the code below I start with angle 'angle' and axis (rx,ry,rz), then I convert it to quaternions (q0,q1,q2,q3). I convert the quaternions to euler angles (roll, pitch, yaw). Then to check it, I convert (roll,pitch,yaw) back to axis-angle as cAngle and (cRx,cRy,cRz). I then do some bounds checking on (roll, pitch,yaw) to keep the numbers between -pi and pi, and then I print them out. It should be that cAngle=angle and (cRx,cRy,cRz)=(rx,ry,rz), but these are both wrong.
The rotations are in order Z*Y*X as is common, I believe. Is there someting wrong with my math? I plan on eventually adding special cases for when pitch is 0 or PI as in http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ but right now I think the problem is separate.
//input is angle 'angle' and axis '(rx,ry,rz)'
//convert rx,ry,rz, angle, into roll, pitch, yaw
double q0 = Math.Cos(angle / 2);
double q1 = Math.Sin(angle / 2) *Math.Cos(rx);
double q2 = Math.Sin(angle / 2) * Math.Cos(ry);
double q3 = Math.Sin(angle / 2) * Math.Cos(rz);
double roll = Math.Atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2));
double pitch = Math.Asin(2 * (q0 * q2 - q3 * q1));
double yaw = Math.Atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3));
//convert back to angle axis
double cAngle = 2 * Math.Cos(Math.Cos(roll / 2) * Math.Cos(pitch / 2) * Math.Cos(yaw / 2) + Math.Sin(roll / 2) * Math.Sin(pitch / 2) * Math.Sin(yaw / 2));
double cRx = Math.Acos((Math.Sin(roll / 2) * Math.Cos(pitch / 2) * Math.Cos(yaw / 2) - Math.Cos(roll / 2) * Math.Sin(pitch / 2) * Math.Sin(yaw / 2)) / Math.Sin(cAngle / 2));
double cRy = Math.Acos((Math.Cos(roll / 2) * Math.Sin(pitch / 2) * Math.Cos(yaw / 2) + Math.Sin(roll / 2) * Math.Cos(pitch / 2) * Math.Sin(yaw / 2)) / Math.Sin(cAngle / 2));
double cRz = Math.Acos((Math.Cos(roll / 2) * Math.Cos(pitch / 2) * Math.Sin(yaw / 2) - Math.Sin(roll / 2) * Math.Sin(pitch / 2) * Math.Cos(yaw / 2)) / Math.Sin(cAngle / 2));
//stay within +/- PI of 0 to keep the number small
if (roll > 3.1416) roll = -Math.PI + (roll - Math.PI);
if (roll < -3.1416) roll = Math.PI + (roll - (-1) * Math.PI);
if (pitch > 3.1416) pitch = -Math.PI + (pitch - Math.PI);
if (pitch < -3.1416) pitch = Math.PI + (pitch - (-1) * 3.1416F);
if (yaw > 3.1416) yaw = -Math.PI + (yaw - Math.PI);
if (yaw < -3.1416) yaw = Math.PI + (yaw - (-1) * Math.PI);
Console.WriteLine("original angle, axis " + angle + ": " + rx + ", " + ry + ", " + rz);
Console.WriteLine("converted angle, axis " + cAngle + ": " + cRx + ", " + cRy + ", " + cRz);
Console.WriteLine("quats " + q0 + ", " + q1 + ", " + q2 + ", " + q3);
Console.WriteLine("roll,pitch,yaw: " + roll + ", " + pitch + ", " + yaw);
I didn't (and I won't) check your code. Even if your code is correct, your test fails for at least 2 reasons.
There are 2 ways to represent the same rotation with Euler angles. See also Euler angle to Quaternion then Quaternion to euler angle, that question is basically about the same problem you are having.
Quaternions have the so-called double covering property: Two unit quaternions correspond to every rotation.
That is, even if your conversions are correct, you can get the other representation and not the one you started with. It doesn't matter whether you started with Euler angles or quaternions.
If you want to test your code, I suggest checking orthogonal rotations of the unit basis vectors. For example rotate [1, 0, 0] with 90 degrees appropriately to get [0, 1, 0]. Check whether you really get the expected [0, 1, 0], etc.
If you got the rotations of all 3 basis vectors right then your code is most likely correct.
This test has the advantage of being unambiguous and if you mess up something (for example a sign in a formula) this test helps you a lot in finding your mistake.
I wouldn't use Euler angles as they screw up the stability of your application. They are not very handy either.
Using quaternions are incorrect.
I want to add to this answer. People use quaternions by convention even when the application is incorrect so this is important.
If your subject of rotation cannot roll then using quaternions to represent your rotation is Incorrect. Quaternions encode 3 dimensions of rotation into the system and if your system has only two the representation is mismatched and incorrect.
Quaternions are an over complicated representation of rotation used to fix gimbal lock and provide better composability ONLY for rotations that involve pitch, yaw AND roll.
If you only have pitch and yaw. Quaternion transformations can give you an answer involving roll which is fundamentally incorrect. Zeroing the roll angle does not prevent your transformations from having a roll value. The Quaternion is not encoded with the concept of rotations Without a roll so it is incorrect to use it here.
For things that can only pitch and yaw and NOT roll, use entities that do not involve the concept of "rolling" like 3D Cartesian coordinates or spherical coordinates (not euler angles). That is enough and more correct. You will not suffer from gimbal lock under these conditions... using quaternions for this is not just over kill but WRONG.

Given an angle in degrees, how can I find the logic for line of travel using x and y? (Math dilemma)

I am making a simple game in HTML5 canvas, it involves driving a little car.
The up arrow moves the car, the left and right arrow steers it.
I have rotation sorted, but now it needs to move its x and y position when holding the up key, based on what angle it is at.
Example:
Angle is 0, the up arrow will only affect the y coordinate.
Angle is 45, the up arrow will affect both x and y coordinates at an equal pace.
What logic can I use if the angle is say, 32?
You could try something like this
velY = Math.cos(angle * Math.PI / 180) * thrust;
velX = Math.sin(angle * Math.PI / 180) * thrust;
x += velX;
y -= velY;
Quick example, angle is just incremented every loop.
http://jsfiddle.net/j5U5h/5/
Angle 0 is up like you have in your initial question.
Here is the jsfiddle modified so the angle of 0 moves you to the right.
http://jsfiddle.net/j5U5h/7/
velX = Math.cos(angle * Math.PI / 180) * thrust;
velY = Math.sin(angle * Math.PI / 180) * thrust;
x += velX;
y += velY;
To make 0 go to the right initially just change to this,
velX = -Math.cos(angle * Math.PI / 180) * thrust;
Did you really mean that 90 moves both axes equally? It seems to me that it should be 45 moves both axes equally.
if 45 moves both axes equally:
xfactor = angle * (1/90)
yfactor = (90 - angle) * (1/90)
xpos = xpos + (xincrement * xfactor)
ypos = ypos + (yincrement * yfactor)
if 90 moves both axes equally:
xfactor = (2 * angle) * (1/180)
yfactor = (180 - (2 * angle)) * (1/180)
xpos = xpos + (xincrement * xfactor)
ypos = ypos + (yincrement * yfactor)

Resources