Get the trajectory of the rocket - math

I need to mathematically (or otherwise) get the 3D trajectory of the rocket. I have several variables: starting position, landing position, maximum altitude, flight angle. Here is a demo:
And yes, I don't use any popular game engine, I use the Lua language, on the MTA engine (MultiTheftAuto GTA SA). I want to get this trajectory mathematically. I need a set of points. Or if you are familiar with this engine, explain to me how to implement such a flight in the MTA. But you can also show me how this problem can be solved mathematically, or in any other languages ​​and even using the built-in functions of these engines, I will convert the code for Lua and find the implementation of your engine functions on the Internet. Thank you!
EDIT
And yes, I need to change exactly the Y coordinate (height) I have X and Z. I have a loop that every meter of the current trajectory goes through, in this cycle I have a variable X and Z , and I need to get Y based on these variables .

// float x = 0.0 - 1.0
y = sin(x * pi) ^ 0.6

Related

Trying to make a circle in Minecraft using coordinates and Sin & Cos

I am trying to write a Minecraft Datapack, which will plot a full armorstand circle around whatever runs the particular command. I am using a 3rd party mathematics datapack to use Sin and Cos. However, when running the command, the resulting plot was... not good. As you can see here: 1. Broken Circle., rather than have each vertex evenly placed in a circular line, I find a strange mess instead.
I would have thought loosing precision in Cos and Sin would simply make the circle more angular, I didn't expect it to spiral. What confuses me, is that +z (the red square) and -x (the purple one) are all alone. You can see on the blue ring (Which was made with a smaller radius) the gap between them persists.
My main issue is; How did my maths go from making a circle to a shredded mushroom, and is there a way to calculate the vertices with a greater precision?
Going into the project I knew I could simply spin the centre entity, and summon an armorstand x blocks in front using ^5 ^ ^, however I wanted to avoid this, due to my desire to be able to change the radius without needing to edit the datapack. To solve this, I used the Sin and Cos components to plot a new point, using a radius defined with scoreboards.
I first tested this using Scratch, in order to check my maths. You can see my code here: 2. Scratch code.
With an addition of the pen blocks, I was able to produce a perfect circle, which you can see here:
. Scratch visual proof.
With my proof of concept working, I looked online and found a Mathematical Functions datapack by yosho27, since the Cos and Sin functions are not built into the game. However, due to how Minecraft scoreboards are only Integers, Yosho27 multiplied the result of Cos and Sin by 100 to preserve 2 decimal places.
To start with, I am using a central armorstand with the tag center, which is at x: 8.5 z: 8.5. The scoreboards built into yosho's datapack that I am using is math_in for the values I want converted and math_out, which is where the final value is dumped.
Using signs, I keep track of the important values I am working with, as seen here: 4. Sign maths.
As I was writing this, I decided to actually compare both numbers to find this: 5. Image comparison, which shows me that somewhere in this calculation process, the maths has gone wrong. I modified the scratch side to match the minecraft conditions as much as possible, such as x100 and adding 850 to the result. From this result, I can see a disparity between x and z, even though they should be equal. Where Minecraft says 1: x= 864 z= 1487, Scratch says 1: x= 862.21668448: z= 1549.89338664. I assume this means the datapack's Cos and Sin are not accurate enough?
In light of this , I looked in yosho's datapack, I found this: 6. Yosho's code., which I just modified to be *= 10 instead of divide, in the hope of getting more precision. Modifying the rest of my code to match, I couldn't see any improvement in the numbers, although the armorstand vertices were a few pixels off the original circle, although I couldn't find a discernible pattern to this shift.
While this doesn't answer your full question, I'd like to point out two different ways you can solve the original issue at hand, no need to rely on some foreign math library:
^ ^ ^
Use Math, but let the game do it for you.
You can use the fact that the game is doing those rotational conversions for you already when using local coordinates. So, if you (or any entity) go to 0 0 0 and look / rotate in the angle that you want to calculate, then move forward by ^ ^ ^1, the position you're at now is basically <sin> 0 <cos>.
You can now take those numbers with your desired precision using data get and continue using them in whatever way you see fit.
Use recursive functions to move in incremenets
You point out in your question that
Going into the project I knew I could simply spin the centre entity, and summon an armorstand x blocks in front using ^5 ^ ^, however I wanted to avoid this, due to my desire to be able to change the radius without needing to edit the datapack. To solve this, I used the Sin and Cos components to plot a new point, using a radius defined with scoreboards.
So, to go back to that original idea, you could fairly easily (at least easier than trying to calculate the SIN/COS manually) find a solution that works for (almost) arbitrary radii and steps: By making the datapack configurable through e.g. scores, you can set it up to for example move forward by ^^^0.1 blocks for every point in a score, that way you can change that score to 50 to get a distance of ^^^5 and to 15 to get a distance of ^^^1.5.
Similarly you could set the "minimum" rotation between summons to be 0.1 degrees, then repeating said rotation for however many times you desire.
Both of these things can be achieved with recursive functions. Here is a quick example where you can control the rotational angle using the #rot steps score and the distance using the #dist steps score as described above (you might want to limit how often this runs with a score, too, like 360/rotation or whatever if you want to do one full circle). This example technically recurses twice, as I'm not using an entity to store the rotation. If there is an entity, you don't need to call the forward function from the rotate function but can call it from step (at the entity).
step.mcfunction
# copy scores over so we can use them
scoreboard players operation #rot_steps steps = #rot steps
scoreboard players operation #dist_steps steps = #dist steps
execute rotated ~ ~0.1 function foo:rotate
rotate.mcfunction
scoreboard players remove #rot_steps steps 1
execute if score #rot_steps matches ..0 positioned ^ ^ ^.1 run function foo:forward
execute if score #rot_steps matches 1.. rotated ~ ~0.1 run function foo:rotate
forward.mcfunction
scoreboard players remove #dist_steps steps 1
execute if score #dist_steps matches ..0 run summon armor_stand
execute if score #dist_steps matches 1.. positioned ^ ^ ^.1 run function foo:forward

