aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorCharles Krinke2008-07-17 19:11:56 +0000
committerCharles Krinke2008-07-17 19:11:56 +0000
commit26fd0595d7ebd150df798c63c8bcfd6b7cf3425c (patch)
treec4f252a94a0cd0db46d28426c0cd96123af1417e /OpenSim
parentRevert "git merge" (diff)
downloadopensim-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 'OpenSim')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs80
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs80
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);