Moving between co-ordinates, Java Algorithms - java

Ok this question is going to be a little abstract.
I have an icon moving along a line which is represented by a series of coordinates stored in a vector, and I am iterating through them. The distance between coordinates is variable. So sometimes the icon will move slowly and smoothly, and others it will jump several 100 pixels at a time.
I am having trouble coming up with an algorithm to split up each set of coordinates it must travel between into a set of relative coordinates where the number is based on size, so that transition is smooth no matter how many co-ords are on a single line.
Any ideas would be much appreciated. Thanks :)

Take a look at this discussion of the Main Game Loop.
And here's a quote from that page:
At this step, updates to all the
objects in the game world are
calculated and performed. Usually, a
time step value is passed to all of
the update methods indicating how much
time has passed since the last update
...
You need to know 3 things:
how much time has elapsed since you last updated the position of your object?
what is the rate of movement of your object?
what is the direction (usually represented as a Ray) your object is moving?
From these, you can calculate the current position of the object.

If you want the object to move at a constant speed, I'd suggest a time-based model, where your object is actually moving at a speed (pixels/second). You can still get it to hit every point(ish) if you spline along a curve (such as a catmull-rom curve).

So you want to move from a initial point (x0/y0) to a end point (x1/y1) along a line by a variable number of steps but with a maximum distance for each step?
This could be done by something like this:
int stepdist = 10; // max pixels per step
double xdiff = x1 - x0;
double ydiff = y1 - y0;
double dist = sqrt( xdiff * xdiff + ydiff * ydiff );
int steps = (int) ( ( dist - 1 ) / stepdist );
if( steps > 0 )
{
xdiff /= steps;
ydiff /= steps;
while( --steps >= 0 )
{
x0 += xdiff;
y0 += ydiff;
moveTo( (int) x0, (int) y0 );
}
}
moveTo( (int) x1, (int) y1 );

Related

How can we write the angle expression for analog clock?