Rotate model around x,y,z axes, without gimbal lock, with input data always as x,y,z axes angle rotations

I have an input device that gives me 3 angles -- rotation around x,y,z axes.
Now I need to use these angles to rotate the 3D space, without gimbal lock. I thought I could convert to Quaternions, but apparently since I'm getting the data as 3 angles this won't help?
If that's the case, just how can I correctly rotate the space, keeping in mind that my input data simply is x,y,z axes rotation angles, so I can't just "avoid" that. Similarly, moving around the order of axes rotations won't help -- all axes will be used anyway, so shuffling the order around won't accomplish anything. But surely there must be a way to do this?
If it helps, the problem can pretty much be reduced to implementing this function:
void generateVectorsFromAngles(double &lastXRotation,
double &lastYRotation,
double &lastZRotation,
JD::Vector &up,
JD::Vector &viewing) {
JD::Vector yaxis = JD::Vector(0,0,1);
JD::Vector zaxis = JD::Vector(0,1,0);
JD::Vector xaxis = JD::Vector(1,0,0);
up.rotate(xaxis, lastXRotation);
up.rotate(yaxis, lastYRotation);
up.rotate(zaxis, lastZRotation);
viewing.rotate(xaxis, lastXRotation);
viewing.rotate(yaxis, lastYRotation);
viewing.rotate(zaxis, lastZRotation);
}
in a way that avoids gimbal lock.
If your device is giving you absolute X/Y/Z angles (which implies something like actual gimbals), it will have some specific sequence to describe what order the rotations occur in.
Since you say that "the order doesn't matter", this suggests your device is something like (almost certainly?) a 3-axis rate gyro, and you're getting differential angles. In this case, you want to combine your 3 differential angles into a rotation vector, and use this to update an orientation quaternion, as follows:
given differential angles (in radians):
dXrot, dYrot, dZrot
and current orientation quaternion Q such that:
{r=0, ijk=rot(v)} = Q {r=0, ijk=v} Q*
construct an update quaternion:
dQ = {r=1, i=dXrot/2, j=dYrot/2, k=dZrot/2}
and update your orientation:
Q' = normalize( quaternion_multiply(dQ, Q) )
Note that dQ is only a crude approximation of a unit quaternion (which makes the normalize() operation more important than usual). However, if your differential angles are not large, it is actually quite a good approximation. Even if your differential angles are large, this simple approximation makes less nonsense than many other things you could do. If you have problems with large differential angles, you might try adding a quadratic correction to improve your accuracy (as described in the third section).
However, a more likely problem is that any kind of repeated update like this tends to drift, simply from accumulated arithmetic error if nothing else. Also, your physical sensors will have bias -- e.g., your rate gyros will have offsets which, if not corrected for, will cause your orientation estimate Q to precess slowly. If this kind of drift matters to your application, you will need some way to detect/correct it if you want to maintain a stable system.
If you do have a problem with large differential angles, there is a trigonometric formula for computing an exact update quaternion dQ. The assumption is that the total rotation angle should be linearly proportional to the magnitude of the input vector; given this, you can compute an exact update quaternion as follows:
given differential half-angle vector (in radians):
dV = (dXrot, dYrot, dZrot)/2
compute the magnitude of the half-angle vector:
theta = |dV| = 0.5 * sqrt(dXrot^2 + dYrot^2 + dZrot^2)
then the update quaternion, as used above, is:
dQ = {r=cos(theta), ijk=dV*sin(theta)/theta}
= {r=cos(theta), ijk=normalize(dV)*sin(theta)}
Note that directly computing either sin(theta)/theta ornormalize(dV) is is singular near zero, but the limit value of vector ijk near zero is simply ijk = dV = (dXrot,dYrot,dZrot), as in the approximation from the first section. If you do compute your update quaternion this way, the straightforward method is to check for this, and use the approximation for small theta (for which it is an extremely good approximation!).
Finally, another approach is to use a Taylor expansion for cos(theta) and sin(theta)/theta. This is an intermediate approach -- an improved approximation that increases the range of accuracy:
cos(x) ~ 1 - x^2/2 + x^4/24 - x^6/720 ...
sin(x)/x ~ 1 - x^2/6 + x^4/120 - x^6/5040 ...
So, the "quadratic correction" mentioned in the first section is:
dQ = {r=1-theta*theta*(1.0/2), ijk=dV*(1-theta*theta*(1.0/6))}
Q' = normalize( quaternion_multiply(dQ, Q) )
Additional terms will extend the accurate range of the approximation, but if you need more than +/-90 degrees per update, you should probably use the exact trig functions described in the second section. You could also use a Taylor expansion in combination with the exact trigonometric solution -- it may be helpful by allowing you to switch seamlessly between the approximation and the exact formula.
I think that the 'gimbal lock' is not a problem of computations/mathematics but rather a problem of some physical devices.
Given that you can represent any orientation with XYZ rotations, then even at the 'gimbal lock point' there is a XYZ representation for any imaginable orientation change. Your physical gimbal may be not able to rotate this way, but the mathematics still works :).
The only problem here is your input device - if it's gimbal then it can lock, but you didn't give any details on that.
EDIT: OK, so after you added a function I think I see what you need. The function is perfectly correct. But sadly, you just can't get a nice and easy, continuous way of orientation edition using XYZ axis rotations. I haven't seen such solution even in professional 3D packages.
The only thing that comes to my mind is to treat your input like a steering in aeroplane - you just have some initial orientation and you can rotate it around X, Y or Z axis by some amount. Then you store the new orientation and clear your inputs. Rotations in 3DMax/Maya/Blender are done the same way.
If you give us more info about real-world usage you want to achieve we may get some better ideas.

