I am working on some simulation software, in which I have an entity that is spiraling around a particular point.
As the entity starts spiraling around the point, and the radius of the spiral continues to grow, I want to display the number of circuits that the entity has completed to the user (completion of a circuit is defined as the location/ time at which the entity reaches the same angle from the origin that it was at when it started spiralling).
I also want to display to the user, the distance from the aircraft's current location to the point at which it will complete the current circuit.
I am doing this using the following section of code:
if (m_OVF_TURN_DIR == TURN_LEFT)
{
arcAngle = 360 - (NormalAngle360(NormalAngle360(ldFAZ_CentrePos_AC) + NormalAngle360(m_circuitStartAngle)));
m_SteerData.DistanceToGo = (arcAngle * PI * m_currentRadius);
}
else
{
arcAngle = 360 - (NormalAngle360(NormalAngle360(m_circuitStartAngle) + NormalAngle360(ldFAZ_CentrePos_AC)));
m_SteerData.DistanceToGo = ((arcAngle * PI * m_currentRadius) / 180.0); // Nm
}
In this code, the lines:
m_SteerData.DistanceToGo = (arcAngle * PI * m_currentRadius);
and
m_SteerData.DistanceToGo = ((arcAngle * PI * m_currentRadius) / 180.0);
are what is calculating the distance from the aircraft's current location to the point at which it will complete a circuit.
The first block is used to calculate the distance when the entity is spiraling in an anti-clockwise direction, and the second block is used when the entity is spiraling in a clockwise direction.
The clockwise direction seems to be working correctly- it displays a number for the distance to go, and this number decreases steadily as the entity follows the path of the spiral. However, the anti-clockwise direction seems to start at a random number, and then increase steadily as the entity follows the path of the spiral... rather than decrease as it should (because the entity is moving closer to the point at which the circuit will be completed).
This suggests to me that I am using an incorrect symbol somewhere in this block (+, -, * or /), but I can't seem to figure out where... Can anyone point me in the right direction?
The function NormalAngle360() is defined with:
double NormalAngle360(const double aInAngle)
{
//## Operation [c0b17aaa-bda1-4164-8ba7-5f960c924a32]
double ldAngle = NormalAngle(aInAngle);
if (ldAngle < 0.0)
ldAngle += 360.0;
return ldAngle;
//## Operation End
}
Since you normalize the angle such that it lies between 0 and 360, there should only be two possibilities. Either the angle starts at some value and decreases to 0, in which case
m_SteerData.DistanceToGo = (arcAngle/180 * PI * m_currentRadius);
should work, or the angle starts at some value and increases up to 360, in which case
m_SteerData.DistanceToGo = ((360 - arcAngle)/180 * PI * m_currentRadius);
should work.
It's possible that you can use the first version for both cases.
If both versions don't work, I think the angle is not what it should be. Maybe you could output the values of arcAngle to check that.
The lines in your if...else branches both do the same thing:
arcAngle = 360 - (NormalAngle360(NormalAngle360(ldFAZ_CentrePos_AC) + NormalAngle360(m_circuitStartAngle)));
arcAngle = 360 - (NormalAngle360(NormalAngle360(m_circuitStartAngle) + NormalAngle360(ldFAZ_CentrePos_AC)));
because 360 - (a+b) is the same as 360 - (b+a). You'll need to rethink this logic.
Also you do not need the two inner calls to NormalAngle360, the line could be written as:
arcAngle = 360 - NormalAngle360( ldLAZ_CentrePos_AC + m_circuitStartAngle );
Perhaps what you're looking for is just changing + to - here; and/or taking out the 360 -.
Also, the NormalAngle360 function should check if the angle >= 360.0 and subtract 360 from it.
I found the issue- the problem was that I had missed out a - sign from the function being called in the if clause of the statement:
if (m_OVF_TURN_DIR == TURN_LEFT)
{
arcAngle = 360 - fabs((NormalAngle360(-NormalAngle360(ldFAZ_CentrePos_AC) + NormalAngle360(m_circuitStartAngle))));
m_SteerData.DistanceToGo = (arcAngle/180 * PI * m_currentRadius);
}
Using `-NormalAngle360(...) in the innermost bracket here resolved the issue that I was having.
Related
I am trying to draw a clock face in which the second hand moves as the time changes.
I am using the following to calculate the points on my circle:
def points_on_circle():
global time, radius, centre, x, y
theta = time% math.pi * 2
c = math.cos(theta)
s = math.sin(theta)
x= centre[0] + radius * c
y =centre[1] + radius * s
return x,y
my timer 'ticks' every tenth second, the radius of my circle is 50, the centre is at (150,150) which is also the origin of my hand, the other end of the hand being (x,y) as calculated above. How do I calculate , I assume by multiplying time by some constant, how fast the x,y should change for this circle ( but for any circle) .
I am using CodeSkulptor from Coursera to try to do this ( the original assignment created a digital timer which I am done. This is not part of the homework ( yet??)
The hand rotates 2 Pi radians every 60 seconds. Assuming you're syncing with real time, time.time() will return the current time in seconds (and milliseconds which I suggest you ignore). If you take the time and first do numseconds = int(time.time()) % 60, you now need to translate that, which is a simple as numseconds * 2 * pi / 60. (Example: numseconds = 0, theta = 0, numseconds = 15, theta = pi /2 (90 degrees).
You will also need to play with your equations as normally theta=0 implies the line is horizontal pointing right (which would be numseconds = 15) and theta=Pi implies the line is vertical pointing up (which would be numseconds = 0)
I'm trying to to rotate a sprite, let's say it's a gun, to a point, by taking the smallest route possible on a 360° (right or left depending on what side the point is closer to) and I'm having a few problems.
On a circle, it jumps from 359° to 0° so I can't direcly use my target angle - current angle.
Leep in mind that I'm using SFML so it's executing the function everyframe while isRotating is true.
This is the information that is available to me :
//The angle in degrees of my sprite
float currentAngle = pSprite.getRotation();
//The angle is needs to be once the rotation is over
float targetAngle = float(atan2(deltaY,deltaX) * 180 / (atan(1)*4) + 180);
I'm using a speed variable to increment or decrement the value of the angle every frame.
distance = Speed*Time.asSeconds();
currentAngle += distance;
First, get the difference:
diff = target - current
diff is either the "short" angle (the one resulting in a shorter rotation), or the "long" angle (rotation in the other direction which is longer). Notice that:
you never need to rotate for more than (as an absolute value) 180 degrees to get from one angle to another.
the "short" angle and the "long" angle have opposite signs (+/-) and their absolute values add to 360.
Example: 0 - 359 = -359. This is the "long" angle. We know this because its absolute value is > 180. The "short" angle will have the opposite sign and its absolute value will add up to 360 with 359, so it is 1.
An easy way to calculate this is:
while (diff < -180)
diff += 360;
while (diff > 180)
diff -= 360;
diff is now the angle you are looking for. So if it is negative, multiply your Speed by -1.
The while (as opposed to if) is there in case the angles are not in [0, 360] - for example, you have current = 1440, target = 359.
Introducing:
I'm developing a little Tower defense game in opengl, currently I'm just despairing of a little problem....
I want the projectiles from the tower to aim with the head facing the unit. So my problem is more a mathmatical one but it belongs to opengl :)
I had the following idea; I could use a dot product to get an angle rotating around the x axis to get the head depending on the distance just straight down or flat to the ground and after that an additional angle to rotate around the y axis that the head of the arrow is everytime adjusted to the unit it's aiming on.
My code for the angle of rotation around the X axis (i called it m_fYNeigung because the height(Y) of the head changes by rotating around the x axis) looks like this:
plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_fYNeigung =
RADIANS_TO_DEGREES (acos ((float)
(
(faTowerPosition[0]) * (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[0]) +
(faTowerPosition[1] - 1) * (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[1]) +
(faTowerPosition[2]) * (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[2])
)
/
(
fabs (faTowerPosition[0]) * fabs (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[0]) +
fabs (faTowerPosition[1] - 1) * fabs (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[1]) +
fabs (faTowerPosition[2]) * fabs (plocalTowerArray[(sizeMapIndexY * 12) + sizeMapIndexX].Projektils[byteProjectilIndex].m_faProDirectionVector[2])
)
));
where faTowerPosition is the first vector, which is pointing down from the top of the tower (the arrow also starts at faTowerPosition[X/Y/Z]) the second vector for the dot product is m_faProDirectionVector which is a normalized direction vector describing the route of the arrow from the tower to the unit.
The Opengl Drawing part looks just as simple as this:
for (sizeJ = 0; sizeJ < localTowerArray[sizeI].m_byteProjectilAmount; sizeJ++)
{
if (localTowerArray[sizeI].Projektils[sizeJ].m_bOnFlight == true)
{
glPushMatrix();
glTranslatef (localTowerArray[sizeI].Projektils[sizeJ].m_faProPosition[0], localTowerArray[sizeI].Projektils[sizeJ].m_faProPosition[1], localTowerArray[sizeI].Projektils[sizeJ].m_faProPosition[2]);
//glRotatef (360.0f - localTowerArray[sizeI].Projektils[sizeJ].m_fXNeigung, 0, 1, 0);
glRotatef (localTowerArray[sizeI].Projektils[sizeJ].m_fYNeigung, 1, 0, 0);
DrawWaveFrontObject (m_pArrowProjektilObject);
glPopMatrix();
}
}
Just ignore the calculations I'm doing to the angle, I just did it to experiment with the acting of the arrows, i just noticed that it appears as would the arrow act different depending on the (i gotta say: the buildable map is scaled by x: -3.4 to 3.4 and z from 4 to -4) cords the tower was builded on -x/z,-z/x,z/x,-z/-x all these cases i guess are different and at least depending on the unit is running left or right side of the tower, the acting is also different.... so what i forgot to remind by using the dot product in this way?
First at all, your code is very difficult to understand, so I'm guessing a lot to try to answer you. If I assume something wrong, my apologize for it.
I am assuming that you want to use the euler angle rotation to align correctly your projectiles. So, first you will do a X rotation and after that, a Y rotation.
To do a X rotation, your vectors, for the dot product, must be on an YZ plane and assuming that your projectile start at Z direction, your first vector is (0, 0, 1). The second vector, as you said, is a vector pointing to unit and could be expressed by (px, py, pz). You must project this vector to the plane YZ to get the second vector for your dot product, so this vector will be (0, py, pz)
Now, to calculate the dot product you apply the following formule
x1.x2+y1.y2+z1.z2 = |p1|.|p2|.cos a, where |p1| and |p2| is the module of vector (its length)
In this example, the first vector is unitary, but the second not. So |p2| = sqrt(py^2 +pz^2). Thereafter:
acos(a) = pz/sqrt(py^2 + pz^2)
This will give you the angle around X axis. Do the same calculation to achieve Y angle rotation
PS. After I wrote this answer, I noted that you use the function "fabs". I guess you want to find the module of you second vector, but fabs give you the absolute value of a escalar. To calculate a module of a vector (its length) you need to use the above formulae as cited.
I need to quantize my vector and generate directional code words from 0 to 15. So I had implemented following code line using C++ to achieve that. Just pass 2 points and calculate atan() value using that points. But it's only return just 0 to 7. other values are not return. Also sometimes it's return very large numbers like 42345. How can I modify this to return directional code words from 0 to 15
double angle = abs(atan((acc.y - acc.lastY)/(acc.x - acc.lastX))/(20*3.14159/180));
That's what the std::atan2 function is for.
Since tan function is periodic over just half circle. Logically, if you negate both coordinates, the expression in the argument comes out the same, so you can't tell the two cases apart. So you have to first look at which quadrant you are in by checking the signs and than adding 180 if you are in the negative half-space. The std::atan2 function will do it for you.
double angle = std::atan2(acc.y - acc.lastY, acc.x - acc.lastX) * (8 / PI);
It has the added benefit of actually working when acc.x == acc.lastX, while your expression will signal division by zero.
Additionally, the use of abs is wrong. If you get angle between -π and π you want to get angle between 0 and 2π, you need to write:
double angle = std::atan2(acc.y - acc.lastY, acc.x - acc.lastX); // keep it in radians
if(angle < 0)
angle += 2 * PI;
return angle * (8 / PI); // convert to <0, 16)
With abs you are unifying the cases with oposite sign of y, but same x.
Additionally if you want to round the values so that 0 represents directions along x axis slightly off to either side, you'll need to modify the rounding by adding half of the interval width and you'll have to do before normalizing to the ⟨0, 2π) range. You'd start with:
double angle = std::atan2(acc.y - acc.lastY, acc.x - acc.lastX) + PI/16;
I want to ask what would be the best formula to convert mouse X,Y position into one of 16 directiones from player position.
I work in c++ ,sfml 1.6 so I get every position easily, but I dont know how to convert them based on angle from player position or something. (I was never good on math and for more than 4 directions if statements looks too complex).
Also I want to send it to server which converts direction back into delta X,Y so he can do something like:
player.Move(deltaX * speed * GetElapsedTime(), ...Y);
The "easiest" way would be to convert your two sets of co-ordinates (one for current player position, one for current mouse position) into an angle relative to the player's position, where an angle of 0 is the line straight ahead of the player (or north, depending on how your game works). Then each of your sixteen directions would translate to a given 22.5 degree interval.
However, since you said you're bad at math, I imagine you're looking for something more concrete than that.
You could use atan2 to get the angle between the mouse position and the positive X axis:
#include <cmath>
float player_x = ...;
float player_y = ...;
float mouse_x = ...;
float mouse_y = ...;
float angle = std::atan2(mouse_y - player_y, mouse_x - player_x);
The angle returned by std::atan2() is a value between -M_PI (exclusive) and M_PI (inclusive):
-M_PI Left (-180°)
-0.5 * M_PI Down (-90°)
0 Right (0°)
0.5 * M_PI Up (90°)
M_PI Left (180°)
You can transform this value depending on how you want your mapping to "one of 16 directions", i.e., depending on what value you want to assign to which discrete direction.
Given the angle, getting a unit vector to represent the X/Y delta is quite easy, too:
float dx = std::cos(angle);
float dy = std::sin(angle);