Math calculation for angle between two points Java - java

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?

Related

Java Arc2D Collision detection (With Rotation)

I have tried to create NPC character that can "see" the player by using cones of vision.
The NPC will rotate back and forth at all times.
My problem is that the arc has a generic and unchanging position, but when its drawn to the screen it looks correct.
[Screenshots of the collisions in action][1]
[GitHub link for java files][2]
I'm using Arc2D to draw the shape like this in my NPC class
// Update the shapes used in the npc
rect.setRect(x, y, w, h);
ellipse.setFrame(rect);
visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle, visionAngle * 2, Arc2D.PIE);
/ CenterX, CenterY (of the npc),
/ the distance from the arc to the npc
/ a constant value around 45 degrees and a constant value around 90 degress (to make a pie shape)
I've tried multiplying the position and the angles by the sin and cosine of the NPC's current angle
something like these
visionArc.setArcByCenter(cx * (Math.cos(Math.toRadians(angle))), cy (Math.sin(Math.toRadians(angle)), visionDistance, visionAngle, visionAngle * 2, Arc2D.PIE);
or
visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle - angle, (visionAngle + angle) * 2, Arc2D.PIE);
or
visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle * (Math.cos(Math.toRadians(angle))), visionAngle * 2, Arc2D.PIE);
I've tried a lot but can't seem to find what works. Making the vision angles not constant makes an arc that expands and contracts, and multiplying the position by the sin or cosine of the angle will make the arc fly around the screen, which doesn't really work either.
This is the function that draws the given NPC
public void drawNPC(NPC npc, Graphics2D g2, AffineTransform old) {
// translate to the position of the npc and rotate
AffineTransform npcTransform = AffineTransform.getRotateInstance(Math.toRadians(npc.angle), npc.x, npc.y);
// Translate back a few units to keep the npc rotating about its own center
// point
npcTransform.translate(-npc.halfWidth, -npc.halfHeight);
g2.setTransform(npcTransform);
// g2.draw(npc.rect); //<-- show bounding box if you want
g2.setColor(npc.outlineColor);
g2.draw(npc.visionArc);
g2.setColor(Color.BLACK);
g2.draw(npc.ellipse);
g2.setTransform(old);
}
This is my collision detection algorithim - NPC is a superclass to ninja (Shorter range, higher peripheral)
public void checkNinjas(Level level) {
for (int i = 0; i < level.ninjas.size(); i++) {
Ninja ninja = level.ninjas.get(i);
playerRect = level.player.rect;
// Check collision
if (playerRect.getBounds2D().intersects(ninja.visionArc.getBounds2D())) {
// Create an area of the object for greater precision
Area area = new Area(playerRect);
area.intersect(new Area(ninja.visionArc));
// After checking if the area intersects a second time make the NPC "See" the player
if (!area.isEmpty()) {
ninja.seesPlayer = true;
}
else {
ninja.seesPlayer = false;
}
}
}
}
Can you help me correct the actual positions of the arcs for my collision detection? I have tried creating new shapes so I can have one to do math on and one to draw to the screen but I scrapped that and am starting again from here.
[1]: https://i.stack.imgur.com/rUvTM.png
[2]: https://github.com/ShadowDraco/ArcCollisionDetection
After a few days of coding and learning and testing new ideas I came back to this program and implemented the collision detection using my original idea (ray casting) and have created the equivalent with rays!
Screenshot of the new product
Github link to the project that taught me the solution
Here's the new math
public void setRays() {
for (int i = 0; i < rays.length; i++) {
double rayStartAngleX = Math.sin(Math.toRadians((startAngle - angle) + i));
double rayStartAngleY = Math.cos(Math.toRadians((startAngle - angle) + i));
rays[i].setLine(cx, cy, cx + visionDistance * rayStartAngleX, cy + visionDistance * rayStartAngleY);
}
}
Here is a link the the program I started after I asked this question and moved on to learn more, and an image to what the new product looks like
(The original github page has been updated with a new branch :) I'm learning git hub right now too
I do not believe that using Arc2D in the way I intended is possible, however there is .setArcByTangent method, it may be possible to use that but I wasn't going to get into that. Rays are cooler.

What is the correct way to rotate a quaternion from its current rotation a certain angle?

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);
}

Rotation of rectangular Slick2d image with LWJGL causing distortion