Finding a Quaternion from Gyroscope Data?

I've been trying to build a filter that can successfully combine compass, geomagnetic, and gyroscopic data to produce a smooth augmented reality experience. After reading this post along with lots of discussions, I finally found out a good algorithm to correct my sensor data. Most examples I've read show how to correct accelerometers with gyroscopes, but not correct compass + accelerometer data with gyroscope. This is the algorithm I've settled upon, which works great except that I run into gimbal lock if I try to look at the scene if I'm not facing North. This algorithm is Balance Filter, only instead of only implemented in 3D
Initialization Step:
Initialize a world rotation matrix using the (noisy) accelerometer and compass sensor data (this is provided by the Android already)
Update Steps:
Integrate the gyroscope reading (time_delta * reading) for each axis (x, y, z)
Rotate the world rotation matrix using the Euler angles supplied by the integration
Find the Quaternion from the newly rotated matrix
Find the rotation matrix from the unfiltered accelerometer + compass data (using the OS provided function, I think it uses angle/axis calculation)
Get the quaternion from the matrix generated in the previous step.
Slerp between quaternion generated in step 2 (from the gyroscope), and the accelerometer data using a coefficient based on some experimental magic
Convert back to a matrix and use that to draw the scene.
My problem is that when I'm facing North and then try to look south, the whole thing blows up and it appears to be gimbal lock. After a few gimbal locks, the whole filter is in an undefined state. Searching around I hear everybody saying "Just use Quaternions" but I'm afraid it's not that simple (at least not to me) and I know there's something I'm just missing. Any help would be greatly appreciated.
The biggest reason to use quaternions is to avoid the singularity problem with Euler angles. You can directly rotate a quaternion with gyro data.
Many appologies if information is delayed or not useful specifically but may be useful to others as I found it after some research:::
a. Using a kalman (linear or non linear) filter you do following ::
Gyro to integrate the delta angle while accelerometers tell you the outer limit.
b. Euler rates are different from Gyro rate of angle change so you ll need quaternion or Euler representation::
Quaternion is non trivial but two main steps are ----
1. For Roll, pitch,yaw you get three quaternions as cos(w) +sin(v) where w is scalar part and v is vector part (or when coding just another variable)
Then simply multiply all 3 quat. to get a delta quaternion
i.e quatDelta[0] =c1c2*c3 - s1s2*s3;
quatDelta[1] =c1c2*s3 + s1s2*c3;
quatDelta[2] =s1*c2*c3 + c1*s2*s3;
quatDelta[3] =c1*s2*c3 - s1*c2*s3;
where c1,c2,c3 are cos of roll,pitch,yaw and s stands for sin of the same actually half of those gyro pre integrated angles.
2. Then just multiply by old quaternion you had
newQuat[0]=(quaternion[0]*quatDelta[0] - quaternion[1]*quatDelta[1] - quaternion[2]*quatDelta[2] - quaternion[3]*quatDelta[3]);
newQuat[1]=(quaternion[0]*quatDelta[1] + quaternion[1]*quatDelta[0] + quaternion[2]*quatDelta[3] - quaternion[3]*quatDelta[2]);
newQuat[2]=(quaternion[0]*quatDelta[2] - quaternion[1]*quatDelta[3] + quaternion[2]*quatDelta[0] + quaternion[3]*quatDelta[1]);
newQuat[3]=(quaternion[0]*quatDelta[3] + quaternion[1]*quatDelta[2] - quaternion[2]*quatDelta[1] + quaternion[3]*quatDelta[0]);
As you loop through the code it gets updated so only quatenion is a global variables not the rest
3. Lastly if you want Euler angles from them then do the following:
`euler[2]=atan2(2.0*(quaternion[0]*quaternion[1]+quaternion[2]*quaternion[3]), 1-2.0*(quaternion[1]*quaternion[1]+quaternion[2]*quaternion[2]))euler[1]=safe_asin(2.0*(quaternion[0]*quaternion[2] - quaternion[3]*quaternion[1]))euler[0]=atan2(2.0*(quaternion[0]*quaternion[3]+quaternion[1]*quaternion[2]), 1-2.0*(quaternion[2] *quaternion[2]+quaternion[3]*quaternion[3]))`
euler[1] is pitch and so on..
I just wanted to outline general steps of quaternion implementation. There may be some minor errors but I tried this myself and it works. Please note that when changing to euler angles you will get singularities also called as "Gimbal lock"
An important note here is that this is not my work but I found it over the internet and wanted to thank who ever did this priceless code...Cheers

