Calculate next position and velocity after “bounce”
up vote
1
down vote
favorite
Intro and code
I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max]
.
public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) {
if (position + velocity < 0) {
return TwoVector.<Double>builder()
.x(Math.abs(position + velocity))
.y(Math.abs(velocity))
.build();
}
if (position + velocity > max) {
return TwoVector.<Double>builder()
.x(max - ((position + velocity) % max))
.y(-Math.abs(velocity))
.build();
}
return TwoVector.<Double>builder()
.x(position + velocity)
.y(velocity)
.build();
}
Explanation
- The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".
- The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".
- If neither condition is true, we can add the current velocity to the current position to get the next position without issue.
Question
Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?
java coordinate-system physics
bumped to the homepage by Community♦ 2 days ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
up vote
1
down vote
favorite
Intro and code
I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max]
.
public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) {
if (position + velocity < 0) {
return TwoVector.<Double>builder()
.x(Math.abs(position + velocity))
.y(Math.abs(velocity))
.build();
}
if (position + velocity > max) {
return TwoVector.<Double>builder()
.x(max - ((position + velocity) % max))
.y(-Math.abs(velocity))
.build();
}
return TwoVector.<Double>builder()
.x(position + velocity)
.y(velocity)
.build();
}
Explanation
- The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".
- The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".
- If neither condition is true, we can add the current velocity to the current position to get the next position without issue.
Question
Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?
java coordinate-system physics
bumped to the homepage by Community♦ 2 days ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
Intro and code
I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max]
.
public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) {
if (position + velocity < 0) {
return TwoVector.<Double>builder()
.x(Math.abs(position + velocity))
.y(Math.abs(velocity))
.build();
}
if (position + velocity > max) {
return TwoVector.<Double>builder()
.x(max - ((position + velocity) % max))
.y(-Math.abs(velocity))
.build();
}
return TwoVector.<Double>builder()
.x(position + velocity)
.y(velocity)
.build();
}
Explanation
- The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".
- The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".
- If neither condition is true, we can add the current velocity to the current position to get the next position without issue.
Question
Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?
java coordinate-system physics
Intro and code
I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max]
.
public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) {
if (position + velocity < 0) {
return TwoVector.<Double>builder()
.x(Math.abs(position + velocity))
.y(Math.abs(velocity))
.build();
}
if (position + velocity > max) {
return TwoVector.<Double>builder()
.x(max - ((position + velocity) % max))
.y(-Math.abs(velocity))
.build();
}
return TwoVector.<Double>builder()
.x(position + velocity)
.y(velocity)
.build();
}
Explanation
- The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".
- The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".
- If neither condition is true, we can add the current velocity to the current position to get the next position without issue.
Question
Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?
java coordinate-system physics
java coordinate-system physics
edited Apr 28 at 21:37
200_success
127k15148411
127k15148411
asked Apr 28 at 20:58
geofflittle
825
825
bumped to the homepage by Community♦ 2 days ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
bumped to the homepage by Community♦ 2 days ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
0
down vote
I.
x(max - ((position + velocity) % max))
doesn't look quite right. % max
does not help here much (see below) it is better replaced with - max
, and thus the whole formula turns into 2 * max - (position + velocity)
.
II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity)
is always LE than max
?
add a comment |
up vote
0
down vote
I assume "next" in getNextPositionAndVelocity
means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.
As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:
public double getNextPositionAndVelocity(double position, double velocity, double max) {
double remainingDistance = Math.abs(velocity);
double currentVelocity = velocity;
double currentPosition = position;
while (remainingDistance > 0.0) {
double nextBoundary;
if (currentVelocity < 0.0) {
nextBoundary = 0.0;
} else {
assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
nextBoundary = max;
}
double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);
if (maximumDistanceToTravelInCurrentDirection <= remainingDistance) {
currentPosition = nextBoundary;
remainingDistance -= maximumDistanceToTravelInCurrentDirection;
currentVelocity *= -1;
} else {
currentPosition += remainingDistance * Math.signum(currentVelocity);
remainingDistance = 0;
}
}
return new double{currentPosition, currentVelocity};
}
Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.
The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.
Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position
lies within the permitted range), but also handling special cases like the infinities or Double.NaN
. E.g., if you check whether position >= 0 && position <= max
, then you automatically have NaN
covered for position
and max
, because the comparison operators and the equality operator ==
always return false
if one operand is NaN
(even Double.NaN == Double.NaN
returns false
, which is why there's a method Double.isNaN(double)
), but position
might still be Double.POSITIVE_INFINITY
if max
is also Double.POSITIVE_INFINITY
. Also, max
should probably be greater than 0
(which would not be covered by the aforementioned condition either).
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
I.
x(max - ((position + velocity) % max))
doesn't look quite right. % max
does not help here much (see below) it is better replaced with - max
, and thus the whole formula turns into 2 * max - (position + velocity)
.
II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity)
is always LE than max
?
add a comment |
up vote
0
down vote
I.
x(max - ((position + velocity) % max))
doesn't look quite right. % max
does not help here much (see below) it is better replaced with - max
, and thus the whole formula turns into 2 * max - (position + velocity)
.
II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity)
is always LE than max
?
add a comment |
up vote
0
down vote
up vote
0
down vote
I.
x(max - ((position + velocity) % max))
doesn't look quite right. % max
does not help here much (see below) it is better replaced with - max
, and thus the whole formula turns into 2 * max - (position + velocity)
.
II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity)
is always LE than max
?
I.
x(max - ((position + velocity) % max))
doesn't look quite right. % max
does not help here much (see below) it is better replaced with - max
, and thus the whole formula turns into 2 * max - (position + velocity)
.
II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity)
is always LE than max
?
answered Apr 28 at 22:30
bipll
5397
5397
add a comment |
add a comment |
up vote
0
down vote
I assume "next" in getNextPositionAndVelocity
means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.
As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:
public double getNextPositionAndVelocity(double position, double velocity, double max) {
double remainingDistance = Math.abs(velocity);
double currentVelocity = velocity;
double currentPosition = position;
while (remainingDistance > 0.0) {
double nextBoundary;
if (currentVelocity < 0.0) {
nextBoundary = 0.0;
} else {
assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
nextBoundary = max;
}
double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);
if (maximumDistanceToTravelInCurrentDirection <= remainingDistance) {
currentPosition = nextBoundary;
remainingDistance -= maximumDistanceToTravelInCurrentDirection;
currentVelocity *= -1;
} else {
currentPosition += remainingDistance * Math.signum(currentVelocity);
remainingDistance = 0;
}
}
return new double{currentPosition, currentVelocity};
}
Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.
The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.
Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position
lies within the permitted range), but also handling special cases like the infinities or Double.NaN
. E.g., if you check whether position >= 0 && position <= max
, then you automatically have NaN
covered for position
and max
, because the comparison operators and the equality operator ==
always return false
if one operand is NaN
(even Double.NaN == Double.NaN
returns false
, which is why there's a method Double.isNaN(double)
), but position
might still be Double.POSITIVE_INFINITY
if max
is also Double.POSITIVE_INFINITY
. Also, max
should probably be greater than 0
(which would not be covered by the aforementioned condition either).
add a comment |
up vote
0
down vote
I assume "next" in getNextPositionAndVelocity
means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.
As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:
public double getNextPositionAndVelocity(double position, double velocity, double max) {
double remainingDistance = Math.abs(velocity);
double currentVelocity = velocity;
double currentPosition = position;
while (remainingDistance > 0.0) {
double nextBoundary;
if (currentVelocity < 0.0) {
nextBoundary = 0.0;
} else {
assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
nextBoundary = max;
}
double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);
if (maximumDistanceToTravelInCurrentDirection <= remainingDistance) {
currentPosition = nextBoundary;
remainingDistance -= maximumDistanceToTravelInCurrentDirection;
currentVelocity *= -1;
} else {
currentPosition += remainingDistance * Math.signum(currentVelocity);
remainingDistance = 0;
}
}
return new double{currentPosition, currentVelocity};
}
Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.
The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.
Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position
lies within the permitted range), but also handling special cases like the infinities or Double.NaN
. E.g., if you check whether position >= 0 && position <= max
, then you automatically have NaN
covered for position
and max
, because the comparison operators and the equality operator ==
always return false
if one operand is NaN
(even Double.NaN == Double.NaN
returns false
, which is why there's a method Double.isNaN(double)
), but position
might still be Double.POSITIVE_INFINITY
if max
is also Double.POSITIVE_INFINITY
. Also, max
should probably be greater than 0
(which would not be covered by the aforementioned condition either).
add a comment |
up vote
0
down vote
up vote
0
down vote
I assume "next" in getNextPositionAndVelocity
means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.
As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:
public double getNextPositionAndVelocity(double position, double velocity, double max) {
double remainingDistance = Math.abs(velocity);
double currentVelocity = velocity;
double currentPosition = position;
while (remainingDistance > 0.0) {
double nextBoundary;
if (currentVelocity < 0.0) {
nextBoundary = 0.0;
} else {
assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
nextBoundary = max;
}
double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);
if (maximumDistanceToTravelInCurrentDirection <= remainingDistance) {
currentPosition = nextBoundary;
remainingDistance -= maximumDistanceToTravelInCurrentDirection;
currentVelocity *= -1;
} else {
currentPosition += remainingDistance * Math.signum(currentVelocity);
remainingDistance = 0;
}
}
return new double{currentPosition, currentVelocity};
}
Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.
The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.
Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position
lies within the permitted range), but also handling special cases like the infinities or Double.NaN
. E.g., if you check whether position >= 0 && position <= max
, then you automatically have NaN
covered for position
and max
, because the comparison operators and the equality operator ==
always return false
if one operand is NaN
(even Double.NaN == Double.NaN
returns false
, which is why there's a method Double.isNaN(double)
), but position
might still be Double.POSITIVE_INFINITY
if max
is also Double.POSITIVE_INFINITY
. Also, max
should probably be greater than 0
(which would not be covered by the aforementioned condition either).
I assume "next" in getNextPositionAndVelocity
means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.
As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:
public double getNextPositionAndVelocity(double position, double velocity, double max) {
double remainingDistance = Math.abs(velocity);
double currentVelocity = velocity;
double currentPosition = position;
while (remainingDistance > 0.0) {
double nextBoundary;
if (currentVelocity < 0.0) {
nextBoundary = 0.0;
} else {
assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
nextBoundary = max;
}
double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);
if (maximumDistanceToTravelInCurrentDirection <= remainingDistance) {
currentPosition = nextBoundary;
remainingDistance -= maximumDistanceToTravelInCurrentDirection;
currentVelocity *= -1;
} else {
currentPosition += remainingDistance * Math.signum(currentVelocity);
remainingDistance = 0;
}
}
return new double{currentPosition, currentVelocity};
}
Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.
The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.
Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position
lies within the permitted range), but also handling special cases like the infinities or Double.NaN
. E.g., if you check whether position >= 0 && position <= max
, then you automatically have NaN
covered for position
and max
, because the comparison operators and the equality operator ==
always return false
if one operand is NaN
(even Double.NaN == Double.NaN
returns false
, which is why there's a method Double.isNaN(double)
), but position
might still be Double.POSITIVE_INFINITY
if max
is also Double.POSITIVE_INFINITY
. Also, max
should probably be greater than 0
(which would not be covered by the aforementioned condition either).
answered Apr 28 at 23:13
Stingy
1,913212
1,913212
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193165%2fcalculate-next-position-and-velocity-after-bounce%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown