Vector Quantizitation to directional code words - c++

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 &langle;0, 2π) range. You'd start with:
double angle = std::atan2(acc.y - acc.lastY, acc.x - acc.lastX) + PI/16;

Related

Compute integer bounds to include scaled floating point values

I am trying to compute integer array bounds that will include floating point limits divided by a scale. For example, if my origin is 0, my floating point maximum is 10 then my integer array bounds need to be 2. The obvious formula is to divide my bounds by the scale, giving the incorrect result of 1.
I need to divide the inclusive maximum values by the scale and add one if the division is an exact multiple.
I am running into a mismatch between the normal way to define and use integer array indexes and my desired way to use real value coordinates. I am trying to map inclusive real value coordinates into integer array indexes, using a scaling term.
(I am actually working with two dimensional maps, but the problem can be expressed more simply in one dimension.)
This is wrong:
int get_array_size(double, scale, double maximum)
{
return std::ceil(maximum / scale); // Fails on exact multiples
}
This is wasteful:
int get_array_size(double, scale, double maximum)
{
return 1 + std::ceil(maximum / scale); // Allocates extra array memory
}
This is ugly and I am not sure if it is correct:
int get_array_size(double, scale, double maximum)
{
if (maximum % scale == 0) // I am not sure if this is correct
return 1 + std::ceil(maximum / scale);
else
return std::ceil(maximum / scale); // Maybe I can eliminate the call to std::ceil?
}
I am trying to get the value maximum / scale on every open ended interval ending at multiples of scale and 1 + maximum / scale on every interval from >= multiple of scale ending at < multiple of scale + 1. I am not sure how to correctly express this in mathematical terms or how to implement it in c++. I would be grateful if someone can clarify my understand and point me in the right direction.
Mathematically I think I am trying to define f(x, s) = y s.t. if s * n <= x and x < s * (n + 1) then y = n + 1. I want to implement this efficiently and respect the difference between <= and < comparison.
The way I interpret this question, I think maximum and scale don't actually matter - what you are really asking about is how to correctly map from floats to ints with specific boundary conditions. For example [0.0, 1.0) to 0, [1.0, 2.0) to 1, etc. So the question becomes a bit simpler if we just consider maximum / scale to be a single quantity; I'll call it t.
I believe you actually want to use std::floor instead of std::ceil:
int scaled_coord_to_index(float t) {
return std::floor(t);
}
And the size of your array should always be the maximum scaled coordinate + 1 (with negative values normalized to start at 0).
int array_size(float min_t, float max_t) {
// NOTE: This will "anchor" your coords based on the most negative value.
// e.g. if that value is 1.6, then your bins will be [1.6, 2.6), [2.6, 3.6), etc.
// To change that behavior you could use std::floor(min_t) instead.
return scaled_coord_to_index(max_t - min_t) + 1;
}

Variable increasing in value rather than decreasing

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.

fastest way to compute angle with x-axis

What is the fastest way to calculate angle between a line and the x-axis?
I need to define a function, which is Injective at the PI:2PI interval (I have to angle between point which is the uppermost point and any point below).
PointType * top = UPPERMOST_POINT;
PointType * targ = TARGET_POINT;
double targetVectorX = targ->x - top->x;
double targetVectorY = targ->y - top->y;
first try
//#1
double magnitudeTarVec = sqrt(targetVectorX*targetVectorX + targetVectorY*targetVectorY);
angle = tarX / magTar;
second try
//#2 slower
angle = atan2(targetVectorY, targetVectorX);
I do not need the angle directly (radians or degrees), just any value is fine as far as by comparing these values of this kind from 2 points I can tell which angle is bigger. (for example angle in example one is between -1 and 1 (it is cosine argument))
Check for y being zero as atan2 does; then The quotient x/y will be plenty fine. (assuming I understand you correctly).
I just wrote Fastest way to sort vectors by angle without actually computing that angle about the general question of finding functions monotonic in the angle, without any code or connections to C++ or the likes. Based on the currently accepted answer there I'd now suggest
double angle = copysign( // magnitude of first argument with sign of second
1. - targetVectorX/(fabs(targetVectorX) + fabs(targetVectorY)),
targetVectorY);
The great benefit compared to the currently accepted answer here is the fact that you won't have to worry about infinite values, since all non-zero vectors (i.e. targetVectorX and targetVectorY are not both equal to zero at the same time) will result in finite pseudoangle values. The resulting pseudoangles will be in the range [−2 … 2] for real angles [−π … π], so the signs and the discontinuity are just like you'd get them from atan2.

Convert Mouse pos into direction and back

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);

Drawing lines at increasing angles

I'm not very good at math or geometry, but I want to draw some line segments at increasing angles. What I want to draw is something like when you hold your hand up and spread your fingers apart: lines that start at a common point and expand out at angles that have an equal difference between them.
I have tried this:
len = 300;
angle = 10;
for (i = 0; i <= 5; ++i) {
endPointX = 50 + len * Math.cos(angle);
endPointY = 50 + len * Math.tan(angle);
draw.Line(50, 50, endPointX, endPointY);
angle += 10;
}
However, that's totally wrong and produces something like this
http://i.stack.imgur.com/taX40.png
But I want something like this (bad mspaint, sorry):
http://i.stack.imgur.com/8xfpp.png
What's the right math for this?
There are two separate issues in your question, I will cover each.
Here's an ASCII picture of your situation:
B
+
/|
/ |
/ |
/ |
len / | y
/ |
/ |
/ |
/ __|
/ θ | |
+----------+
A x C
This is a right triangle. It has three sides:
The diagonal side in the picture opposite to the 90° angle is called the hypotenuse and has a length len. The hypotenuse is what you're trying to draw.
The vertical side is the side opposite to the angle θ and has a length y.
The horizontal side is the side adjacent to the angle θ and has a length x.
Given the above illustration the following equations are true:
cos(θ) = x/len
sin(θ) = y/len
These equations are another way of saying:
The cosine of an angle is equal to the length of the adjacent side divided by the length of the hypotenuse.
The sine of an angle is equal to the length of the opposite side divided by the length of the hypotenuse.
When solving the equation for x and y, you get:
x = len * cos(θ)
y = len * sin(θ)
So you want sin() and cos(), not cos() and tan(). If the point A is not at the origin, you would need to offset x and y by addition, like so:
x = len * cos(θ) + 50
y = len * sin(θ) + 50
With the values for x and y, you can find the coordinates for point B on the triangle, and thus be able to draw your lines.
Also, assuming you're programming in Java, the trigonometric functions in the Math class expect the angle in radians, not degrees. Lots of programming languages that provides trigonometric functions are like this.
Radians and degrees measure the same thing, but a complete rotation in degrees goes from 0 to 360° while a complete rotation in radians go from 0 to 2π.
To convert angles in degrees to radians, multiply the angle by π/180. In Java, the constant π is provided by Math.PI.
For example, an angle of 10° degrees is equivalent to 10 * π/180, or π/18 radians.
Firstly, you want cos and sin, not cos and tan.
Secondly, most maths libraries perform trigonometric functions in radians, not degrees. So 10 is a very large difference indeed! To convert from degrees to radians, multiply by (pi/180).
You shouldn't be using tan, but sin. If I remember correctly, it should be something like:
Math.cos(angle/180);
-Math.sin(angle/180);
The negative on sin is important.
The reason you are getting uneven looking angles is that every time you add 10 you're actually spinning the line around the circle 1.6 times.
The math functions expect angles to be in radians, not degrees.
360 degrees = 2*Math.PI radians.
Instead of 10, write "2*Math.PI/36.0"
Also, use sin instead of tan.