How to get Y value from X value in JFreeChart - java

I'm using JFreeChart to draw chart. I have XYSeries with points (0, 0), (1, 2), (2, 5) and I want to read Y value for let's say x=1.5.
Is it possible to read value for points which are not in XYSeries? I couldn't find similar topic.

This is not supported directly. It does not make sense in many cases: There simply is no data available for x=1.5. The value there could be 1000.0, or -3.141. You don't know.
However, you're most likely looking for a linear interpolation. The pragmatic approach is thus to find the interval that contains the respective x-value, and interpolate the y-values linearly.
There are some technical caveats. E.g. the XYSeries may be not sorted, or may contain duplicate x-values, in which case there is no unique y-value for a given x-value. But for now, we can assume that the data set does not have these properties.
The following is an example of how this could be implemented. Note that this is not very efficient. If you have to compute many intermediate values (that is, if you intend to call the interpolate method very often), it would be beneficial to create a tree-based data structure that allows looking up the interval in O(logn).
However, if this is not time critical (e.g. if you only intend to show the value in a tooltip or so), you may interpolate the values like this:
import java.util.List;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
public class XYInterpolation
{
public static void main(String[] args)
{
XYSeries s = new XYSeries("Series");
s.add(0,0);
s.add(1,2);
s.add(2,5);
double minX = -0.5;
double maxX = 3.0;
int steps = 35;
for (int i=0; i<=steps; i++)
{
double a = (double)i / steps;
double x = minX + a * (maxX - minX);
double y = interpolate(s, x);
System.out.printf("%8.3f : %8.3f\n", x, y);
}
}
private static double interpolate(XYSeries s, double x)
{
if (x <= s.getMinX())
{
return s.getY(0).doubleValue();
}
if (x >= s.getMaxX())
{
return s.getY(s.getItemCount()-1).doubleValue();
}
List<?> items = s.getItems();
for (int i=0; i<items.size()-1; i++)
{
XYDataItem i0 = (XYDataItem) items.get(i);
XYDataItem i1 = (XYDataItem) items.get(i+1);
double x0 = i0.getXValue();
double y0 = i0.getYValue();
double x1 = i1.getXValue();
double y1 = i1.getYValue();
if (x >= x0 && x <= x1)
{
double d = x - x0;
double a = d / (x1-x0);
double y = y0 + a * (y1 - y0);
return y;
}
}
// Should never happen
return 0;
}
}
(This implementation clamps at the limits. This means that for x-values that are smaller than the minimum x-value or larger than the maximum x-value, the y-value of the minimum/maximum x-value will be returned, respectively)

You can use DatasetUtils.findYValue() from package org.jfree.data.general

Related

Detect collision with lines and limit movement

