quaternion to angle - java

Alright, so this is how I am doing it:
float xrot = 0;
float yrot = 0;
float zrot = 0;
Quaternion q = new Quaternion().fromRotationMatrix(player.model.getRotation());
if (q.getW() > 1) {
q.normalizeLocal();
}
float angle = (float) (2 * Math.acos(q.getW()));
double s = Math.sqrt(1-q.getW()*q.getW());
// test to avoid divide by zero, s is always positive due to sqrt
// if s close to zero then direction of axis not important
if (s < 0.001) {
// if it is important that axis is normalised then replace with x=1; y=z=0;
xrot = q.getXf();
yrot = q.getYf();
zrot = q.getZf();
// z = q.getZ();
} else {
xrot = (float) (q.getXf() / s); // normalise axis
yrot = (float) (q.getYf() / s);
zrot = (float) (q.getZf() / s);
}
But it doesn't seem to work when I try to put it into use:
player.model.addTranslation(xrot * player.speed, 0, zrot * player.speed);
AddTranslation takes 3 numbers to move my model by than many spaces (x, y, z), but hen I give it the numbers above it doesn't move the model in the direction it has been rotated (on the XZ plane)
Why isn't this working?
Edit: new code, though it's about 45 degrees off now.
Vector3 move = new Vector3();
move = player.model.getRotation().applyPost(new Vector3(1,0,0), move);
move.multiplyLocal(-player.speed);
player.model.addTranslation(move);

