Implementing the answer from this thread I have this code that translates the deltayaw, deltaroll and deltapitch angles into one angle and rotates a node around it. The angles that are taken as the parameters are momentary changes of angles since giving the whole angles would ignore the changes in orientation.
public static void matrixRotate(Group n, double deltaroll, double deltapitch, double deltayaw){
double A11 = Math.cos(deltaroll)*Math.cos(deltayaw);
double A12 = Math.cos(deltapitch)*Math.sin(deltaroll)+Math.cos(deltaroll)*Math.sin(deltapitch)*Math.sin(deltayaw);
double A13 = Math.sin(deltaroll)*Math.sin(deltapitch)-Math.cos(deltaroll)*Math.cos(deltapitch)*Math.sin(deltayaw);
double A21 =-Math.cos(deltayaw)*Math.sin(deltaroll);
double A22 = Math.cos(deltaroll)*Math.cos(deltapitch)-Math.sin(deltaroll)*Math.sin(deltapitch)*Math.sin(deltayaw);
double A23 = Math.cos(deltaroll)*Math.sin(deltapitch)+Math.cos(deltapitch)*Math.sin(deltaroll)*Math.sin(deltayaw);
double A31 = Math.sin(deltayaw);
double A32 =-Math.cos(deltayaw)*Math.sin(deltapitch);
double A33 = Math.cos(deltapitch)*Math.cos(deltayaw);
double d = Math.acos((A11+A22+A33-1d)/2d);
if(d!=0d){
double den=2d*Math.sin(d);
Point3D p= new Point3D((A32-A23)/den,(A13-A31)/den,(A21-A12)/den);
Rotate r = new Rotate();
r.setAxis(p);
r.setAngle(Math.toDegrees(d));
n.getTransforms().add(r);
Transform all = n.getLocalToSceneTransform();
n.getTransforms().clear();
n.getTransforms().add(all);
}
}
(I'm using rotate because I need to always rotate the object around the origin, not the center)
Now this creates a problem as I'm no longer able to get the actual pitch, roll and yaw angles.
I used to keep track of them like this (which doesn't take into account the changing orientation):
roll +=deltaroll;
pitch += deltapitch;
yaw += deltayaw;
And later I've come up with this, which is a bit more accurate, but doesn't track the changes that occur if the angles are not directly modified(inserted after the n.getTransforms().add(all) in the main snippet):
roll+= Math.toDegrees(d)*((A32-A23)/den);
pitch += Math.toDegrees(d)*((A13-A31)/den);
yaw += Math.toDegrees(d)*((A21-A12)/den);
I've been searching around for solutions and found this answer which is supposed to give the angle from the final transform but I haven't been able to get it working for all angles.
double xx = n.getLocalToSceneTransform().getMxx();
double xy = n.getLocalToSceneTransform().getMxy();
double roll = Math.atan2(-xy, xx);
Again what I'm trying to get are the full angles (composited out of the transforms made from the delta angles in different orientations) relative to the scene's coodrdinate system. I'm really bad at this so all help would be great.
If you want to get the pitch, yaw and roll angles at any stage after several rotations, you can get them from the transformation matrix of the 3D model.
If you have a look at the transformation matrix after several rotations:
Transform T = model3D.getLocalToSceneTransform();
System.out.println(T);
you'll see something like this:
Transform [
0.9034731871219395, -0.4260296991535005, -0.04727468234587054, 1.4044414829046357
0.3743586809560477, 0.837958815679334, -0.39709016761704913, 0.5234811188037405
0.2087864414768669, 0.3410626315861443, 0.9165612381019399, -1.1277640590168572
]
If you want the angles, you just need to compare this matrix with this one from this answer:
As you have already stated, to get the roll angle you can use T.getMxx() and T.getMyx():
double roll = Math.atan2(-T.getMyx(),T.getMxx());
Now, for the pitch, you can use T.getMzy() and T.getMzz() in the same way:
double pitch = Math.atan2(-T.getMzy(),T.getMzz());
Finally, for the yaw, use T.getMzx(), T.getMzy() and T.getMzz():
double yaw = Math.atan2(T.getMzx(),Math.sqrt(T.getMzy()*T.getMzy()+T.getMzz()*T.getMzz()));
This will give for the above matrix the angles you are looking for (in radians):
roll: -0.39281984604895126
pitch: -0.356235553820928
yaw: 0.21033388848106072
Related
I need to convert an angle axis representation to a Quaternion using Eigen
For example I have the following angle axis representation of a pose from a UR robot (rotation part of the pose of the robot only)
(-2.237 -2.217 -0.030)
I want to convert this to a Quaternion using Eigen
I tried this code
Eigen::Quaterniond q;
q = AngleAxisd(-2.237, Vector3d::UnitX())
* AngleAxisd(-2.217, Vector3d::UnitY())
* AngleAxisd(-0.030, Vector3d::UnitZ());
but I end up with
qx: -3.9853142115731549e-01
qy: -4.0057160431638472e-01
qz: 7.9758941987327925e-01
qw: 2.1110711374071198e-01
When I use this online conversion tool I get something different
https://www.andre-gaschler.com/rotationconverter/
What am I doing wrong?
Thanks
Managed to get it sorted this way
Eigen::Vector3d rotation(roll, pitch, yaw);
double angle = rotation.norm();
Eigen::Vector3d axis = rotation.normalized();
Eigen::Quaterniond q(Eigen::AngleAxisd(angle, axis));
Currently I'm working on a orbit system for a game. I've got it so an object will move along a circle based on a progress value that'll be between 0.0 and 1.0 (0.5 being half way around the circle). I calculate this like this:
float angle = Mathf.Deg2Rad * 360 * t;
float xPos = Mathf.Sin(angle) * xAxis;
float yPos = Mathf.Cos(angle) * yAxis;
return new Vector3(xPos, yPos, 0.0f);
With t simply being deltatime and the xAxis/yAxis variables being the radius of the circle.
What I'm a little stuck on currently though is how I could possibly get the progress around the circle based on a poisition. So if I have an object that hits the bottom of the circle, how do I calculate that to be a progress of 0.5?
First step: Find out the angle of your given position with the y-axis.
Second step: Calculate the fraction of a full circle (360 degs) that your angle has.
First step involves a bit of trigonometry, and there you have to make sure to get the right type of angle based on what quadrant you're in. Second step should be trivial then.
You can check out the atan2 function that's available in many programming languages: https://en.wikipedia.org/wiki/Atan2
It gives the angle between a point (x, y) and the positive x-axis. So then in your case, depending on where your circle starts, you'd then shift that by 90 degrees to get the angle with the positive y-axis. Other than that it should work fine though.
So I have one point in 3D space, and I have location and rotation of the Camera in 3D space.
So basically there is Vector3 on the object.
Camera Vector3 and Quaternion.
I need to get how to look at that point.
I want to tell user how to move to that point.
Should user direct camera left or right or behind?
One way to do this is to calculate the direction the camera is currently facing as a yaw angle (like a compass heading), and calculate the direction it needs to face in order to be looking at the point.
Subtract one from the other and adjust the result so that it is in the range of -180 to 180 degrees (or -pi to pi radians) and then tell the user to turn left or right based on the sign. If the absolute value is more than 120 degrees (or some configurable value) then tell them it is behind them.
To find the camera's current heading, transform the vector (0, 0, 1) by the quaternion to get the forward vector, then calculate the heading using atan2(forward.z, forward.x).
To calculate the heading required to look at the point, subtract the current camera position from the point to get a desired forward vector and then pass to atan:
Vector3 desired_forward = point - camera_pos;
float desired_heading = atan2(desired_forward.z, desired_forward.x);
Then find the rotation needed:
float rotation_needed = desired_heading - heading;
if(rotation_needed > Math.PI)
rotation_needed -= 2 * Math.PI;
if(rotation_needed < -Math.PI)
rotation_needed += 2 * Math.PI;
Now tell the user to rotate left or right based on the sign of the rotation needed.
If you want to do it for look up/down, you can calculate a pitch angle by first calculating the length of the forward vector in the XZ plane and then using atan2 again:
float xzLength = sqrt(forward.x * forward.x + forward.z * forward.z);
float pitch_angle = atan2(forward.y, xzLength);
Do the same for the desired forward vector and subtract the current from the desired. Check the sign to tell the user whether to look up or down.
There's a few likely complications. For example, depending on whether the camera quaternion specifies the transform from world space to camera space or vice versa, you might need to negate the calculated camera heading.
I'm using this very simple code to rotate objects around their own origin
void Entity::rotate(unsigned short axis, float speed, float delta)
{
m_Orientation[axis] += delta * speed;
glm::quat quaternion = glm::quat(glm::vec3(m_Orientation[0], m_Orientation[1], m_Orientation[2]));
m_RotationMatrix = glm::mat4_cast(quaternion);
}
The issue I'm facing is that the rotation is only relative to object's direction on the X axis. Meaning that no matter which way the object is facing (what it's orientation is), if I rotate it around X it will always rotate around it's own X axis. That is what I would like to do, but on the other 2 axis as well.
But Y and Z always rotate around world X and Y axis, disregarding which way my object is facing.
My code is so small and simple I don't really see the problem? Is the X rotation being always correct the accident, or is it that the other two are wrong?
I suggest that you try this:
#include <glm/gtx/euler_angles.hpp>
/**
If you change speed to a vec3,
it do all the calculations at once
(you won't have to do it for each angle)
**/
void Entity::rotate(glm::vec3 speed, float delta)
{
rotation = speed * data
m_modelMatrix *= glm::eulerAngleXYZ(rotation.x, rotation.y, rotation.z);
}
The glm::eulerAngleXYZ function will take the angles and create a rotation matrix from it.
But be aware of gimbal lock.
If you do your multiplication of the matrix from right to left, it will rotate around the global axis. If you do it the other way, it will rotate around the local axis.
I want to create a graphic calculator and Im stuck with the graph bit. I want to know how to plot a graph for sin(x) cos(x) tan(x). I have made the grid already. I dont want to use core plot framework.
Any help would be appreciated.
Thanks.
To actually plot the function, do like you would with paper and pencil: evaluate the function for a number of inputs. Then draw lines to connect the resulting points.
Not that I would actually do this (I would look at Core Plot), but you could plot such a graph using a Core Image generator filter, like this:
//wavelength and magnitude are distances in destination pixels. Think of them as the width and height of each wave.
kernel vec4 sineWave(float wavelength, float magnitude, __color color)
{
vec2 coord = destCoord();
coord.y -= magnitude;
coord /= vec2(wavelength, magnitude / 2.0);
float pi = radians(180.0);
float value = sin(coord.x * pi);
//Smaller threshold = finer wave line. For a gradient, replace the comparison with 1.0 - abs(…).
float threshold = 0.1;
float alpha = abs(coord.y - value) <= threshold;
return color * alpha;
}
Here is some pseudo-code that could answer your question:
for i = xmin to xmax do
{
draw XY point at X=(i*x_scale_factor+x_offset) and Y=(sin(i)*y_scale_factor+Y_offset);
}
And beware: don't use floats in for loops
EDIT in response to comments
The easiest way to proceed, IMHO, would be to get the bounds of your view, to get the min and max values of your data on both X and Y axis.
You then can use a NSAffineTransform instance to transform the coordinates of your drawings. So everything can be done in your graphic coordinates, which is easier. You can write a label at coordinates (4.6, 3.2*10-7) if you wish to. This is a key point to get you started. The road is long. But using NSAffineTransform will make it easier.