I am having a user draw a line on the screen, there is a start point and a end point. If the user extends over a certain angle I change the position of the endpoint so the user cannot extend beyond the specified angle. However it seems that when I cacluate the angle the user is drawing and make suer it is not over MAX ANGLE, and set the angle to the MAX ANGLE, there is a difference. This can be seen by when I draw the line, once i get to a certain angle, the line jumps and locks at the MAX ANGLE, but there shouldnt be any jump, it should be smooth, like the line ran into a invisible barrier. This could just be me though, my PosX and PosY are floats.
private void CheckAngle() {
double adj = Math.abs(PosX - PosX2);
double c1 = adj;
double c2 = Math.abs(PosY - PosY2);
double hyp = Math.hypot(c1, c2);
double angle = Math.cos((adj/hyp));
angle = angle * 100;
if (angle > MAX_ANGLE) {
double opp = (Math.tan(MAX_ANGLE) * Math.abs(PosX - PosX2));
if (PosY > PosY2) {
PosY2 =(float) (PosY - opp);
} else {
PosY2 =(float) (PosY + opp);
}
}
}
My answer was a combination of using radians, as well as unsing
Math.acos() & Math.atan()
so the final code looks like this
private void CheckAngle() {
double adj = Math.abs(PosX - PosX2);
double opp = Math.abs(PosY - PosY2);
double hyp = Math.sqrt((adj*adj)+(opp*opp));
double angle = Math.acos((adj/hyp));
angle = angle * 100;
angle = Math.toRadians(angle);
if (angle > MAX_ANGLE) {
opp = (Math.atan(MAX_ANGLE) * adj);
if (PosY > PosY2) {
PosY2 =(float) (PosY - opp);
} else {
PosY2 =(float) (PosY + opp);
}
}
}
Here's the conversion:
final double MAX_ANGLE = Math.toRadians(80);
Note that this is identical to saying:
final double MAX_ANGLE = 80 * Math.PI / 180;
Related
I need to calculate the angle in degrees between two points for my own Point class, Point a shall be the center point.
Method:
public float getAngle(Point target) {
return (float) Math.toDegrees(Math.atan2(target.x - x, target.y - y));
}
Test 1: // returns 45
Point a = new Point(0, 0);
System.out.println(a.getAngle(new Point(1, 1)));
Test 2: // returns -90, expected: 270
Point a = new Point(0, 0);
System.out.println(a.getAngle(new Point(-1, 0)));
How can i convert the returned result into a number between 0 and 359?
you could add the following:
public float getAngle(Point target) {
float angle = (float) Math.toDegrees(Math.atan2(target.y - y, target.x - x));
if(angle < 0){
angle += 360;
}
return angle;
}
by the way, why do you want to not use a double here?
I started with johncarls solution, but needed to adjust it to get exactly what I needed.
Mainly, I needed it to rotate clockwise when the angle increased. I also needed 0 degrees to point NORTH. His solution got me close, but I decided to post my solution as well in case it helps anyone else.
I've added some additional comments to help explain my understanding of the function in case you need to make simple modifications.
/**
* Calculates the angle from centerPt to targetPt in degrees.
* The return should range from [0,360), rotating CLOCKWISE,
* 0 and 360 degrees represents NORTH,
* 90 degrees represents EAST, etc...
*
* Assumes all points are in the same coordinate space. If they are not,
* you will need to call SwingUtilities.convertPointToScreen or equivalent
* on all arguments before passing them to this function.
*
* #param centerPt Point we are rotating around.
* #param targetPt Point we want to calcuate the angle to.
* #return angle in degrees. This is the angle from centerPt to targetPt.
*/
public static double calcRotationAngleInDegrees(Point centerPt, Point targetPt)
{
// calculate the angle theta from the deltaY and deltaX values
// (atan2 returns radians values from [-PI,PI])
// 0 currently points EAST.
// NOTE: By preserving Y and X param order to atan2, we are expecting
// a CLOCKWISE angle direction.
double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x);
// rotate the theta angle clockwise by 90 degrees
// (this makes 0 point NORTH)
// NOTE: adding to an angle rotates it clockwise.
// subtracting would rotate it counter-clockwise
theta += Math.PI/2.0;
// convert from radians to degrees
// this will give you an angle from [0->270],[-180,0]
double angle = Math.toDegrees(theta);
// convert to positive range [0-360)
// since we want to prevent negative angles, adjust them now.
// we can assume that atan2 will not return a negative value
// greater than one partial rotation
if (angle < 0) {
angle += 360;
}
return angle;
}
Based on Saad Ahmed's answer, here is a method that can be used for any two points.
public static double calculateAngle(double x1, double y1, double x2, double y2)
{
double angle = Math.toDegrees(Math.atan2(x2 - x1, y2 - y1));
// Keep angle between 0 and 360
angle = angle + Math.ceil( -angle / 360 ) * 360;
return angle;
}
The javadoc for Math.atan(double) is pretty clear that the returning value can range from -pi/2 to pi/2. So you need to compensate for that return value.
Why is everyone complicating this?
The only problem is Math.atan2( x , y)
The corret answer is Math.atan2( y, x)
All they did was mix the variable order for Atan2 causing it to reverse the degree of rotation.
All you had to do was look up the syntax
https://www.google.com/amp/s/www.geeksforgeeks.org/java-lang-math-atan2-java/amp/
angle = Math.toDegrees(Math.atan2(target.x - x, target.y - y));
now for orientation of circular values to keep angle between 0 and 359 can be:
angle = angle + Math.ceil( -angle / 360 ) * 360
If you want the "bearing" degrees from north, so:
Direction
Degees
North
0
North East
45
East
90
South East
135
South
180
South West
-135
West
-95
North West
-45
you can do this:
public static final double RAD_360_DEG = Math.PI * 360d / 180d;
public static final double RAD_180_DEG = Math.PI * 180d / 180d;
public static final double RAD_90_DEG = Math.PI * 90d / 180d;
/**
* #return The angle from north from p1 to p2. Returns (in radians) -180 to 180, with 0 as north.
*/
public static double getAngleBearing(double p1x, double p1y, double p2x, double p2y) {
double result = Math.atan2(p2y - p1y, p2x - p1x) + RAD_90_DEG;
if (result > RAD_180_DEG) {
result = result - RAD_360_DEG;
}
return result;
}
double bearingAngle = Math.toDegrees(getAngleBearing(...));
my realization:
private double searchAngle(Point posOne, Point posTwo) {
int sumPos = (posOne.x * posTwo.x) + (posOne.y * posTwo.y);
double moduleOne = Math.sqrt( (posOne.x * posOne.x) + (posOne.y * posOne.y) );
double moduleTwo = Math.sqrt( (posTwo.x * posTwo.x) + (posTwo.y * posTwo.y) );
return Math.toDegrees( Math.acos( sumPos / (Math.abs( moduleOne ) * Math.abs( moduleTwo )) ) );
}
Input:
posOne: (x = 50, y = 43)
posTwo: (x = 12, y = 42)
Output is
33.35907305958513
in degrees.
What about something like :
angle = angle % 360;
I have a point that follows the mouse that I made in Processing.
void move() {
double slope = (y - mouseY)/(x-mouseX);
double atanSlope = atan(slope);
if (slope < 0 && mouseY < y ) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else if (slope >= 0 && mouseY < y) {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
} else if (slope > 0) {
x += cos(atanSlope)*(speed);
y += sin(atanSlope)*(speed);
} else {
x -= cos(atanSlope)*(speed);
y -= sin(atanSlope)*(speed);
}
}
How could I change this or add to this to make the point have a limited turning rate? What I had in mind would be similar to the missiles in this game. https://scratch.mit.edu/projects/181364872/
I don't know how I'd even start to limit the turning rate of the point. Any help would be appreciated.
(I tagged java too, because though this is in Processing, Processing is pretty much Java with built in methods at times.)
One way to do this is to keep the object current direction. You can then use the cross product of the vector to the mouse, and the vector along the object's direction to find the angle it needs to turn to point to the mouse. You can then limit the turn and add the change to get the new direction.
double direction = ?; // the current direction of object in radians
double x = ?; // the current position
double y = ?;
double maxTurn = ?; // Max turn speed in radians
double speed = ?;
void move() {
double mvx = mouseX - x; // get vector to mouse
double mvy = mouseY - y;
double dist = Math.sqrt(mvx * mvx + mvy * mvy); // get length of vector
if(dist > 0){ // must be a distance from mouse
mvx /= dist; // normalize vector
mvy /= dist;
double ovx = Math.cos(direction); // get direction vector
double ovx = Math.sin(direction);
double angle = Math.asin(mvx * ovy - mvy * ovx); // get angle between vectors
if(-mvy * ovy - mvx * ovx < 0){ // is moving away
angle = Math.sign(angle) * Math.PI - angle; // correct angle
}
// angle in radians is now in the range -PI to PI
// limit turn angle to maxTurn
if(angle < 0){
if(angle < -maxTurn){
angle = -maxTurn;
}
}else{
if(angle > maxTurn){
angle = maxTurn;
}
}
direction += angle; // turn
// move along new direction
x += Math.cos(direction) * speed;
y += Math.sin(direction) * speed;
}
}
The following code is called every 50ms.
// Start point
private double x;
private double y;
private double z;
private double y1;
#Override
public void run() {
double x1 = Math.cos(y1);
double z1 = Math.sin(y1);
double y2 = 4D - y1;
double x2 = Math.sin(y2);
double z2 = Math.cos(y2);
// First new point
double pX1 = x + x1;
double pY1 = y + y1;
double pZ1 = z + z1;
// Second new point
double pX2 = x + x2;
double pY2 = y + y2;
double pZ2 = z + z2;
if (y1 > 4D) {
y1 = 0D;
} else {
y1 = y1 + 0.1D;
}
}
Here is the output in a game. It generates two helices.
I cannot control more than the radius.
I am looking for code I can easily customize to fit my preferences.
How do I control the following aspects?
How fast the helix rises.
Where the helix begins.
helix is circular shape with 'linear' movement of the plane
you use plane xz as helix base and y axis as height
so you need:
r - radius
d - distance between two screws (the y movement after full circle)
t - parameter <0,1> determining the position on helix
h0,h1 - start end height of helix (y-axis)
a0 - angular start position [rad]
Now how to get the point on helix as function of parameter these parameters
aa=fabs(h1-h0)*2.0*M_PI/d; // angular speed coefficient
// if you need opposite angular direction then add aa=-aa;
x=r*cos(a0+aa*t);
z=r*sin(a0+aa*t);
y=h0+((h1-h0)*t);
aa can be precomputed once
now if t=0.0 then you get the start point of helix
if t=1.0 then you got the endpoint of helix
so speed is just how much you add to t during animation per timer cycle
d controls number of screw loops
h1-h0 is the helix height
code is in C++ (sorry I am not a JAVA coder)
One part of the helix begins at:
(x, y, z) = (1.0, 0.0, 0.0)
And the other at:
(x, y, z) = (-0.8, 4.0, -0.7)
And the particle rises at a rate of 0.1 (from y1 = y1 + 0.1D).
So, to control how fast the particles rise, just change this value.
To control where the helix begins you need to change the angle. For example, add some value to the sines and cosines. Like this:
Math.cos(y1 + dy);
To make more rotations before restarting from the ground you can multiply the angle. Make it twice as fast:
Math.cos(2 * y1);
Helix is circular shape with progressive Y value.
// Start point
private double x;
private double y;
private double z;
private double degree;
private double rY;
#Override
public void run() {
// We use the same formula that is used to find a point of a circumference
double rX = Math.cos(degree);
double rZ = Math.sin(degree);
// New point
double pX = x + rX;
double pY = y + rY;
double pZ = z + rZ;
if (degree > 2D * Math.PI) {
degree = 0D;
} else {
degree = degree + 0.2D;
}
if (pY > 2D) {
pY = 0D;
} else {
pY = pY + 0.02D;
}
}
I need to calculate the angle in degrees between two points for my own Point class, Point a shall be the center point.
Method:
public float getAngle(Point target) {
return (float) Math.toDegrees(Math.atan2(target.x - x, target.y - y));
}
Test 1: // returns 45
Point a = new Point(0, 0);
System.out.println(a.getAngle(new Point(1, 1)));
Test 2: // returns -90, expected: 270
Point a = new Point(0, 0);
System.out.println(a.getAngle(new Point(-1, 0)));
How can i convert the returned result into a number between 0 and 359?
you could add the following:
public float getAngle(Point target) {
float angle = (float) Math.toDegrees(Math.atan2(target.y - y, target.x - x));
if(angle < 0){
angle += 360;
}
return angle;
}
by the way, why do you want to not use a double here?
I started with johncarls solution, but needed to adjust it to get exactly what I needed.
Mainly, I needed it to rotate clockwise when the angle increased. I also needed 0 degrees to point NORTH. His solution got me close, but I decided to post my solution as well in case it helps anyone else.
I've added some additional comments to help explain my understanding of the function in case you need to make simple modifications.
/**
* Calculates the angle from centerPt to targetPt in degrees.
* The return should range from [0,360), rotating CLOCKWISE,
* 0 and 360 degrees represents NORTH,
* 90 degrees represents EAST, etc...
*
* Assumes all points are in the same coordinate space. If they are not,
* you will need to call SwingUtilities.convertPointToScreen or equivalent
* on all arguments before passing them to this function.
*
* #param centerPt Point we are rotating around.
* #param targetPt Point we want to calcuate the angle to.
* #return angle in degrees. This is the angle from centerPt to targetPt.
*/
public static double calcRotationAngleInDegrees(Point centerPt, Point targetPt)
{
// calculate the angle theta from the deltaY and deltaX values
// (atan2 returns radians values from [-PI,PI])
// 0 currently points EAST.
// NOTE: By preserving Y and X param order to atan2, we are expecting
// a CLOCKWISE angle direction.
double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x);
// rotate the theta angle clockwise by 90 degrees
// (this makes 0 point NORTH)
// NOTE: adding to an angle rotates it clockwise.
// subtracting would rotate it counter-clockwise
theta += Math.PI/2.0;
// convert from radians to degrees
// this will give you an angle from [0->270],[-180,0]
double angle = Math.toDegrees(theta);
// convert to positive range [0-360)
// since we want to prevent negative angles, adjust them now.
// we can assume that atan2 will not return a negative value
// greater than one partial rotation
if (angle < 0) {
angle += 360;
}
return angle;
}
Based on Saad Ahmed's answer, here is a method that can be used for any two points.
public static double calculateAngle(double x1, double y1, double x2, double y2)
{
double angle = Math.toDegrees(Math.atan2(x2 - x1, y2 - y1));
// Keep angle between 0 and 360
angle = angle + Math.ceil( -angle / 360 ) * 360;
return angle;
}
The javadoc for Math.atan(double) is pretty clear that the returning value can range from -pi/2 to pi/2. So you need to compensate for that return value.
Why is everyone complicating this?
The only problem is Math.atan2( x , y)
The corret answer is Math.atan2( y, x)
All they did was mix the variable order for Atan2 causing it to reverse the degree of rotation.
All you had to do was look up the syntax
https://www.google.com/amp/s/www.geeksforgeeks.org/java-lang-math-atan2-java/amp/
angle = Math.toDegrees(Math.atan2(target.x - x, target.y - y));
now for orientation of circular values to keep angle between 0 and 359 can be:
angle = angle + Math.ceil( -angle / 360 ) * 360
If you want the "bearing" degrees from north, so:
Direction
Degees
North
0
North East
45
East
90
South East
135
South
180
South West
-135
West
-95
North West
-45
you can do this:
public static final double RAD_360_DEG = Math.PI * 360d / 180d;
public static final double RAD_180_DEG = Math.PI * 180d / 180d;
public static final double RAD_90_DEG = Math.PI * 90d / 180d;
/**
* #return The angle from north from p1 to p2. Returns (in radians) -180 to 180, with 0 as north.
*/
public static double getAngleBearing(double p1x, double p1y, double p2x, double p2y) {
double result = Math.atan2(p2y - p1y, p2x - p1x) + RAD_90_DEG;
if (result > RAD_180_DEG) {
result = result - RAD_360_DEG;
}
return result;
}
double bearingAngle = Math.toDegrees(getAngleBearing(...));
my realization:
private double searchAngle(Point posOne, Point posTwo) {
int sumPos = (posOne.x * posTwo.x) + (posOne.y * posTwo.y);
double moduleOne = Math.sqrt( (posOne.x * posOne.x) + (posOne.y * posOne.y) );
double moduleTwo = Math.sqrt( (posTwo.x * posTwo.x) + (posTwo.y * posTwo.y) );
return Math.toDegrees( Math.acos( sumPos / (Math.abs( moduleOne ) * Math.abs( moduleTwo )) ) );
}
Input:
posOne: (x = 50, y = 43)
posTwo: (x = 12, y = 42)
Output is
33.35907305958513
in degrees.
What about something like :
angle = angle % 360;
I have an image that rotating in a counter clockwise direction. Now, I want it to move in a random direction during or whenever it touch the wall. The problem is I can't do it, please help me about this matter.
This is my code :
private double x;
private double y;
private double speed;
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx = speed * dt_s;
double dy = speed * dt_s;
final double right_border = 100;
final double up_border = 100;
final double down_border = 0.0;
final double left_border = 0.0;
x += dx;
if (x >= right_border)
{
x = right_border;
if (y >= down_border)
{
y += dy;
}
}
if (y > up_border)
{
y = up_border;
if (x >= left_border)
{
speed *= -1;
}
}
if (x <= left_border)
{
x = left_border;
if (y <= up_border)
{
y += dy;
}
}
if (y < down_border)
{
y = down_border;
if (x <= right_border)
{
speed *= -1;
}
}
}
First you must solve the problem of your class being directionless - you have speed, but your direction is fixed at 45 degree north east (increment x and y the same).
Add direction to your class as follows:
...
private double speed;
private double angle; // in radians - makes math easier
public void move(long dt) {
...
double dx = speed * dt_s * Math.sin(angle);
double dy = speed * dt_s * Math.cos(angle);
...
Now to head in a random direction:
myObject.setAngle(Math.PI * 2 * Math.random()); // Math.PI * 2 = 360 degrees
If hitting a wall, you will have to limit your angle to an angle that's away from the wall you are hitting. I'll leave that to you, but it will take the form of:
myObject.setAngle(minAngle + ((maxAngle - minAngle) * Math.random()));
This is one possible solution.
Generate a random point (x,y) on one of the boundaries (other than the boundary that the image just hit), and make the image move towards that point. All you have to do is, find the slope between the point P1(x1,y1) it just hit, and the random point just generated P2(x2,y2). Using the slope you can find the equation of the line, it has to travel in. You're done!!