I'm trying to make a bitmap rotate and point towards the mouse but I get strange results:
Video: http://www.truploader.com/view/993341
The mouse isn't visible it does rotate, however it doesn't rotate to the tip of the mouse point.
Code:
/**
* Rotates the object based on a point
*/
public void setRotation(float x, float y)
{
float XDistance = this.xPos - x;
float YDistance = this.yPos - y;
float Radians = (float) Math.atan2(YDistance, XDistance);
this.degrees = Math.round((Radians*180/Math.PI));
this.moveObject();
this.r.setRotate(this.degrees, this.picture.getWidth() / 2, this.picture.getHeight()); //origin of the base
// this.r.setRotate(this.degrees, this.picture.getWidth() / 2, this.picture.getHeight() / 2);
}
Mouse position is x, and y. Anyone any ideas?
Where do you get the "mouse position"? I guess you take it from a MotionEvent, so notice this coordinates are relative to the target View origin.
What results do you expect? Rotates the object based on a point could mean a lot of things. What is wrong with it?
Are the degrees correct? Initialize your object, fake a mouse position and see if this.degrees is what you expect it to be and what you need it to be. If it doesn't work, consider writing a unit test.
What does this.moveObject(); do? Does it do, what it's supposed to do correctly?
this.r.setRotate( does it need degrees? Why this.picture.getWidth() / 2? About what point does it rotate?
So, what's wrong?
Related
I am trying to use quaternion rotation using the quaternion from JOML: https://github.com/JOML-CI/JOML/blob/main/src/org/joml/Quaternionf.java.
I can get objects to rotate but they get stuck and are unable to complete a full rotation. The object is being updated every frame.
Edit:
Removed all euler related code and am simply trying to get the object to rotate on a single axis based on a certain angle.
Edit 2:
Am trying to use the conjugate and multiplying the quaternions together like I have seen in some videos. I'm not quite there though as the model spins itself off the screen for some reason.
Edit 3:
Normalizing the quaternion fixed the disappearing behaviour. The issue seems to be that there's no simple way to rotate a certain amount without either having a timer to lerp over which will not work in my case as I am trying to rotate an object an arbitrary amount with no set beginning and end.
Rotation function
public void rotate(float angle, float x, float y, float z) {
Quaternionf rot = new Quaternionf();
rot.rotateAxis((float) Math.toRadians(angle), x, y, z);
Quaternionf conjugate = rot.conjugate();
rotation = rot.mul(rotation).mul(conjugate);
}
Calling the rotation function
entity.transform.rotate( 1,0,1, 0);
It does not matter whether you transform your Euler angles into a matrix or a quaternion or whatever representation: As long as you use Euler angles to represent an orientation, Gimbal Lock is unavoidable.
So, in order to avoid Gimbal Lock from happening, you must discard using Euler Angles and stay with one representation for an orientation (like a 3x3 matrix or a quaternion) and apply delta changes to them, instead of trying to represent a full orientation as three Euler angles. So, whenever you - let's say - rotate the object a few degrees around a certain axis, you apply that delta change or orientation to the matrix/quaternion.
I believe I have figured it out.
You need to create a quaternion and rotate it to your delta values, do not manipulate quaternion values directly (e.g. use rotationX function instead).
To add quaternions together you multiply them.
Finally you need to use the equation:
delta quaternion * quaternion to rotate * inverse of delta quaternion
Code:
public void rotate(float x, float y, float z) {
//Use modulus to fix values to below 360 then convert values to radians
float newX = (float) Math.toRadians(x % 360);
float newY = (float) Math.toRadians(y % 360);
float newZ = (float) Math.toRadians(z % 360);
//Create a quaternion with the delta rotation values
Quaternionf rotationDelta = new Quaternionf();
rotationDelta.rotationXYZ(newX, newY, newZ);
//Calculate the inverse of the delta quaternion
Quaternionf conjugate = rotationDelta.conjugate();
//Multiply this transform by the rotation delta quaternion and its inverse
rotation.mul(rotationDelta).mul(conjugate);
}
I'm trying to do some basic trigonometry with Java and LibGDX on android.
I've spent a long time googling "How to find an angle in right triangles".
I still don't really understand :(
I want to give an Actor subclass a random direction to follow. So what is the angle - and what should I set xSpeed and ySpeed to, in order to move at the correct angle.
I started writing an app to help me see how it works.
There are two objects - An origin point and a touch point. User presses screen, touchPoint moves to where user touched. Methods fire to figure out the appropriate values. I know the XDistance and YDistance between the two points. That means I know the Opposite length and the Adjacent length. So all I need to do is tan-1 of (opposite / adjacent), am I right?
I just don't understand what to do with the numbers my program spits out.
Some code:
In create event of main class:
stage.addListener(new ClickListener() {
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
touchPoint.setX(x);
touchPoint.setY(y);
touchPoint.checkDistance(); // saves x and y distances from origin in private fields
atan2D = getAtan2(touchPoint.getYDistance(), touchPoint.getXDistance());
tanhD = getTanh(touchPoint.getYDistance(), touchPoint.getXDistance());
xDistanceLbl.setText("X Distance: " + touchPoint.getXDistance());
yDistanceLbl.setText("Y Distance: " + touchPoint.getYDistance());
atan2Lbl.setText("Atan2: " + atan2D);
tanhLbl.setText("Tanh: " + tanhD);
angleLbl.setText("Angle: No idea");
}
})
...
private double getAtan2(float adjacent, float opposite) {
return Math.atan2(adjacent, opposite);
}
private double getTanh(float adjacent, float opposite) {
return Math.tanh((adjacent / opposite));
}
These two functions give me numbers between (atan2: -pi to pi) and (tanh: -1.0 to 1.0)
How do I turn these values into angles from which I can then work backwards and get the opposite and adjacent again?
Doing this should allow me to create and object with a random direction, which I can use in 2D games.
atan2 gives you direction in radians. Direction from origin (0,0) to touchPoint. If you need direction from some object to touchPoint, then subtract object coordinates. Perhaps you also want to see direction in degrees (this is only for human eyes)
dx = x - o.x
dy = y - o.y
dir = atan2(dy, dx)
dir_in_degrees = 180 * dir / Pi
I you have direction and want to retrieve coordinate differences, you need to store distance
distance = sqrt(dx*dx + dy*dy)
later
dx = distance * cos(dir)
dy = distance * sin(dir)
But note that often storing dx and dy is better, because some calculations might be performed without trigonometric functions
Just noticed - using tanh is completely wrong, this is hyperbolic tangent function, it has no relation to geometry.
You can use arctan, but it gives angle in half-range only (compared with atan2)
I am trying to make a calculation for an angle between my mouse and the 'player' Im using lwjgl and opengl. This is what is use to rotate the image:
GL11.glTranslatef(p.getPosition().x+playerTexture.getTextureWidth()/2, p.getPosition().y+playerTexture.getTextureHeight()/2, 0);
GL11.glRotated(0, 0.0f, 0.0f, 1.0f);
GL11.glTranslatef(-p.getPosition().x+-playerTexture.getTextureWidth()/2, -p.getPosition().y+-playerTexture.getTextureHeight()/2, 0);`
I have tried two things but everytime it just keeps spinning the image non stop. My attempts:
public float getAngle(Player p) {
float angle = (float) (Math.atan2(Mouse.getY() -
p.getPosition().y+playerTexture.getTextureHeight()/2 , Mouse.getX() -
p.getPosition().x+playerTexture.getTextureWidth()/2));
return angle;
}
public void calcAngle(Player p){
double y = Mouse.getY() - p.getPosition().y;
double x = Mouse.getX() - p.getPosition().x;
double dir = Math.atan2(y, x);
}
I hope someone knows a fix for this. Thanks.
I can't see where you're actually using your getAngle method, but I suspect you're using the angle calculated from Math.atan2 directly in the openGL rotate function?
If that's the case, I would guess you've got a mixup of units. I believe Math.atan2 returns radians, and openGL expects degrees. Try using Math.toDegrees(angle).
However, I'd expect this to show really tiny angles rather than spinning like mad...
First thing I'd do to diangose the issue is write the angle into the console. Is it 0, 90, 180 etc, or 0, 1.723, 3.1431 etc?
I created my first JavaFX app that displays images. I want it to zoom the image to full size on mouse down (centered on cursor position) and to refit the image on mouse up.
All is working fine but the i don't know how to center on cursor position. My zoom method looks like that at the moment:
private void zoom100(double cursorx, double cursory){
double centery = imageView.getLayoutBounds().getHeight()/2;
double centerx = imageView.getLayoutBounds().getWidth()/2;
imageView.setFitHeight(-1); //zooms height to 100%
imageView.setFitWidth(-1); //zooms width to 100%
imageView.setTranslateX(centerx-cursorx); //moves x
imageView.setTranslateY(centery-cursory); //moves y
}
My idea is to set an offset with translate. I am not sure if translate is the correct approach. If it is the correct approach how to calculate the correct values? (centerx-cursorx) is wrong!
I uploaded the code here: https://github.com/dermoritz/FastImageViewer (it is working now - see my answer)
I didn't test it but I think the order is wrong. you calculate the center before you set the fit size. By setting the fit size your image view will change it's preferred size. therefore the center point won't match anymore.
I found a solution, but i am still not sure if this is a good way to go:
private void zoom100(double x, double y) {
double oldHeight = imageView.getBoundsInLocal().getHeight();
double oldWidth = imageView.getBoundsInLocal().getWidth();
boolean heightLarger = oldHeight>oldWidth;
imageView.setFitHeight(-1);
imageView.setFitWidth(-1);
//calculate scale factor
double scale=1;
if(heightLarger){
scale = imageView.getBoundsInLocal().getHeight()/oldHeight;
}else {
scale = imageView.getBoundsInLocal().getWidth()/oldWidth;
}
double centery = root.getLayoutBounds().getHeight() / 2;
double centerx = root.getLayoutBounds().getWidth() / 2;
double xOffset = scale * (centerx - x);
double yOffset = scale *(centery - y);
imageView.setTranslateX(xOffset);
imageView.setTranslateY(yOffset);
}
The picture must be centered within "root". I think there should be something more direct - only using properties of imageview?!
Meanwhile the app works using this code: https://github.com/dermoritz/FastImageViewer
I'm making pretty simple game. You have a sprite onscreen with a gun, and he shoots a bullet in the direction the mouse is pointing. The method I'm using to do this is to find the X to Y ratio based on 2 points (the center of the sprite, and the mouse position). The X to Y ratio is essentially "for every time the X changes by 1, the Y changes by __".
This is my method so far:
public static Vector2f getSimplifiedSlope(Vector2f v1, Vector2f v2) {
float x = v2.x - v1.x;
float y = v2.y - v1.y;
// find the reciprocal of X
float invert = 1.0f / x;
x *= invert;
y *= invert;
return new Vector2f(x, y);
}
This Vector2f is then passed to the bullet, which moves that amount each frame.
But it isn't working. When my mouse is directly above or below the sprite, the bullets move very fast. When the mouse is to the right of the sprite, they move very slow. And if the mouse is on the left side, the bullets shoot out the right side all the same.
When I remove the invert variable from the mix, it seems to work fine. So here are my 2 questions:
Am I way off-track, and there's a simpler, cleaner, more widely used, etc. way to do this?
If I'm on the right track, how do I "normalize" the vector so that it stays the same regardless of how far away the mouse is from the sprite?
Thanks in advance.
Use vectors to your advantage. I don't know if Java's Vector2f class has this method, but here's how I'd do it:
return (v2 - v1).normalize(); // `v2` is obj pos and `v1` is the mouse pos
To normalize a vector, just divide it (i.e. each component) by the magnitude of the entire vector:
Vector2f result = new Vector2f(v2.x - v1.x, v2.y - v1.y);
float length = sqrt(result.x^2 + result.y^2);
return new Vector2f(result.x / length, result.y / length);
The result is unit vector (its magnitude is 1). So to adjust the speed, just scale the vector.
Yes for both questions:
to find what you call ratio you can use the arctan function which will provide the angle of of the vector which goes from first object to second object
to normalize it, since now you are starting from an angle you don't need to do anything: you can directly use polar coordinates
Code is rather simple:
float magnitude = 3.0; // your max speed
float angle = Math.atan2(y,x);
Vector2D vector = new Vector(magnitude*sin(angle), magnitude*cos(angle));