I'm making a game with libGDX in Java. I'm trying to make a collision detection. As you can see in the image, I have a line which is a wall and a player with specified radius. The desired position is the next location which the player is trying to be in. But because there is a wall, he's placed in the Actual Position which is on the Velocity vector, but more closer to the prev location. I'm trying to figure out how can I detect that closer position?
My attempt:
private void move(float deltaTime) {
float step;
beginMovementAltitude();
if (playerComponent.isWalking())
step = handleAcceleration(playerComponent.getSpeed() + playerComponent.getAcceleration());
else step = handleDeacceleration(playerComponent.getSpeed(), playerComponent.getAcceleration());
playerComponent.setSpeed(step);
if (step == 0) return;
takeStep(deltaTime, step, 0);
}
private void takeStep(float deltaTime, float step, int rotate) {
Vector3 position = playerComponent.getCamera().position;
float x = position.x;
float y = position.y;
int radius = playerComponent.getRadius();
auxEnvelope.init(x, x + radius, y, y + radius);
List<Line> nearbyLines = lines.query(auxEnvelope);
float theta;
int numberOfIntersections = 0;
float angleToMove = 0;
Gdx.app.log(step + "", "");
for (Line line : nearbyLines) {
VertexElement src = line.getSrc();
VertexElement dst = line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z, rotate);
float nextX = x + (step * deltaTime) * (auxVector3.x);
float nextY = y + (step * deltaTime) * playerComponent.getCamera().direction.y;
float dis = Intersector.distanceLinePoint(src.getX(), src.getY(), dst.getX(), dst.getY(), nextX, nextY);
boolean bodyIntersection = dis <= 0.5f;
auxVector21.set(src.getX(), src.getY());
auxVector22.set(dst.getX(), dst.getY());
auxVector23.set(nextX, nextY);
if (bodyIntersection) {
numberOfIntersections++;
if (numberOfIntersections > 1) {
return;
}
theta = auxVector22.sub(auxVector21).nor().angle();
float angle = (float) (180.0 / MathUtils.PI * MathUtils.atan2(auxVector23.y - position.y, auxVector23.x - position.x));
if (angle < 0) angle += 360;
float diff = (theta > angle) ? theta - angle : angle - theta;
if (step < 0) step *=-1;
angleToMove = (diff > 90) ? theta + 180 : theta;
}
}
if (numberOfIntersections == 0) {
moveCameraByWalking(deltaTime, step, rotate);
} else {
moveCameraInDirection(deltaTime, step, angleToMove);
}
}
The idea is to find intersection of path of object center and the line moved by radius of the circle, see that picture.
At first, you need to find a normal to the line. How to do it, depends on how the line is defined, if it's defined by two points, the formula is
nx = ay - by
ny = bx - ax
If the line is defined by canonical equation, then coefficients at x and y define normal, if I remembered correctly.
When normal is found, we need to normalize it - set length to 1 by dividing coordinates by vector length. Let it be n.
Then, we will project starting point, desired point and randomly chosen point on line to n, treating them as radius vectors.
Projection of vector a to vector b is
project (a, b) = scalar_product (a, b) / length (b)**2 * b
but since b is n which length equals 1, we will not apply division, and also we want to only find length of the result, we do not multiply by b. So we only compute scalar product with n for each of three aforementioned points, getting three numbers, let s be the result for starting point, d for desired point, l for chosen point on the line.
Then we should modify l by radius of the circle:
if (s < d) l -= r;
else if (s > d) l += r;
If s = d, your object moves in parallel along the line, so line can't obstruct its movement. It's highly improbable case but should be dealt with.
Also, that's important, if l was initially between s and d but after modifying is no longer between then, it's a special case you may want to handle (restrict object movement for example)
Ather that, you should compute (d - s) / (l - s).
If the result is greater or equals 1, the object will not reach the line.
If the result is between 0 and 1, the line obstructs movement and the result indicates part of the path the object will complete. 0.5 means that object will stop halfway.
If the result is negative, it means the line is behind the object and will not obstruct movement.
Note that when using floating point numbers the result will not be perfectly precise, that's why we handle that special case. If you want to prevent this from happening at all, organize loop and try approximations until needed precision is reached.

Java: Rotations and 3D distortions