xrot, yrot, and zrot define the axis of the rotation specified by the quaternion. I don't think you want to be using them in your addTranslation() call...in general, that won't have anything to do with the direction of motion.
What I mean by that is: your 3-D object -- let's say for the sake of argument that it's an airplane -- will have a certain preferred direction of motion in its original coordinate
system. So if the original orientation has the center of mass at the origin, and the
propeller somewhere along the +X axis, the plane wants to fly in the +X direction.
Now you introduce some coordinate transformation that rotates the airplane into some other orientation. That rotation is described by a rotation matrix, or equivalently, by a
quaternion. Which way does the plane want to move after the rotation?
You could find
that by taking a unit vector in the +X direction: (1.0, 0.0, 0.0), then applying the
rotation matrix or quaternion to that vector to transform it into the new coordinate
system. (Then scale it by the speed, as you're doing above.) The X, Y, and Z components
of the transformed, scaled vector give the desired incremental motion along each axis. That transformed vector is generally not going to be the rotation axis of the quaternion, and I think that's probably your problem.

Related

Move camera to the direction it's facing

I have a camera that has X, Y and Z Coordinates.
The camera also has a Yaw and a pitch.
int cameraX = Camera.getX();
int cameraY = Camera.getY();
int cameraZ = Camera.getZ();
int cameraYaw = Camera.getYaw();
int cameraPitch = Camera.getPitch();
The yaw has 2048 units in 360 degrees, so at 160 degrees the getYaw() method will return 1024.
Currently I move the camera forward by just setting the Y + 1 in each loop.
Camera.setY(Camera.getY() + 1);
How would I set the camera X and Y to the direction I'm facing (The Yaw)?
I don't want to use the pitch in this situation, just the Yaw.
If I understand your question correctly, you're trying to get the camera to move in the direction you're looking (in 2D space, you're only moving horizontally).
I made a small LookAt header-only library for C++, but here is part of it rewritten in Java. What this code does is it takes a rotation and a distance, then calculates how far you need to move (in both the x and y coordinate) to get there.
// Returns how far you need to move in X and Y to get to where you're looking
// Rotation is in degrees, distance is how far you want to move
public static double PolarToCartesianX(double rotation, double distance) {
return distance * Math.cos(rotation * (Math.PI / 180.0D));
}
public static double PolarToCartesianY(double rotation, double distance) {
return distance * Math.sin(rotation * (Math.PI / 180.0D));
}

Can't Correctly rotate 3D Point A to B (on X, Y, Z axis)

I has tirelessly been researching for three weeks now, each and every procedure for rotating a 3D Point 'A' to 3D Point 'B', the following are the techniques I attempted with no success:
Rotation Matrix
Euler Angles to Rotation Matrix
Axis Angle to Rotation Matrix
Quaternion Coordinate Rotation
Trigonometry Multiple Axis Rotation
I would like to perform a simultaneous 3d 3 axis (so, X, Y, Z) rotation in java (please know I don't particularly understand the mathematics behind it, I would prefer the answer to be in java code, with the example I displayed).
e.g.
Pointf a = new Pointf(0f, 2f, 0f);
Pointf b = new Pointf(2f, 0f, 2f);
// ~~~ Start of Rotation Matrix ~~~
// azimuth (Z Axis)
float azimuth = (float) Math.toRadians(90f);
// elevation (Y Axis)
float elevation = (float) Math.toRadians(0f);
// tilt (X Axis)
float tilt = (float) Math.toRadians(90f);
/*
public static Matrix4x4f createRotationMatrix(double azimuth, double elevation, double tilt) {
// Assuming the angles are in radians.
//Precompute sines and cosines of Euler angles
double su = sin(tilt);
double cu = cos(tilt);
double sv = sin(elevation);
double cv = cos(elevation);
double sw = sin(azimuth);
double cw = cos(azimuth);
//Create and populate RotationMatrix
Matrix4x4f A = Matrix4x4f.create();
A.values[0] = (float) (cv*cw);
A.values[1] = (float) ((su*sv*cw) - (cu*sw));
A.values[2] = (float) ((su*sw) + (cu*sv*cw));
A.values[4] = (float) (cv*sw);
A.values[5] = (float) ((cu*cw) + (su*sv*sw));
A.values[6] = (float) ((cu*sv*sw) - (su*cw));
A.values[8] = (float) -sv;
A.values[9] = (float) (su*cv);
A.values[10] = (float) (cu*cv);
return A;
}
*/
// Multiplies the Z * Y * X Rotation Matrices to form 'Matrix4x4f m'
Matrix4x4f m = Matrix4x4.createRotationMatrix(azimuth, elevation, tilt);
// Multiple point 'a' with Matrix4x4f 'm' to get point 'b'
m.transform(a); // Should return {2, 0, 2} same 'b', but returns {2, 0, 0}
// ~~~ End of Rotation Matrix ~~~
FYI. My main source of information was from the following:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
Thanks All
I can explain an algorithm for finding the matrix of rotation, though I don't have code for it.
Every rotation is around an axis. I assume that you want an axis that goes through the origin O. In that case, the rotation takes place in the plane defined by the three points O, A, and B. As the rotation axis, you can use the vector which is the cross product of the two vectors OA and OB. Here is the formula.
Let's call the three components of this direction vector for the axis (u,v,w), for simplicity (and we'll assume its normalized). Next find the angle theta between OA and OB, this is found by the standard formula for the angle between two vectors.
Finally, the hard part is done for you at this site, which links to the following 3D matrix of rotation about the origin, which will rotate A to B. Java code for this matrix can be downloaded at this site.
You can check out some rotations interactively here.

Move in the same angle from point to point?

I need to be able to move my player x and y pixels in the same direction as a point to a point. It's hard to explain, but this is what I am trying to do:
Angles 1 and 2 have to be the same. Point 1 stays the same at (100, 100), however point 2 constantly changes and so must the angles. I have tried this:
moveRectangle.setX(touchEvent.getX());
moveRectangle.setY(touchEvent.getY());
float theta = (float) Math.toDegrees(Math.atan2(touchEvent.getY() - 100,touchEvent.getY() - 100));
float velX = (float) (getSpeed() * Math.cos(theta));
float velY = (float) (getSpeed() * Math.sin(theta));
player.move(velX, velY);
The above code is constantly run when the user puts his finger on moveRectangle (Point 2) and moves it. But the above code does not work. The player just moves in one of two directions. player.move just adds velX and velY velocity. So how can I get the two angles and move the player in the right direction? Thanks.
Would it be easier to approach this problem using a cartesian approach (vectors) versus polar approach (angle and magnitude)? So, if the player is at point p0 and the "finger" is at point p1, then the direction the player should be moving v is given by the vector p1-p0. You can then scale the resulting vector v by the player's speed, and add the player's speed to his position. You can do this easily on a frame-by-frame basis.
Do you need just to know velocity on X and Y axis? You can do it without using trigonometry (just use Pythagorean theorem).
final float deltaX = touchEvent.getX() - player.x; // player.x is point1.x
final float deltaY = touchEvent.getY() - player.y; // player.y is point1.y
final float length = Maths.sqrt((deltaX)^2 + (deltaY)^2);
final float itterations = length / getSpeed();
final float velX = deltaX / itterations;
final float velY = deltaY / itterations;
player.move(velX, velY);
Or you need a code of player moving in cycle?
Remove Math.toDegrees().
From the Math.sin() / cos() Javadoc:
Parameters:
a - an angle, in radians.
Returns:
the sine of the argument.

draw an angled square using sine and cosine

this is my first time posting on a forum. But I guess I will just jump in and ask.. I am trying to draw a rectangle with x, y, width, height, and angle. I do not want to create a graphics 2D object and use transforms. I'm thinking that's an inefficient way to go about it. I am trying to draw a square with rotation using a for loop to iterate to the squares width, drawing lines each iteration at the squares height. My understanding of trig is really lacking so... My current code draws a funky triangle. If there is another question like this with an answer sorry about the duplicate. If you have got any pointers on my coding I would love some corrections or pointers.
/Edit: Sorry about the lack of a question. I was needing to know how to use sine and cosine to draw a square or rectangle with a rotation centered at the top left of the square or rectangle. By using sin and cos with the angle to get the coordinates (x1,y1) then using the sin and cos functions with the angle plus 90 degrees to get the coordinates for (x2,y2). Using the counter variable to go from left to right drawing lines from top to bottom changing with the angle.
for (int s = 0; s < objWidth; s++){
int x1 = (int)(s*Math.cos(Math.toRadians(objAngle)));
int y1 = (int)(s*Math.sin(Math.toRadians(objAngle)));
int x2 = (int)((objWidth-s)*Math.cos(Math.toRadians(objAngle+90)));
int y2 = (int)((objHeight+s)*Math.sin(Math.toRadians(objAngle+90)));
b.setColor(new Color((int)gArray[s]));
b.drawLine(objX+x1, objY+y1, objX+x2, objY+y2);
}
It is called the Rotation matrix.
If your lines has the following coordinates before rotation:
line 1: (0, 0) - (0, height)
line 2: (1, 0) - (1, height)
...
line width: (width, 0) - (width, height)
Then applying the rotation matrix transform will help you:
for (int s = 0; s < objWidth; s++){
int x1 = cos(angle)*s
int y1 = sin(angle)*s
int x2 = s * cos(angle) - objHeight * sin(angle)
int y2 = s * sin(angle) + objHeight * cos(angle)
//the rest of code
}
Hope I didn't make a mistakes.
Do you mean like a "rhombus"? http://en.wikipedia.org/wiki/Rhombus (only standing, so to speak)
If so, you can just draw four lines, the horizontal ones differing in x by an amount of xdiff = height*tan(objAngle).
So that your rhombus will be made up by lines with points as
p1 = (objX,objY) (lower left corner)
p2 = (objX+xdiff,objY+height) (upper left corner)
p3 = (objX+xdiff+width,objY+height) (upper right corner)
p4 = (objX+xdiff+width,objY) (lower right corner)
and you will draw lines from p1 to p2 to p3 to p4 and back again to p1.
Or did you have some other shape in mind?

Translate Java 3D coordinates to 2D screen coordinates

I'm working with a Java 3D application called "Walrus" that is used to display directed graphs. The code already has a feature to highlight a node and draw label adjacent in graph given its screen coordinates.
Upon rotating the screen, the node is no more highlighted.
What I have is the node coordinates in 3D. I need to draw label to it.
Code for highlight using 3D coordinates
Point3d p = new Point3d();
m_graph.getNodeCoordinates(node, p);
PointArray array = new PointArray(1, PointArray.COORDINATES);
array.setCoordinate(0, p);
m_parameters.putModelTransform(gc);
gc.setAppearance(m_parameters.getPickAppearance());
How can I draw Label with 3D coordinates( Raster graphics throws error Renderer: Error creating immediate mode Canvas3D graphics context )
How can I convert 3D coordinates to 2D screen and use existing code to draw label at 2D screen point
Thanks,
Dakshina
I have an algorithm/method for converting [x,y,z] into [x,y] with the depth parameter:
The x value is : (int) (x - (z / depth * x))
The y value is : (int) (y - (z / depth * y))
Essentially, the depth is the focal point. The vanishing point will be at [0,0,depth].
Here's what i used to convert my 3D coordinates into perspective 2D, x2 and y2 being the 2dimensional coordinates, xyz being the 3D coordinates.
use these formulas:
x2 = cos(30)*x - cos(30)*y
y2 = sin(30)*x + sin(30)*y + z
I picked the angle 30 as it is easy for perspective purposes, also used in Isometric grids for drawing 3D on 2D papers. As the z axe will be the vertical one, x and y are the ones at 60 degrees from it right and left. Isometric Grid Picture.
I'm still working on rotation, but without altering the axes, just coordinate rotation in 3D.
Enjoy.
I found the solution.
This is the function to display Text3D at image 2D coordinates
public void drawLabel(GraphicsContext3D gc, double x, double y, int zOffset, String s) {
boolean frontBufferRenderingState = gc.getFrontBufferRendering();
gc.setBufferOverride(true);
gc.setFrontBufferRendering(true);
Point3d eye = getEye();
double labelZ = zOffset * LABEL_Z_OFFSET_SCALE
+ LABEL_Z_SCALE * eye.z + LABEL_Z_OFFSET;
double xOffset = LABEL_X_OFFSET * m_pixelToMeterScale;
double yOffset = LABEL_Y_OFFSET * m_pixelToMeterScale;
Point3d p = new Point3d(x + xOffset, y + yOffset, 0.0);
{
// Project given (x, y) coordinates to the plane z=labelZ.
// Convert from image-plate to eye coordinates.
p.x -= eye.x;
p.y -= eye.y;
double inversePerspectiveScale = 1.0 - labelZ / eye.z;
p.x *= inversePerspectiveScale;
p.y *= inversePerspectiveScale;
// Convert from eye to image-plate coordinates.
p.x += eye.x;
p.y += eye.y;
}
Transform3D scale = new Transform3D();
scale.set(LABEL_SCALE);
Vector3d t = new Vector3d(p.x, p.y, labelZ);
Transform3D translation = new Transform3D();
translation.set(t);
translation.mul(scale);
Transform3D transform = new Transform3D(m_imageToVworld);
transform.mul(translation);
gc.setModelTransform(transform);
//-----------------
int fontSize=(int)(10*m_magnification);
if(fontSize>20)
fontSize=20;
//---------------
// XXX: Courier may not be available on all systems.
Text2D text = new Text2D(s, new Color3f(1.0f, 1.0f, 1.0f),
"Courier", fontSize, Font.BOLD);
gc.draw(text);
gc.flush(true);
// NOTE: Resetting the model transform here is very important.
// For some reason, not doing this causes the immediate
// following frame to render incorrectly (but subsequent
// frames will render correctly). In some ways, this
// makes sense, because most rendering code assumes that
// GraphicsContext3D has been set to some reasonable
// transform.
gc.setModelTransform(m_objectTransform);
gc.setFrontBufferRendering(frontBufferRenderingState);
}
This is the function to take 3D coordinates and convert them to image 2D coordinates and render using above function
private boolean displayOnScreenLabel(int node, String label) {
boolean success = false;
try {
Transform3D transform = m_parameters.getObjectToEyeTransform();
Point3d nodeC = new Point3d();
m_graph.getNodeCoordinates(node, nodeC);
transform.transform(nodeC);
Point3d eye = m_parameters.getEye();
double perspectiveScale = 1.0 / (1.0 - nodeC.z / eye.z);
double centerX = eye.x + nodeC.x * perspectiveScale;
double centerY = eye.y + nodeC.y * perspectiveScale;
GraphicsContext3D gc = m_canvas.getGraphicsContext3D();
m_parameters.drawLabel(gc, centerX, centerY, m_labelZOffsetCounter++, label);
success = true;
} catch (final java.lang.OutOfMemoryError error) {
JOptionPane.showMessageDialog(m_frame, "The 3D Graphics is unable to find enough memory on your system. Kill the application!", "Out Of Memory!", JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
success = false;
}
return success;
}

Categories