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:
wmayer
2022-02-15 21:05:11 +01:00
parent 97d1c114d0
commit 0208608b9e
8 changed files with 110 additions and 40 deletions

View File

@@ -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;
}