30/05/2016, 10:01 PM  #1 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

i_quat 1.4 – Quaternions and spatial geometry
i_quat Download Notice: GetVehicleRotationQuat may return incorrect results for vehicles which are unoccupied. Better check if there's a driver inside, if you want the correct rotation. What does this do? This library will make your spatial geometry dreams come true! It contains various functions to convert between relative and absolute coordinates and rotation, as well as Euler and quaternion conversion and basic quaternion manipulation. What the sprunk is a quaternion? SAMP uses mostly rotation expressed in Euler angles (XYZ). However, one function (and more with YSF) uses a different method of rotation  quaternions. A quaternion (unit quaternion, specifically, also known as a versor) is a fourcomponent "number" which represents a 3D rotation. It has many advantages over Euler angles, including unambiguity, easy composition and decomposition, and painlesstoimplement operations. A quaternion represents an axis, specified by a unit vector, and a rotation around that axis, instead of 3 axes like in Euler. Algebraically, quaternions are an extension of complex numbers. Changelog 1.4  added GetQuatInverse (was in the native list, but without an actual implementation), corrected GetQuaternionAngles to account for gimbal lock (was returning imprecise values near the poles), and added a bunch of utility macros. 1.3 – added GetVehicleRotationQuatFixed which returns correct values for unoccupied vehicles. GetVehicleMatrix must be provided by a plugin. 1.2 – trigonometric functions won't return NaN for invalid values, rather they clamp their arguments to (1; 1). 1.1 – fixed math operations. 1.0 – initial release. What are the functions? The most useful functions GetVehicleRotation(vehicleid, &Float:x, &Float:y, &Float:z)Returns a vehicle's rotation in Euler angles The following bunch of functions are meant for conversion between absolute and relative coordinates. By absolute I don't mean world coordinates, but simply coordinates unattached to any body. A body can be an object, vehicle or player, which can have objects attached to. The body is represented with a quaternion or Euler angles specifying its rotation. The second parameter is an input, either a 3D vector (XYZ offsets) or an Euler or quaternion rotation. The third parameter is the output of the transformation. The first part of the function's name is what will be converted, the second part is whether from relative to absolute or vice versa, and optinally it can end with Quat, meaning the rotation of the body is specified with a quaternion, otherwise with Euler angles. VectorRelToAbsQuat(Float:q[4], Float:v1[3], Float:v2[3])Converts a vector in coordinates relative to a body with rotation specified by a quaternion to a vector in absolute coordinates RotationRelToAbsQuat(Float:q[4], Float:r1[3], Float:r2[3])Converts an Euler rotation relative to a body with rotation specified by a quaternion to an absolute rotation stock QuaternionRelToAbsQuat(Float:q[4], Float:q1[4], Float:q2[4])Converts a quaternion rotation relative to a body with rotation specified by a quaternion to an absolute rotation VectorRelToAbs(Float:r[3], Float:v1[3], Float:v2[3])Converts a vector in coordinates relative to a body with rotation specified by Euler angles to a vector in absolute coordinates RotationRelToAbs(Float:r[3], Float:r1[3], Float:r2[3])Converts an Euler rotation relative to a body with rotation specified by Euler angles to an absolute rotation stock QuaternionRelToAbs(Float:r[3], Float:q1[4], Float:q2[4])Converts a quaternion rotation relative to a body with rotation specified by Euler angles to an absolute rotation stock VectorAbsToRelQuat(Float:q[4], Float:v1[3], Float:v2[3])Converts a vector in absolute coordinates to a vector in coordinates relative to a body with rotation specified by a quaternion RotationAbsToRelQuat(Float:q[4], Float:r1[3], Float:r2[3])Converts an Euler rotation to a rotation relative to a body with rotation specified by a quaternion QuaternionAbsToRelQuat(Float:q[4], Float:q1[4], Float:q2[4])Converts an absolute quaternion rotation to a rotation relative to a body with rotation specified by Euler angles VectorAbsToRel(Float:r[3], Float:v1[3], Float:v2[3])Converts a vector in absolute coordinates to a vector in coordinates relative to a body with rotation specified by Euler angles RotationAbsToRel(Float:r[3], Float:r1[3], Float:r2[3])Converts an Euler rotation to a rotation relative to a body with rotation specified by Euler angles QuaternionAbsToRel(Float:r[3], Float:q1[4], Float:q2[4])Converts an absolute quaternion rotation to a rotation relative to a body with rotation specified by Euler angles Quaternion operations IsValidQuaternion(Float:q[4])Checks if a quaternion is a valid rotation quaternion GetQuaternionAngles(Float:w, Float:x, Float:y, Float:z, &Float:xa, &Float:ya, &Float:za)Returns a set of Euler angles from a quaternion GetRotationQuaternion(Float:x, Float:y, Float:z, &Float:qw, &Float:qx, &Float:qy, &Float:qz)Creates a quaternion from Euler angles GetQuaternionVector(Float:qw, Float:qx, Float:qy, Float:qz, &Float:x, &Float:y, &Float:z)Returns the vector component of a quaternion GetQuaternionAngle(Float:w, &Float:a)Returns the angle component of a quaternion RotateVectorQuat(Float:v1[3], Float:q[4], Float:v2[3])Rotates a vector with a specified quaternion performing a conjugation v2 = q v1 q* GetQuatConjugate(Float:q1[4], Float:q2[4])Returns the conjugate of a quaternion, with all nonreal component inversed GetQuatInverse(Float:q1[4], Float:q2[4])Returns the inverse of a quaternion, that is the conjugate divided by the norm squared. GetQuatProduct(Float:q1[4], Float:q2[4], Float:q3[4])Returns the Hamilton product of two quaternions There are also macros to help you working with arrays, like SET_A3 to copy one array (size 3) to another, ADD_A3 to add two arrays, or MUL_A3 to multiply an array with a number. To expand an array when passing its values as parameters, you can use the EXP_A3 macro. What can this be used for?
How did you come up with all this maths stuff? Well, for my mapping/filming/freeroam/anything server, a possibility to edit an attached object would have had been always neat for mappers. However, I had struggled with correctly converting the Euler angles to quaternion and viceversa, and many formulas I've found on the internet were simply incorrect. The reason is rather unusual ordering and orientation of the axes and angles in GTA. Finally, thanks to brilliant people on math@stackexchange, I was able to get the correct conversion formula and begin to implement all the functions. Last edited by IllidanS4; 13/10/2018 at 09:26 PM. 
30/05/2016, 10:48 PM  #2 
Gangsta
Join Date: Oct 2012
Posts: 695
Reputation: 121

