FastLED 3.10.6
Loading...
Searching...
No Matches

◆ invert3x3()

bool fl::colorimetric_response::invert3x3 ( const float in[3][3],
float out[3][3] )
inline

Definition at line 115 of file colorimetric_response.h.

115 {
116 const float a = in[0][0], b = in[0][1], c = in[0][2];
117 const float d = in[1][0], e = in[1][1], f = in[1][2];
118 const float g = in[2][0], h = in[2][1], i = in[2][2];
119 const float det = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
120
121 // Scale the test by the matrix's own magnitude, because an absolute
122 // threshold cannot see the ratio that actually decides invertibility.
123 //
124 // Each column is divided by its largest entry and the determinant of
125 // *that* matrix is what gets tested. The obvious alternative -- compare
126 // |det| against the product of the column 2-norms -- needs `a * a`, which
127 // overflows float32 for entries past about 1.8e19: `diag(1e20, 1e-20, 1)`
128 // has determinant 1 and a perfectly representable inverse, and squaring
129 // would send its first column norm to infinity and reject it. Dividing
130 // first cannot overflow, and it costs three divisions instead of three
131 // square roots.
132 const float scale_a = detail::columnScale(a, d, g);
133 const float scale_b = detail::columnScale(b, e, h);
134 const float scale_c = detail::columnScale(c, f, i);
135
136 // One negated `>`, which covers three cases at once and is why there is
137 // no separate zero or NaN check: a zero column makes its scale zero, so
138 // the division below yields infinity or NaN and the comparison fails; a
139 // NaN anywhere makes every comparison false, so the negation rejects. An
140 // explicit `scale > 0` clause was written here first, and mutation
141 // testing showed it could not fire.
142 const float an = a / scale_a, dn = d / scale_a, gn = g / scale_a;
143 const float bn = b / scale_b, en = e / scale_b, hn = h / scale_b;
144 const float cn = c / scale_c, fn = f / scale_c, in_ = i / scale_c;
145 const float det_normalized = an * (en * in_ - fn * hn) -
146 bn * (dn * in_ - fn * gn) +
147 cn * (dn * hn - en * gn);
148 if (!(fl::fabs(det_normalized) > detail::kRelativeSingularity)) {
149 return false;
150 }
151
152 const float inv_det = 1.0f / det;
153 out[0][0] = (e * i - f * h) * inv_det;
154 out[0][1] = (c * h - b * i) * inv_det;
155 out[0][2] = (b * f - c * e) * inv_det;
156 out[1][0] = (f * g - d * i) * inv_det;
157 out[1][1] = (a * i - c * g) * inv_det;
158 out[1][2] = (c * d - a * f) * inv_det;
159 out[2][0] = (d * h - e * g) * inv_det;
160 out[2][1] = (b * g - a * h) * inv_det;
161 out[2][2] = (a * e - b * d) * inv_det;
162 return true;
163}
constexpr float kRelativeSingularity
How small a determinant may be, relative to the matrix's own scale, before the inverse is rounding no...
float columnScale(float a, float b, float c) FL_NO_EXCEPT
Largest absolute entry of a column, which is its infinity norm.
double fabs(double value) FL_NO_EXCEPT
Definition math.h:509
InputGamut g
Definition rgbw.h:124

References fl::colorimetric_response::detail::columnScale(), fl::fabs(), fl::FL_NO_EXCEPT, fl::g, and fl::colorimetric_response::detail::kRelativeSingularity.

Referenced by build_rgb_colorimetric_cache(), and build_source_matrix().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: