I have this sensor fused data coming from a GYRO-ACC-MAG-hardware sensor.
It's data (YAW-PITCH-ROLL) goes from -180 to +180 or -90 to +90
Which algorithm helps me offset this to an arbitrary position and also have no sign change to minus?
What I mean is: -180 to +180 for instance leads to 0 to 359. And I want 0 not where 0 of the sensor is but also offset to a certain position. In other words, picture a circle. Now put a zero at an arbitrary position on that circle. Now rotate that circle around it's center point. The zero rotates along, so it is now at a different position than it was before, right? That's the idea.
What I did:
YAW + 180 leads to 0 to 359. Pitch + 90 leads to 0 to 179. Roll + 180 leads to 0 to 359.
If I understand you correctly, you want to make use of the modulo operator:
double YAW360 = (YAW+180)%360;
See http://msdn.microsoft.com/en-us/library/0w4e0fzs.aspx
The modulo operator makes a division and returns the division remainder:
17 / 5 = 3 rest 2
Therefore:
17 % 5 = 2
Related
I am making a Unity Multiplayer game, and I wanted to compress the Y rotation axis from sending the whole Quaternion to just sending one byte.
My first compression attempt:
Instead of sending Quaternion, I have just sent a Y-axis float value
Result: 16 bytes -> 4 bytes (12 bytes saved overall)
Second compression attempt:
I have cached lastSentAxis variable (float) which contains the last Y-axis value that has been sent to the server
When a player changes their rotation (looks right/left), then a new Y-axis is compared to the cached one, and a delta value is prepared (delta is guaranteed to be less than 255).
Then, I create a new sbyte - which contains rotation way (-1, if turned left, 1, if turned right)
Result: 4 bytes -> 2 bytes (2 bytes saved, 14 overall)
Third compression attempt (failed)
Define a byte flag instead of creating a separated byte mentioned before (1 - left, 2 - right)
Get a delta rotation value (as mentioned previously), but add it to the byte flag
PROBLEM: I have looped through 0 to 255 to find which numbers will collide with the byte flag.
POTENTIAL SOLUTION: Check if flag + delta is in the colliding number list. If yes, don't send a rotation request.
Every X requests, send a correction float value
Potential result: 2 bytes -> 1 byte (1 byte saved, 15 overall)
My question is, is it possible to make a third compression attempt in a more... proper way or my potential solution is only possible thing I can achieve?
I would not claim that you saved overall 15 bytes ^^
If you only need one component of the rotation anyway then the first step of syncing a single float (4 bytes) seems actually pretty obvious ;)
I would also say that going beyond that sounds a bit like an unnecessary micro optimization.
The delta sync is quite clever and at first glance is a 100% improvement from 4 bytes to 2 bytes.
But
it is also quite error prone and could go desync if only one single transmission fails.
this of course lowers the precision down to 1 degree integer steps instead of a full float value.
Honestly I would stick to the 4 bytes just for stability and precision.
2 bytes - about 0.0055° precision
With 2 bytes you can actually go way better than your attempt!
Why waste an entire byte just for the sign of the value?
use a short
uses a single bit for the sign
still has 15 bits left for the value!
You just would have to map your floating point range of -180 to 180 to the range -32768 to 32767.
Sending
// your delta between -180 and 180
float actualAngleDelta;
var shortAngleDelta = (short)Mathf.RondToInt(actualAngleDelta / 180f * shortMaxValue);
var sendBytes = BitConverter.GetBytes(shortAngleDelta);
Receiving
short shortAngleDelta = BitConverter.ToInt16(receivedBytes);
float actualAngleDelta = (float) shortAngleDelta / (float)short.MaxValue * 360f;
But honestly then you should rather not sync the delta but the actual value.
So, use a ushort!
It covers values from 0 to 65535 so just map the possible 360 degrees on that. Sure you lose a little bit on precision but not down to full degrees ;)
// A value between 0 and 360
float actualAngle;
ushort ushortAngle = (ushort) Mathf.RoundToInt((actualAngle % 360f) / 360f * ushort.MaxValue);
byte[] sendBytes = BitConverter.GetBytes(ushortAngle);
Receiving
ushort ushortAngle = BitConverter.ToUInt16(receivedBytes, 0);
float actualAngle = (float)ushortAngle / (float)ushort.MaxValue * 360f;
Both maintains a precision down to about 0.0055 (= 360/65535) degrees!
Single byte - about 1.41° precision
If a lower precision is an option for you anyway you could however go totally fancy and say you don't sync every exact rotation angle in degrees but rather divide a circle not by 360 but by 256 steps.
Then you could map the delta to your lesser grained "degree" angles and could cover the entire circle in a single byte:
Sending
byte sendByte = (byte)Mathf.RoundToInt((actualAngle % 360f) / 360f * (float)byte.MaxValue);
receiving
float actualAngle = receivedByte / (float)byte.MaxValue * 360f;
which would have a precision of about 1.4 degrees.
BUT honestly, is all this forth and back calculations really worth the 2/3 saved bytes?
We have a monitoring application that can monitor in intervals like 5 minutes, 15 minutes, 1 hour, etc. That's represented on the x-axis; The y-axis is also scalable and have values like 1.2345 - 1.5567 or can be switched to values like 26000 - 30000, etc.
Once the scale is set on the x and y axis, they don't dynamically change without a whole complete data refresh.
That being said, we only want certain people to be notified depending on the clock angle, of say, the last 5 intervals along the y axis.
The clock angles will never go counter-clockwise past 0/12; likewise, they'll never go past 6 clockwise.
I know the 3 o'clock angle is obvious when the x axis value is exactly the same as it was 5 intervals ago.
But how does one even start coding for everything in between? I can get the differences in x values easily (in the example graphic below, it's 0.3), and the difference in the y-axis in the below graphic is 4.
So with trigonometry that's opposite over adjacent, which means a tan operation I believe? If so, 0.3/5 doesn't seem to yield any values that seem like a clock angle.
Since I can't get any farther than that, I have no idea how it would be coded in C# other than calculating the differences.
Any help would be greatly appreciated!
You should be using atan2 (wiki , docs)
From the wiki:
atan2(y, x) returns the angle θ between the ray to the point (x, y) and the positive x axis, confined to (−π, π]
Note that the result is in radians, so you need to convert it if you want degrees
As stated, one radian is equal to 180/π degrees. Thus, to convert from radians to degrees, multiply by 180/π.
A couple of things here. First I think what you are asking for is the angle φ below, given two data points (x1,y1) and (x2,y2).
The problem here is that the angle is measuring the indicated triangle in pixels and not in x, y units.
So it is incorrect to do var φ = Math.Atan( (y2-y1)/(x2-x1) ); because the x and y axis have different units and angles are always dimensionless.
What additional information is needed, is the size of the graph area in pixels, as well as the range of values. Alternatively, the scaling gx,gy in pixels/unit for both axis.
For example, if the x-axis needs 45 pixels to span 1 grid of 1 hour (60 minutes) then te scaling is double gx = 45/60.0, and if the y-axis needs also 45 pixels to span 1 grid of 0.1 value then double gy = 45/0.1.
Then you can use this to calculate the sides of the triangle in pixels before calculating the angle
var adjacent = gx*(x2-x1); // convert x-axis units to pixels
var opposing = gy*(y2-y1); // convert y-axis units to pixels
var φ = Math.Atan(addjacent/opposing) * (180/Math.PI);
The last part calculates the angle φ and converts it from radians to degrees.
I'm working on a map generator for a popular 3D game engine just to see if I can. I've created a simple set of tiles to test with, such as corner pieces and vert/horizontal hallways. All tiles are the same size (192 l x 192 w x 136 h), and consist of planes to represent walls, floor, and ceiling. I've coded the logic for generating the tile order and am now ready to set the coordinates.
For example sake, I'm trying to move a tile up (Y-axis) exactly 192 units.
Before I made these tiles, I was testing with single objects and simply added 192 units to the object's Y-axis. That worked fine. However, after testing a move up with one of these tiles, I notice it's more than the Y-axis that needs calculating.
Here's what the tile map file looks like before the position is moved upwards 192 units:
https://pastebin.com/6iqQwN50
solid
{
"id" "2"
side
{
"id" "1"
"plane" "(0 192 8) (192 192 8) (192 0 8)"
"material" "CONCRETE/BAGGAGE_CONCRETEFLOORA"
"uaxis" "[1 0 0 0] 0.25"
"vaxis" "[0 -1 0 0] 0.25"
"rotation" "0"
"lightmapscale" "16"
"smoothing_groups" "0"
}
And here's what it looks like after the move:
https://pastebin.com/7cCnTndZ
solid
{
"id" "2"
side
{
"id" "1"
"plane" "(0 192 8) (0 384 8) (192 384 8)"
"material" "CONCRETE/BAGGAGE_CONCRETEFLOORA"
"uaxis" "[1 0 0 0] 0.25"
"vaxis" "[0 -1 0 256] 0.25"
"rotation" "0"
"lightmapscale" "16"
"smoothing_groups" "0"
}
I might be in over my head, but is there a C# class or perhaps function to help me position the X Y Z coordinates of these objects?
If it helps, I'm referring to this site as documentation on the code structure for planes:
https://developer.valvesoftware.com/wiki/Valve_Map_Format#Planes
I have an idea how to accomplish this, such as comparing the before and after code above and calculating the changed axis for every plane, but there must be a better way to approach this.
There is no standard class/method in C# that will do this for you.
It is also important to understand that there is an infinite number of possible combinations of points that will define the same plane. According to the documentation that you referred to these are simply three points in the plane (which are not on one line).
This means that adding a fixed amount to all Y coordinates will move the plane in the Y direction.
I have read some of the duplicate answers about angle between two vectors, but I'm still stuck with my problem. I have two vectors and I want that the angle between them to always be 90 degrees. To achieve that I need to find the angle between them, so that I can subtract or add the correct amount of degrees so that the angle between them always is 90 degrees.
The picture illustrates a sprite and two vectors. How do I find the angle A between them two? I have tried to use this code to get the angle between two vectors, but I must have missed something out, because I don't get the correct results:
public float GetAngleBetween (Vector2 A, Vector2 B)
{
float DotProd = Vector2.Dot (A, B);
float Length = A.Length () * B.Length ();
return (float)MathHelper.ToDegrees ((float)Math.Acos (DotProd/Length));
}
Any input is welcome and thank you in advance for any answers.
The actual angle in radians is
Math.ACos(Vector2.Dot(a, b));
Make sure that a and b are normalized vectors or the results can get pretty weird.
I think you may be looking for the Vector2.Dot method which is used to calculate the product of two vectors, and can be used for angle calculations.
For example:
// the angle between the two vectors is less than 90 degrees.
Vector2.Dot(vector1.Normalize(), vector2.Normalize()) > 0
// the angle between the two vectors is more than 90 degrees.
Vector2.Dot(vector1.Normalize(), vector2.Normalize()) < 0
// the angle between the two vectors is 90 degrees; that is, the vectors are orthogonal.
Vector2.Dot(vector1.Normalize(), vector2.Normalize()) == 0
// the angle between the two vectors is 0 degrees; that is, the vectors point in the same direction and are parallel.
Vector2.Dot(vector1.Normalize(), vector2.Normalize()) == 1
// the angle between the two vectors is 180 degrees; that is, the vectors point in opposite directions and are parallel.
Vector2.Dot(vector1.Normalize(), vector2.Normalize()) == -1
Is this what you're looking for, or do you need the exact angle?
If I understand your question diagram and comments, the Dot product and Acos are not the only bits of info you need. You also need to account for when the sprite is not located at (0,0).
float angleInRadians = (float) Math.Acos(Vector2.Dot(Vector2.Normalize(vector1 - spritePosition), Vector2.Normalize(vector2 - spritePosition)));
int angleInDegrees = MathHelper.ToDegrees(angleInRadians);
I have two 2D objects and each one has a transform matrix in C#.
in fact one of these gets from rotation of the other one.
How can I calculate the angle between these two matrix?
Is there any method that can do it directly?
Any 2D angle transform rotating through an angle θ will look like this:
| cos(θ) -sin(θ) 0 |
T = | sin(θ) cos(θ) 0 |
| 0 0 1 |
If you multiply your two transformation matricies together you'll get another one that's of the same form. It should be easy to calculate the angle.
It depends on how matrix is stored, but usually it's stored in "column based" order, which means
XAxis_x YAxis_x Offset_x
XAxis_y YAxis_y Offset_y
0 0 1
So if you get XAxis like a vector from one matrix and XAxis from another, you can measure angle between those 2 vectors. After measure in the same way an angle between YAxises of both matrices. So at the end you will have 2 angles: Rx, Ry, which applying on first matrix, will generated you the second one.