Skip to content

Commit 506bacb

Browse files
committed
Optimize Basis4D.inverse
1 parent 767313f commit 506bacb

File tree

1 file changed

+49
-19
lines changed

1 file changed

+49
-19
lines changed

math/basis_4d.cpp

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,17 @@ Basis4D Basis4D::rotate_plane_local(const Vector4 &p_local_plane_from, const Vec
128128
// Inversion methods.
129129

130130
Basis4D Basis4D::inverse() const {
131-
return adjugate() / determinant();
131+
const Basis4D adj = adjugate();
132+
// Use the adjugate's values instead of calling determinant() to avoid redundant calculations.
133+
// Note: The adjugate already applies the sign changes needed, so these are all added here.
134+
const real_t det = x.x * adj.x.x + y.x * adj.x.y + z.x * adj.x.z + w.x * adj.x.w;
135+
// We want to only fail for values *really* close to zero.
136+
// A scale of 0.00001 (1e-5) in 4D results in a 1e-20 determinant.
137+
if (Math::is_equal_approx(det, (real_t)0.0, (real_t)1e-20) || !Math::is_finite(det)) {
138+
ERR_PRINT("Basis4D.inverse: Cannot invert matrix with zero or near-zero determinant (" + String::num(det) + "). Returning identity matrix.");
139+
return Basis4D();
140+
}
141+
return adj / det;
132142
}
133143

134144
void Basis4D::transpose() {
@@ -147,24 +157,44 @@ Basis4D Basis4D::transposed() const {
147157
}
148158

149159
Basis4D Basis4D::adjugate() const {
150-
// This method accumulates a lot of floating-point error,
151-
// but doing all calculations in at least doubles helps a ton.
152-
const real_t xx = y.y * (double_t)z.z * w.w + z.y * (double_t)w.z * y.w + w.y * (double_t)y.z * z.w - w.y * (double_t)z.z * y.w - z.y * (double_t)y.z * w.w - y.y * (double_t)w.z * z.w;
153-
const real_t xy = w.y * (double_t)z.z * x.w + z.y * (double_t)x.z * w.w + x.y * (double_t)w.z * z.w - x.y * (double_t)z.z * w.w - z.y * (double_t)w.z * x.w - w.y * (double_t)x.z * z.w;
154-
const real_t xz = x.y * (double_t)y.z * w.w + y.y * (double_t)w.z * x.w + w.y * (double_t)x.z * y.w - w.y * (double_t)y.z * x.w - y.y * (double_t)x.z * w.w - x.y * (double_t)w.z * y.w;
155-
const real_t xw = z.y * (double_t)y.z * x.w + y.y * (double_t)x.z * z.w + x.y * (double_t)z.z * y.w - x.y * (double_t)y.z * z.w - y.y * (double_t)z.z * x.w - z.y * (double_t)x.z * y.w;
156-
const real_t yx = w.x * (double_t)z.z * y.w + z.x * (double_t)y.z * w.w + y.x * (double_t)w.z * z.w - y.x * (double_t)z.z * w.w - z.x * (double_t)w.z * y.w - w.x * (double_t)y.z * z.w;
157-
const real_t yy = x.x * (double_t)z.z * w.w + z.x * (double_t)w.z * x.w + w.x * (double_t)x.z * z.w - w.x * (double_t)z.z * x.w - z.x * (double_t)x.z * w.w - x.x * (double_t)w.z * z.w;
158-
const real_t yz = w.x * (double_t)y.z * x.w + y.x * (double_t)x.z * w.w + x.x * (double_t)w.z * y.w - x.x * (double_t)y.z * w.w - y.x * (double_t)w.z * x.w - w.x * (double_t)x.z * y.w;
159-
const real_t yw = x.x * (double_t)y.z * z.w + y.x * (double_t)z.z * x.w + z.x * (double_t)x.z * y.w - z.x * (double_t)y.z * x.w - y.x * (double_t)x.z * z.w - x.x * (double_t)z.z * y.w;
160-
const real_t zx = y.x * (double_t)z.y * w.w + z.x * (double_t)w.y * y.w + w.x * (double_t)y.y * z.w - w.x * (double_t)z.y * y.w - z.x * (double_t)y.y * w.w - y.x * (double_t)w.y * z.w;
161-
const real_t zy = w.x * (double_t)z.y * x.w + z.x * (double_t)x.y * w.w + x.x * (double_t)w.y * z.w - x.x * (double_t)z.y * w.w - z.x * (double_t)w.y * x.w - w.x * (double_t)x.y * z.w;
162-
const real_t zz = x.x * (double_t)y.y * w.w + y.x * (double_t)w.y * x.w + w.x * (double_t)x.y * y.w - w.x * (double_t)y.y * x.w - y.x * (double_t)x.y * w.w - x.x * (double_t)w.y * y.w;
163-
const real_t zw = z.x * (double_t)y.y * x.w + y.x * (double_t)x.y * z.w + x.x * (double_t)z.y * y.w - x.x * (double_t)y.y * z.w - y.x * (double_t)z.y * x.w - z.x * (double_t)x.y * y.w;
164-
const real_t wx = w.x * (double_t)z.y * y.z + z.x * (double_t)y.y * w.z + y.x * (double_t)w.y * z.z - y.x * (double_t)z.y * w.z - z.x * (double_t)w.y * y.z - w.x * (double_t)y.y * z.z;
165-
const real_t wy = x.x * (double_t)z.y * w.z + z.x * (double_t)w.y * x.z + w.x * (double_t)x.y * z.z - w.x * (double_t)z.y * x.z - z.x * (double_t)x.y * w.z - x.x * (double_t)w.y * z.z;
166-
const real_t wz = w.x * (double_t)y.y * x.z + y.x * (double_t)x.y * w.z + x.x * (double_t)w.y * y.z - x.x * (double_t)y.y * w.z - y.x * (double_t)w.y * x.z - w.x * (double_t)x.y * y.z;
167-
const real_t ww = x.x * (double_t)y.y * z.z + y.x * (double_t)z.y * x.z + z.x * (double_t)x.y * y.z - z.x * (double_t)y.y * x.z - y.x * (double_t)x.y * z.z - x.x * (double_t)z.y * y.z;
160+
// This method accumulates a lot of floating-point error, but doing
161+
// all calculations in "at least doubles" (double_t) helps a ton.
162+
// Canonical 2x2 minors.
163+
const double_t dxy_zw = (double_t)x.z * (double_t)y.w - (double_t)x.w * (double_t)y.z;
164+
const double_t dxz_zw = (double_t)x.z * (double_t)z.w - (double_t)x.w * (double_t)z.z;
165+
const double_t dxw_zw = (double_t)x.z * (double_t)w.w - (double_t)x.w * (double_t)w.z;
166+
const double_t dyz_zw = (double_t)y.z * (double_t)z.w - (double_t)y.w * (double_t)z.z;
167+
const double_t dyw_zw = (double_t)y.z * (double_t)w.w - (double_t)y.w * (double_t)w.z;
168+
const double_t dzw_zw = (double_t)z.z * (double_t)w.w - (double_t)z.w * (double_t)w.z;
169+
const double_t dxy_yw = (double_t)x.y * (double_t)y.w - (double_t)x.w * (double_t)y.y;
170+
const double_t dxz_yw = (double_t)x.y * (double_t)z.w - (double_t)x.w * (double_t)z.y;
171+
const double_t dxw_yw = (double_t)x.y * (double_t)w.w - (double_t)x.w * (double_t)w.y;
172+
const double_t dyz_yw = (double_t)y.y * (double_t)z.w - (double_t)y.w * (double_t)z.y;
173+
const double_t dyw_yw = (double_t)y.y * (double_t)w.w - (double_t)y.w * (double_t)w.y;
174+
const double_t dzw_yw = (double_t)z.y * (double_t)w.w - (double_t)z.w * (double_t)w.y;
175+
const double_t dxy_yz = (double_t)x.y * (double_t)y.z - (double_t)x.z * (double_t)y.y;
176+
const double_t dxz_yz = (double_t)x.y * (double_t)z.z - (double_t)x.z * (double_t)z.y;
177+
const double_t dxw_yz = (double_t)x.y * (double_t)w.z - (double_t)x.z * (double_t)w.y;
178+
const double_t dyz_yz = (double_t)y.y * (double_t)z.z - (double_t)y.z * (double_t)z.y;
179+
const double_t dyw_yz = (double_t)y.y * (double_t)w.z - (double_t)y.z * (double_t)w.y;
180+
const double_t dzw_yz = (double_t)z.y * (double_t)w.z - (double_t)z.z * (double_t)w.y;
181+
// Adjugate entries.
182+
const real_t xx = +(double_t)y.y * dzw_zw - (double_t)z.y * dyw_zw + (double_t)w.y * dyz_zw;
183+
const real_t xy = -(double_t)w.y * dxz_zw + (double_t)z.y * dxw_zw - (double_t)x.y * dzw_zw;
184+
const real_t xz = +(double_t)x.y * dyw_zw - (double_t)y.y * dxw_zw + (double_t)w.y * dxy_zw;
185+
const real_t xw = -(double_t)z.y * dxy_zw + (double_t)y.y * dxz_zw - (double_t)x.y * dyz_zw;
186+
const real_t yx = -(double_t)w.x * dyz_zw + (double_t)z.x * dyw_zw - (double_t)y.x * dzw_zw;
187+
const real_t yy = +(double_t)x.x * dzw_zw - (double_t)z.x * dxw_zw + (double_t)w.x * dxz_zw;
188+
const real_t yz = -(double_t)w.x * dxy_zw + (double_t)y.x * dxw_zw - (double_t)x.x * dyw_zw;
189+
const real_t yw = +(double_t)x.x * dyz_zw - (double_t)y.x * dxz_zw + (double_t)z.x * dxy_zw;
190+
const real_t zx = +(double_t)y.x * dzw_yw - (double_t)z.x * dyw_yw + (double_t)w.x * dyz_yw;
191+
const real_t zy = -(double_t)w.x * dxz_yw + (double_t)z.x * dxw_yw - (double_t)x.x * dzw_yw;
192+
const real_t zz = +(double_t)x.x * dyw_yw - (double_t)y.x * dxw_yw + (double_t)w.x * dxy_yw;
193+
const real_t zw = -(double_t)z.x * dxy_yw + (double_t)y.x * dxz_yw - (double_t)x.x * dyz_yw;
194+
const real_t wx = -(double_t)w.x * dyz_yz + (double_t)z.x * dyw_yz - (double_t)y.x * dzw_yz;
195+
const real_t wy = +(double_t)x.x * dzw_yz - (double_t)z.x * dxw_yz + (double_t)w.x * dxz_yz;
196+
const real_t wz = -(double_t)w.x * dxy_yz + (double_t)y.x * dxw_yz - (double_t)x.x * dyw_yz;
197+
const real_t ww = +(double_t)x.x * dyz_yz - (double_t)y.x * dxz_yz + (double_t)z.x * dxy_yz;
168198
return Basis4D(xx, xy, xz, xw, yx, yy, yz, yw, zx, zy, zz, zw, wx, wy, wz, ww);
169199
}
170200

0 commit comments

Comments
 (0)