Basically, I have an angle that can only change a certain "turn radius" (say, 60/256 of a rotation) each time it updates. It is changed by an input angle that could be any angle. I need to clamp this input angle so that if it is outside of the turn radius, it will go to the nearest valid angle
For example:
Turn radius: 4°
Original angle = 0°
Input angle = 180.01°
Output angle = -4° or 356° (actual output should be within [0, 360) of course)
or
Turn radius: 4°
Original angle = 0°
Input angle = 179.99°
Output angle = 4°
or
Turn radius: 4°
Original angle = 45°
Input angle = 46°
Output angle = 46°
I am not sure exactly how to properly wrap the angle, so I'm a bit stuck here.
First, find the difference between the original angle and the input angle. (Just subtract.)
Then, "normalize" this difference to between -180 degrees and 180 degrees.
normalized_difference = (((( raw_difference % 360) + 540) % 360) - 180)
Then, if the "normalized" difference is outside the desired range, change it to be within range. Then add the (possibly changed) normalized difference to the original angle to get the output angle. If you wish to normalize the output angle to between 0 degrees and 359.99... degrees, you can do it thus:
normalized_angle = (((raw_angle % 360) + 360) % 360)
Based on #robert-lozyniak's answer, this is what I ended up with:
fn clamp_angle_update(angle: u8, target: u8, limit: u8) -> u8 {
let mut difference = target as isize - angle as isize;
// normalize the difference
difference += 256 + 256 / 2;
difference %= 256;
difference -= 256 / 2;
let limit = limit as isize;
difference = if difference > limit {
limit
} else if difference < -limit {
-limit
} else { difference };
// add the difference to the original angle
let mut angle = angle as isize + difference;
// normalize the angle
angle %= 256;
angle += 256;
angle %= 256;
angle as u8
}
Related
Given a Player.X and Player.Y, and a Unit.X and Unit.Y, what is the formula to calculate the proper amount in radians to face the player towards, so that the player is facing directly towards the units x,y position..
Minimum radians is 0, maximum radains is ~6.3(360 degrees) for radians in the game I am modding in C++.
Example:
Player.x = -9000
Player.y = -150
Unit.x = -8950
Unit.y = -132
I am not great at math, so thank you in advance!
If you use std::atan2 from <cmath>, then you might be able to do something like:
template <typename P, typename U>
double delta_theta(P p, U u) {
auto delta = std::atan2(u.y, u.x) - std::atan2(p.y, p.x);
if (delta > M_PI) return delta - 2*M_PI;
if (delta < -M_PI) return return delta + 2*M_PI;
return delta;
}
This generally returns positive if u is to the left (turn counter-clockwise) and negative if u is to the right (turn clockwise).
For example, I have an angle with value 350 degree, and I want to constraint it in a range with max positive offset of 30 and a max negative offset of 40.
As a result, the angle value should be in a range of (310, 360) and (0, 20). If the computed angle value is 304, the angle value should be constrainted to 310, and if the computed angle value is 30, the angle value should be constrainted to 20.
I have already implemented a method, but it's not efficient enough(Most of the effort is to solve the issue when the angle value is near 360~0 ). What is the fast way to achieve this please?
Function:
// All values are in the range [0.0f, 360.0f]
// Output: the angle value after constraint.
float _KeepAngleValueBetween(float originalAngle, float currentAngle, float MaxPositiveOffset, float MaxNegativeOffset).
For example:
KeepAngleValueBetween(350.0f, 302.0f, 30.0f, 40.0f)
result: 310.0f
KeepAngleValueBetween(350.0f, 40.0f, 30.0f, 40.0f)
result: 20.0f
KeepAngleValueBetween(140.0f, 190.0f, 45.0f, 40.0f)
result: 185.0f
I couldn't come up with a solution that doesn't use if. Anyway, I handle the problem around 0/360 by translating the values before checking if currentAngle is in the desired range.
Pseudo code (Ok, it's C. It is also valid Java. And C++.):
float _KeepAngleValueBetween(float originalAngle, float currentAngle, float MaxPositiveOffset, float MaxNegativeOffset) {
// Translate so that the undesirable range starts at 0.
float translateBy = originalAngle + MaxPositiveOffset;
float result = currentAngle - translateBy + 720f;
result -= ((int)result/360) * 360;
float undesiredRange = 360f - MaxNegativeOffset - MaxPositiveOffset;
if (result >= undesiredRange) {
// No adjustment needed
return currentAngle;
}
// Perform adjustment
if (result * 2 < undesiredRange) {
// Return the upper limit because it is closer.
result = currentAngle + MaxPositiveOffset;
} else {
// Return the lower limit
result = currentAngle - MaxNegativeOffset + 360f;
}
// Translate to the range 0-360.
result -= ((int)result)/360 * 360;
return result;
}
I have an interesting mathematical problem that I just cant figure out.
I am building a watch face for android wear and need to work out the angle of rotation for the hands based on the time.
Ordinarily this would be simple but here's the kicker: the hands are not central on the clock.
Lets say I have a clock face that measures 10,10
My minute hand pivot point resides at 6,6 (bottom left being 0,0) and my hour hand resides at 4,4.
How would I work out the angle at any given minute such that the point always points at the correct minute?
Thanks
Ok, with the help Nico's answer I've manage to make tweaks and get a working example.
The main changes that needed to be incorporated were changing the order of inputs to the atan calculation as well as making tweaks because of android's insistence to do coordinate systems upside down.
Please see my code below.
//minutes hand rotation calculation
int minute = mCalendar.get(Calendar.MINUTE);
float minutePivotX = mCenterX+minuteOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float minutePivotY = mWidth - mCenterY - minuteOffsetY;
//calculate target position
double minuteTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(minute * 6));
double minuteTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(minute * 6));
//calculate the direction vector from the hand's pivot to the target
double minuteDirectionX = minuteTargetX - minutePivotX;
double minuteDirectionY = minuteTargetY - minutePivotY;
//calculate the angle
float minutesRotation = (float)Math.atan2(minuteDirectionY,minuteDirectionX );
minutesRotation = (float)(minutesRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
minutesRotation = minutesRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (minutesRotation < 0)
{
minutesRotation = (minutesRotation+360);
}
//hours rotation calculations
float hour = mCalendar.get(Calendar.HOUR);
float minutePercentOfHour = (minute/60.0f);
hour = hour+minutePercentOfHour;
float hourPivotX = mCenterX+hourOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float hourPivotY = mWidth - mCenterY - hourOffsetY;
//calculate target position
double hourTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(hour * 30));
double hourTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(hour * 30));
//calculate the direction vector from the hand's pivot to the target
double hourDirectionX = hourTargetX - hourPivotX;
double hourDirectionY = hourTargetY - hourPivotY;
//calculate the angle
float hoursRotation = (float)Math.atan2(hourDirectionY,hourDirectionX );
hoursRotation = (float)(hoursRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
hoursRotation = hoursRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (hoursRotation < 0)
{
hoursRotation = (hoursRotation+360);
}
This also included a small helper function:
public double ConvertToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
Thanks for your help all
Just calculate the angle based on the direction vector.
First, calculate the target position. For the minute hand, this could be:
targetX = radius * sin(2 * Pi / 60 * minutes)
targetY = radius * cos(2 * Pi / 60 * minutes)
Then calculate the direction vector from the hand's pivot to the target:
directionX = targetX - pivotX
directionY = targetY - pivotY
And calculate the angle:
angle = atan2(directionX, directionY)
I would like to know how to move an object from pointA towards pointB by a small distance.
I know how it's done in 2d, but 3d is definitely a little different.
Here is some code of how i do it in 2D.
Vector pointA = ccp(1,1);
Vector pointB = ccp(10,10);
//find angle between the two points
float diffX = pointA.x - pointB.x;
float diffY = pointA.y - pointB.y;
float angle = atan2f(diffX, diffZ);
angle -= CC_DEGREES_TO_RADIANS(90);
float dis = 1.5;//how far away this should extend from the last particle
float x = -cosf(angle)*dis;
float y = sinf(angle)*dis;
object.position = ccp(object.position.x+x,object.position.y+y);
With that code i can successfully move an object by a distance of 1.5 towards pointB.
BUT i just can't find out how to do it with 3 dimensions.
So my question is how do i accomplish this in 3D?
Uh, I think you don't need to calculate angle.
Just normalize gap and move.
Vector pointA = Vector(1,1,1);
Vector pointB = Vector(10,10,10);
Vector gap = pointB - pointA;
// This code can occur division-by-zero error.
Vector dir = gap / sqrt(gap.x * gap.x + gap.y * gap.y + gap.z * gap.z);
float dist = 1.5;
object.position += dir * dist;
Background: I have a bird view's JavaScript game where the player controls a space ship by touching a circle -- e.g. touch to the left of the circle center, and the ship will move left, touch the top right and it will move to the top right and so on... the further away from the circle center of pseudo joystick, the more speed in that direction. However, I'm not directly adjusting the ship's speed, but rather set a targetSpeed.x and targetSpeed.y value, and the ship will then adjust its speed using something like:
if (this.speed.x < this.targetSpeed.x) {
this.speed.x += this.speedStep;
}
else if (this.speed.x > this.targetSpeed.x) {
this.speed.x -= this.speedStep;
}
... and the same for the y speed, and speedStep is a small value to make it smoother and not too abrupt (a ship shouldn't go from a fast leftwards direction to an immediate fast rightwards direction).
My question: Using above code, I believe however that the speed will be adjusted quicker in diagonal directions, and slower along the horizontal/ vertical lines. How do I correct this to have an equal target speed following?
Thanks so much for any help!
var xdiff = targetSpeed.x - speed.x;
var ydiff = targetSpeed.y - speed.y;
var angle = Math.atan2(ydiff, xdiff);
speed.x += speedStep * Math.cos(angle);
speed.y += speedStep * Math.sin(angle);
Assuming you already checked that the touch is inside the circle, and that the edge of the circle represents max speed, and that the center of the circle is circleTouch == [0, 0]
In some C++-like pseudo code:
Scalar circleRadius = ...;
Scalar maxSpeed = ...;
Scalar acceleration = ...;
Vector calculateTargetSpeed( Vector circleTouch ) {
Vector targetSpeed = maxSpeed * circleTouch / circleRadius;
return targetSpeed;
}
Vector calculateNewSpeed( Vector currentSpeed, Vector targetSpeed ) {
Vector speedDiff = targetSpeed - currentSpeed;
Vector newSpeed = currentSpeed + acceleration * normalized(speedDiff);
return newSpeed;
}
// Divide v by its length to get normalized vector (length 1) with same x/y ratio
Vector normalized( Vector v ) {
return v / length(v);
}
// Pythagoras for the length of v
Scalar length( Vector v ) {
Scalar length = sqrt(v.x * v.x + v.y * v.y); // or preferably hypot(v.x, v.y)
return length;
}
This is just off the top of my head, and i haven't tested it. The other answer is fine, i just wanted to give an answer without trigonometry functions. :)