Rotate the least amount with two vectors - vector

I've gone through a lot of questions online for the last few hours trying to figure out how to calculate the rotation between two vectors, using the least distance. Also, what is the difference between using Atan2 and using the dot product? I see them the most often.
The purpose is to rotate in the y axis only based on differences in X/Z position (Think top down rotation in a 3D world).
Option 1: use Atan2. Seems to work really well, except when it switchs the radians from positive to negative.
float radians = (float)Math.Atan2(source.Position.X - target.Position.X, source.Position.Z - target.Position.Z);
npc.ModelPosition.Rotation = new Vector3(0,
npc.ModelPosition.Rotation.Y + (radians),
0);
This works fine, except at one point it starts jittering then swings back the other way.
Use the dot product. Can't seem to make it work well, it ALWAYS turns in the same direction - is it possible to get it to swing in the least direction? I understand it ranges from 0 to pi - can I use that?
float dot = Vector3.Dot(Vector3.Normalize(source.Position), Vector3.Normalize(target.Position));
float angle = (float)Math.Acos(dot);
npc.ModelPosition.Rotation = new Vector3(0,
npc.ModelPosition.Rotation.Y + (angle),
0);
Thanks,
James

You calculate two different angles:
Angle alpha is the angle calculated with atan2 (which equals opposite side / adjacent side). Angle beta is the one calculated with the dot product.
You can achieve similar results (as with atan) with the dot product with
angle = acos(dot(normalize(target - source), -z))
(-z is the unit vector in negative z direction)
However, you will lose the sign.

Related

Understanding Angular velocities and their application

