mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 03:26:09 +08:00
638 lines
15 KiB
C++
638 lines
15 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
ON_Quaternion ON_CrossProduct( const ON_Quaternion& p, const ON_Quaternion& q)
|
|
{
|
|
return ON_Quaternion(0.0, p.c*q.d - p.d*q.c, p.d*q.b - p.b*q.d, p.b*q.c - p.c*q.d);
|
|
}
|
|
|
|
ON_Quaternion ON_QuaternionProduct( const ON_Quaternion& p, const ON_Quaternion& q)
|
|
{
|
|
return ON_Quaternion( p.a*q.a - p.b*q.b - p.c*q.c - p.d*q.d,
|
|
p.a*q.b + p.b*q.a + p.c*q.d - p.d*q.c,
|
|
p.a*q.c - p.b*q.d + p.c*q.a + p.d*q.b,
|
|
p.a*q.d + p.b*q.c - p.c*q.b + p.d*q.a);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////
|
|
|
|
const ON_Quaternion ON_Quaternion::Zero(0.0,0.0,0.0,0.0);
|
|
const ON_Quaternion ON_Quaternion::Identity(1.0,0.0,0.0,0.0);
|
|
const ON_Quaternion ON_Quaternion::I(0.0,1.0,0.0,0.0);
|
|
const ON_Quaternion ON_Quaternion::J(0.0,0.0,1.0,0.0);
|
|
const ON_Quaternion ON_Quaternion::K(0.0,0.0,0.0,1.0);
|
|
|
|
void ON_Quaternion::SetRotation(double angle, const ON_3dVector& axis)
|
|
{
|
|
double s = axis.Length();
|
|
s = (s > 0.0) ? sin(0.5*angle)/s : 0.0;
|
|
a = cos(0.5*angle);
|
|
b = s*axis.x;
|
|
c = s*axis.y;
|
|
d = s*axis.z;
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Rotation(double angle, const ON_3dVector& axis)
|
|
{
|
|
double s = axis.Length();
|
|
s = (s > 0.0) ? sin(0.5*angle)/s : 0.0;
|
|
return ON_Quaternion(cos(0.5*angle),s*axis.x,s*axis.y,s*axis.z);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Exp(ON_Quaternion q)
|
|
{
|
|
// Added 8 Jan 2010 - not tested yet
|
|
double v = ((const ON_3dVector*)&q.b)->Length();
|
|
if ( !(v > ON_DBL_MIN) )
|
|
v = 0.0;
|
|
double ea = exp(q.a);
|
|
double z = (v > 0.0) ? ea*sin(v)/v : 0.0;
|
|
return ON_Quaternion( ea*cos(v), z*q.b, z*q.c, z*q.d );
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Log(ON_Quaternion q)
|
|
{
|
|
// Added 8 Jan 2010 - not tested yet
|
|
double lenq = q.Length();
|
|
double v = ((const ON_3dVector*)&q.b)->Length();
|
|
if ( !(v > ON_DBL_MIN) )
|
|
v = 0.0;
|
|
double z = (v > 0.0) ? acos(q.a/lenq)/v : 0.0;
|
|
return ON_Quaternion(log(lenq), z*q.b, z*q.c, z*q.d );
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Pow(ON_Quaternion q,double t)
|
|
{
|
|
// Added 8 Jan 2010 - not tested yet
|
|
return ON_Quaternion::Exp( t * ON_Quaternion::Log(q) );
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Slerp(ON_Quaternion q0, ON_Quaternion q1, double t)
|
|
{
|
|
ON_Quaternion q;
|
|
if ( t <= 0.5 )
|
|
{
|
|
q = q0.Inverse()*q1;
|
|
q = q0*ON_Quaternion::Pow(q,t);
|
|
}
|
|
else
|
|
{
|
|
q = q1.Inverse()*q0;
|
|
q = q1*ON_Quaternion::Pow(q,1.0-t);
|
|
}
|
|
return q;
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::RotateTowards(ON_Quaternion q0, ON_Quaternion q1, double MaxRadians)
|
|
{
|
|
ON_Quaternion Q = q0.Inverse() * q1;
|
|
ON_Quaternion logQ = Log(Q);
|
|
|
|
double t = MaxRadians / (2.0*logQ.Length());
|
|
|
|
return (t < 1.0) ? Slerp(q0, q1, t) : q1;
|
|
}
|
|
|
|
|
|
void ON_Quaternion::Set(double qa, double qb, double qc, double qd)
|
|
{
|
|
a = qa;
|
|
b = qb;
|
|
c = qc;
|
|
d = qd;
|
|
}
|
|
|
|
void ON_Quaternion::SetRotation(const ON_Plane& plane0, const ON_Plane& plane1 )
|
|
{
|
|
double m[3][3], r, s;
|
|
double* q;
|
|
int i,j,k;
|
|
|
|
// set m[][] = rotation matrix (acting on the left)
|
|
m[0][0] = plane1.xaxis.x*plane0.xaxis.x
|
|
+ plane1.yaxis.x*plane0.yaxis.x
|
|
+ plane1.zaxis.x*plane0.zaxis.x;
|
|
m[0][1] = plane1.xaxis.x*plane0.xaxis.y
|
|
+ plane1.yaxis.x*plane0.yaxis.y
|
|
+ plane1.zaxis.x*plane0.zaxis.y;
|
|
m[0][2] = plane1.xaxis.x*plane0.xaxis.z
|
|
+ plane1.yaxis.x*plane0.yaxis.z
|
|
+ plane1.zaxis.x*plane0.zaxis.z;
|
|
m[1][0] = plane1.xaxis.y*plane0.xaxis.x
|
|
+ plane1.yaxis.y*plane0.yaxis.x
|
|
+ plane1.zaxis.y*plane0.zaxis.x;
|
|
m[1][1] = plane1.xaxis.y*plane0.xaxis.y
|
|
+ plane1.yaxis.y*plane0.yaxis.y
|
|
+ plane1.zaxis.y*plane0.zaxis.y;
|
|
m[1][2] = plane1.xaxis.y*plane0.xaxis.z
|
|
+ plane1.yaxis.y*plane0.yaxis.z
|
|
+ plane1.zaxis.y*plane0.zaxis.z;
|
|
m[2][0] = plane1.xaxis.z*plane0.xaxis.x
|
|
+ plane1.yaxis.z*plane0.yaxis.x
|
|
+ plane1.zaxis.z*plane0.zaxis.x;
|
|
m[2][1] = plane1.xaxis.z*plane0.xaxis.y
|
|
+ plane1.yaxis.z*plane0.yaxis.y
|
|
+ plane1.zaxis.z*plane0.zaxis.y;
|
|
m[2][2] = plane1.xaxis.z*plane0.xaxis.z
|
|
+ plane1.yaxis.z*plane0.yaxis.z
|
|
+ plane1.zaxis.z*plane0.zaxis.z;
|
|
|
|
k = 1;
|
|
s = ON_SQRT_EPSILON;
|
|
for ( i = 0; i < 3 && k; i++ ) for ( j = 0; j < 3; j++ )
|
|
{
|
|
if ( i == j )
|
|
{
|
|
if (fabs(m[i][i]-1.0) > s )
|
|
{
|
|
k = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fabs(m[i][j]) > s )
|
|
{
|
|
k = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( k )
|
|
{
|
|
// m[][] is the identity matrix
|
|
a = 1.0;
|
|
b = c = d = 0.0;
|
|
return;
|
|
}
|
|
|
|
i = (m[0][0] >= m[1][1])
|
|
? ((m[0][0] >= m[2][2])?0:2)
|
|
: ((m[1][1] >= m[2][2])?1:2);
|
|
j = (i+1)%3;
|
|
k = (i+2)%3;
|
|
|
|
// Note:
|
|
// For any rotation matrix, the diagonal is
|
|
// x^2(1-cos(t)) + cos(t), y^2(1-cos(t)) + cos(t), z^2(1-cos(t)) + cos(t),
|
|
// where (x,y,z) is the unit vector axis of rotation and "t" is the angle.
|
|
// So the trace = 1 + 2cos(t).
|
|
//
|
|
// When cos(t) >= 0, m[i][i] corresponds to the axis component that has
|
|
// the largest absolute value.
|
|
//
|
|
//
|
|
//
|
|
// Observe that
|
|
// s = 1 + m[i][i] - m[j][j] - m[k][k]
|
|
// = 1 + 2*m[i][i] - m[i][i] - m[j][j] - m[k][k]
|
|
// = 1 + 2*m[i][i] - trace
|
|
// = 2*(m[i][i] - cos(t))
|
|
// = 2*(w^2(1-cos(t)^2) + cos(t) - cos(t))
|
|
// = 2*w*w*(sin(t)^2)
|
|
//
|
|
// When cos(t) >= 0, m[i][i] corresponds to the coordinate of
|
|
// the rotation axis with largest absolute value.
|
|
|
|
|
|
s = 1.0 + m[i][i] - m[j][j] - m[k][k];
|
|
if ( s > ON_DBL_MIN )
|
|
{
|
|
r = sqrt(s);
|
|
s = 0.5/r;
|
|
a = s*(m[k][j] - m[j][k]);
|
|
q = &b;
|
|
q[i] = 0.5*r;
|
|
q[j] = s*(m[i][j] + m[j][i]);
|
|
q[k] = s*(m[k][i] + m[i][k]);
|
|
}
|
|
else
|
|
{
|
|
if ( s < -1.0e-14 )
|
|
ON_ERROR("noisy rotation matrix");
|
|
a = 1.0;
|
|
b = c = d = 0.0;
|
|
}
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Rotation(const ON_Plane& plane0, const ON_Plane& plane1)
|
|
{
|
|
ON_Quaternion q;
|
|
q.SetRotation(plane0,plane1);
|
|
return q;
|
|
}
|
|
|
|
bool ON_Quaternion::GetRotation(ON_Xform& xform) const
|
|
{
|
|
bool rc;
|
|
ON_Quaternion q(*this);
|
|
if ( q.Unitize() )
|
|
{
|
|
if ( fabs(q.a-a) <= ON_ZERO_TOLERANCE
|
|
&& fabs(q.b-b) <= ON_ZERO_TOLERANCE
|
|
&& fabs(q.c-c) <= ON_ZERO_TOLERANCE
|
|
&& fabs(q.d-d) <= ON_ZERO_TOLERANCE
|
|
)
|
|
{
|
|
// "this" was already unitized - don't tweak bits
|
|
q = *this;
|
|
}
|
|
xform[1][0] = 2.0*(q.b*q.c + q.a*q.d);
|
|
xform[2][0] = 2.0*(q.b*q.d - q.a*q.c);
|
|
xform[3][0] = 0.0;
|
|
|
|
xform[0][1] = 2.0*(q.b*q.c - q.a*q.d);
|
|
xform[2][1] = 2.0*(q.c*q.d + q.a*q.b);
|
|
xform[3][1] = 0.0;
|
|
|
|
xform[0][2] = 2.0*(q.b*q.d + q.a*q.c);
|
|
xform[1][2] = 2.0*(q.c*q.d - q.a*q.b);
|
|
xform[3][2] = 0.0;
|
|
|
|
q.b = q.b*q.b;
|
|
q.c = q.c*q.c;
|
|
q.d = q.d*q.d;
|
|
xform[0][0] = 1.0 - 2.0*(q.c + q.d);
|
|
xform[1][1] = 1.0 - 2.0*(q.b + q.d);
|
|
xform[2][2] = 1.0 - 2.0*(q.b + q.c);
|
|
|
|
xform[0][3] = xform[1][3] = xform[2][3] = 0.0;
|
|
xform[3][3] = 1.0;
|
|
rc = true;
|
|
}
|
|
else if ( IsZero() )
|
|
{
|
|
xform = ON_Xform::Zero4x4;
|
|
rc = false;
|
|
}
|
|
else
|
|
{
|
|
// something is seriously wrong
|
|
ON_ERROR("ON_Quaternion::GetRotation(ON_Xform) quaternion is invalid");
|
|
xform = ON_Xform::IdentityTransformation;
|
|
rc = false;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Quaternion::GetRotation(ON_Plane& plane) const
|
|
{
|
|
plane.xaxis.x = a*a + b*b - c*c - d*d;
|
|
plane.xaxis.y = 2.0*(a*d + b*c);
|
|
plane.xaxis.z = 2.0*(b*d - a*c);
|
|
|
|
plane.yaxis.x = 2.0*(b*c - a*d);
|
|
plane.yaxis.y = a*a - b*b + c*c - d*d;
|
|
plane.yaxis.z = 2.0*(a*b + c*d);
|
|
|
|
plane.zaxis.x = 2.0*(a*c + b*d);
|
|
plane.zaxis.y = 2.0*(c*d - a*b);
|
|
plane.zaxis.z = a*a - b*b - c*c + d*d;
|
|
|
|
plane.xaxis.Unitize();
|
|
plane.yaxis.Unitize();
|
|
plane.zaxis.Unitize();
|
|
plane.origin.Set(0.0,0.0,0.0);
|
|
plane.UpdateEquation();
|
|
|
|
return plane.IsValid();
|
|
}
|
|
|
|
bool ON_Quaternion::GetRotation(double& angle, ON_3dVector& axis) const
|
|
{
|
|
const double s = Length();
|
|
angle = (s > ON_DBL_MIN) ? 2.0*acos(a/s) : 0.0;
|
|
axis.x = b;
|
|
axis.y = c;
|
|
axis.z = d;
|
|
return (axis.Unitize() && s > ON_DBL_MIN);
|
|
}
|
|
|
|
ON_3dVector ON_Quaternion::Vector() const
|
|
{
|
|
return ON_3dVector(b,c,d);
|
|
}
|
|
|
|
double ON_Quaternion::Scalar() const
|
|
{
|
|
return a;
|
|
}
|
|
|
|
bool ON_Quaternion::IsZero() const
|
|
{
|
|
return (0.0 == a && 0.0 == b && 0.0 == c && 0.0 == d);
|
|
}
|
|
|
|
bool ON_Quaternion::IsNotZero() const
|
|
{
|
|
return ( (0.0 != a || 0.0 != b || 0.0 != c || 0.0 != d)
|
|
&& ON_IsValid(a)
|
|
&& ON_IsValid(b)
|
|
&& ON_IsValid(c)
|
|
&& ON_IsValid(d)
|
|
);
|
|
}
|
|
|
|
bool ON_Quaternion::IsScalar() const
|
|
{
|
|
return (0.0 == b && 0.0 == c && 0.0 == d);
|
|
}
|
|
|
|
bool ON_Quaternion::IsVector() const
|
|
{
|
|
return (0.0 == a && (0.0 != b || 0.0 != c || 0.0 != d));
|
|
}
|
|
|
|
bool ON_Quaternion::IsValid() const
|
|
{
|
|
return ((ON_IS_VALID(a) && ON_IS_VALID(b) && ON_IS_VALID(c) && ON_IS_VALID(d)) ? true : false);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Conjugate() const
|
|
{
|
|
return ON_Quaternion(a,-b,-c,-d);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::Inverse() const
|
|
{
|
|
double x = a*a+b*b+c*c+d*d;
|
|
x = ( x > ON_DBL_MIN ) ? 1.0/x : 0.0;
|
|
return ON_Quaternion(a*x,-b*x,-c*x,-d*x);
|
|
}
|
|
|
|
bool ON_Quaternion::Invert()
|
|
{
|
|
double x = a*a+b*b+c*c+d*d;
|
|
if ( x <= ON_DBL_MIN )
|
|
return false;
|
|
x = 1.0/x;
|
|
a *= x;
|
|
x = -x;
|
|
b *= x;
|
|
c *= x;
|
|
d *= x;
|
|
return true;
|
|
}
|
|
|
|
ON_3dVector ON_Quaternion::Rotate(ON_3dVector v) const
|
|
{
|
|
// returns q*(0,v.x,v.y,v.z)*Inverse(q)
|
|
double x = a*a + b*b + c*c + d*d;
|
|
x = ( x > ON_DBL_MIN ) ? 1.0/x : 0.0;
|
|
const ON_Quaternion qinv(a*x,-b*x,-c*x,-d*x);
|
|
|
|
const ON_Quaternion qv( -b*v.x - c*v.y - d*v.z,
|
|
a*v.x + c*v.z - d*v.y,
|
|
a*v.y - b*v.z + d*v.x,
|
|
a*v.z + b*v.y - c*v.x);
|
|
|
|
v.x = qv.a*qinv.b + qv.b*qinv.a + qv.c*qinv.d - qv.d*qinv.c;
|
|
v.y = qv.a*qinv.c - qv.b*qinv.d + qv.c*qinv.a + qv.d*qinv.b;
|
|
v.z = qv.a*qinv.d + qv.b*qinv.c - qv.c*qinv.b + qv.d*qinv.a;
|
|
return v;
|
|
}
|
|
|
|
double ON_Quaternion::DistanceTo(const ON_Quaternion& q) const
|
|
{
|
|
const ON_Quaternion pq(q.a-a,q.b-b,q.c-c,q.d-d);
|
|
return pq.Length();
|
|
}
|
|
|
|
|
|
double ON_Quaternion::Distance(const ON_Quaternion& p, const ON_Quaternion& q)
|
|
{
|
|
const ON_Quaternion pq(q.a-p.a,q.b-p.b,q.c-p.c,q.d-p.d);
|
|
return pq.Length();
|
|
}
|
|
|
|
|
|
double ON_Quaternion::Length() const
|
|
{
|
|
double len;
|
|
double fa = fabs(a);
|
|
double fb = fabs(b);
|
|
double fc = fabs(c);
|
|
double fd = fabs(d);
|
|
if ( fb >= fa && fb >= fc && fb >= fd)
|
|
{
|
|
len = fa; fa = fb; fb = len;
|
|
}
|
|
else if ( fc >= fa && fc >= fb && fc >= fd)
|
|
{
|
|
len = fa; fa = fc; fc = len;
|
|
}
|
|
else if ( fd >= fa && fd >= fb && fd >= fc)
|
|
{
|
|
len = fa; fa = fd; fd = len;
|
|
}
|
|
|
|
// 15 September 2003 Dale Lear
|
|
// For small denormalized doubles (positive but smaller
|
|
// than DBL_MIN), some compilers/FPUs set 1.0/fa to +INF.
|
|
// Without the ON_DBL_MIN test we end up with
|
|
// microscopic quaternions that have infinite norm!
|
|
//
|
|
// This code is absolutely necessary. It is a critical
|
|
// part of the bug fix for RR 11217.
|
|
if ( fa > ON_DBL_MIN )
|
|
{
|
|
len = 1.0/fa;
|
|
fb *= len;
|
|
fc *= len;
|
|
fd *= len;
|
|
len = fa*sqrt(1.0 + fb*fb + fc*fc + fd*fd);
|
|
}
|
|
else if ( fa > 0.0 && ON_IS_FINITE(fa) )
|
|
len = fa;
|
|
else
|
|
len = 0.0;
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
double ON_Quaternion::LengthSquared() const
|
|
{
|
|
return (a*a + b*b + c*c + d*d);
|
|
}
|
|
|
|
|
|
ON_Xform ON_Quaternion::MatrixForm() const
|
|
{
|
|
double m[4][4];
|
|
m[0][0] = a; m[0][1] = b; m[0][2] = c; m[0][3] = d;
|
|
m[1][0] = -b; m[1][1] = a; m[1][2] = -d; m[1][3] = c;
|
|
m[2][0] = -c; m[2][1] = d; m[2][2] = a; m[2][3] = -b;
|
|
m[3][0] = -d; m[3][1] = -c; m[3][2] = b; m[3][3] = a;
|
|
return ON_Xform(&m[0][0]);
|
|
}
|
|
|
|
bool ON_Quaternion::Unitize()
|
|
{
|
|
double x = Length();
|
|
|
|
if (x > ON_DBL_MIN)
|
|
{
|
|
x = 1.0/x;
|
|
a *= x; b *= x; c *= x; d *= x;
|
|
}
|
|
else if ( x > 0.0 )
|
|
{
|
|
ON_Quaternion q(a*1.0e300,b*1.0e300,c*1.0e300,c*1.0e300);
|
|
if ( !q.Unitize() )
|
|
return false;
|
|
a = q.a;
|
|
b = q.b;
|
|
c = q.c;
|
|
d = q.d;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
ON_Quaternion::ON_Quaternion(double qa, double qb, double qc, double qd) : a(qa),b(qb),c(qc),d(qd) {}
|
|
|
|
ON_Quaternion::ON_Quaternion(const ON_3dVector& v) : a(0.0),b(v.x),c(v.y),d(v.z) {}
|
|
|
|
ON_Quaternion& ON_Quaternion::operator=(const ON_3dVector& v)
|
|
{
|
|
a = 0.0;
|
|
b = v.x;
|
|
c = v.y;
|
|
d = v.z;
|
|
return *this;
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator*(int x) const
|
|
{
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator*(float x) const
|
|
{
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator*(double x) const
|
|
{
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator/(int y) const
|
|
{
|
|
double x = (0!=y) ? 1.0/((double)y) : 0.0;
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator/(float y) const
|
|
{
|
|
double x = (0.0f!=y) ? 1.0/((double)y) : 0.0;
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator/(double y) const
|
|
{
|
|
double x = (0.0!=y) ? 1.0/((double)y) : 0.0;
|
|
return ON_Quaternion(a*x,b*x,c*x,d*x);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator+(const ON_Quaternion& q) const
|
|
{
|
|
return ON_Quaternion(a+q.a,b+q.b,c+q.c,d+q.d);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator-(const ON_Quaternion& q) const
|
|
{
|
|
return ON_Quaternion(a-q.a,b-q.b,c-q.c,d-q.d);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::operator*(const ON_Quaternion& q) const
|
|
{
|
|
return ON_Quaternion(a*q.a - b*q.b - c*q.c - d*q.d,
|
|
a*q.b + b*q.a + c*q.d - d*q.c,
|
|
a*q.c - b*q.d + c*q.a + d*q.b,
|
|
a*q.d + b*q.c - c*q.b + d*q.a);
|
|
}
|
|
|
|
ON_Quaternion operator*(int x, const ON_Quaternion& q)
|
|
{
|
|
return ON_Quaternion(x*q.a,x*q.b,x*q.c,x*q.d);
|
|
}
|
|
|
|
ON_Quaternion operator*(float x, const ON_Quaternion& q)
|
|
{
|
|
return ON_Quaternion(x*q.a,x*q.b,x*q.c,x*q.d);
|
|
}
|
|
|
|
ON_Quaternion operator*(double x, const ON_Quaternion& q)
|
|
{
|
|
return ON_Quaternion(x*q.a,x*q.b,x*q.c,x*q.d);
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::RotationZYX(double yaw, double pitch, double roll)
|
|
{
|
|
ON_Xform X;
|
|
X.RotationZYX(yaw, pitch, roll);
|
|
ON_Quaternion q;
|
|
X.GetQuaternion(q);
|
|
return q;
|
|
}
|
|
|
|
ON_Quaternion ON_Quaternion::RotationZYZ(double alpha, double beta, double gamma)
|
|
{
|
|
ON_Xform X;
|
|
X.RotationZYZ(alpha, beta, gamma );
|
|
ON_Quaternion q;
|
|
X.GetQuaternion(q);
|
|
return q;
|
|
}
|
|
|
|
|
|
bool ON_Quaternion::GetYawPitchRoll(double& yaw, double& pitch, double& roll) const
|
|
{
|
|
ON_Xform X;
|
|
bool rc = GetRotation(X);
|
|
if (rc)
|
|
rc = GetYawPitchRoll(yaw, pitch, roll);
|
|
return rc;
|
|
}
|
|
|
|
bool ON_Quaternion::GetEulerZYZ(double& alpha, double& beta, double& gamma) const
|
|
{
|
|
ON_Xform X;
|
|
bool rc = GetRotation(X);
|
|
if (rc)
|
|
rc = GetEulerZYZ(alpha, beta, gamma);
|
|
return rc;
|
|
|
|
}
|
|
|