Instead of typing it all out, here's a picture for you to see what I want. You know what they say, a picture is worth a thousand words.
What I have is p1, Θ, and d and speed, s of the projectile.
Speed:
From this I can deduce p2 using the equation p1.x * speed, p1.y * speed which are the co-ordenates for p2. From this I can calculate the distance using the equation |dx| + |dy|.
Distance
However, if I wasn't given speed, how would I be able to calculate the co-ordenates of p2 only using Θ, p1 and d?
Are there any other methods that would be the most efficent?
public double getDistanceTraveled() {
return Math.abs(x - oldX) + Math.abs(y - oldY);
} //use Manhattan aproach as it is more efficent than Euclidean
public double getSpeed() {
return getDistanceTraveled() / level.TICKS_PER_SECOND;
}
is what I am using at the moment. I realized that I had the variable time, so I was able to deduce p2 using this method:
d = |dx| + |dy|d = s / ts = t(|dx| + |dy|)
Not sure if this is that efficient though. Any suggestions to this problem, and just to repeat: I have the variables theta, p1, d and t and I have to find p2.
Efficency >>> Accuracy
If theta is the angle between line and y-axis.
Then you can calculate it with the following formulas.
Let P1 be the point (p1x, p1y). and P2 be the point (p2x, p2y)
p2x = p1x + d * sin(theta)
p2y = p1y + d * cos(theta)
If you use Math.sin(theta), then keep in mind that theta should be in radians. You can use Math.toRadian(degree) to get angle in radians.
You know what they say, a picture is worth a thousand words.
If you want efficiency, there's actually a much better approach than using the trig operations at all. Basically, since you already have d, the only thing you care about is the relative movement along x and y, which is defined by theta.
Knowing that, it's pretty trivial to just store unit vectors at whatever your required granularity is in a hashmap and multiply by d
After you've decided on your granularity, just pre-calculate a HashMap like so:
{0: [1, 0],
0.01: [0.99, 0.001], etc...
}
Then round the incoming number, see this question for details on making sure it matches your granularity. Then the calculation is just (in pseudo-code):
x = p1[0] + d * <HashMap>.getKey(angle)[0]
y = p2[1] + d * <HashMap>.getKey(angle)[1]
A HashMap lookup and a multiplication is WAY more efficient than even a single trig operation. Preliminary tests got me ~10x speedup but YMMV.
Related
I'm trying to make a program that outputs the roots of a given cubic equation. I therefore decided to make a version using the cubic formula (http://www.math.vanderbilt.edu/~schectex/courses/cubic/). This formula should be able to output the result of one of the roots.
However, it doesnt seem to work and I'm not sure if it the code or the idea that is flawed. Here the coefficients 1, -6, 11 and -6 should create an output of either 1, 2 or 3. Instead NaN is outputted. The same has applied to other coefficients I have tried to use. Thanks for all your help!
public class CubicFormula {
public static void main(String[] args) {
System.out.println(new CubicFormula().findRoots(1.0, -6.0, 11.0, -6.0));
}
public double findRoots(double a, double b, double c, double d) {
double p = -(b)/(3*a);
double q = Math.pow(p, 3) + (b*c - 3*a*d)/(6*Math.pow(a, 2));
double r = c/(3*a);
return Math.cbrt(q + Math.sqrt(Math.pow(q, 2.0) + Math.pow((r - Math.pow(p, 2.0)), 3)))
+ Math.cbrt(q - Math.sqrt(Math.pow(q, 2.0) + Math.pow((r - Math.pow(p, 2.0)), 3))) + p;
}
}
From the very link you have mentioned
One reason is that we're trying to avoid teaching them about complex numbers. Complex numbers (i.e., treating points on the plane as numbers) are a more advanced topic, best left for a more advanced course. But then the only numbers we're allowed to use in calculus are real numbers (i.e., the points on the line). That imposes some restrictions on us --- for instance, we can't take the square root of a negative number. Now, Cardan's formula has the drawback that it may bring such square roots into play in intermediate steps of computation, even when those numbers do not appear in the problem or its answer.
This part
Math.sqrt(Math.pow(q, 2.0) + Math.pow((r - Math.pow(p, 2.0)), 3))
will end up being sqrt of negative number, which is imaginary, but in java
doubles world ends up being NaN.
I'd like to use my accelerometer in my car and with the accelerometer values, draw a trajectory in excel or any other platform with the origin in the first position value, that is the beginning of the path.
How can I achieve this? Please give me details I don't have any physics notion.
Please help, thanks in advance.
PS: I already programmed the SensorListener...
I have this for instance:
#Override
public void onSensorChanged(SensorEvent event){
if(last_values != null){
float dt = (event.timestamp - last_timestamp) * NS2S;
for(int index = 0 ; index < 3 ; ++index){
acceleration[index] = event.values[index];
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += velocity[index] * dt;
}
vxarr.add(velocity[0]);
vyarr.add(velocity[1]);
vzarr.add(velocity[2]);
axarr.add(acceleration[0]);
ayarr.add(acceleration[1]);
azarr.add(acceleration[2]);
}
else{
last_values = new float[3];
acceleration = new float[3];
velocity = new float[3];
position = new float[3];
velocity[0] = velocity[1] = velocity[2] = 0f;
position[0] = position[1] = position[2] = 0f;
}
xarr.add(position[0]);
yarr.add(position[1]);
zarr.add(position[2]);
tvX.setText(String.valueOf(acceleration[0]));
tvY.setText(String.valueOf(acceleration[1]));
tvZ.setText(String.valueOf(acceleration[2]));
last_timestamp = event.timestamp;
}
but when I draw a circle with my phone I got this:
Sometimes I have just only negative values and sometimes I have just positive values, I never have negative AND positive values in order to have circle.
Acceleration is the derivative of speed by time (in other words, rate of change of speed); speed is the derivative of position by time. Therefore, acceleration is the second derivative of position. Conversely, position is the second antiderivative of acceleration. You could take the accelerometer measurements and do the double intergration over time to obtain the positions for your trajectory, except for two problems:
1) It's an indefinite integral, i.e. there are infinitely many solutions (see e.g. https://en.wikipedia.org/wiki/Antiderivative). In this context, it means that your measurements tell you nothing about the initial speed. But you can get it from GPS (with limited accuracy) or from user input in some form (e.g. assume the speed is zero when the user hits some button to start calculating the trajectory).
2) Error accumulation. Suppose the accelerometer error in any given direction a = 0.01 m/s^2 (a rough guess based on my phone). Over t = 5 minutes, this gives you an error of a*t^2/2 = 450 meters.
So you can't get a very accurate trajectory, especially over a long period of time. If that doesn't matter to you, you may be able to use code from the other answer, or write your own etc. but first you need to realize the very serious limitations of this approach.
How to calculate the position of the device using the accelerometer values?
Physicists like to think of the position in space of an object at a given time as a mathematical function p(t) with values ( x(t), y(t), z(t) ). The velocity v(t) of that object turns out to be the first derivative of p(t), and the acceleration a(t) nicely fits in as the first derivative of v(t).
From now on, we will just look at one dimension, the other two can be treated in the same way.
In order to get the velocity from the acceleration, we have to "reverse" the operation using our known initial values (without them we would not obtain a unique solution).
Another problem we are facing is that we don't have the acceleration as a function. We just have sample values handed to us more or less frequently by the accelerometer sensor.
So, with a prayer to Einstein, Newton and Riemann, we take these values and think of the acceleration function as a lot of small lines glued together. If the sensor fires often, this will be a very good approximation.
Our problem now has become much simpler: the (indefinite) integral (= antiderivative) to a linear function
f(t) = m*t + b is F(t) = m/2 * t^2 + b*t + c, where c can be chosen to satisfy the initial condition (zero velocity in our case) .
Let's use the point-slope form to model our approximation (with time values t0 and t1 and corresponding acceleration values a0 and a1):
a(t) = a0 + (a1 – a0)/(t1 – t0) * (t – t0)
Then we get (first calculate v(t0) + "integral-between-t0-and-t-of-a", then use t1 in place of t)
v(t1) = v(t0) + (a1 + a0) * (t1 – t0) / 2
Using the same logic, we also get a formula for the position:
p(t1) = p(t0) + (v(t1) + v(t0)) * (t1 – t0) / 2
Translated into code, where last_values is used to store the old acceleration values:
float dt = (event.timestamp - last_timestamp) * NS2S;
for(int index = 0 ; index < 3 ; ++index){
acceleration[index] = event.values[index];
float last_velocity = velocity[index];
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += (velocity[index] + last_velocity )/2 * dt;
last_values[index] = acceleration[index];
}
**EDIT: **
All of this is only useful for us as long as our device is aligned with the world's coordinate system. Which will almost never be the case. So before calculating our values like above, we first have to transform them to world coordinates by using something like the rotation matrix from SensorManager.getRotationMatrix().
There is a code snippet in this answer by Csaba Szugyiczki which shows how to get the rotation matrix.
But as the documentation on getRotationMatrix() states
If the device is accelerating, or placed into a strong magnetic field, the returned matrices may be inaccurate.
...so I'm a bit pessimistic about using it while driving a car.
I have been looking for an answer for several hours now, and have turned up nothing. If this is a duplicate, I apologize but I have been unable to find a solution to my specific problem on StackOverflow.
I have a function that finds the angle between a point and the y-axis:
public static double getAngle(float x1,float y1) {
float y_x = 0;
float y_y = 1;
float p_x = x1;
float p_y = y1;
float theta = (float)Math.atan2((p_x-y_x),(p_y-y_y));
return (float)Math.toDegrees(theta)
}
Then when I call it, i get strange behavior:
getAngle(1,1); //returns 90.00000250447816
getAngle(5,5); //returns 51.34019265119512
getAngle(10,10); //returns 48.012787449847956
getAngle(100,100); //returns 45.287917631417216
getAngle(1000,1000); //returns 45.02866072599646
I know the answer is 45. It would appear the function `getAngle(x,x) is converging on 45 as the limit of x approaches infinity. The issue is I need this function to work for values between 0.01 and 10.0
Does anybody know why the function is behaving this way and how I can get the answer I am looking for?
P.S. I initially tried using the dot-product identity acos((ax*bx+ay*by)/|a||b|) and got a similar problem
You should simply use
float theta = (float) ((Math.PI/2) - Math.atan2(y1, x1));
The reason that your getAngle(x, x) approaches the correct angle when x approaches infinity is that you were effectively computing
Math.atan2(x, x-1)
which is equivalent to
Math.atan(x / (x-1))
and hence obviously approaches the correct
Math.atan(1)
when x approaches infinity.
It seems like your math is wrong. My approach would be to find the angle to the horizontal and do 90 minus that. For example:
double theta = Math.PI/2 - Math.atan2(y1,x1); //answer in radians
Why you are wrong is because you are subtracting the vectors from each one another so that you are getting the angle of a triangle defined by the new vector. By measuring it to the X axis and subtracting it from 90 it will be a lot easier :D
I have one line segment formed by two vectors, let's say v1 and v2, a vector v3 and an angle a. How do I write a method in Java (I'm also using Apache Commons Math to represent a vector) which gives me a vector v4, so that the line segments v1-v2 and v3-v4 are at angle a? There are infinite v4 elements, it would even be better if I could give a size to that method so that the line segment v3-v4 has that size. (all in 2d space, angle can be radians or degrees, doesn't matter)
Edit: as promised I have included an image of the problem I'm trying to solve. I have a line segment defined by 2 vectors (the line is a bit longer but that doesn't matter), an angle, and a third point. I need to draw the second line which intersects the first one at angle a. Since all lines in Javafx (which I'm using here) are drawn by defining two points, I needed to find the red point (or any of the possible ones).
Edit: Using Ali's answer I got the following method which does what I need:
public Pair<Vector2D, Vector2D> calculateFourthPoint(Vector2D v1, Vector2D v2, Vector2D v3, double angleInDegrees) {
Vector2D r = v1.subtract(v2);
double rx = r.getX();
double ry = r.getY();
double angle = toRadians(angleInDegrees);
double a = pow(rx, 2) + pow(ry, 2);
double b = 2 * sqrt(pow(rx, 2) + pow(ry, 2)) * cos(angle) * rx;
double c = pow(rx, 2) * pow(cos(angle), 2) + pow(ry, 2) * pow(cos(angle), 2) - pow(ry, 2);
double discriminant = sqrt(pow(b, 2) - (4 * a * c));
double sx1 = (-b + discriminant) / (2 * a);
double sx2 = (-b - discriminant) / (2 * a);
double sy1 = sqrt(1 - pow(sx1, 2));
double sy2 = sqrt(1 - pow(sx2, 2));
Vector2D s1 = new Vector2D(sx1, sy1);
Vector2D s2 = new Vector2D(sx2, sy2);
Vector2D v4_1 = v3.subtract(s1);
Vector2D v4_2 = v3.subtract(s2);
return new Pair<Vector2D, Vector2D>(v4_1, v4_2);
}
I don't know Apache Commons Math so I am writing in pseudo code. Let vx and vy denote the x and y components of vector v, respectively.
Let r=v1-v2 and s=v3-v4. You have 2 unknowns (namely sx and sy; and v4=v3-s) so you need 2 equations. These should be:
dot_product(r,s)=length(r)*cos a // forces the desired angle
dot_product(s,s)=1 // just sets the length of s to 1
To spell it out, the above equations are:
(1) rx*sx + ry*sy = sqrt(rx^2+ry^2)*cos a
(2) sx^2 + sy^2 = 1
The first equation is linear in both sx and sy. Let's eliminate sy from the first equation (assuming that ry is not zero)
sy = (1/ry)*(sqrt(rx^2+ry^2)*cos a - rx*sx)
and substitute this sy into the second equation. You get a quadratic equation in sy (I don't want to write it here because it is complicated) and that has 2 solutions. You get the corresponding sx by substituting the sy values into (assuming rx is not zero):
sx = (1/rx)*(sqrt(rx^2+ry^2)*cos a - ry*sy).
Finally, v4=v3-s. You get 2 solutions for v4, one for each of the solutions to the quadratic equation. (Degenerate cases, such as r being a null vector, are ignored in my answer.)
Shame we can't do LaTeX-style equations here (or can we? I dunno, never done it here...), but here goes:
v1-v2 · v3-v4 = |v1-v2| * |v3-v4| * cos(a) (by definition)
define |v3-v4| to be a unit vector, so that
v1-v2 · v3-v4 = |v1-v2|*1*cos(a) = |v1-v2|*cos(a)
working the left hand side out gives
v1·v4 + v2·v4 = |v1-v2|*cos(a) - v1·v3 + v2·v3
or
(v1+v2)·v4 = |v1-v2|*cos(a) - (v1-v2)·v3
while
|v3-v4| = (v3-v4)·(v3-v4) = 1
So, there are 2 equations in 2 unknowns. Now, for brevity,
aa = (v1+v2|x
bb = (v1+v2|y
x1 = v4|x
x2 = v4|y
A = |v1-v2|*cos(a) - (v1-v2)·v3
where |x means x-component, etc. With this, trivial substitution gives us
( (A-aa*x1)/bb )^2 + (aa*x1)^2 = 1 (-> 2 solutions)
( (A-bb*x2)/aa )^2 + (bb*x2)^2 = 1 (-> another 2 solutions)
The solutions are a bit too messy to write down here, but they are plain quadratic equations that can be easily solved.
You then have 4 unique vectors which lie on a unit circle around v3 (see picture). These 4 vectors result in only 2 distinct lines, but it is still a good idea to find all 4 vectors (as a self-check, and to improve robustness -- there can be some fringe cases where one of the vectors is such that something like catastrophic cancellation occurs).
Which line is best suited for you, depends of course on your use case.
Whatever the solution you pick, you should of course always verify whether
arccos(((v1-v2)·(v3-v4))/|v1-v2|) = a
as it should be.
Is it even that inaccurate? I re-implented the whole thing with Apfloat arbitrary precision and it made no difference which I should have known to start with!!
public static double bearing(LatLng latLng1, LatLng latLng2) {
double deltaLong = toRadians(latLng2.longitude - latLng1.longitude);
double lat1 = toRadians(latLng1.latitude);
double lat2 = toRadians(latLng2.latitude);
double y = sin(deltaLong) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLong);
double result = toDegrees(atan2(y, x));
return (result + 360.0) % 360.0;
}
#Test
public void testBearing() {
LatLng first = new LatLng(36.0, 174.0);
LatLng second = new LatLng(36.0, 175.0);
assertEquals(270.0, LatLng.bearing(second, first), 0.005);
assertEquals(90.0, LatLng.bearing(first, second), 0.005);
}
The first assertion in the test gives this:
java.lang.AssertionError:
expected:<270.0> but
was:<270.29389750911355>
0.29 seems to quite a long way off? Is this the formula i chose to implement?
If you've done what you seem to have done and done it correctly you have figured out the bearing of A from B along the shortest route from A to B which, on the surface of the spherical (ish) Earth is the arc of the great circle between A and B, NOT the arc of the line of latitude between A and B.
Mathematica's geodetic functions give the bearings, for your test positions, as 89.7061 and 270.294.
So, it looks as if (a) your calculation is correct but (b) your navigational skills need polishing up.
Are you sure this is due to numeric problems? I must admit, that I don't exactly know what you are trying to calculate, but when you dealing with angles on a sphere, small deviations from what you would expect in euclidian geometry.
java.lang.AssertionError: expected:<270.0> but was:<270.29389750911355>
This 0.29 absolute error represents a relative error of 0.1%. How is this "a long way off"?
Floats will give 7 significant digits; doubles are good for 16. Could be the trig functions or the degrees to radians conversion.
Formula looks right, if this source is to be believed.
If I plug your start and final values into that page, the result that they report is 089°42′22″. If I subtract your result from 360 and convert to degrees, minutes, and seconds your result is identical to theirs. Either you're both correct or you're both wrong.