Re: i_quat  Quaternions and spatial geometry
I would suggest you to add the very main usage it has as the example, turning a position into a vehicle's offset, people around tend to get very confused when decent examples are not offered, using all the functions provided wrong. seeing how you actually use a combination of these to turn say an object position into a vehicle's offsets to attach it to the vehicle tends to bring more casual usages of the include.
Great job either way tho, well done. 
31/05/2016, 09:10 AM  #3 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

Re: i_quat  Quaternions and spatial geometry
Thanks for the tip, check the first example.

05/06/2016, 04:44 PM  #4 
Little Clucker
Join Date: Mar 2012
Location: Hungary
Posts: 21
Reputation: 16

Re: i_quat  Quaternions and spatial geometry
Hi!
Looks like ReattachObject does not works fine. https://www.youtube.com/watch?v=pxh1oGxGxyE This happens when i try to use it. Code: http://pastebin.com/wNAiPqtA If the problem is with my code, please help me fix it, because i dont know how to use quaternions.. Thanks! 
05/06/2016, 05:25 PM  #5 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

Re: i_quat  Quaternions and spatial geometry
Oh I am sorry, I forgot to include a warning  if the vehicle is left unoccupied, the quaternion returned by GetVehicleRotationQuat will be incorrect. IsValidQuaternion tries to compensate for it, but even some invalid quaternions are technically valid, and the object will be reattached with incorrect offsets. I bet it's a meter under the vehicle. Anyway, you simply have to be in the vehicle to correctly reattach the object. Disable the engine to move the camera without driving forward.

05/06/2016, 05:58 PM  #6 
Little Clucker
Join Date: Mar 2012
Location: Hungary
Posts: 21
Reputation: 16

Re: i_quat  Quaternions and spatial geometry
As you said, now, i was in the car and i turned off the engine.
I have a new code this time. Works almost well but when i press the save button, the object shows up randomly as you can see in the video below. https://youtu.be/z6a6rGzT7GI http://pastebin.com/xfh4jaXN This time i used your original ReattachObject without Dynamic objects... 
05/06/2016, 07:40 PM  #7 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

Re: i_quat  Quaternions and spatial geometry
Sorry, I see I've made a mistake. When I was "fixing" RotateVectorQuat to be more mathematically accurate, I forgot to update the other functions. Script updated to 1.1, please check it. I hope its all okay now.

05/06/2016, 10:25 PM  #8 
Little Clucker
Join Date: Mar 2012
Location: Hungary
Posts: 21
Reputation: 16

Re: i_quat  Quaternions and spatial geometry

05/01/2017, 10:12 PM  #9 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

Re: i_quat  Quaternions and spatial geometry
Added GetVehicleRotationQuatFixed which returns correct values for unoccupied vehicles. GetVehicleMatrix must be provided by a plugin, like YSF. If you are using VehicleMatrix.inc, it could fix a couple of cases, but it will still be mostly garbage values. A plugin is required to read the matrix from the server's memory.
Why GetVehicleMatrix? Internally, the server stores the vehicle's rotation as a 3×3 rotation matrix, the same way as the game does. For some reason, this matrix is not exposed to scripts, only the conversion to a quaternion. Unfortunately, unoccupied vehicle updates damage the third row of the matrix and invalidate the values, changing them to nearzeros (mostly denormal floats). I have no idea why that is, I guess some sort of a game/server bug. The internal conversion to the quaternion sadly uses the third row (though it doesn't have to, two rows of the matrix are completely sufficient), returning complete bogus in case it was damaged. Now that I know the third row is actually redundant and is just a cross product of the other rows, if I can obtain the internal matrix, just fixing the third row via this method is sufficient and produces correct quaternions. Due to the imprecise floating point calculations, the reconstructed row is a bit inaccurate, but still really close to the correct one. It should fix 100 % of wrong quaternions. Last edited by IllidanS4; 06/02/2017 at 06:37 PM. 
01/10/2017, 10:26 PM  #10 
Huge Clucker
Join Date: Feb 2013
Posts: 341
Reputation: 260

Re: i_quat  Quaternions and spatial geometry
New version!
Aside from some useful macros to make working with arrays easier (check the main topic or the source code), I have corrected the core function of this include  GetQuaternionAngles. Near the poles or singularities of the rotation system, it returned incorrect values, mainly due to float rounding errors. Unfortunately, this requires an arbitrary value (socalled epsilon) to be used to specify the limit where the calculation should be corrected (that's why quaternions are better, you don't have to handle this mess). I have empirically measured the epsilon to be about 0.000002, but if you want to change it, simply #define QUAT_FLOAT_EPSILON with the new value. It should be positive number not larger than 1, but reasonably small. The smaller the epsilon, the higher chance of returning incorrect results. The larger the epsilon, the more imprecise the results for normal cases. If you expect "random" quaternions, you don't have to worry about this. 
Thread Tools  
Display Modes  

