Loss of precision calculating degrees from two points - java

I have made a class Location which allows to set, change a location (coordinates x,y , the limits are decided by xMin,xMax,yMin,yMax), to caluculate the distance between two points, and to get the direction from another location.
The direction is in degress (in [0,2pi]) from another location.
The direction goes from North (assuming that North is the pole oriented where there are higher coordinates), in clockwise order.
package TruckingCompany;
public class Location
{
private double x;
private double y;
private static final double xMax=1000.0;
private static final double xMin=-1000.0;
private static final double yMax=1000.0;
private static final double yMin=-1000.0;
public Location()
{
setX(0.0);
setY(0.0);
}
public Location(double x,double y)
{
setX(x);
setY(y);
}
public Location(Location location)
{
setX(location.getX());
setY(location.getY());
}
public void setX(double x)
{
if(x>=xMin && x<=xMax)
this.x=x;
}
public void setY(double y)
{
if(y>=yMin && y<=yMax)
this.y=y;
}
public void set(double x,double y)
{
setX(x);
setY(y);
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
public double getDistanceFrom(Location from)
{
double dx,dy;
dx=from.getX()-x;
dy=from.getY()-y;
return Math.sqrt(Math.pow(dx, 2.0)+Math.pow(dy, 2.0));
}
public double getDirectionFrom(Location from)
{
double dy=from.getY()-y;
double direction=Math.PI/4 - Math.asin (Math.toRadians(dy/getDistanceFrom(from)));
if(Double.isNaN(direction)==false)
{
if(from.getX()-x<0.0)
direction+=Math.PI/2;
if(dy<0.0)
direction+=Math.PI;
}
return direction;
}
#Override
public String toString()
{
return "(" + x + " , " + y + ")";
}
}
The problem is the the precision, for example I try to calculate the distance from these two locations:
Location l1,l2;
l1=new Location(0.0,0.0);
l2=new Location(300.0,300.0);
System.out.print(Math.toDegrees(l1.getDirectionFrom(l2)));
The problem is the precision: in this example it prints 44.29 degrees, it should be 45.0, why a so huge loss of precision?

You're near 45 degrees, which means you're going to be operating close to maxima and minima for some trig functions. I'd check the steps and see if you're getting an intermediate result very close to 0.
Try replacing the call to pow with dx*dx and dy*dy.
Break this up with intermediate results.

Use Math.atan2(deltaX, deltaY) to calculate the angle of a vector in radians. It returns answers all the way from 0 to 2 * Math.PI without having to do casework depending on the signs of the inputs.

Related

How do you convert between polar coordinates and cartesian coordinates assuming north is zero radians?

I've been trying to make a simple physics engine for games. I am well aware that this is re-inventing the wheel but it's more of a learning exercise than anything else. I never expect it to be as complete as box2d for instance.
I'm having issues with my implementation of 2d Vectors. The issue is related to the fact that in the game world I want to represent north as being zero radians and east as being 1/2 PI Radians, or 0 and 90 degrees respectively. However in mathematics (or maybe more specifically the Math class of Java), I believe trigonometry functions like sine and cosine assume that "east" is zero radians and I think north is 1/2 PI Radians?
Anyway I've written a small version of my vector class that only demonstrates the faulty code.
public class Vector {
private final double x;
private final double y;
public Vector(double xIn, double yIn) {
x = xIn;
y = yIn;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getR() {
return Math.sqrt((x * x) + (y * y));
}
public double getTheta() {
return Math.atan(y / x);
}
public double bearingTo(Vector target) {
return (Math.atan2(target.getY() - y, target.getX() - x));
}
public static Vector fromPolar(double magnitude, double angle) {
return new Vector(magnitude * Math.cos(angle),
magnitude * Math.sin(angle));
}
}
And here is the test code to demonstrate the issue:
public class SOQuestion {
public static void main(String[] args) {
//This works just fine
Vector origin = new Vector(0, 0);
Vector target = new Vector(10, 10);
double expected = Math.PI * 0.25;
double actual = origin.bearingTo(target);
System.out.println("Expected: " + expected);
System.out.println("Actual: " + actual);
//This doesn't work
origin = new Vector(0, 0);
target = new Vector(10, 0);
expected = Math.PI * 0.5; //90 degrees, or east.
actual = origin.bearingTo(target); //Of course this is going to be zero, because in mathematics right is zero
System.out.println("Expected: " + expected);
System.out.println("Actual: " + actual);
//This doesn't work either
Vector secondTest = Vector.fromPolar(100, Math.PI * 0.5); // set the vector to the cartesian coordinates of (100,0)
System.out.println("X: " + secondTest.getX()); //X ends up being basically zero
System.out.println("Y: " + secondTest.getY()); //Y ends up being 100
} }
The requirements are:
fromPolar(magnitude,angle) should return a vector with x and y initialized to the appropriate values assuming north is at zero radians and east is at 1/2 PI radians. for example fromPolar(10,PI) should construct a vector with x: 0 and y: -1
getTheta() should return a value greater than or equal to zero and less than 2 PI. Theta is the angular component of the vector it's called on. For example a vector with x:10 and y:10 would return a value of 1/4 PI when getTheta() is called.
bearingTo(target) should return a value that is greater than or equal to zero and less than 2 PI. The value represents the bearing to another vector.
The test code demonstrates that when you try to get the bearing of one point at (0,0) to another point at (10,0), it doesn't produce the intended result, it should be 90 degrees or 1/2 PI Radians.
Likewise, trying to initialize a vector from polar coordinates sets the x and y coordinate to unexpected values. I'm trying to avoid saying "incorrect values" since it' not incorrect, it just doesn't meet the requirements.
I've messed around with the code a lot, adding fractions of PI here or taking it away there, switching sine and cosine, but all of these things only fix parts of the problem and never the whole problem.
Finally I made a version of this code that can be executed online http://tpcg.io/OYVB5Q
Typical polar coordinates 0 points to the East and they go counter-clockwise. Your coordinates start at the North and probably go clockwise. The simplest way to fix you code is to first to the conversion between angles using this formula:
flippedAngle = π/2 - originalAngle
This formula is symmetrical in that it converts both ways between "your" and "standard" coordinates. So if you change your code to:
public double bearingTo(Vector target) {
return Math.PI/2 - (Math.atan2(target.getY() - y, target.getX() - x));
}
public static Vector fromPolar(double magnitude, double angle) {
double flippedAngle = Math.PI/2 - angle;
return new Vector(magnitude * Math.cos(flippedAngle),
magnitude * Math.sin(flippedAngle));
}
It starts to work as your tests suggest. You can also apply some trigonometry knowledge to not do this Math.PI/2 - angle calculation but I'm not sure if this really makes the code clearer.
If you want your "bearing" to be in the [0, 2*π] range (i.e. always non-negative), you can use this version of bearingTo (also fixed theta):
public class Vector {
private final double x;
private final double y;
public Vector(double xIn, double yIn) {
x = xIn;
y = yIn;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getR() {
return Math.sqrt((x * x) + (y * y));
}
public double getTheta() {
return flippedAtan2(y, x);
}
public double bearingTo(Vector target) {
return flippedAtan2(target.getY() - y, target.getX() - x);
}
public static Vector fromPolar(double magnitude, double angle) {
double flippedAngle = flipAngle(angle);
return new Vector(magnitude * Math.cos(flippedAngle),
magnitude * Math.sin(flippedAngle));
}
// flip the angle between 0 is the East + counter-clockwise and 0 is the North + clockwise
// and vice versa
private static double flipAngle(double angle) {
return Math.PI / 2 - angle;
}
private static double flippedAtan2(double y, double x) {
double angle = Math.atan2(y, x);
double flippedAngle = flipAngle(angle);
// additionally put the angle into [0; 2*Pi) range from its [-pi; +pi] range
return (flippedAngle >= 0) ? flippedAngle : flippedAngle + 2 * Math.PI;
}
}

Shooting inaccurate bullets due to x,y stepping

when shooting (slow) bullets in my Java game, they move at incorrect angles, however when sped up they become more and more accurate.
My x, y, speed and directions are all int, however I've tried converting to floats for more accuracy but I'm still having the same error. I believe it's happening because the lowest movement steps I can have are in integers like (+2x and +1y a step and not +1.7x and +0.88y - and I can't be on 0.5 of a pixel)
How do I 'microstep' the bullets to shoot them on the correct angle?
The only other solution I can think of to shoot them at the correct angle is to calculate the end collision point and step towards that point.
Desired behavior is for bullets to shoot at the correct angle (player to mouse) rather then at 'off' angles based on the bullets speed.
public class Bullet extends GameObject
{
private int x;
private int y;
private int speed = 2;
private int direction;
private int length = 70;
public Bullet(int x, int y, int direction)
{
this.x = x;
this.y = y;
this.direction = direction; //Set the direction.
}
public void update(Game game, GameController gc, float dt)
{
x += GameController.lengthdir_x(speed, direction);
y += GameController.lengthdir_y(speed, direction);
}
public void render(Game game, Renderer r)
{
//Draw the bullet with the tail behind it.
r.drawLine(x, y, x + GameController.lengthdir_x(length, direction - 180), y + GameController.lengthdir_y(length, direction - 180), color);
r.drawText("Dir: " + direction, x + 50, y + 20, 0xff0077ff); //Draws the players angle.
}
}
Lengthdir Code: (The angle calculates correctly as I can draw a line between two points perfectly, just when I add movement it messes up)
public static int lengthdir_x(int len, int dir)
{
return (int) (len * Math.cos(Math.toRadians(dir - 90)));
}
public static int lengthdir_y(int len, int dir)
{
return (int) (len * Math.sin(Math.toRadians(dir - 90)));
}
I've also tried doubles for variables: https://pastebin.com/fbrF17bD
Example: http://puu.sh/x9OnN/be4e3f2c80.png
The long blue line is from the player to the mouse, the yellow lines are bullets which are at the correct angle it was shot at - but not travelling the correct direction which should be exactly on the blue line. This was at a bullet speed of 2 - if the bullets are at a speed of 20, they are much closer to the blue line as per the next img: http://puu.sh/x9OwY/a54f201c91.png
I got your Problem: you use Integer-cast on the calculation result, that means you just remove everything after ., so if you get 1.9 as result you will return 1 as length. If you increase speed this error will be reduced, thats why you get better result for higher speed. You need to round your result before you return it. On the other hand you should really change to double. In the code you shown where you use double you didn't changed it in length-function, thats why you don't get better result using double. So your code should look like this:
public static double lengthdir_x(int len, int dir)
{
//don't cast here to int!!!!
return len * Math.cos(Math.toRadians(dir - 90));
}
public class Bullet extends GameObject
{
private double x;
private double y;
private int speed = 2;
private int direction;
private int length = 70;
public Bullet(double x, double y, int direction)
{
this.x = x;
this.y = y;
this.direction = direction; //Set the direction.
}
public void update(Game game, GameController gc, float dt)
{
x += GameController.lengthdir_x(speed, direction);
y += GameController.lengthdir_y(speed, direction);
}
public void render(Game game, Renderer r)
{
//Draw the bullet with the tail behind it.
r.drawLine((int)Math.round(x), (int)Math.round(y), x + GameController.lengthdir_x(length, direction - 180), y + GameController.lengthdir_y(length, direction - 180), color);
r.drawText("Dir: " + direction, (int)x + 50, (int)y + 20, 0xff0077ff); //Draws the players angle.
}
}
Maybe you will need to convert something to int or double somewhere, but make sure lengthdir returns double as result or at least (int)Math.round(...)

Calculating distance between two points in 3D

My assignment is to create main class in which I initialize the value of any point to be at (0,0,0) and to be able to access and mutate all three values (x,y,z) individually. To do this I have used getters and setters. My next task is to create a method within my main class (which I shall call "distanceTo") that calculates the distance between two points.
How do I go about creating the method "distanceTo" that calculates the distance between two points by taking in the x,y,z coordinates ? I assume my answer will have something to do with sqrt((x1-x2)^2+(y1-y2)^2+(z1-z2)^2) but I do not know how I can write that in my method in my main class if my points are not defined until my second test point class
So far I only have two points, but I am looking for a more general answer (so that if I created three points, p1 p2 and p3, I could calculate the distance between p1 and p2 or the distance between p2 and p3 or the distance between p1 and p3.
My main class:
package divingrightin;
public class Point3d {
private double xCoord;
private double yCoord;
private double zCoord;
public Point3d(double x, double y, double z){
xCoord = x;
yCoord = y;
zCoord = z;
}
public Point3d(){
this (0,0,0);
}
public double getxCoord() {
return xCoord;
}
public void setxCoord(double xCoord) {
this.xCoord = xCoord;
}
public double getyCoord() {
return yCoord;
}
public void setyCoord(double yCoord) {
this.yCoord = yCoord;
}
public double getzCoord() {
return zCoord;
}
public void setzCoord(double zCoord) {
this.zCoord = zCoord;
}
//public double distanceTo(double xCoord, double yCoord, double zCoord ){
}
My class with the test points:
package divingrightin;
public class TestPoints {
public static void main(String[] args) {
Point3d firstPoint = new Point3d();
firstPoint.setxCoord(2.2);
firstPoint.setyCoord(1);
firstPoint.setzCoord(5);
//System.out.println(firstPoint.getxCoord());
Point3d secondPoint = new Point3d();
secondPoint.setxCoord(3.5);
secondPoint.setyCoord(22);
secondPoint.setzCoord(20);
}
}
As #Dude pointed out in the comments, you should write a method:
public double distanceTo(Point3d p) {
return Math.sqrt(Math.pow(x - p.getxCoord(), 2) + Math.pow(y - p.getyCoord(), 2) + Math.pow(z - p.getzCoord(), 2));
}
Then if you want to get the distance between 2 points you just call:
myPoint.distanceTo(myOtherPoint);
//or if you want to get the distance to some x, y, z coords
myPoint.distanceTo(new Point3d(x,y,z);
You could even make the method static and give it 2 points to compare:
public static double getDistance(Point3d p1, Point3d p2) {
return Math.sqrt(Math.pow(p1.getxCoord() - p2.getxCoord(), 2) + ...
}
P.S. my first answer :)
public double distanceTo(Point3d other) {
return Math.sqrt(Math.pow(this.xCoord-other.getxCoord(), 2)
+ Math.pow(this.yCoord-other.getyCoord(), 2)
+ Math.pow(this.zCoord-other.getzCoord(), 2));
}
Add this to your Point3d class. When you need to calculate the distance in the TestPoints class, you do something like
double distance = firstPoint.distanceTo(secondPoint);
You have two possible approaches, according to what you want to achieve.
You can put your "distanceTo" method inside the class Point3D:
public class Point3d {
...
public double distanceTo(Point3d ) {
return Math.sqrt( Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2) + Math.pow(this.z - that.z, 2));
}
In this case, you are always using the first point as the first argument, and any other point as the one you want to compute the distance from.
Alternatively, you can have a generic distanceTo method that lives somewhere(such as in your Program class, where you have your main method), that takes two points and compute the distance between those:
public class Program {
static public void main(String[] args) {}
public double distanceTo(Point3d p1, Point3d p2) {
return Math.sqrt( Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2) + Math.pow(p1.z - p2.z, 2));
}
}
Which one is better? Depends on how you use them in the common case :)
Just use the getters
float distance = Math.sqrt(Math.pow(secondPoint.getXCoord() - firstPoint.getXCoord()), 2) + ...)
Two ideas.
Either add a:
public double distanceTo(Point3d otherPoint) {
// return distance by using this.getxCoord(), this.getyCoord(), etc.
// and otherPoint.getxCoord(), otherPoint.getyCoord()
}
method to your Point3d class.
Then, at the end of your main method, you can do:
System.out.println(firstPoint.distanceTo(secondPoint));
System.out.println(tenthPoint.distanceTo(ninthPoint));
Or, add a static method to your main TestPoints class:
public static double distanceBetween(Point3d point1, Point3d point2) {
// return distance by using point1.getxCoord(), etc. and point2.getxCoord()
}
Then, at the end of your main method, you can do:
System.out.println(distanceBetween(firstPoint, secondPoint));
System.out.println(distanceBetween(tenthPoint, ninthPoint));

Problems with setters and getters in java program dealing with circles

I have been assigned the following task for an introductory java course:
You should write a class that represents a circle object and includes the following:
Private class variables that store the radius and centre coordinates of the object.
Constructors to create circle objects with nothing supplied, with just a radius value supplied and with a radius and centre coordinates supplied.
Public instance methods that allow the radius and centre coordinates to be set and retrieved (often known as set/get methods).
Public instance methods that return the circumference and area of the circle.
A public class method that tests if two circle objects overlap or not
Here is my code:
import java.lang.Math;
public class Circle {
private double xCentre, yCentre, Radius;
// constructors
public Circle() {
xCentre = 0.0;
yCentre = 0.0;
Radius = 1.0;
}
public Circle(double R) {
xCentre = 0.0;
yCentre = 0.0;
Radius = R;
}
public Circle(double x, double y, double R) {
xCentre = x;
yCentre = y;
Radius = R;
}
//getters
public double getX() {
return xCentre;
}
public double getY() {
return yCentre;
}
public double getRadius() {
return Radius;
}
//setters
public void setX(double NewX) {
xCentre = NewX;
}
public void setY(double NewY) {
yCentre = NewY;
}
public void setRadius(double NewR) {
Radius = NewR;
}
//calculate circumference and area
public double Circumference() {
return 2*Math.PI*Radius;
}
public double Area() {
return Math.PI*Radius*Radius;
}
//determine overlap
public static double Overlap(Circle c1, Circle c2) {
double xDelta = c1.getX() - c2.getX();
double yDelta = c1.getY() - c2.getY();
double separation = Math.sqrt(xDelta*xDelta + yDelta*yDelta);
double radii = c1.getRadius() + c2.getRadius();
return separation - radii;
}
}
}
and
import java.io.Console;
public class cp6 {
public static void main(String args[]){
//Set up the Console
Console myConsole = System.console();
//Declare cirlce
Circle first = new Circle(2.0,4.0,6.0);
myConsole.printf("Circumference of first circle is ", first.Circumference(), "\n");
myConsole.printf("Area of first circle is ", first.Circumference(), "/n");
first.setRadius(2);
first.setX(2);
first.setY(2);
myConsole.printf("New X of first circle is ", first.getX(), "/n");
myConsole.printf("New Y of first circle is ", first.getY(), "/n");
myConsole.printf("New Radius of first circle is ", first.getRadius(), "/n");
Circle second = new Circle(-1.0,3.0,5.0);
Circle third = new Circle(1,1,1);
if (Circle.Overlap(second, third) <= 0) {
myConsole.printf("Second and third circles overlap");
}
else {
myConsole.printf("Second and third circles do not overlap");
}
myConsole.printf("New Y of first circle is ", first.getY());
Calculate and print out distance between them using the class method
myConsole.printf("Distance between first and second is : %.5g\n", Circle.Overlap(first, second));
}
}
The second program just has to demonstrate each aspect addressed in the brief I pasted at the top and I've only a rough idea of how to do this so if what I'm doing seems stupid to any of you please offer suggestions of what else I can do.
Your problem is that you're using the Console.printf() method incorrectly.
The first parameter to this method should be a format, and it has to have placeholders inside it for the other parameters. Read up on it in The Java Platform documentation. In fact, you should familiarize yourself with the Java platform documentation. You need to use it often to make sure you're calling methods correctly or what methods are available in a given class.
So, your printout lines should actually have been:
myConsole.printf("Circumference of first circle is %.2f%n", first.Circumference());
myConsole.printf("Area of first circle is %.2f%n", first.Area());
...etc.
The format %.2f means "The corresponding parameter is a floating-point number. Display it with a precision of 2 digits after the decimal point". The %n replaces your "\n" - the whole "template" of the print should be just in the format string. And in this type of format, one should use %n instead of \n.
I'm not sure why you opted for using the system console rather than the usual System.out.println(). If you choose to go with System.out, there is also a printf() method there that works exactly as Console.printf() - the first parameter is a format, the others are embedded in it.
One last comment: there are conventions when writing Java code:
Indent your code properly
Class names' first letter is always uppercase.
Non-constant fields and local variable names' first letter is always lowercase.
Method names also start with a lowercase letter.