I'm trying to rotate a rectangular Slick2d image with pixel size 666 x 333 using LWJGL. I was able to rotate a square image with pixel size 666 x 666 around its center, but the rectangular image does distort during the rotation and this is my problem.
Here is the image I use for testing purposes:
http://i.stack.imgur.com/0bjr5.jpg
The left window shows the image before the rotation, the right window shows the image how it looks when I rotate it 90 degrees, it's distorted:
http://i.stack.imgur.com/FGcNB.jpg
Here is my source code snippet for the rotation:
float x = 0.335f;
float y = 0.335f;
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(x, y, 0f);
glRotatef(angle, 0f, 0f, 1f);
glTranslatef(-x, -y, 0f);
glMatrixMode(GL_MODELVIEW);
You may wonder why I don't use the function “setRotation” or “rotate” of a Slick2d Image. The reason I don't use this does not matter here, but I simply can't use it in my real project and furthermore I want to do it with gl.
It's the first time ever I touch LWJGL and Slick2d and I need it only for a small part of my project. If you know how to rotate the image like above without the distortion, please help me. Thank you.
The problem could be because:
You are using Slick-2D. glRotatef and glTranslatef require a Z coordinate. This could confuse slick 2D. Also what is your angle variable? glTranslatef translates the position of a quad. With lwjgl 3D this would be used to translate the object. glRotatef uses vector rotation. Try researching vector rotation.
Here is a simple pseudocode formula:
Calculate the sine and cosine of the angle once. Dim cosTheta As Double, sinTheta As Single cosTheta = Cos(DegreesToRadians(Angle)) sinTheta = Sin(DegreesToRadians(Angle)) ' Get the disance between the center and the point. Dim dblDistanceX As Double, dblDistanceY As Double dblDistanceX = (PointX - CenterX) dblDistanceY = (PointY - CenterY) ' Set the default position. ReturnX = CenterX ReturnY = CenterY 'Update with the Y offset ReturnX = (ReturnX + dblDistanceY * sinTheta) ReturnY = (ReturnY + dblDistanceY * cosTheta) 'Update with the X offset ReturnX = (ReturnX + dblDistanceX * cosTheta) ReturnY = (ReturnY - dblDistanceX * sinTheta)
90 degree rotation is extremely simple. Just rotate the quad and rebind texture. If you can't do this, then make a 90 degree rotated texture. Just ask if you want another answer with my 90 degree rotation code. I tried to explain how you could use vectors for 360 degree rotation.

Draw a curved path on Canvas?

How could I draw a quadratic curve or a trigonometric curve (such as sin(x)) on a Canvas?
Like you, I needed to draw a curved line from point(x1, y1) to point (x2, y2). I did some searching around which lead me to the Path class (android.graphics.Path). Path has numerous methods for drawing lines. Once you have created a path you use a draw method to make the actual line. The paths can be rotated, transformed, saved, and added to. There are arcs, circles, and rectangles that be drawn with this class too.
http://developer.android.com/reference/android/graphics/Path.html
Set start point of path → mPath.moveTo(x1, y1);
Set constant and end points → mPath.quadTo(cx, cy, x2, y2);
Convert path to line → canvas.drawPath(mPath, mPaint);
Here is a drawEquation() method I wrote for a Graph class - I think it may help. The basic idea to create a method that accepts an equation (which is basically just a function) like
function(x) = Math.sin(x);
and then loop through the bounds of the graph and draws small segments connecting each point. The transformContext() just inverts the canvas context so that increasing values of y go upwards and not downwards:
Graph.prototype.transformContext = function(){
var canvas = this.canvas;
var context = this.context;
// move context to center of canvas
this.context.translate(this.centerX, this.centerY);
// stretch grid to fit the canvas window, and
// invert the y scale so that that increments
// as you move upwards
context.scale(this.scaleX, -this.scaleY);
};
Graph.prototype.drawEquation = function(equation, color, thickness){
var canvas = this.canvas;
var context = this.context;
context.save();
this.transformContext();
context.beginPath();
context.moveTo(this.minX, equation(this.minX));
for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
context.lineTo(x, equation(x));
}
context.restore();
context.lineJoin = "round";
context.lineWidth = thickness;
context.strokeStyle = color;
context.stroke();
};
Most drawing APIs dont provide such functions, you will have to calculate the pixels of your desired curve in pixels and draw piece by piece on the canvas using one or more calls to the canvas API.
Use Canvas.drawPath and Path.quadTo.
I'm going to assume that you are familiar with drawing basic lines on a canvas, if not then respond back and we can delve further back. However, as far as just drawing a sine function there is a function within the Math class that has just what you need.
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Math.html#sin%28double%29
From there you just need to pass your x variable(in radians) into the function and save it's output as a y variable. This represent a point on your graph. Now increment the x1 variable by a small amount (perhaps 1/100 of your graph, though you will need to adjust this to taste), run it through the function again and save those variables(x2 and y2) as your second point. Draw a line between these two points. Save your x2,y2 variables as x1, y1 and increment your x value again to find the third point, so on and so forth. This is not a "true" curve as it is really just a series of lines which approximate the function, a calculus approach if you will.
So:
x1 = x; // where x is some point on the x axis which you would like to start graphing at.
y1 = sin(x);
x2 = x1 + increment;
y2 = sin(x2);
//Draw a line here
x1 = x2;
y1 = y2;
//return to top, this code would obviously be in a loop in which uses increment as it's own increment with the initial value being equal to the amount you want to increment each time(let's say....5) and the "next" statement being increment = increment + 5.
There is also a GraphCanvas class which I am unfamiliar with which appears to take those same points and draw the curve between them, though I am unsure what sort of transform is being used to draw the curve and how accurate that is. Here is the Class:
http://www.java2s.com/Code/Java/Swing-Components/GraphCanvas.htm

Android programming bitmap rotation

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?

Categories