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
The jump size with these equations decreases as amount of updates per second goes down. With a delta value multiplying gravity force and amount that jumpspeed force decreases, as well as time elapsed being added by delta every iteration (the delta value is the amount of milliseconds passed since last update), one would think that it would work fine.
//d is delta
...
if(isFalling||isJumping){
elapsedTime +=d;
//the elapsed time is the total amount of time passed since one started jumping,
//so that's logical to add the amount of time since last update.
long tesquared = (long) Math.pow(elapsedTime, 2);
//amount of time elapsed squared.
jumpSpeed+=-0.0000005*elapsedTime*d;
//this is the amount that jumpspeed is taken down by every time.
if(jumpSpeed > 0){
isJumping = true;
} else {
isJumping = false;
}
double fGravity = 0.0000001*tesquared*d;
// this is the equation for gravity, the amount that the player goes down
yRend += jumpSpeed - fGravity;
//the amount it goes up, minus the amount it goes down.
xRend -= strafeSpeed;
oldyRend = yRend;
}
To start a jump, one adds jumpSpeed by whatever amount.
The problem is that when the amount of updates per second decreases, the jumps decrease in duration and magnitute. I'm fairly certain that the delta values here are fine, which means that the problem must be in the equations themselves.
I'm thinking that fGravity is overrunning jumpSpeed more quickly when the delta is larger.
So my question. If the problem really is in the equations themselves, what is the correct way to model the upward force of a player minus the downward gravity force other than
jumpSpeed+=-0.0000005*elapsedTime*d;
and
double fGravity = 0.0000001*tesquared*d;?
If the problem is in the delta value not being applied correctly, then what would be the correct way to apply it?
Players do not have an "upward force" (except at the very point at which they're jumping). Forces impart momentum generating velocity. Once in the air, they do feel a downward force (i.e. gravity) which causes them to decelerate, ultimately generating a negative velocity which returns them to the ground.
If the player starts jumping upwards with velocity u, then at time t after the start of that jump the classic equation for calculating the position is y = ut + 0.5 * at^2.
In this case, a is gravity (which is negative, if y is "up"), giving y = u * t - 0.5 * g * t ^ 2
Basically the equation of a jump are like that:
the gravity applies vertically and produce a constant force downward. So the vertical velocity is vy = vy0 - elapsedTime * g with g being the gravity constant and vy0 the initial velocity at the beginning of the jump.
You don't have to compute the elapsed time. Simply at every frame, you do this:
vy -= g * dt; // dt is the elapsed time since last frame
y += vy * dt;
x += vx * dt; // vx doesn't change in the jump
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.
I want to set time from the analog clock in an Android Application. For this I have overridden the Analogclock.java class and have established the Ontouchevent listener. I followed this method and this formula to calculate the angle between the hour and the minute hand from the obtained Coordinates. Now I'm able to move the hand to a new position. And I can also fetch the new angle between the needles from this. This is the code for the same :
case MotionEvent.ACTION_MOVE:
x = (int)event.getX();
y = (int)event.getY();
double dx = x - minuteRect.centerX();
double dy = -(y - minuteRect.centerY());
double inRads = Math.atan2(dy,dx);
if (inRads < 0)
inRads = Math.abs(inRads);
else
inRads = 2*Math.PI - inRads;
double newDegree = Math.toDegrees(inRads);
if(isMove()){
setAngle(newDegree);
invalidate();
}
I now want to set the time where the needle is being moved.
Is there any way I can calculate the time from the Coordinates or from the angle between the two needles?
I don't know the code, but the math is not hard:
Divide the angle of the hour hand by 2PI, multiply by 12 and truncate, and you have the hours.
Divide the angle of the minute hand by 2PI, multiply by 60 and truncate, and you have the minutes.
Example : 06:15:
The hour angle is a little bit more than PI. (PI / 2PI) * 12 = 6
The minute angle is PI/2. ((PI/2) / 2PI) * 60 = 15
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 );