Base: fix Matrix4D::hasScale
* If all column vectors of the 3x3 sub-matrix are equal the function incorrectly claims that it's uniform scaling. * Detect also non-uniform scaling and if was applied from the left or right side * Replace the int with an enum and expose it to Python * Add several new unit tests
This commit is contained in:
@@ -155,6 +155,18 @@ double Matrix4D::determinant() const
|
||||
return fDet;
|
||||
}
|
||||
|
||||
double Matrix4D::determinant3() const
|
||||
{
|
||||
double a = dMtrx4D[0][0] * dMtrx4D[1][1] * dMtrx4D[2][2];
|
||||
double b = dMtrx4D[0][1] * dMtrx4D[1][2] * dMtrx4D[2][0];
|
||||
double c = dMtrx4D[1][0] * dMtrx4D[2][1] * dMtrx4D[0][2];
|
||||
double d = dMtrx4D[0][2] * dMtrx4D[1][1] * dMtrx4D[2][0];
|
||||
double e = dMtrx4D[1][0] * dMtrx4D[0][1] * dMtrx4D[2][2];
|
||||
double f = dMtrx4D[0][0] * dMtrx4D[2][1] * dMtrx4D[1][2];
|
||||
double det = (a + b + c) - (d + e + f);
|
||||
return det;
|
||||
}
|
||||
|
||||
void Matrix4D::move (const Vector3f& rclVct)
|
||||
{
|
||||
move(convertTo<Vector3d>(rclVct));
|
||||
@@ -821,42 +833,46 @@ Matrix4D& Matrix4D::Hat(const Vector3d& rV)
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Matrix4D::hasScale(double tol) const
|
||||
ScaleType Matrix4D::hasScale(double tol) const
|
||||
{
|
||||
// check for uniform scaling
|
||||
//
|
||||
// scaling factors are the column vector length. We use square distance and
|
||||
// ignore the actual scaling signess
|
||||
//
|
||||
// Note: In general using the column vectors to get the scaling factors makes
|
||||
// sense if a scaling matrix was multiplied from the left side. If a scaling
|
||||
// matrix was multiplied from the right side then the row vectors must be used.
|
||||
// However, since this function checks for _uniform_ scaling it doesn't make a
|
||||
// difference if row or column vectors are used.
|
||||
|
||||
// TODO:
|
||||
// The int should be replaced with an enum class that tells the calling
|
||||
// instance whether:
|
||||
// * a uniform scaling was applied
|
||||
// * a non-uniform scaling from the right side was applied
|
||||
// * a non-uniform scaling from the left side was applied
|
||||
// * no scaling at all
|
||||
|
||||
// For a scaled rotation matrix it matters whether
|
||||
// the scaling was applied from the left or right side.
|
||||
// Only in case of uniform scaling it doesn't make a difference.
|
||||
if (tol == 0.0)
|
||||
tol = 1e-9;
|
||||
|
||||
// get column vectors
|
||||
double dx = Vector3d(dMtrx4D[0][0],dMtrx4D[1][0],dMtrx4D[2][0]).Sqr();
|
||||
double dy = Vector3d(dMtrx4D[0][1],dMtrx4D[1][1],dMtrx4D[2][1]).Sqr();
|
||||
if (fabs(dx-dy) > tol) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
double dz = Vector3d(dMtrx4D[0][2],dMtrx4D[1][2],dMtrx4D[2][2]).Sqr();
|
||||
if (fabs(dy-dz) > tol)
|
||||
return -1;
|
||||
double dz = Vector3d(dMtrx4D[0][2],dMtrx4D[1][2],dMtrx4D[2][2]).Sqr();
|
||||
double dxyz = sqrt(dx * dy * dz);
|
||||
|
||||
// get row vectors
|
||||
double du = Vector3d(dMtrx4D[0][0],dMtrx4D[0][1],dMtrx4D[0][2]).Sqr();
|
||||
double dv = Vector3d(dMtrx4D[1][0],dMtrx4D[1][1],dMtrx4D[1][2]).Sqr();
|
||||
double dw = Vector3d(dMtrx4D[2][0],dMtrx4D[2][1],dMtrx4D[2][2]).Sqr();
|
||||
double duvw = sqrt(du * dv * dw);
|
||||
|
||||
double d3 = determinant3();
|
||||
|
||||
// This could be e.g. a projection, a shearing,... matrix
|
||||
if (fabs(dxyz - d3) > tol && fabs(duvw - d3) > tol) {
|
||||
return ScaleType::Other;
|
||||
}
|
||||
|
||||
if (fabs(dx-1.0) > tol)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
if (fabs(duvw - d3) <= tol && (fabs(du - dv) > tol || fabs(dv - dw) > tol)) {
|
||||
return ScaleType::NonUniformLeft;
|
||||
}
|
||||
|
||||
if (fabs(dxyz - d3) <= tol && (fabs(dx - dy) > tol || fabs(dy - dz) > tol)) {
|
||||
return ScaleType::NonUniformRight;
|
||||
}
|
||||
|
||||
if (fabs(dx - 1.0) > tol) {
|
||||
return ScaleType::Uniform;
|
||||
}
|
||||
|
||||
return ScaleType::NoScaling;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user