SA-MP Forums [Include] i_quat - Quaternions and spatial geometry
 New Account Members List Search Today's Posts Mark Forums Read

 30/05/2016, 10:01 PM #1 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 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? SA-MP 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 four-component "number" which represents a 3D rotation. It has many advantages over Euler angles, including unambiguity, easy composition and decomposition, and painless-to-implement 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 non-real 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?Editing attached objects. Normally, you can't use EditObject on an attached object, like neons on a vehicle for example, but if you obtain its attached offsets and rotation, you can use VectorRelToAbsQuat and RotationRelToAbsQuat to "remove" the vehicle's rotation from them and then simply detach the object (attach it to INVALID_VEHICLE_ID) and set its position to that. After you're done editing, repeat the process backwards, this time with VectorAbsToRelQuat and RotationAbsToRelQuat: Code: ```stock UnattachObject(objId, veh) //Unattachs the object from a vehicle { new Float:q[4]; GetVehicleRotationQuat(veh, q[0], q[1], q[2], q[3]); if(!IsValidQuaternion(q)) return; //Vehicles left unoccupied for some time will return wrong values new Float:a[3], Float:ar[3]; GetObjectAttachedOffset(objId, a[0], a[1], a[2], ar[0], ar[1], ar[2]); //requires YSF VectorRelToAbsQuat(q, a, a); //a is now a world-relative vector RotationRelToAbsQuat(q, ar, ar); //ar is now a world-relative rotation new Float:x, Float:y, Float:z; GetVehiclePos(veh, x, y, z); AttachObjectToVehicle(objId, INVALID_VEHICLE_ID, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); SetObjectPos(objId, x+a[0], y+a[1], z+a[2]); SetObjectRot(objId, ar[0], ar[1], ar[2]); } stock ReattachObject(objId, veh) //Reattachs the object to a vehicle { new Float:q[4]; GetVehicleRotationQuat(veh, q[0], q[1], q[2], q[3]); if(!IsValidQuaternion(q)) return INVALID_VEHICLE_ID; new Float:a[3], Float:ar[3]; GetObjectPos(objId, a[0], a[1], a[2]); GetObjectRot(objId, ar[0], ar[1], ar[2]); new Float:x, Float:y, Float:z; GetVehiclePos(veh, x, y, z); a[0] -= x; a[1] -= y; a[2] -= z; VectorAbsToRelQuat(q, a, a); //a is now a vehicle-relative vector RotationAbsToRelQuat(q, ar, ar); //a is now a vehicle-relative rotation AttachObjectToVehicle(objId, veh, a[0], a[1], a[2], ar[0], ar[1], ar[2]); }``` Boosting vehicle forward: Code: ```new veh = GetPlayerVehicleID(playerid); new Float:q[4]; GetVehicleRotationQuat(veh, q[0], q[1], q[2], q[3]); new Float:v[3]; v[1] = 10.0; //10 m/s forward VectorRelToAbsQuat(q, v, v); //v is now an absolute vector, usable in the world coordinate system SetVehicleVelocity(veh, v[0], v[1], v[2]);``` If you are building a movable (space)ship with attached objects in a map editor, you can compute their relative offsets and rotations with VectorAbsToRel and RotationAbsToRel, specifying the ship's body rotation. And much more... 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 vice-versa, 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 [email protected], I was able to get the correct conversion formula and begin to implement all the functions. Last edited by IllidanS4; 01/10/2017 at 10:18 PM.
 30/05/2016, 10:48 PM #2 PrO.GameR Gangsta     Join Date: Oct 2012 Posts: 732 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. __________________ Blueberry Prison Roleplay will be back soon! Follow the forums for more information about opening day. Forums
 31/05/2016, 09:10 AM #3 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 Re: i_quat - Quaternions and spatial geometry Thanks for the tip, check the first example.
 05/06/2016, 04:44 PM #4 TwisT3R Little Clucker     Join Date: Mar 2012 Location: Hungary Posts: 24 Reputation: 16 Re: i_quat - Quaternions and spatial geometry Hi! Looks like ReattachObject does not works fine. https://www.*******.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 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 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 TwisT3R Little Clucker     Join Date: Mar 2012 Location: Hungary Posts: 24 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://*********/z6a6rGzT7GI http://pastebin.com/xfh4jaXN This time i used your original ReattachObject without Dynamic objects... __________________
 05/06/2016, 07:40 PM #7 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 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 TwisT3R Little Clucker     Join Date: Mar 2012 Location: Hungary Posts: 24 Reputation: 16 Re: i_quat - Quaternions and spatial geometry Finally it worked. Thank you https://www.*******.com/watch?v=ylbB...ature=********* __________________
 05/01/2017, 10:12 PM #9 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 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 near-zeros (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 IllidanS4 Banned   Join Date: Feb 2013 Posts: 270 Reputation: 85 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 (so-called 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 Linear Mode

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is Off Forum Rules