I recently had to convert euler rotation rates to vectorial angular velocity.
From what I understand, in a local referential, we can express the vectorial angular velocity by:
R = [rollRate, pitchRate, yawRate] (which is the correct order relative to the referential I want to use).
I also know that we can convert angular velocities to rotations (quaternion) for a given time-step via:
alpha = |R| * ts
nR = R / |R| * sin(alpha) <-- normalize and multiply each element by sin(alpha)
Q = [nRx i, nRy j, nRz k, cos(alpha)]
When I test this for each axis individually, I find results that I totally expect (i.e. 90°pitch/time-unit for 1 time unit => 90° pitch angle).
When I use two axes for my rotation rates however, I don't fully understand the results:
For example, if I use rollRate = 0, pitchRate = 90, yawRate = 90, apply the rotation for a given time-step and convert the resulting quaternion back to euler, I obtain the following results:
(ts = 0.1) Roll: 0.712676, Pitch: 8.96267, Yaw: 9.07438
(ts = 0.5) Roll: 21.058, Pitch: 39.3148, Yaw: 54.9771
(ts = 1.0) Roll: 76.2033, Pitch: 34.2386, Yaw: 137.111
I Understand that a "smooth" continuous rotation might change the roll component mid way.
What I don't understand however is after a full unit of time with a 90°/time-unit pitchRate combined with a 90°/time-unit yawRate I end up with these pitch and yaw angles and why I still have roll (I would have expected them to end up at [0°, 90°, 90°].
I am pretty confident on both my axis + angle to quaternion and on my quaternion to euler formulas as I've tested these extensively (both via unit-testing and via field testing), I'm not sure however about the euler rotation rate to angular-velocity "conversion".
My first bet would be that I do not understand how euler rotation-rates axes interacts on themselves, my second would be that this "conversion" between euler rotation-rates and angular velocity vector is incorrect.
Euler angles are not good way of representing arbitrary angular movement. Its just a simplification used for graphics,games and robotics. They got some pretty hard restrictions like your rotations consist of only N perpendicular axises in ND space. That is not how rotation works in real world. On top of this spherical representation of reper endpoint it creates a lot of singularities (you know when you cross poles ...).
The rotation movement is analogy for translation:
position speed acceleration
pos = Integral(vel) = Integral(Integral(acc))
ang = Integral(omg) = Integral(Integral(eps))
That in some update timer can be rewritten to this:
vel+=acc*dt; pos+=vel*dt;
omg+=eps*dt; ang+=omg*dt;
where dt is elapsed time (Timer interval).
The problem with rotation is that you can not superimpose it like translation. As each rotation has its own axis (and it does not need to be axis aligned, nor centered) and each rotation affect the axis orientation of all others too so the order of them matters a lot. On top of all this there is also gyroscopic moment creating 3th rotation from any two that has not parallel axis. Put all of this together and suddenly you see Euler angles does not match the real geometrics/physics of rotation. They can describe orientation and fake its rotation up to a degree but do not expect to make real sense once used for physic simulation.
The real simulation would require list of rotations described by the axis (not just direction but also origin), angular speed (and its change) and in each simulation step the recomputing of the axis as it will change (unless only single rotation is present).
This can be done by using coumulative homogenous transform matrices along with incremental rotations.
Sadly the majority of programmers prefers Euler angles and Quaternions simply by not knowing that there are better and simpler options and once they do they stick to Euler angles anyway as matrix math seem to be more complicated to them... That is why most nowadays games have gimbal locks, major rotation errors and glitches, unrealistic physics.
Do not get me wrong they still have their use (liek for example restrict free look for camera etc ... but they missused for stuff they are the worse option to use for.

Moving an object diagonally inside a square

I am stuck on a particular problem. I am learning on how to create a very basic game, where a ball will travel diagonally from either top left corner of a square or a rectangular down to the bottom right corner in a straight line (As shown in Fig 1 & 2). Now I know that the ball x and y position will both need to be changed frame by frame but I am unsure on how to go about this.
enter image description here
Math is not my strong point and I am unsure how do I calculate the exact route, especially since both the square and rectangle will have a different angles. Are there any math formulas I can use to calculate the diagonal line and by how much each of the x and y coordinates of the ball will need to be adjusted frame by frame.
From the research that I have done I think that I will most likely need to calculate the angle using the sin or cos functions but I am not sure how everything fits together. Have been using https://www.mathsisfun.com/sine-cosine-tangent.html to try and learn more.
I am planning on starting to code this but would really appreciate answers to these basic questions. I am trying to learn both the programming and the mathematical aspect at the same time and I feel that this approach would be the best fit.
Many Thanks for any suggestions/help, I would really appreciate it.
Since it's rectangular, just calculate the slope: rise (Y) / run (X). That will give you how much to increase the object's location in each direction per frame. Depending on how fast or slow you want the object to move, you'll need to apply some modifier to that (e.g., if you want the object to move twice as fast, you'll need to multiple 2 by the change in a particular direction before you actually change the object's location.
For square :
If you are using Frame or JFrame, you have coordinate with you.
You can move ball from left top to right down as follow ->
Suppose ur top left corner is at (0,0), add 1in both coordinate until you reach right bottom corner.
U can do this using for loop
You don't technically need the angle for this mapping. You know that the formula for a line is "y = m * x + b." I presume that you can calculate m,b. If not, let me know.
Given that - you can simply increment x based on anything you like (timer, event, etc. ). You can place your incremented x into the equation above to get your respective y.
Now, that won't be quite enough as you are dealing with pixels instead of actual numbers. For example, lest assume that in your game x/y are in feet. You will need to know how many pixels represent a foot. Then when you draw to the screen you adjust your coordinates by dividing by pixels per foot.
So...
1. Calculate your m and b for your path.
2. Use a timer. At each tick, adjust your x value
3. Use your x value to calculate your y value
4. Divide x and y by a scaling number
5. Use the new scaled x and y to plot your object
Now...There are all kinds of tricks you can play with the math, but that should get you started.
Let's left bottom corner of rectangle (or square) has coordinates (x0, y0), and right top corner (x1, y1). Then diagonal has equation
X(t) = x0 + t * (x1 - x0)
Y(t) = y0 + t * (y1 - y0)
where t is parameter in range 0..1. Point at t=0 corresponds to (x0, y0), at t=1 to (x1, y1), and at t=0.5 - to the center of rectangle. So all you need is vary parameter t and calculate position.
When your object will move with constant absolute speed in arbitrary direction, use horizontal and vertical components of velocity vx and vy. At every moment get coordinates as x_new = x_old + delta_time * vx. Note that reflection from vertical edge just changes horizontal component of velocity 'vx = - vx' and so on.

Dynamic Shape Creation(Processing)

I'm trying to create a program that creates a custom pattern. I have it so that if sides = 3, it's a triangle 4 = rect and anything else above that has a formula so that, if you really wanted, you could have 25 sides. I'm using lines, rotation and rotation to plant, turn, draw repeat.
angleMeasure = (180 * (sides-2) ) /sides;
println(angleMeasure);
println(radians(angleMeasure));
//creating the 5+ shape
pushMatrix();
translate(width/2, height/2); //translating the whole shape/while loop
while(counter < sides){
line(0,0,170,0);
translate(170,0);//THIS translate is what makes the lines go in the direction they need too.
rotate(angleMeasure);
counter = counter + 1;
This works almost correctly. The last and first lines don't connect. Suggestions? Maybe it's a problem with the math, but println reveals a correct angle measure in degrees. Here's what it looks like: http://i.stack.imgur.com/TwYMj.png
EDIT: Changed the rotate from rotate(angleMeasure) to rotate(angleMeasure * -1). This rotated the whole shape and made it clear that the angle on the very first line is off. See:http://i.stack.imgur.com/Z1KmY.png
You actually need to turn by angle=360°/sides. And convert this angle into radians.
Thus for a pentagram you need angle=72°. The number you computed is 108, which interpreted as radians is 34 full turns plus an angle of about 67°. This falls 5° short of the correct angle, so that you obtain a somewhat correct picture with slightly too wide inner angles, resulting in the gap (and not a crossing as when the angle were larger than the correct angle).

Intersection between two Arcs? (arc = distance between pair of angles)

I'm trying to find a way to calculate the intersection between two arcs.
I need to use this to determine how much of an Arc is visually on the right half of a circle, and how much on the left.
I though about creating an arc of the right half, and intersect that with the actual arc.
But it takes me wayyy to much time to solve this, so I thought about asking here - someone must have done it before.
Edit:
I'm sorry the previous illustration was provided when my head was too heavy after crunching angles. I'll try to explain again:
In this link you can see that I cut the arc in the middle to two halves, the right part of the Arc contains 135 degrees, and the left part has 90.
This Arc starts at -180 and ends at 45. (or starts at 180 and ends at 405 if normalized).
I have managed to create this code in order to calculate the amount of arc degrees contained in the right part, and in the left part:
f1 = (angle2>270.0f?270.0f:angle2) - (angle1<90.0f?90.0f:angle1);
if (f1 < 0.0f) f1 = 0.0f;
f2 = (angle2>640.0f?640.0f:angle2) - (angle1<450.0f?450.0f:angle1);
if (f2 < 0.0f) f2 = 0.0f;
f3 = (angle2>90.0f?90.0f:angle2) - angle1;
if (f3<0.0f) f3=0.0f;
f4 = (angle2>450.0f?450.0f:angle2) - (angle1<270.0f?270.0f:angle1);
if (f4<0.0f) f4=0.0f;
It works great after normalizing the angles to be non-negative, but starting below 360 of course.
Then f1 + f2 gives me the sum of the left half, and f3 + f4 gives me the sum of the right half.
It also does not consider a case when the arc is defined as more than 360, which may be an "error" case.
BUT, this seems like more of a "workaround", and not a correct mathematical solution.
I'm looking for a more elegant solution, which should be based on "intersection" between two arc (because math has no "sides", its not visual";
Thanks!!
I think this works, but I haven't tested it thoroughly. You have 2 arcs and each arc has a start angle and a stop angle. I'll work this in degrees measured clockwise from north, as you have done, but it will be just as easy to work in radians measured anti-clockwise from east as the mathematicians do.
First 'normalise' your arcs, that is, reduce all the angles in them to lie in [0,360), so take out multiples of 360deg and make all the angles +ve. Make sure that the stop angle of each arc lies to clockwise of the start angle.
Next, choose the start angle of one of your arcs, it doesn't matter which. Sort all the angles you have (4 of them) into numerical order. If any of the angles are numerically smaller than the start angle you have chosen, add 360deg to them.
Re-sort the angles into increasing numerical order. Your chosen start angle will be the first element in the new list. From the start angle you already chose, what is the next angle in the list ?
1) If it is the stop angle of the same arc then either there is no overlap or this arc is entirely contained within the other arc. Make a note and find the next angle. If the next angle is the start angle of the other arc there is no overlap and you can stop; if it is the stop angle of the other arc then the overlap contains the whole of the first arc. Stop
2) If it is the start angle of the other arc, then the overlap begins at that angle. Make a note of this angle. The next angle your sweep encounters has to be a stop angle and the overlap ends there. Stop.
3) If it is the stop angle of the other arc then the overlap comprises the angle between the start angle of the first arc and this angle. Stop.
This isn't particularly elegant and relies on ifs rather more than I generally like but it should work and be relatively easy to translate into your favourite programming language.
And look, no trigonometry at all !
EDIT
Here's a more 'mathematical' approach since you seem to feel the need.
For an angle theta in (-pi,pi] the hyperbolic sine function (often called sinh) maps the angle to an interval on the real line in the interval (approximately) (-11.5,11.5]. Unlike arcsin and arccos the inverse of this function is also single-valued on the same interval. Follow these steps:
1) If an arc includes 0 break it into 2 arcs, (start,0) and (0,stop). You now have 2, 3 or 4 intervals on the real line.
2) Compute the intersection of those intervals and transform back from linear measurement into angular measurement. You now have the intersection of the two arcs.
This test can be resumed with a one-line test. Even if a good answer is already posted, let me present mine.
Let assume that the first arc is A:(a0,a1) and the second arc is B:(b0,b1). I assume that the angle values are unique, i.e. in the range [0°,360°[, [0,2*pi[ or ]-pi,pi] (the range itself is not important, we will see why). I will take the range ]-pi,pi] as the range of all angles.
To explain in details the approach, I first design a test for interval intersection in R. Thus, we have here a1>=a0 and b1>=b0. Following the same notations for real intervals, I compute the following quantity:
S = (b0-a1)*(b1-a0)
If S>0, the two segments are not overlapping, else their intersection is not empty. It is indeed easy to see why this formula works. If S>0, we have two cases:
b0>a1 implies that b1>a0, so there is no intersection: a0=<a1<b0=<b1.
b1<a0 implies that b0<b1, so there is no intersection: b0=<b1<a0=<a1.
So we have a single mathematical expression which performs well in R.
Now I expand it over the circular domain ]-pi,pi]. The hypotheses a0<a1 and b0<b1 are not true anymore: for example, an arc can go from pi/2 to -pi/2, it is the left hemicircle.
So I compute the following quantity:
S = (b0-a1)*(b1-a0)*H(a1-a0)*H(b1-b0)
where H is the step function defined by H(x)=-1 if x<0 else H(x)=1
Again, if S>0, there is no intersection between the arcs A and B. There are 16 cases to explore, and I will not do this here ... but it is easy to make them on a sheet :).
Remark: The value of S is not important, just the signs of the terms. The beauty of this formula is that it is independant from the range you have taken. Also, you can rewrite it as a logical test:
T := (b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0)
where ^ is logical XOR
EDIT
Alas, there is an obvious failure case in this formula ... So I correct it here. I realize that htere is a case where the intersection of the two arcs can be two arcs, for example when -pi<a0<b1<b0<a1<pi.
The solution to correct this is to introduce a second test: if the sum of the angles is above 2*pi, the arcs intersect for sure.
So the formula turns out to be:
T := (a1+b1-a0-b0+2*pi*((b1<b0)+(a1<a0))<2*pi) | ((b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0))
Ok, it is way less elegant than the previous one, but it is now correct.

Trigonometry and collisions/reflection in Pong game

For fun I am making Pong in Python with Pygame. I have run into some trouble with reflections.
So the ball has an angle associated with it. Since positive y is down this angle is downward. If the ball hits the top or bottom walls I can simply negate the angle and it will reflect properly, but the trouble is with the left and right walls. I cannot figure out the trigonometry for how to change the angle in this case. I am currently trying combinations of the below snippet but with no luck.
self.angle = -(self.angle - math.pi/2)
I have attached the code. You can try it for yourself easily. Just remember to take out the "framerate" module which I have not included or used yet. I would appreciate any input. Thanks!
You'll want to look into Angle of Incidence.
Basically you'll want to find the angle theta between your incoming vector and the normal of the wall the ball is hitting. Where the incoming angle is (wall normal)-theta the resulting angle is (wall normal)+theta.
The angle can be found using the dot product between your incoming vector and the normal of the wall, then taking the inverse cosine (normalize your vectors first).
You should use:
math.pi - angle

Resources