I'm writing a program that will rotate a rectangular prism around a point. It handles the rotations via 3 rotation methods that each manage a rotation around a single axis (X, Y, and Z). Here's the code
public void spinZ(Spin spin) {
if (x == 0 && y == 0) {
return;
}
double mag = Math.sqrt(x * x + y * y);
double pxr = Math.atan(y / x);
x = Math.cos(spin.zr + pxr) * mag;
y = Math.sin(spin.zr + pxr) * mag;
}
public void spinY(Spin spin) {
if (z == 0 && x == 0) {
return;
}
double mag = Math.sqrt(x * x + z * z);
double pxr = Math.atan(z / x);
x = Math.cos(spin.yr + pxr) * mag;
z = Math.sin(spin.yr + pxr) * mag;
}
public void spinX(Spin spin) {
if (z == 0 && y == 0) {
return;
}
double mag = Math.sqrt(y * y + z * z);
double pxr = Math.atan(z / y);
y = Math.cos(spin.xr + pxr) * mag;
z = Math.sin(spin.xr + pxr) * mag;
}
public void addSpin(Spin spin) {
spinY(spin);
spinX(spin);
spinZ(spin);
}
Spin is a useless class that stores three doubles (which are rotations). These methods basically convert the rotations into 2D vectors (how I store the points) and rotate them as such. The first if statement makes sure the 2D vectors don't a magnitude of 0. They are allowed to, but in that case it's not necessary to carry out the rotation calculations. The other part just handles the trig. The bottom method just ties everything together and allows me to quickly change the order of the rotations (because order should and does affect the final rotation).
The problem isn't with the individual rotations but when they all come together. I can easily get a single rotation around a single axis to work without distorting the rectangular prism. When I put them all together, like if you were to call addSpin().
When spinY is called first, the prism is distorted when the rotations include a Y rotation (if the y component of the rotation is zero, and no rotation around the y-axis should occur, then no distortion occurs). In fact, if spinY() is called anytime but last a distortion of the cube will occur.
The same is the case with spinZ(). If spinZ() is called last, the cube won't get warped. However spinX() can go anywhere and not cause a distortion.
So the question is: Is there a problem with how I'm going about the rotations? The other question is while all rotations cannot be encompassed by rotations along just the X and Y axes or any other pair of distinct axes (like X and Z, or Y and Z), can those three sets collectively make all rotations? To clarify, can the rotations, which cannot be reached by a set of rotations around the X and Y axes, be reached by a set of rotations around the X and Z axes or the Y and Z axes?
I trust the medium I'm using to display the prisms. It's a ray-tracer I made that works well with rectangular prisms. This is a more math-based question, but it has a fairly comprehensive programming component.
These are some parallel calculations that still yield in distortions.
public void spinZ(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double xp = x*c - y*s;
double yp = y*s + x*c;
x = xp;
y = yp;
}
public void spinY(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
}
public void spinX(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double yp = y*c - z*s;
double zp = z*c + y*s;
y = yp;
z = zp;
}
Your checks for things like
x == 0
are unnecessary and dangerous as a double almost never will have the precise value 0. The atan when you have a division can lead to catastrophic loss of precision as well.
Why are they unnecessary? Because the following performs your rotation in a cleaner (numerically stable) fashion:
double c = Math.cos(spin.yr);
double s = Math.cos(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
Of course, my example assumes you treat the y rotation with a right handed orientation, but from your sample code you seem to be treating it as left handed. Anyways, the wikipedia article on the Rotation matrix explains the math.

Euler Method in Java, Variable Initial Condition

How would I write the Euler method in Java for a variable initial condition? For example, the initial condition that y(w)=0.
The equation I'm trying to solve is:
dy/dx = (y-sqrt(x^2 + y^2))/x
My initial code is simple.
import java.lang.Math;
public class euler
{
public static void main(String arg[])
{
int N = 10;
double h = 1.0/N;
double x0 = w; //This is what I would like to put in
double y0 = 0;
double x = x0, y = y0;
for (int i=0;i < N;i++)
{
y += h*f(x, y);
x += h;
System.out.println("x, y = " + x + ", " + y);
}
}
static double f(double x, double y)
{
return((y-Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)))/x);
}
}
My code should work for any kind of integer value of x0, but how could I get it to work for a variable w?
You get not only one solution, you get a family of solutions parametrized by the initial condition. Through every point (x0,y0) there is a solution, some, but not all, will give the same solution.
Thus y(w)=0 resp. the pair (x0=w, y0=0) will give a solution for every w, there is nothing to solve to get a specific value of w.
?? Could w stand for omega and that for infinity ?? That would be a valid question, to control the asymptotic behavior.
The only critical point of this problem is x=0, and even that only for y(0)<0, since then the differential equation has a singularity.

Z-buffering algorithm not drawing 100% correctly

