@@ -128,7 +128,17 @@ Basis4D Basis4D::rotate_plane_local(const Vector4 &p_local_plane_from, const Vec
128128// Inversion methods.
129129
130130Basis4D 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
134144void Basis4D::transpose () {
@@ -147,24 +157,44 @@ Basis4D Basis4D::transposed() const {
147157}
148158
149159Basis4D 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