VirtualKitten Posted January 2, 2021 Share Posted January 2, 2021 (edited) Hi everyone have a great new year with much love in it.xD I am scratching my blonde head with rotations in LSL and real angles and think I am missing something I have written this routine to work like a stepper motor in RL so it calculates zero from its current position then adds on the rest from zero to give you the rotation angle from existing angle ( confussed lol since last year when I started this and have got nofurther ) // Rememeber check corect axis this Floor has y for horizontal origin. // takes a degree angle and turn it into a stepper angle from 0 degrees float _getRotInAngleReqToBringToAngle(float angle) { vector euler = llRot2Euler(llList2Rot( llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0))*RAD_TO_DEG; if(euler.y>361) return_value = _fmod(360,euler.y); else return_value = euler.y; llOwnerSay("Adjusted for modulus:"+(string)return_value); if(llFabs(return_value) != return_value && return_value !=180) return_value = 360+return_value; else if((integer)return_value == 0 && angle == 0) return_value = 180; else return_value = llFabs(return_value) ; llOwnerSay("Adjusted for negative cater for -0 and -180:"+(string)return_value); return_value = return_value + angle ; llOwnerSay ("Original Angle: "+(string)euler.y+"Angle: "+(string)return_value+ "Angle To set to : "+(string)angle); return return_value; } Now this works upto a point but goes strange at 0 degrees or past 180 . I am feeding angles like this if(llList2String(r_list,1)=="All Up") {MoveRootRot(_getRotInAngleReqToBringToAngle(0), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Down") {MoveRootRot(_getRotInAngleReqToBringToAngle(180), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Left") {MoveRootRot(_getRotInAngleReqToBringToAngle(90), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Right") {MoveRootRot(_getRotInAngleReqToBringToAngle(270), "z", LINK_THIS);} But they don't always work depending on the current rotation. Can anyone help before i have no hair left Thanks for looking I know the code line above is a simple use of it but eventually I want to be able to provide it with any angle . Can anyone help no sarcastic comments please . Edited January 2, 2021 by VirtualKitten Link to comment Share on other sites More sharing options...
animats Posted January 2, 2021 Share Posted January 2, 2021 3 hours ago, VirtualKitten said: if(euler.y>361) return_value = _fmod(360,euler.y); else return_value = euler.y; llOwnerSay("Adjusted for modulus:"+(string)return_value); if(llFabs(return_value) != return_value && return_value !=180) return_value = 360+return_value; else if((integer)return_value == 0 && angle == 0) return_value = 180; else return_value = llFabs(return_value) ; This is why everybody in graphics uses a homogeneous representation of rotations. No special cases at zero degrees. In Second Life, that's quaternions. The key idea here is that you can multiply LSL rotations to get a new rotation. So, compute the rotation quaternion for the change you want to make using llEulerToQuat, then multiply the object's old rotation (from llGetRotation or llGetLinkPrimitiveParams) by the quaternion for the change to get the object's new rotation. Then apply that to the object with llSetRotation or llSetLinkPrimitiveParams. Ref: http://wiki.secondlife.com/wiki/Rotation This area is confusing but well documented. If you just want to spin something, see the functions which mention "Omega". Link to comment Share on other sites More sharing options...
Nova Convair Posted January 3, 2021 Share Posted January 3, 2021 What animats says. Look at the example in the wiki: http://wiki.secondlife.com/wiki/LlSetLocalRot Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 3, 2021 Author Share Posted January 3, 2021 Thank for looking Nova I can't spin it with Target Omega its a linked-set as it has two more moving components . Yes Nova am using llSetLinkPrinitiveParamsFast( in my MoveRootRot function and it was not worthy of mention as is not the problem . The problem is that when i have a position in a circle that the stepper is facing when it is set at 0 as in description it has nothing to go on to get back to zero. Likewise past 180 seems a problem there well may be others but haven't found exactly what they are which is messing up this stepper positioning it should always calculate an offset from zero. Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 3, 2021 Author Share Posted January 3, 2021 Animats I think you are missing what this code is trying to do sorry but dont think any of that would help meas I sad the moment is accomplished its just the linden degrees from an object to return a pointer to 0 and calculate offset as a stepper motor does as it con-senqually travels in a circle Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted January 3, 2021 Share Posted January 3, 2021 (edited) 20 hours ago, VirtualKitten said: if(euler.y>361) return_value = _fmod(360,euler.y); else return_value = euler.y; So what happens when you have a value between 360.0001 and 360.99999 ? (If you are going to feed integer values to things that use floats be prepared to suffer the default rounding, which might not be at all what you believe it will be) Animat's advice to use quaternions is the best one, but if you must use Euler there's no reason why you can't, with a bit of extra coding. Edited January 3, 2021 by Profaitchikenz Haiku Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 3, 2021 Author Share Posted January 3, 2021 Because my script doesn't work like that and don't understand him Its just confusing me Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted January 3, 2021 Share Posted January 3, 2021 (edited) I understand, sometimes I don't even understand myself. Seriously though, in that piece of code, check against 360.0 (not 360) and use >= so that if the Y value is >= 360.000 you subtract 360.000 from it and revert to 0.0. The reason for specifying .000 is an old one and possibly modern compilers do things better now, but it is to remind yourself (and other coders if you're on a team) what degree of floating point precision you wish. If you say a number is 360.0 then it could be anywhere in the range 359.95999 to 360.049999, both are the extents of a range that rounds to 360.0. If you say 360.00 then you are specifying a tighter range, 359.995999 to 360.004999, and so on. Edited January 3, 2021 by Profaitchikenz Haiku 1 Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted January 3, 2021 Share Posted January 3, 2021 (edited) @VK, after a quick play in a sandbox, I think I see your problem, it is where you are looking for negative angles: you test for a negative value that is NOT -180 and act accordingly, but then the other if---else clauses handle everything EXCEPT -180, so you need to add a clause to explicitly handle -180. (Which if I understand what you are trying to do requires you to invert it) I made the alterations that I suggested above and dropped the integer comparisons as well. eg return_value = 0.0 && value = 0.0, but this is rather sloppy coding, you should ideally test for llFAbs(return_value) <= 0.001 or some similar tolerance figure Edited January 3, 2021 by Profaitchikenz Haiku 1 Link to comment Share on other sites More sharing options...
Wulfie Reanimator Posted January 3, 2021 Share Posted January 3, 2021 (edited) 6 hours ago, Profaitchikenz Haiku said: So what happens when you have a value between 360.0001 and 360.99999 ? (If you are going to feed integer values to things that use floats be prepared to suffer the default rounding, which might not be at all what you believe it will be) Comparing ints with floats is "accurate," there won't be any rounding involved. llOwnerSay((string)[ (0.1 * 10) > 1 ]); // output: TRUE // 0.1 is not a representable float. // The actual value is 0.100000001490116119384765625 // 0.1 * 10 = 1.00000001490116119384765625 // ...which is greater than 1 5 hours ago, Profaitchikenz Haiku said: The reason for specifying .000 is an old one and possibly modern compilers do things better now, but it is to remind yourself (and other coders if you're on a team) what degree of floating point precision you wish. If you say a number is 360.0 then it could be anywhere in the range 359.95999 to 360.049999, both are the extents of a range that rounds to 360.0. If you say 360.00 then you are specifying a tighter range, 359.995999 to 360.004999, and so on. Do you have a source (or demonstration) for this? Because that doesn't seem to be true at all, and would be extremely unreliable behavior and not compliant with the IEEE standard LSL uses. 360 and 360.0 and 360.000 all get converted to the exact same float value; precisely 360.0. There is no "implicit rounding" of floats within LSL beyond converting them to strings. Edited January 3, 2021 by Wulfie Reanimator Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted January 3, 2021 Share Posted January 3, 2021 36 minutes ago, Wulfie Reanimator said: Do you have a source (or demonstration) for this? Nope. I'm going by an old coding standard I worked to on one of my earliest projects, which was that when specifying floats as literals you should indicate how many places of precision you wanted to see to the right of the decimal point. It's possible they were over-prescriptive, it's too late now to go and ask them. Do bear in mind I began coding before some of these standards became commonplace But it does make sense to me. If somebody says 9.5 I understand them to mean "I'm Ok with what you give me so long as it round to 9.5", so if it's a piece of wood they've asked for I'll cut it so that it's 9.45 to 9.55. But if they say 9.50 I'll cut it so it's 9.405 to 9.505. And now I suspect you'll want to query the value of the kerf Link to comment Share on other sites More sharing options...
Wulfie Reanimator Posted January 3, 2021 Share Posted January 3, 2021 9 minutes ago, Profaitchikenz Haiku said: Do bear in mind I began coding before some of these standards became commonplace I wasn't aware. However, the current IEEE-754 standard has been in place for 35 years. Link to comment Share on other sites More sharing options...
Mollymews Posted January 4, 2021 Share Posted January 4, 2021 can simplify this by using llAxisAngle2Rot http://wiki.secondlife.com/wiki/LlAxisAngle2Rot a usage example to rotate a object on its local Y axis rotation start_rot; float angle; default { state_entry() { start_rot = llGetLocalRot(); } touch_start(integer total_number) { // angle in degrees angle += 13.0; // angle -= 10.0; // -angle will rotate in the opposite direction // fmod longhand if (angle > 360.0) angle -= 360.0; else if (angle < -360.0) angle += 360.0; // rotate on the local Y axis <0, 1, 0> llSetLocalRot(llAxisAngle2Rot(<0, 1, 0>, angle * DEG_TO_RAD) * start_rot ); } } 1 Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 6, 2021 Author Share Posted January 6, 2021 @Mollymews Thanks Molly for the example but its in a linked set and stepping is not a problem imagine you have ten stepping around and they do it at different rates the code above is to reset them all from their current position to work out the offset and get them at this position . I think your example is just stepping around, thanks for looking. Link to comment Share on other sites More sharing options...
Mollymews Posted January 6, 2021 Share Posted January 6, 2021 the axis order to calculate a rotation is Z, Y, X and it uses shortest path the effect of this is is that <180,0,0> results in <180,0,0> whereas <0,180,0> results in <180,0,180> so your function has to take this into consideration a alternative is to build the device to operate on the X axis, when so then the issue you have goes away for myself then if I wanted to continue with the Y axis then I would refactor the app to use llAxisAngle2Rot and its companions llRot2Angle, llRot2Axis and llAngleBetween Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 7, 2021 Author Share Posted January 7, 2021 Molly it depends on the blender model and the import as to the orientation please look at my code if you have time in first pot and let me know what you think is wrong thanks for looking Link to comment Share on other sites More sharing options...
Mollymews Posted January 7, 2021 Share Posted January 7, 2021 28 minutes ago, VirtualKitten said: if you have time in first pot and let me know what you think is wrong thanks for looking "the axis order to calculate a rotation is Z, Y, X and it uses shortest path the effect of this is is that <180,0,0> results in <180,0,0> whereas <0,180,0> results in <180,0,180> so your function has to take this into consideration" when we read the local rotation and convert to euler we do not get <0, 180, 0> we get <180, 0, 180>. euler.y = 0 and not 180 as we might presume. Therefore 0 + 90 = 90 and not 180 + 90 = 270 as presumed. We can see this: default { state_entry() { vector euler = <0,180,0>; llSetLocalRot(llEuler2Rot(euler * DEG_TO_RAD)); vector result = llRot2Euler(llGetLocalRot()) * RAD_TO_DEG; llOwnerSay((string)result); } } so this is what is wrong with your current code. The code doesn't compensate for the resulting behaviour of the method used internally by LSL to calculate rotations Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 9, 2021 Author Share Posted January 9, 2021 (edited) Molly thanks for your kind help , but you have confused me sorry . My axis is not changing in original post its static to between 0 - 360 . I know my post has errors or it would do what i expected i was hopeful someone knew why my apologies if i have not understood am not having a good day sorry Are you saying vector euler = llRot2Euler(llList2Rot( llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0))*RAD_TO_DEG; is wrong and should be something else? Please seeif(llList2String(r_list,1)=="All Up") {MoveRootRot(_getRotInAngleReqToBringToAngle(0), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Down") {MoveRootRot(_getRotInAngleReqToBringToAngle(180), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Left") {MoveRootRot(_getRotInAngleReqToBringToAngle(90), "z", LINK_THIS);} else if(llList2String(r_list,1)=="All Right") {MoveRootRot(_getRotInAngleReqToBringToAngle(270), "z", LINK_THIS);} // Rememeber check corect axis this Floor has y for horizontal origin. // takes a degree angle and turn it into a stepper angle from 0 degrees float _getRotInAngleReqToBringToAngle(float angle) { vector euler = llRot2Euler(llList2Rot( llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0))*RAD_TO_DEG; if(euler.y>361) return_value = _fmod(360,euler.y); else return_value = euler.y; llOwnerSay("Adjusted for modulus:"+(string)return_value); if(llFabs(return_value) != return_value && return_value !=180) return_value = 360+return_value; else if((integer)return_value == 0 && angle == 0) return_value = 180; else return_value = llFabs(return_value) ; llOwnerSay("Adjusted for negative cater for -0 and -180:"+(string)return_value); return_value = return_value + angle ; llOwnerSay ("Original Angle: "+(string)euler.y+"Angle: "+(string)return_value+ "Angle To set to : "+(string)angle); return return_value; } Edited January 9, 2021 by VirtualKitten Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted January 9, 2021 Share Posted January 9, 2021 (edited) Molly's answer makes sense to me (and explains the odd figures I've seen in the build floater for years but just accepted), but when you say "my axis is not changing, it's static within 0 - 360) all I can assume is that you want the Y-axis of the child prim to alter it's value according to how the root prim rotation has changed, i.e to perform as a gyroscope might do and attempt to resist turning forces. Is there any way you could make a test harness with only two prims involved to demonstrate this problem such that others can try to replicate it? I still don't really understand what it is you're trying to do, let alone how this problem is actually affecting things. Edited January 9, 2021 by Profaitchikenz Haiku geriatria Link to comment Share on other sites More sharing options...
Mollymews Posted January 10, 2021 Share Posted January 10, 2021 (edited) 13 hours ago, VirtualKitten said: Are you saying vector euler = llRot2Euler(llList2Rot( llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0))*RAD_TO_DEG; is wrong and should be something else? the value of euler is not wrong per se. It is just not what your code is anticipating it to be. Your code as wrote anticipates euler.y to be in the range [0 < 360] and the X and Z axis values to remain unchanged when Y changes to better help understand what happens when rotations (quaternions) are converted to euler then is best to enter values into the Build Editor directly and see the results what we see in the Build Editor is the same result of llRot2Euler() in our scripts for example we type <0, 180, 0> into the Build Editor. This euler (vector) value (in degrees) is converted to a quaternion. This quaternion is applied as a rotation to the object. Then the newly applied quaternion is read and converted back to euler, this euler value (in degrees) is displayed in the Build Editor <0,179,0> convert to quaternion. Convert quaternion back to euler vector results in -> <0,179,0> <0,180,0> convert to quaternion. Convert quaternion back to euler vector results in -> <180,0,180> <0,181,0> convert to quaternion. Convert quaternion back to euler vector results in -> <180,359,180> <0,269,0> -> <180,271,180> <0,270,0> -> <0,270,0> <0,271,0> -> <0,271,0> <0,89,0> -> <0,89,0> <0,90,0> -> <0,90,0> <0,91,0> -> <180,89,180> <0,359,0> -> <0,359,0> <0,0,0> -> <0,0,0> <0,1,0> -> <0,1,0> so when we are working with the Y axis then our code has to be written with a clear understanding of how quaternion to euler conversion is done by the SL engine is possible to write a translation table/function to map the result of PRIM_LOCAL_ROT to the range <0,0,0> ... <0,359,0> but my recommendation is not to work on the Y axis and avoid all the hassle that you are currently experiencing in attempting to do this suggest that you go back into Blender, reorient the objects to operate on the X axis. Because X is always in the euler result range <0,0,0> .. <359,0,0> <0,n,n> -> <0,n,n> <91,n,n> -> <91,n,n> <181,n,n> -> <181,n,n> <269,n,n> -> <269,n,n> <359,n,n> -> <359,n,n> if tho you do continue wanting to work on the Y axis then you will need to write your function: _getRotInAngleReqToBringToAngle(float angle) as a translation table function, mapping the returned euler value of llRot2Euler(.. PRIM_ROT_LOCAL .. ) to the range <n,0,n> .. <n,359, n> Edited January 10, 2021 by Mollymews ROT_LOCAL 1 1 Link to comment Share on other sites More sharing options...
VirtualKitten Posted January 10, 2021 Author Share Posted January 10, 2021 Hi Molly thank you for that great reply I had not understood you was talking about quaternions . I should state the Y axis is an anomaly of my mesh orientation and not actually Y in world per ce. However your wonderful explanations of quaternions is making me understand a little better that they contain more information that might help me. Perhaps looking at the Y not really the Y. I need to look at other axis too in my calculations to derive a position at 0 and at 180. This is becoming more complicated sighs. Thanks for your assistance Denise X 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now