This is the expression given as solution in the book I referred to but it seems to be beyond my understanding. Please anyone help to understand how are we exactly writing this angle? Why subtract pi/2? I really have no idea
xs=(int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys=(int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
xm=(int)(Math.cos(m*3.14f/30-3.14f/2)*40+xcentre);
ym=(int)(Math.sin(m*3.14f/30-3.14f/2)*40+ycentre);
xh=(int)(Math.cos((h*30+m/2)*3.14f/180-3.14f/2)*30+xcentre);
yh=(int)(Math.sin((h*30+m/2)*3.14f/180-3.14f/2)*30+ycentre);
Seems like it's giving the cartesian coordinates of the ends of the three hands of a clock centered at the origin, with up being negative y, and right being positive x. I can say this just by trying some values.
I wrapped your basic code like this:
static class ClockCoords {
int xs, ys;
int xm, ym;
int xh, yh;
public String toString() {
return String.format("h: %3d,%3d m: %3d,%3d s: %3d,%3d", xh, yh, xm, ym, xs, ys);
}
}
public static ClockCoords coords(int h, int m, int s) {
ClockCoords r = new ClockCoords();
int xcentre = 0;
int ycentre = 0;
r.xs = (int) (Math.cos(s * 3.14f / 30 - 3.14f / 2) * 45 + xcentre);
r.ys = (int) (Math.sin(s * 3.14f / 30 - 3.14f / 2) * 45 + ycentre);
r.xm = (int) (Math.cos(m * 3.14f / 30 - 3.14f / 2) * 40 + xcentre);
r.ym = (int) (Math.sin(m * 3.14f / 30 - 3.14f / 2) * 40 + ycentre);
r.xh = (int) (Math.cos((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + xcentre);
r.yh = (int) (Math.sin((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + ycentre);
return r;
}
public static void main(String[] args) throws IOException {
System.out.println(coords(0, 0, 0));
System.out.println(coords(0, 0, 45));
System.out.println(coords(6, 0, 0));
System.out.println(coords(6, 30, 0));
}
which gives me this:
h: 0,-29 m: 0,-39 s: 0,-44
h: 0,-29 m: 0,-39 s: -44, 0
h: 0, 29 m: 0,-39 s: 0,-44
h: -7, 28 m: 0, 39 s: 0,-44
So, if I haven't messed this up, the hour hand is 29 units long, the minute hand is 39 units long, and the second hand is 44 units long. At the start of the day, the first entry, they're all pointing straight up. 45 seconds into the day, the second entry, sees the second hand pointing off to the left, but the other two hands are still point straight up given integer granularity and hands that aren't too long. The third entry, 6:00, just flips the hour hand to point down. The fourth entry is interesting, 6:30, in that it points the minute hand down, but also moves the hour hand a little to the left and up...our first hand in a position not at a 90 degree angle to center. Interesting stuff. As to the WHY of all of this...I assume it's all basic trig and cartesian math.
Wait a sec...there one thing strange I don't get...I see in the formulas where each hand is given a different length. Why are the hand lengths I see off by 1 from what's in the formulas? My guess is that it has to do with the very rough approximation of PI that's used. I think those hands aren't pointing quite straight up. That's all I can think of. Maybe tomorrow I'll try plugging in a better value for PI.
Let me provide you some background information as well.
Trigonometry
is all about a circle, having a radius of 1 unit, centered in the origo, that is, point (0, 0). The coordinates of a point on the circle can be calculated as x = cos(alpha), y = sin(alpha), where alpha is the angle. Since all the points of the circle are of equal distance from the center, you only need to know the angle to compute the coordinates, which are (cos(alpha), sin(alpha)).
Reason: Look at Pythagoras's theorem, which is, by the way, a consequence of the law of cosines, where the largest angle of the triangle is of 90 degree.
Pythagoras's theorem states that
where a, b and c are lengths of sides of the triangle, the triangle being perpendicular and a < c > b is true. So, the cos and sin is due to trigonometrical coordinates.
Radians, PI/2
Units of angle can be measured in degrees (360 degrees being the full circle) or radians (2 PI being the full circle). Let's talk in radians. In math, 0 radians is the angle of the upmost point of the circle. pi/2 is the left-most. pi is the downmost. 3pi/2 is the rightmost. Notice, that as the angle increases your point moves counter-clockwise.
Since this is periodic, it is true that
2 * k * pi + alpha = alpha
On screens, y points downwards, by contrast to the standard in math, where y vertex points upwards. So, if you start from 0 radians, that will be the downmost point when shown on the screen and due to the invert y, as you increase the angle, you move to the clockwise direction. Removing pi / 2 from 0 points you to the rightmost point.
Variables
(xh, yh) are the hour coordinates
(xm, ym) are the minute coordinates
(xs, ys) are the second coordinates
They are the hands of a traditional clock.
h is the hour angle
m is the minute angle
s is the second angle
(xcentre, ycentre) are the coordinates of the center. They might be different from (0, 0), so coordinate moving, the so-called translation is supported.
Step sizes
There are 60 seconds in a minute and there are 60 minutes in an hour, so the angle step needs to be the same for them, even though, the frequency of steps is different, while there are 24 hours in a day, so the angle step of hour needs to be both less frequent and larger (12 positions on a traditional clock).
Length of hands
Hour, minute and second hands (no pun intended) differ in their length, this is why the unit of the trigonometric circle is multiplied by 45, 40 and 30, respectively.
As time passes, presumably the angles are changed and subsequently their coordinates change.
A less-exhaustive explanation, looking only at seconds:
xs = (int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys = (int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
As Steve's answer notes, drawing a line from (xcentre, ycentre) to (xs, ys) would display a seconds-hand, with "up" being "y = 0" -- so that axis is reversed compare to traditional plots. This actually works in our favor: normally, as angles grow, they are displayed as going anti-clockwise. Since the y axis is reversed in screen coordinates, this is fine for us: our hands will advance clockwise, as expected.
Let us look at the maths, using xs:
xs = Math.cos(s*3.14f/30-3.14f/2)*45; // removed rounding & using xcentre=0
xs = Math.cos((s/30)*PI - PI/2) * sHandLength; // use PI=3.14..., sHandLength=45
Now, at time 0, we want the seconds-hand to look straight up. But normally cos(0) = 1. If we substract 90º (PI/2), it will be looking straight up:
xs = Math.cos((s/30)*PI - zeroIsUp) * sHandLength;
We can undo this to keep on reasoning about the remaining expression:
xs = Math.cos((s/30)*PI); // sHandlength of 1, time 0 is left
All that is missing is that mysterious s/30*PI. Let's make a small table:
seconds(s) radians(argument to Math.cos())
0 0
15 PI/2 -- a quarter-turn of the hand
30 PI -- a half-turn
45 3*PI/2 -- a three-quarters turn
60 2*PI, or 0 -- a full turn
So it seems that it is simply that (s/30) * PI is short for (s/60) * (2*PI).
For a book on Java, I would have expected a much clearer way of writing this. My personal preference would have been:
xs = (int)(Math.cos(base60toRadians(s) - zeroIsUp) * secondHandLength + xCentre);
ys = (int)(Math.sin(base60toRadians(s) - zeroIsUp) * secondHandLength + yCentre);
// ... somewhere else
private float base60toRadians(int b60) { return (b60 / 60) * (2 * Math.PI); }
The coordinates of the clock's centre are (xcentre, ycentre).
With a geometric affine translation to the centre you can calculate like from (0, 0).
The hands are rotating clock wise, in the negative direction.
Now the hands of a clock start at the top, and (0, 1), which has an angle π/2 (90°). (1, 0) being where the angle starts, (-1, 0) halfways having angle π (180°).
The full 360° angle being 2π, 1/60th thereof becomes:
Seconds: 60 seconds = 2π; angle 2π / 60 = π / 30
double startAngle = Math.PI / 2; // Value 0 has angle π/2
double rs = 45;
xs = (int)(Math.cos(-s * Math.PI / 30 - startAngle) * rs + xcentre);
ys = ... sin ...
Hours: 24 hours = 2π; angle 2π / 24 = π / 12

Calculating speed from set of longitude and latitudes values obtained in one minute?

I need to calculate speed after each 10 seconds or less (currently i am using fused location api to get the location after each 10 seconds). The problem is that the equipment is too slow and sometimes it gives the distance covers equal to zero.
I have tried using Location.distanceBetween() but it also produces zeros even when the equipment is moving. I have tried to calculate distance by a formula but sometimes distance is too small that it gives zero.
Now i want to calculate average speed. I want to save the points obtained in 1 minute (6 lat long values). And then after each 10 seconds, i want to calculate average speed between them. Thus after each 10 seconds I will add one points at the end and remove one point from the start. That will remove the possibility of zero.
Now is there any formula that can calculate speed or distance from set of lat long values or any better approach will be highly appreciated.
You can calculate distance between two point, that are close enough, using simple geometry
deltaLngMeters = R * cos(latitude) * deltaLongitudeRadians;
deltaLatMeters = R * deltaLatitudeRadians;
whereas deltas are in radians, deltaLatitudeRadians = deltaLatitudeDegrees * pi / 180
Hence distance = sqrt(deltaLngMeters ^2 + deltaLatMeters ^ 2).
To sum up
function distance(point1, point2) {
var degToRad = Math.PI / 180;
return R * degToRad * Math.sqrt(Math.pow(Math.cos(point1.lat * degToRad ) * (point1.lng - point2.lng) , 2) + Math.pow(point1.lat - point2.lat, 2));
}
If you have array of six points, you can calculate average speed.
points = [{lat: .., lng: ..}, ... ]; // 6 points
distancesSum = 0;
for(i = 0; i < distances.length - 1; i++) {
distancesSum += distance(points[i], points[i + 1]);
}
return (distancesSum / (points.length - 1));
Yes, R is for the Earth radius, R = 6371000;// meters
You can use multi threading(Thread.sleep()) to calculate a formula repeatedly for every 10 seconds. You can verify it here https://beginnersbook.com/2013/03/multithreading-in-java/.
For small distances(hope the device won't move at speeds above 1 km/s), earth's surface can be treated as a plane. Then the latitude and longitude will be the coordinates of the device on the Cartesian plane attached to earth. Hence you can calculate the distance by this formula:
√(delta(longitude)^2 + delta(latitude)^2)
delta: difference

Bertrand's Paradox Simulation

So, I saw this on Hacker News the other day: http://web.mit.edu/tee/www/bertrand/problem.html
It basically says what's the probability that a random chord on a circle with radius of 1 has a length greater than the square root of 3.
Looking at it, it seems obvious that the answer is 1/3, but comments on HN have people who are smarter than me debating this. https://news.ycombinator.com/item?id=10000926
I didn't want to debate, but I did want to make sure I wasn't crazy. So I coded what I thought would prove it to be P = 1/3, but I end up getting P ~ .36. So, something's got to be wrong with my code.
Can I get a sanity check?
package com.jonas.betrand;
import java.awt.geom.Point2D;
import java.util.Random;
public class Paradox {
final static double ROOT_THREE = Math.sqrt(3);
public static void main(String[] args) {
int greater = 0;
int less = 0;
for (int i = 0; i < 1000000; i++) {
Point2D.Double a = getRandomPoint();
Point2D.Double b = getRandomPoint();
//pythagorean
if (Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)) > ROOT_THREE) {
greater++;
} else {
less++;
}
}
System.out.println("Probability Observerd: " + (double)greater/(greater+less));
}
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
boolean xsign = new Random().nextBoolean();
if (!xsign) {
x *= -1;
}
//formula for a circle centered on origin with radius 1: x^2 + y^2 = 1
double y = Math.sqrt(1 - (Math.pow(x, 2)));
boolean ysign = new Random().nextBoolean();
if (!ysign) {
y *= -1;
}
Point2D.Double point = new Point2D.Double(x, y);
return point;
}
}
EDIT: Thanks to a bunch of people setting me straight, I found that my method of finding a random point wasn't indeed so random. Here is a fix for that function which returns about 1/3.
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
Random r = new Random();
if (!r.nextBoolean()) {
x *= -1;
}
//circle centered on origin: x^2 + y^2 = r^2. r is 1.
double y = Math.sqrt(1 - (Math.pow(x, 2)));
if (!r.nextBoolean()) {
y *= -1;
}
if (r.nextBoolean()) {
return new Point2D.Double(x, y);
} else {
return new Point2D.Double(y, x);
}
}
I believe you need to assume one fixed point say at (0, 1) and then choose a random amount of rotation in [0, 2*pi] around the circle for the location of the second point of the chord.
Just for the hell of it I wrote your incorrect version in Swift (learn Swift!):
struct P {
let x, y: Double
init() {
x = (Double(arc4random()) / 0xFFFFFFFF) * 2 - 1
y = sqrt(1 - x * x) * (arc4random() % 2 == 0 ? 1 : -1)
}
func dist(other: P) -> Double {
return sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y))
}
}
let root3 = sqrt(3.0)
let total = 100_000_000
var samples = 0
for var i = 0; i < total; i++ {
if P().dist(P()) > root3 {
samples++
}
}
println(Double(samples) / Double(total))
And the answer is indeed 0.36. As the comments have been explaining, a random X value is more likely to choose the "flattened area" around pi/2 and highly unlikely to choose the "vertically squeezed" area around 0 and pi.
It is easily fixed however in the constructor for P:
(Double(arc4random()) / 0xFFFFFFFF is fancy-speak for random floating point number in [0, 1))
let angle = Double(arc4random()) / 0xFFFFFFFF * M_PI * 2
x = cos(angle)
y = sin(angle)
// outputs 0.33334509
Bertrand's paradox is exactly that: a paradox. The answer can be argued to be 1/3 or 1/2 depending on how the problem is interpreted. It seems you took the random chord approach where one side of the line is fixed and then you draw a random chord to any part of the circle. Using this method, the chances of drawing a chord that is longer than sqrt(3) is indeed 1/3.
But if you use a different approach, I'll call it the random radius approach, you'll see that it can be 1/2! The random radius is this, you draw a radius in the circle, and then you take a random chord that this radius bisects. At this point, a random chord will be longer than sqrt(3) 1/2 of the time.
Lastly, the random midpoint method. Choose a random point in the circle, and then draw a chord with this random point as the midpoint of the chord. If this point falls within a concentric circle of radius 1/2, then the chord is shorter than sqrt(3). If it falls outside the concentric circle, it is longer than sqrt(3). A circle of radius 1/2 has 1/4 the area of a circle with radius 1, so the chance of a chord smaller than sqrt(3) is 1/4.
As for your code, I haven't had time to look at it yet, but hope this clarifies the paradox (which is just an incomplete question not actually a paradox) :D
I would argue that the Bertrand paradox is less a paradox and more a cautionary lesson in probability. It's really asking the question: What do you mean by random?
Bertrand argued that there are three natural but different methods for randomly choosing a chord, giving three distinct answers. But of course, there are other random methods, but these methods are arguably not the most natural ones (that is, not the first that come to mind). For example, we could randomly position the two chord endpoints in a non-uniform manner. Or we position the chord midpoint according to some non-uniform density, like a truncated bi-variate normal.
To simulate the three methods with a programming language, you need to be able to generate uniform random variables on the unit interval, which is what all standard (pseudo)-random number generators should do. For one of the methods/solutions (the random midpoint one), you then have to take the square root of one of the uniform random variables. You then multiple the random variables by a suitable factor (or rescale). Then for each simulation method (or solution), some geometry gives the expressions for the two endpoints.
For more details, I have written a post about this problem. I recommend the links and books I have cited at the end of that post, under the section Further reading. For example, see Section 1.3 in this new set of published lecture notes. The Bertrand paradox is also in The Pleasures of Probability by Isaac. It’s covered in a non-mathematical way in the book Paradoxes from A to Z by Clark.
I have also uploaded some simulation code in MATLAB, R and Python, which can be found here.
For example, in Python (with NumPy):
import numpy as np; #NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt #for plotting
from matplotlib import collections as mc #for plotting line chords
###START Parameters START###
#Simulation disk dimensions
xx0=0; yy0=0; #center of disk
r=1; #disk radius
numbLines=10**2;#number of lines
###END Parameters END###
###START Simulate three solutions on a disk START###
#Solution A
thetaA1=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
thetaA2=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
#calculate chord endpoints
xxA1=xx0+r*np.cos(thetaA1);
yyA1=yy0+r*np.sin(thetaA1);
xxA2=xx0+r*np.cos(thetaA2);
yyA2=yy0+r*np.sin(thetaA2);
#calculate midpoints of chords
xxA0=(xxA1+xxA2)/2; yyA0=(yyA1+yyA2)/2;
#Solution B
thetaB=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pB=r*np.random.uniform(0,1,numbLines); #choose radial component uniformly
qB=np.sqrt(r**2-pB**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaB=np.sin(thetaB);
cos_thetaB=np.cos(thetaB);
#calculate chord endpoints
xxB1=xx0+pB*cos_thetaB+qB*sin_thetaB;
yyB1=yy0+pB*sin_thetaB-qB*cos_thetaB;
xxB2=xx0+pB*cos_thetaB-qB*sin_thetaB;
yyB2=yy0+pB*sin_thetaB+qB*cos_thetaB;
#calculate midpoints of chords
xxB0=(xxB1+xxB2)/2; yyB0=(yyB1+yyB2)/2;
#Solution C
#choose a point uniformly in the disk
thetaC=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pC=r*np.sqrt(np.random.uniform(0,1,numbLines)); #choose radial component
qC=np.sqrt(r**2-pC**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaC=np.sin(thetaC);
cos_thetaC=np.cos(thetaC);
#calculate chord endpoints
xxC1=xx0+pC*cos_thetaC+qC*sin_thetaC;
yyC1=yy0+pC*sin_thetaC-qC*cos_thetaC;
xxC2=xx0+pC*cos_thetaC-qC*sin_thetaC;
yyC2=yy0+pC*sin_thetaC+qC*cos_thetaC;
#calculate midpoints of chords
xxC0=(xxC1+xxC2)/2; yyC0=(yyC1+yyC2)/2;
###END Simulate three solutions on a disk END###

at the end of a hypotenuse line image bounces back and forth from 2 points close to the end point

I am trying to learn to make game for the Android. I am trying to make an image move along a hypotenuse line.
I got the math and code down (I think, got it from some place off google) but what happens is that after it travels down the line (which it looks like it does fine) when the image comes to the end of the line it "bounces" between 2 points right next to the destination point. like it can't get to the end of the line so it just goes to the 2 closest points it can get to and jumps back and forth between them.
The question:
How would I get it to not jump from the 2 points and stick to the point at the end of the Hypotenuse line?
Here is my code:
// to find the distance between the 2 points
distX = endX - imaX;
distY = endY - imaY;
// find the hypotenuse
hyp = Math.sqrt(distX*distX + distY*distY);
// don't know what this is for
len = 160/hyp;
distX *= len;
distY *= len;
// and to move the image. The points have to be an int.
imaX += (int) (distX * 0.05);
imaY += (int) (distY * 0.05);
Thank you:)
Edit: added the question and fixed the error I made in here.
If you googled this code, you should keep googling. It's a confusing piece of overkill if all you want to do is travel a line.
Consider the case when you are exactly one pixel away in both dimensions:
distX = 1
distY = 1
hyp = sqrt(2) ~1.414
len = 160/hyp ~ 113.15
imaX += (113.15 * 0.05) ~ 5
imaY += (113.15 * 0.05) ~ 5
So, if you're one pixel away in both the X/Y dimensions, it'll try to move 5 pixels in each direction each time. Not good
You should also try to achieve framerate independence, which is something this code can't handle. There are literally tons of articles about this on the web.
Edit: oh, and it should be:
hyp = Math.sqrt(distX*distX + distY*distY);
You confused a multiply with an add.

Mathematical issue (Increasing and deceasing two variables inside one loop)

I have a for loop and inside that integer x will increase from 533 to 813. That means 280 increments. In side the same loop I want to decrease y's value from 300 to 200 when above happens. Which means when x is 533 y must be 300 and when x is 813 y must be 200. I know this can do by decrease y's value by 100/280 in each iteration. But both are integers.
Here are some code sample i used but it is not working.:
for(int i = 0; i < b.getSize(); i++) {
x = b.getCar(i).getPosX();
b.getCar(i).setPosX(++x);
if(x >= ((getWidth() / 2) - 140) && x < ((getWidth() / 2) + 140)){
y = b.getCar(i).getPosY();
y = (double)(y - (10.0f / 28.0f));
b.getCar(i).setPosY((int)y);
}
}
How can I possibly do this. Thanks!
There are two solutions, a simple and a complex one. The simple one:
y = yoff + (int)( (double) height * x / width )
where yoff = 300, height = -100, width = 813-533. Basically, you do a floating point operation and then you round the result.
Alternatively, the same can be done using pure integer math using the Bresenham line algorithm but that would take a lot more code.
y must be a double or a float and you need to round its value when you want to use it.
If you wanna do animation, just have a look at interpolators. You can abstract the logic of computing the values in between your extremas.
Basically at the beginning, you give your interpolator the start and end values.
Then, you give the interpolator a time and it gives you back the value between start and end for that time value.
Bonus: it will allow you to change your animation look & feel without touching the rest of the code. (what you are trying to do is in fact a linear interpolation, but it will look much nicer using a sine function for instance, or some other algorithm such as bouncing, quadratic, ...)
It looks like the logic for drawing a line. The Bresenham's algorithm should be the best option.
Keep a helping variable double dy that keeps track of the precise value for y. At each iteration, update dy using your formula, then update y by taking the rounded/truncated value of dy.
NOt sure what you like to do, but your current solution sufers from rounding of floats to integers. To avoid this, calculate with floats / doubles and convert them to integer whensetting positions.

Categories