I'm programming a software renderer in Java, and am trying to use Z-buffering for the depth calculation of each pixel. However, it appears to work inconsistently. For example, with the Utah teapot example model, the handle will draw perhaps half depending on how I rotate it.
My z-buffer algorithm:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
Method for calculating the z value of a point, given a triangle and the ray origin:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
Method for calculating if the ray origin is within a projected triangle:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
Method for calculating surface normal of a triangle:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
Example of the incorrectly drawn teapot:
What am I doing wrong? I feel like it must be some small thing. Given that the triangles draw at all, I doubt it's the pointWithinTriangle method. Backface culling also appears to work correctly, so I doubt it's that. The most likely culprit to me is the zValueOfPoint method, but I don't know enough to know what's wrong with it.
My zValueOfPoint method was not working correctly. I'm unsure why :( however, I changed to a slightly different method of calculating the value of a point in a plane, found here: http://forum.devmaster.net/t/interpolation-on-a-3d-triangle-using-normals/20610/5
To make the answer here complete, we have the equation of a plane:
A * x + B * y + C * z + D = 0
Where A, B, and C are the surface normal x/y/z values, and D is -(Ax0 + By0 + Cz0).
x0, y0, and z0 are taken from one of the vertices of the triangle. x, y, and z are the coordinates of the point where the ray intersects the plane. x and y are known values (rayOrigin.x, rayOrigin.y) but z is the depth which we need to calculate. From the above equation we derive:
z = -A / C * x - B / C * y - D
Then, copied from the above link, we do:
"Note that for every step in the x-direction, z increments by -A / C, and likewise it increments by -B / C for every step in the y-direction.
So these are the gradients we're looking for to perform linear interpolation. In the plane equation (A, B, C) is the normal vector of the plane.
It can easily be computed with a cross product.
Now that we have the gradients, let's call them dz/dx (which is -A / C) and dz/dy (which is -B / C), we can easily compute z everywhere on the triangle.
We know the z value in all three vertex positions.
Let's call the one of the first vertex z0, and it's position coordinates (x0, y0). Then a generic z value of a point (x, y) can be computed as:"
z = z0 + dz/dx * (x - x0) + dz/dy * (y - y0)
This found the Z value correctly and fixed my code. The new zValueOfPoint method is:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double dzdx = -A / C;
double dzdy = -B / C;
double rayZ = triangle.getV1().z * modelViewer.getModelScale() + dzdx * (rayOrigin.x - triangle.getV1().projectPoint(modelViewer).x) + dzdy * (rayOrigin.y - triangle.getV1().projectPoint(modelViewer).y);
return rayZ;
}
We can optimize this by only calculating most of it once, and then adding dz/dx to get the z value for the next pixel, or dz/dy for the pixel below (with the y-axis going down). This means that we cut down on calculations per polygon significantly.
this must be really slow
so much redundant computations per iteration/pixel just to iterate its coordinates. You should compute the 3 projected vertexes and iterate between them instead look here:
triangle/convex polygon rasterization
I dislike your zValueOfPoint function
can not find any use of x,y coordinates from the main loops in it so how it can compute the Z value correctly ?
Or it just computes the average Z value per whole triangle ? or am I missing something? (not a JAVA coder myself) in anyway it seems that this is your main problem.
if you Z-value is wrongly computed then Z-Buffer can not work properly. To test that look at the depth buffer as image after rendering if it is not shaded teapot but some incoherent or constant mess instead then it is clear ...
Z buffer implementation
That looks OK
[Hints]
You have too much times terms like x + getWidth()/2 why not compute them just once to some variable? I know modern compilers should do it anyway but the code would be also more readable and shorter... at least for me

Most efficient way to find distance between two circles in java?

