diff options
author | Charles Krinke | 2008-07-17 19:11:56 +0000 |
---|---|---|
committer | Charles Krinke | 2008-07-17 19:11:56 +0000 |
commit | 26fd0595d7ebd150df798c63c8bcfd6b7cf3425c (patch) | |
tree | c4f252a94a0cd0db46d28426c0cd96123af1417e | |
parent | Revert "git merge" (diff) | |
download | opensim-SC-26fd0595d7ebd150df798c63c8bcfd6b7cf3425c.zip opensim-SC-26fd0595d7ebd150df798c63c8bcfd6b7cf3425c.tar.gz opensim-SC-26fd0595d7ebd150df798c63c8bcfd6b7cf3425c.tar.bz2 opensim-SC-26fd0595d7ebd150df798c63c8bcfd6b7cf3425c.tar.xz |
Mantis#1598. Thank you kindly, Matth for a patch that addresses:
The previous implementation of llEuler2Rot was not mathematically
incorrect, but it was an awkward way of posing the problem that
led to a few degenerate cases which were not handled correctly -
for example, PI rotations around X and Z axes were wrong. I put
some comments in the source about how I arrived at the current
implementation, which I think is easier to read, and gives
results that match SL.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs | 80 | ||||
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 80 |
2 files changed, 105 insertions, 55 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs index a03d8a6..b53f6c0 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs | |||
@@ -354,48 +354,72 @@ namespace OpenSim.Region.ScriptEngine.Common | |||
354 | return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z))); | 354 | return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z))); |
355 | } | 355 | } |
356 | 356 | ||
357 | |||
358 | // Xantor's newer llEuler2Rot() *try the second* inverted quaternions (-x,-y,-z,w) as LL seems to like | ||
359 | // New and improved, now actually works as described. Prim rotates as expected as does llRot2Euler. | ||
360 | |||
361 | /* From wiki: | 357 | /* From wiki: |
362 | The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes | 358 | The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes |
363 | in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation, | 359 | in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation, |
364 | a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting | 360 | a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting |
365 | vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis. | 361 | vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis. |
366 | */ | 362 | */ |
363 | |||
364 | /* How we arrived at this llEuler2Rot | ||
365 | * | ||
366 | * Experiment in SL to determine conventions: | ||
367 | * llEuler2Rot(<PI,0,0>)=<1,0,0,0> | ||
368 | * llEuler2Rot(<0,PI,0>)=<0,1,0,0> | ||
369 | * llEuler2Rot(<0,0,PI>)=<0,0,1,0> | ||
370 | * | ||
371 | * Important facts about Quaternions | ||
372 | * - multiplication is non-commutative (a*b != b*a) | ||
373 | * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication | ||
374 | * | ||
375 | * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot): | ||
376 | * Qx = c1+i*s1 | ||
377 | * Qy = c2+j*s2; | ||
378 | * Qz = c3+k*s3; | ||
379 | * | ||
380 | * Rotations applied in order (from above) Z, Y, X | ||
381 | * Q = (Qz * Qy) * Qx | ||
382 | * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3) | ||
383 | * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3) | ||
384 | * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3) | ||
385 | * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3+ik*s1*c2*s3+jk*c1*s2*s3+kk*s1*s2*s3 | ||
386 | * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3 -j*s1*c2*s3 +i*c1*s2*s3 -s1*s2*s3 | ||
387 | * regroup: x=i*(s1*c2*c3+c1*s2*s3) | ||
388 | * y=j*(c1*s2*c3-s1*c2*s3) | ||
389 | * z=k*(s1*s2*c3+c1*c2*s3) | ||
390 | * s= c1*c2*c3-s1*s2*s3 | ||
391 | * | ||
392 | * This implementation agrees with the functions found here: | ||
393 | * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions | ||
394 | * And with the results in SL. | ||
395 | * | ||
396 | * It's also possible to calculate llEuler2Rot by direct multiplication of | ||
397 | * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function | ||
398 | * from the wiki). | ||
399 | * Apparently in some cases this is better from a numerical precision perspective? | ||
400 | */ | ||
367 | 401 | ||
368 | public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v) | 402 | public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v) |
369 | { | 403 | { |
370 | m_host.AddScriptLPS(1); | 404 | m_host.AddScriptLPS(1); |
371 | 405 | ||
372 | double x,y,z,s,s_i; | 406 | double x,y,z,s; |
373 | 407 | ||
374 | double cosX = Math.Cos(v.x); | 408 | double c1 = Math.Cos(v.x/2.0); |
375 | double cosY = Math.Cos(v.y); | 409 | double c2 = Math.Cos(v.y/2.0); |
376 | double cosZ = Math.Cos(v.z); | 410 | double c3 = Math.Cos(v.z/2.0); |
377 | double sinX = Math.Sin(v.x); | 411 | double s1 = Math.Sin(v.x/2.0); |
378 | double sinY = Math.Sin(v.y); | 412 | double s2 = Math.Sin(v.y/2.0); |
379 | double sinZ = Math.Sin(v.z); | 413 | double s3 = Math.Sin(v.z/2.0); |
380 | 414 | ||
381 | s = Math.Sqrt(cosY * cosZ - sinX * sinY * sinZ + cosX * cosZ + cosX * cosY + 1.0f) * 0.5f; | 415 | x = s1*c2*c3+c1*s2*s3; |
382 | if (Math.Abs(s) < 0.00001) // null rotation | 416 | y = c1*s2*c3-s1*c2*s3; |
383 | { | 417 | z = s1*s2*c3+c1*c2*s3; |
384 | x = 0.0f; | 418 | s = c1*c2*c3-s1*s2*s3; |
385 | y = 1.0f; | 419 | |
386 | z = 0.0f; | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | s_i = 1.0f / (4.0f * s); | ||
391 | x = - (-sinX * cosY - cosX * sinY * sinZ - sinX * cosZ) * s_i; | ||
392 | y = - (-cosX * sinY * cosZ + sinX * sinZ - sinY) * s_i; | ||
393 | z = - (-cosY * sinZ - sinX * sinY * cosZ - cosX * sinZ) * s_i; | ||
394 | } | ||
395 | return new LSL_Types.Quaternion(x, y, z, s); | 420 | return new LSL_Types.Quaternion(x, y, z, s); |
396 | } | 421 | } |
397 | 422 | ||
398 | |||
399 | public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up) | 423 | public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up) |
400 | { | 424 | { |
401 | m_host.AddScriptLPS(1); | 425 | m_host.AddScriptLPS(1); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index bb292f1..260457b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -341,46 +341,72 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
341 | return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z))); | 341 | return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z))); |
342 | } | 342 | } |
343 | 343 | ||
344 | // Xantor's newer llEuler2Rot() *try the second* inverted quaternions (-x,-y,-z,w) as LL seems to like | ||
345 | // New and improved, now actually works as described. Prim rotates as expected as does llRot2Euler. | ||
346 | |||
347 | /* From wiki: | 344 | /* From wiki: |
348 | The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes | 345 | The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes |
349 | in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation, | 346 | in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation, |
350 | a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting | 347 | a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting |
351 | vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis. | 348 | vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis. |
352 | */ | 349 | */ |
350 | |||
351 | /* How we arrived at this llEuler2Rot | ||
352 | * | ||
353 | * Experiment in SL to determine conventions: | ||
354 | * llEuler2Rot(<PI,0,0>)=<1,0,0,0> | ||
355 | * llEuler2Rot(<0,PI,0>)=<0,1,0,0> | ||
356 | * llEuler2Rot(<0,0,PI>)=<0,0,1,0> | ||
357 | * | ||
358 | * Important facts about Quaternions | ||
359 | * - multiplication is non-commutative (a*b != b*a) | ||
360 | * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication | ||
361 | * | ||
362 | * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot): | ||
363 | * Qx = c1+i*s1 | ||
364 | * Qy = c2+j*s2; | ||
365 | * Qz = c3+k*s3; | ||
366 | * | ||
367 | * Rotations applied in order (from above) Z, Y, X | ||
368 | * Q = (Qz * Qy) * Qx | ||
369 | * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3) | ||
370 | * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3) | ||
371 | * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3) | ||
372 | * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3+ik*s1*c2*s3+jk*c1*s2*s3+kk*s1*s2*s3 | ||
373 | * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3 -j*s1*c2*s3 +i*c1*s2*s3 -s1*s2*s3 | ||
374 | * regroup: x=i*(s1*c2*c3+c1*s2*s3) | ||
375 | * y=j*(c1*s2*c3-s1*c2*s3) | ||
376 | * z=k*(s1*s2*c3+c1*c2*s3) | ||
377 | * s= c1*c2*c3-s1*s2*s3 | ||
378 | * | ||
379 | * This implementation agrees with the functions found here: | ||
380 | * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions | ||
381 | * And with the results in SL. | ||
382 | * | ||
383 | * It's also possible to calculate llEuler2Rot by direct multiplication of | ||
384 | * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function | ||
385 | * from the wiki). | ||
386 | * Apparently in some cases this is better from a numerical precision perspective? | ||
387 | */ | ||
353 | 388 | ||
354 | public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v) | 389 | public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v) |
355 | { | 390 | { |
356 | m_host.AddScriptLPS(1); | 391 | m_host.AddScriptLPS(1); |
357 | 392 | ||
358 | double x,y,z,s,s_i; | 393 | double x,y,z,s; |
359 | 394 | ||
360 | double cosX = Math.Cos(v.x); | 395 | double c1 = Math.Cos(v.x/2.0); |
361 | double cosY = Math.Cos(v.y); | 396 | double c2 = Math.Cos(v.y/2.0); |
362 | double cosZ = Math.Cos(v.z); | 397 | double c3 = Math.Cos(v.z/2.0); |
363 | double sinX = Math.Sin(v.x); | 398 | double s1 = Math.Sin(v.x/2.0); |
364 | double sinY = Math.Sin(v.y); | 399 | double s2 = Math.Sin(v.y/2.0); |
365 | double sinZ = Math.Sin(v.z); | 400 | double s3 = Math.Sin(v.z/2.0); |
366 | 401 | ||
367 | s = Math.Sqrt(cosY * cosZ - sinX * sinY * sinZ + cosX * cosZ + cosX * cosY + 1.0f) * 0.5f; | 402 | x = s1*c2*c3+c1*s2*s3; |
368 | if (Math.Abs(s) < 0.00001) // null rotation | 403 | y = c1*s2*c3-s1*c2*s3; |
369 | { | 404 | z = s1*s2*c3+c1*c2*s3; |
370 | x = 0.0f; | 405 | s = c1*c2*c3-s1*s2*s3; |
371 | y = 1.0f; | 406 | |
372 | z = 0.0f; | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | s_i = 1.0f / (4.0f * s); | ||
377 | x = - (-sinX * cosY - cosX * sinY * sinZ - sinX * cosZ) * s_i; | ||
378 | y = - (-cosX * sinY * cosZ + sinX * sinZ - sinY) * s_i; | ||
379 | z = - (-cosY * sinZ - sinX * sinY * cosZ - cosX * sinZ) * s_i; | ||
380 | } | ||
381 | return new LSL_Types.Quaternion(x, y, z, s); | 407 | return new LSL_Types.Quaternion(x, y, z, s); |
382 | } | 408 | } |
383 | 409 | ||
384 | public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up) | 410 | public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up) |
385 | { | 411 | { |
386 | m_host.AddScriptLPS(1); | 412 | m_host.AddScriptLPS(1); |