2D orbital physics

I'm working on a 2D physics engine for a game. I have gravity and masses working, using a simple iterative approach (that I know I'll have to upgrade eventually); I can push the masses around manually and watch them move and it all works as I'd expect.
Right now I'm trying to set up the game world in advance with a satellite in a simple circular orbit around a planet. To do this I need to calculate the initial velocity vector of the satellite given the mass of the planet and the desired distance out; this should be trivial, but I cannot for the life of me get it working right.
Standard physics textbooks tell me that the orbital velocity of an object in circular orbit around a mass M is:
v = sqrt( G * M / r )
However, after applying the appropriate vector the satellite isn't going anything like fast enough and falls in in a sharply elliptical orbit. Random tinkering shows that it's off by about a factor of 3 in one case.
My gravity simulation code is using the traditional:
F = G M m / r^2
G is set to 1 in my universe.
Can someone confirm to me that these equations do still hold in 2D space? I can't see any reason why not, but at this point I really want to know whether the problem is in my code or my assumptions...
Update: My physics engine works as follows:
for each time step of length t:
reset cumulative forces on each object to 0.
for each unique pair of objects:
calculate force between them due to gravity.
accumulate force to the two objects.
for each object:
calculate velocity change dV for this timestep using Ft / m.
v = v + dV.
calculate position change dS using v * t.
s = s + dS.
(Using vectors where appropriate, of course.)
Right now I'm doing one physics tick every frame, which is happening about 500-700 times per second. I'm aware that this will accumulate errors very quickly, but it should at least get me started.
(BTW, I was unable to find an off-the-shelf physics engine that handles orbital mechanics --- most 2D physics engines like Chipmunk and Box2D are more focused on rigid structures instead. Can anyone suggest one I could look at?)
You need to make sure that your delta t iterative time value is small enough. You will definitely have to tinker with the constants in order to get the behaviour you expect. Iterative simulation in your case and most cases is a form of integration where errors build up fast and unpredictably.
Yes, these equations hold in 2D space, because your 2D space is just a 2D representation of a 3D world. (A "real" 2D universe would have different equations, but that's not relevant here.)
A long shot: Are you perhaps using distance to the surface of the planet as r?
If that isn't it, try cutting your time step in half; if that makes a big difference, keep reducing it until the behavior stops changing.
If that makes no difference, try setting the initial velocity to zero, then watching it fall for a few iterations and measuring its acceleration to see if it's GM/r2. If the answer still isn't clear, post the results and we'll try to figure it out.

Calculating rotation along a path

I am trying to animate an object, let's say its a car. I want it go from point
x1,y1,z1
to point x2,y2,z2 . It moves to those points, but it appears to be drifting rather than pointing in the direction of motion. So my question is: how can I solve this issue in my updateframe() event? Could you point me in the direction of some good resources?
Thanks.
First off how do you represent the road?
I recently done exactly this thing and I used Catmull-Rom splines for the road. To orient an object and make it follow the spline path you need to interpolate the current x,y,z position from a t that walks along the spline, then orient it along the Frenet Coordinates System or Frenet Frame for that particular position.
Basically for each point you need 3 vectors: the Tangent, the Normal, and the Binormal. The Tangent will be the actual direction you will like your object (car) to point at.
I choose Catmull-Rom because they are easy to deduct the tangents at any point - just make the (vector) difference between 2 other near points to the current one. (Say you are at t, pick t-epsilon and t+epsilon - with epsilon being a small enough constant).
For the other 2 vectors, you can use this iterative method - that is you start with a known set of vectors on one end, and you work a new set based on the previous one each updateframe() ).
You need to work out the initial orientation of the car, and the final orientation of the car at its destination, then interpolate between them to determine the orientation in between for the current timestep.
This article describes the mathematics behind doing the interpolation, as well as some other things to do with rotating objects that may be of use to you. gamasutra.com in general is an excellent resource for this sort of thing.
I think interpolating is giving the drift you are seeing.
You need to model the way steering works .. your update function should 1) move the car always in the direction of where it is pointing and 2) turn the car toward the current target .. one should not affect the other so that the turning will happen and complete more rapidly than the arriving.
In general terms, the direction the car is pointing is along its velocity vector, which is the first derivative of its position vector.
For example, if the car is going in a circle (of radius r) around the origin every n seconds then the x component of the car's position is given by:
x = r.sin(2πt/n)
and the x component of its velocity vector will be:
vx = dx/dt = r.(2π/n)cos(2πt/n)
Do this for all of the x, y and z components, normalize the resulting vector and you have your direction.
Always pointing the car toward the destination point is simple and cheap, but it won't work if the car is following a curved path. In which case you need to point the car along the tangent line at its current location (see other answers, above).
going from one position to another gives an object a velocity, a velocity is a vector, and normalising that vector will give you the direction vector of the motion that you can plug into a "look at" matrix, do the cross of the up with this vector to get the side and hey presto you have a full matrix for the direction control of the object in motion.

Resources