A really simple Java question

I'm trying to call angles from from the angle method down below in the Rotate90 method but I'm not sure of the syntax. What is the correct syntax?
import java.lang.Math;
public class CartesianPoint implements Point
{
private double xCoord;
private double yCoord;
public CartesianPoint (double xCoordinate,double yCoordinate)
{
xCoord = xCoordinate;
yCoord = yCoordinate;
}
public double xCoordinate ()
{
return xCoord;
}
public double yCoordinate ()
{
return yCoord;
}
public double angle ()
{
double angles;
angles = Math.cos( xCoord / Math.sqrt( xCoord*xCoord + yCoord*yCoord));
return angles;
}
public double radius ()
{
double radius;
radius = (yCoord*yCoord + xCoord*xCoord); //?
return radius;
}
public Point rotate90()
{
double rotated;
rotated = angles.angle + 90.0; //██████████ Error here ██████████
return rotated;
}
public double distanceFrom(Point other)
{
return 0;
}
}
I think you mean
rotated = angle() + 90.0;
Except I think you'll find that Math.cos uses radians not degrees, so you're not going to get the result you think you are. And shouldn't that be arc cos, not cosine? Something like this might be more what you're looking for:
public double angle()
{
return Math.atan2(ycoord, xcoord) * 180 / Math.PI;
}
If you want rotate90 to return a new Point that is 90 degrees from the current point, then change it to the following:
public Point rotate90()
{
return new CartesianPoint(-yCoord, xCoord);
}
Method invocations in Java always have trailing parentheses even when they don't have any arguments:
rotated = angle() + 90.0;
Method call requires parenthesis even if there are no parameters needed. This is different from other languages, e.g.groovy.
To answer your question directly: If you want to be able to access the variable "angles" from outside the "angle" function, you must make it a class variable. That is, declare it outside of any function, like you have declared xCoord and yCoord. Then refer to it by its simple name without any reference to the function that created it.
Note that if rotate90 tries to reference angle before angles() is called, angle will contain zero (or whatever default value you set) and is unlikely to be useful.
It's not clear to me exactly what you're trying to accomplish. I think that your intent is that the angles function would take the arc cosine, not the cosine.

Categories

Resources