So apparently calculating square roots is not very efficient, which leaves me wondering what the best way is to find out the distance (which I've called range below) between two circles is?
So normally I would work out:
a^2 + b^2 = c^2
dy^2 + dx^2 = h^2
dy^2 + dx^2 = (r1 + r2 + range)^2
(dy^2 + dx^2)^0.5 = r1 + r2 + range
range = (dy^2 + dx^2)^0.5 - r1 - r2
Trying to avoid the square root works fine when you just look for the situation when "range" is 0 for collisions:
if ( (r1 + r2 + 0 )^2 > (dy^2 + dx^2) )
But if I'm trying to work out that range distance, I end up with some unwieldy equation like:
range(range + 2r1 + 2r2) = dy^2 + dx^2 - (r1^2 + r2^2 + 2r1r2)
which isn't going anywhere. At least I don't know how to solve it for range from here...
The obvious answer then is trignometry and first find theta:
Tan(theta) = dy/dx
theta = dy/dx * Tan^-1
Then the find the hypotemuse
Sin(theta) = dy/h
h = dy/Sin(theta)
Finally work out the range
range + r1 + r2 = dy/Sin(theta)
range = dy/Sin(theta) - r1 - r2
So that's what I've done and have got a method that looks like this:
private int findRangeToTarget(ShipEntity ship, CircularEntity target){
//get the relevant locations
double shipX = ship.getX();
double shipY = ship.getY();
double targetX = target.getX();
double targetY = target.getY();
int shipRadius = ship.getRadius();
int targetRadius = target.getRadius();
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.atan( ( dY / dX ) );
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
// finally range between ship/target is:
int range = (int) (hypotemuse - shipRadius - targetRadius);
return range;
}
So my question is, is using tan and sin more efficient than finding a square root?
I might be able to refactor some of my code to get the theta value from another method (where I have to work it out) would that be worth doing?
Or is there another way altogether?
Please excuse me if I'm asking the obvious, or making any elementary mistakes, it's been a long time since I've used high school maths to do anything...
Any tips or advice welcome!
****EDIT****
Specifically I'm trying to create a "scanner" device in a game that detects when enemies/obstacles are approaching/ going away etc. The scanner will relay this information via an audio tone or a graphical bar or something. Therefore although I don't need exact numbers, ideally I would like to know:
target is closer/further than before
target A is closer/further than target B, C, D...
A (linear hopefully?) ratio that expresses how far a target is from the ship relative to 0 (collision) and max range (some constant)
some targets will be very large (planets?) so I need to take radius into account
I'm hopeful that there is some clever optimisation/approximation possible (dx + dy + (longer of dx, dy?), but with all these requirements, maybe not...
Math.hypot is designed to get faster, more accurate calculations of the form sqrt(x^2 + y^2). So this should be just
return Math.hypot(x1 - x2, y1 - y2) - r1 - r2;
I can't imagine any code that would be simpler than this, nor faster.
If you really need the accurate distance, then you can't really avoid the square root. Trigonometric functions are at least as bad as square root calculations, if not worse.
But if you need only approximate distances, or if you need only relative distances for various combinations of circles, then there are definitely things you can do. For example, if you need only relative distances, note that squared numbers have the same greater-than relationship as do their square roots. If you're only comparing different pairs, skip the square root step and you'll get the same answer.
If you only need approximate distances, then you might consider that h is roughly equal to the longer adjacent side. This approximation is never off by more than a factor of two. Or you could use lookup tables for the trigonometric functions -- which are more practical than lookup tables for arbitrary square roots.
I tired working out whether firstly the answers when we use tan, sine is same as when we use sqrt functions.
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
double shipX = 5;
double shipY = 5;
double targetX = 1;
double targetY = 1;
int shipRadius = 2;
int targetRadius = 1;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
}
The answer which i got was :
4.700885452542996
1.7008854
5.656854249492381
2.6568542
Now there seems a difference between the value with sqrt ones being more correct.
talking abt the performance :
Consider your code snippet :
i calculated the time of performance- which comes out as:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer - 639.3204215458475,
610.32043,
Elapsed milliseconds: 2
And when we try out with sqrt root one:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer -
769.3321779309637,
740.33215,
Elapsed milliseconds: 1
Now if we check for the difference the difference between the two answer is also huge.
hence i would say that if you making a game more accurate the data would be more fun it shall be for the user.
The problem usually brought up with sqrt in "hard" geometry software is not its performance, but the loss of precision that comes with it. In your case, sqrt fits the bill nicely.
If you find that sqrt really brings performance penalties - you know, optimize only when needed - you can try with a linear approximation.
f(x) ~ f(X0) + f'(x0) * (x - x0)
sqrt(x) ~ sqrt(x0) + 1/(2*sqrt(x0)) * (x - x0)
So, you compute a lookup table (LUT) for sqrt and, given x, uses the nearest x0. Of course, that limits your possible ranges, when you should fallback to regular computing. Now, some code.
class MyMath{
private static double[] lut;
private static final LUT_SIZE = 101;
static {
lut = new double[LUT_SIZE];
for (int i=0; i < LUT_SIZE; i++){
lut[i] = Math.sqrt(i);
}
}
public static double sqrt(final double x){
int i = Math.round(x);
if (i < 0)
throw new ArithmeticException("Invalid argument for sqrt: x < 0");
else if (i >= LUT_SIZE)
return Math.sqrt(x);
else
return lut[i] + 1.0/(2*lut[i]) * (x - i);
}
}
(I didn't test this code, please forgive and correct any errors)
Also, after writing this all, probably there is already some approximate, efficient, alternative Math library out there. You should look for it, but only if you find that performance is really necessary.

Categories

Resources