Difference in two angles in radians? - c#

I have a simple chart whereby the user can determine a start & end direction in radians. The control then draws the chart using an override of OnRender. I am drawing the arcs with StreamGeometryContext.ArcTo. This method has an IsLargeArc property which determines how the arc is drawn (true for > 180 degrees (PI), false for < 180 degrees). I am determining this value from a condition which works fine:
//Rule does not exceed 180 degrees in direction (radian), IsLargeArc= False else true
if (Start < Math.PI && (End - Start) < Math.PI || //currently unknow condition in here to deal with < PI when start angle is > then end angle?)
{
//IsLargeArc = false;
}
else
{
//IsLargeArc= true;
}
The issue comes when the start < end. e.g. From 270 degrees to 120 degrees. I need a condition to satisfy an angle over 180 degrees (PI) in this situation. Maths is not my strong point. I think I need to add PI*2 to the end and then somehow compare the two values but not sure on how to achieve this?

Well, you could add a full circle to the end, (or start; according to the direction) angle e.g.:
if (start < end)
start += 2 * Math.PI; //full circle in radians.
This way you'll add a full circle to the end angle, which doesn't change the position for your drawing and results in a valid and correct angle if you subtract them (start - end).
Although I must say, I would expect a start > endcondition.
If start > end or visa versa, than this tells you something about the direction.

You can use Math.Abs method to get the absolute value of the difference.
Your code might look like the following:
if ((Start < Math.PI && Math.Abs(End - Start) < Math.PI) ||
(Start > Math.PI && End - Start < 0 ))
{
//IsLargeArc = false;
}
else
{
//IsLargeArc= true;
}

private bool IsLargeArc(Styled2DRange range)
{
double angleDiff = GetPositiveAngleDifference(End - Start);
if (angleDiff > Math.PI)
{
return true;
}
return false;
}
private double GetPositiveAngleDifference(double angleDiff)
{
return (angleDiff + (2*Math.PI))%(2*Math.PI);
}

Related

Counting Rotations [Unity C#]

Trying to figure out a way to increment the rotation count after the spinner passes 360 degrees. Though this never works because eulerAngles reset at 360. What's a good way to do this? I tried doing > 355, but that is't a great solution.
Spinner.transform.Rotate(0, 0, speed);
float angleZ = Spinner.rotation.eulerAngles.z;
if (angleZ > 360)
{
Rotations++;
}
You would need to check the angle before & after the rotation.
According to the documentation "speed" is the number of degrees to rotate, so add the integer division of speed by 360 to Rotations & then check for the final value having been reset.
float angleZ1 = Spinner.rotation.eulerAngles.z;
Spinner.transform.Rotate(0, 0, speed);
float angleZ2 = Spinner.rotation.eulerAngles.z;
float angleZDiff = angleZ2 - angleZ1;
Rotations += (int)(speed / 360);
if ((speed >0) && (angleZDiff < 0))
Rotations++
else if ((speed < 0) && (angleZDiff > 0))
Rotations--;
You can divide the angle by 360 and cast it to an int to get the number of rotations.
Rotations = (int)(angle / 360f);
You could add two colliders at varying distances then the collision check points will give extra data points that are correct regardless of the speed

MathHelper.WrapAngle() rotation issue

My game involves ships moving and rotating around a target (i.e., an enemy ship). Rotation depends on whether the user wants to rotate by port/starboard, or just by the closest side to the enemy.
The problem:
The angles are being wrapped with MathHelper.WrapAngle(). Keeping the angles between PI and -PI works great, until the rotating ship gets to the point where -3.141 becomes 3.141 (and vice versa). For example, the ship is rotating to port correctly, then when it hits this line it flips over starboard, then back to port again, then starboard again and so on!
I would be very grateful if the community could point out:
What I can do to make the ship rotate logic work correctly when going over the PI/-PI wrap 'barrier'
Point out any inefficiencies in my code (I'm sure there are many, and I'm sure there are many other ways to do this more efficiently)
Link to any relevant articles or tutorials that can help me overcome this issue (this is my first game)
Additional Information:
Ship.ShipMoveState.NoMoveRotate is essentially a flag that tells the ship to rotate (starting at 100th of max speed up until we hit max speed) either port or starboard, whichever is closest. The ship rotates to these sides as that is where the weapons are located. ShipMoveState.AwaitFurtherOrders is tells the ship to rotate depending on the difference in angle between closest side (port/starboard) and angle to enemy.
ShipCompartment primeCompartment = TargetShip.CenterCompartment;
if (FireState == ShipFireState.FireAtTarget)
primeCompartment = TargetCompartment;
// If ship is to the left of target, below will work
Vector2 distanceToDestination = primeCompartment.Position - CenterCompartment.Position;
float angleToEnemy = (float)Math.Atan2(distanceToDestination.Y, distanceToDestination.X);
angleToEnemy = MathHelper.WrapAngle(angleToEnemy);
CenterCompartment.Rotation = MathHelper.WrapAngle(CenterCompartment.Rotation);
float portBatteryAngle = MathHelper.WrapAngle(CenterCompartment.Rotation - Helpers.RightAngle);
float starboardBatteryAngle = MathHelper.WrapAngle(CenterCompartment.Rotation + Helpers.RightAngle);
float allowance = 0.005f;
bool portIsClosest = false;
switch (primaryFacing)
{
case PreferredFacing.None:
// If port battery not facing enemy
if (angleToEnemy > (MathHelper.WrapAngle(portBatteryAngle + allowance))
|| angleToEnemy < (MathHelper.WrapAngle(portBatteryAngle - allowance)))
{
// And starboard battery not facing either
if (angleToEnemy > (MathHelper.WrapAngle(starboardBatteryAngle + allowance))
|| angleToEnemy < (MathHelper.WrapAngle(starboardBatteryAngle - allowance)))
MoveState = Ship.ShipMoveState.NoMoveRotate;
else
MoveState = ShipMoveState.AwaitFurtherOrders;
}
else
{
portIsClosest = true;
MoveState = ShipMoveState.AwaitFurtherOrders;
}
if (MoveState == ShipMoveState.AwaitFurtherOrders)
{
float diff = 0f;
if (portIsClosest)
diff = angleToEnemy - portBatteryAngle;
else
diff = angleToEnemy - starboardBatteryAngle;
RotateShip(diff);
}
else if (MoveState == Ship.ShipMoveState.NoMoveRotate)
{
// Turn to port (if target is between 6 and 9 o'clock)
if (angleToEnemy < portBatteryAngle)
RotateShip(-MaxRotation / 100);
// Turn to starboard (if target is between 3 and 6 o'clock)
else if (angleToEnemy > starboardBatteryAngle)
RotateShip(MaxRotation / 100);
else
{
if (angleToEnemy > portBatteryAngle && angleToEnemy < starboardBatteryAngle)
{
// Turn to starboard (if target is between 9 and 12 o'clock)
if (angleToEnemy < CenterCompartment.Rotation)
RotateShip(MaxRotation / 100);
// Turn to port (if target is between 12 and 3 o'clock)
else
RotateShip(-MaxRotation / 100);
}
}
}
break;
}
Please let me know if you require any further information. Thank you very much for your assistance.
Instead of, for instance,
a < wrap(b-c)
use
0 < wrap(b-c-a)
or
0 > wrap(a-b+c)
This makes it a little less readable, but is the correct way to compare (supposedly small) angle differences.

Method to 'rock' a value back and forth

I'm working on a small game, I have objects which I want to elevate up and down. Object moves to max value of Y -> Object moves to min value of Y -> Repeat. I have a rough idea of how to do this, I would put this in a timer/my update method.
if(Y >= max)
{
direction = "down";
}
if(y =< min)
{
direction = "up";
}
if(direction == "up") Y -= speed;
if(direction == "down") Y += speed;
(Could also use a bool ofcourse but, for the sake of implicity)
But it feels like I'm just re-inventing the wheel, is there by any chance a built in method/math function to do this automatically? eg. SomeFunction(min, max, increment).
I'm using the XNA framework, so functions built into that are ofcourse welcome as well.
Forget having a separate direction flag.
Just use a negative speed for "up" to simplify the code:
if ((Y >= max) || (Y <= min)) // Hit an edge?
speed = -speed; // Reverse direction.
Y += speed;

Randomly pick two numbers in a range so that the sum of their squares is constant

I'm currently developing a 2-player Ping-Pong game (in 2D - real simple) from scratch, and it's going good. However Theres a problem I just can't seem to solve - I'm not sure if this should be located here or on MathExchange - anyway here goes.
Initially the ball should be located in the center of the canvas. When pressing a button the ball should be fired off in a completely random direction - but always with the same velocity.
The Ball object has (simplified) 4 fields - The position in X and Y, and the velocity in X and Y. This makes it simple to bounce the ball off the walls when it hits, simple by inverting the velocities.
public void Move()
{
if (X - Radius < 0 || X + Radius > GameWidth)
{
XVelocity = -XVelocity;
}
if (Y - Radius < 0 || Y + Radius > GameHeight)
{
YVelocity = -YVelocity;
}
X+= XVelocity;
Y+= YVelocity;
}
I figured the velocity should be the same in each game, so I figures I would use Pythagoras - the square of the two velocities should always be the same.
SO for the question:
Is there a way to randomly select two numbers (doubles) such that the sum of their squares is always a specific number - more formally:
double x = RandomDouble();
double y = RandomDouble();
if (x^2 + y^2 = 16) {/* should always be true */ }
Any help appreciated :)
Randomly pick an angle theta and multiply that by the magnitude of the distance d you want. Something like:
double theta = rand.NextDouble() * 2.0 * Math.PI;
double x = d * Math.Cos(theta);
double y = d * Math.Sin(theta);
If the constant is C, pick a number x between 0 and sqrt(C).
Solve for the other number y using simple algebra.
why not try this:
double x = RandomDouble();
double y = square(16-x^2);
as your application allow double type.
does this solve your problem?
if not, please let me know

Problem with bounds of an angle

Heads up: Even though this problem arose while I was working with Unity, it has nothing specific to Unity, and is more about programming logic, so please don't shy away.
I'm using Unity and rotating an object by script. The thing is, if I rotate it to, say, 180 degrees, the object does not rotate exactly to that much and tends to stop at between 179 and 181 degrees. So, to check if rotation is complete I check if the rotation angle is targetAngle +/- 1, which works.
I check using
if (transform.eulerAngles.z > lowerLimit && transform.eulerAngles.z < upperLimit)
where
lowerLimit = targetAngle-1;
upperLimit = targetAngle + 1;
Now, the problem arises when the targetAngle is 0. In this case, my script checks if rotation angle is between -1 and 1. But, -1 should really be 359, so it needs to check if the angle lies between 359 and 1.
How can I implement this?
In other words, I guess I'm asking how to implement a wrap-around number system.
EDIT
Found one work-around. If targetAngle is 0, I treat is specially. It works, but isn't the most elegant.
if (targetAngle == 0.0)
{
if ((transform.eulerAngles.z > 359.0 && transform.eulerAngles.z <= 360.0) || (transform.eulerAngles.z >= 0.0 && transform.eulerAngles.z <= 1))
{
rotate = false;
}
}
else
{
if (transform.eulerAngles.z > targetAngle - 1 && transform.eulerAngles.z < targetAngle + 1)
{
rotate = false;
}
}
You could do ...
lowerLimit = (targetAngle % 360) + 359; //360 - 1;
upperLimit = (targetAngle % 360) + 361; //360 + 1;
if (((transform.eulerAngles.z + 360) % 360) > lowerLimit
&& ((transform.eulerAngles.z + 360) % 360) < upperLimit)
This moves the check away from the zero and you wouldn't have to deal with positive/negative checking.
EDIT
The % operator on the targetAngle restricts the rotating to +/-359 degrees, so a target angle of 721 would come down to 1, and a target angle of -359 would come down to 1. This should do nicely for all cases I think.
EDIT 2
To fix the last case you mentioned in your comment, I guess you'd need to apply the same wrapping logic to your transform.eulerAngles.z values. Probably best to put this wrapping in an extra function now, so try this:
int wrapNumber(int input) // replace int with whatever your type is
{
// this will always return an angle between 0 and 360:
// the inner % 360 restricts everything to +/- 360
// +360 moves negative values to the positive range, and positive ones to > 360
// the final % 360 caps everything to 0...360
return ((input % 360) + 360) % 360;
}
lowerLimit = wrapNumber(targetAngle) + 359; //360 - 1;
upperLimit = wrapNumber(targetAngle) + 361; //360 + 1;
if (wrapNumber(transform.eulerAngles.z) + 360 > lowerLimit
&& wrapNumber(transform.eulerAngles.z) + 360 < upperLimit)
Depending on how often you need to use this, checking for some cases might remove unneeded overhead. For example, the final % 360 within wrapNumber is only needed if the input was positive. If you're calling this ten times per minute it probably won't matter. If you're calling it a hundred times per second, you may want to check how it performs in this situation.
This may be an old thread but after looking at many different snippets all trying to deal with Wrapping I found that Unity has a nice builtin function that simply takes care of business, At least in my case that the end result i required was a lerp so i only had to change it to LerpAngle and it returned a solid result.
Mathf.LerpAngle is your friend.. solved all my issues with popping etc..
http://docs.unity3d.com/ScriptReference/Mathf.LerpAngle.html

Categories