GCC Code Coverage Report


Directory: ./
File: lib/exploragram/hexdom/frame.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 0 145 0.0%
Functions: 0 19 0.0%
Branches: 0 238 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <exploragram/hexdom/frame.h>
41
42 namespace GEO {
43
44 mat3 normalize_columns(const mat3& B) {
45 mat3 res;
46 vec3 n;
47 FOR(j, 3) n[j] = col(B, j).length(); //= std::sqrt(pow(B(0, j), 2) + pow(B(1, j), 2) + pow(B(2, j), 2));
48 FOR(j, 3) geo_assert(n[j] > 1e-20);
49 FOR(i, 3)FOR(j, 3) res(i, j) = B(i, j) / n[j];
50 return res;
51 }
52
53 mat3 invert_columns_norm(const mat3& B) {
54 mat3 res;
55 vec3 n;
56 FOR(j, 3) n[j] = col(B, j).length2();// pow(B(0, j), 2) + pow(B(1, j), 2) + pow(B(2, j), 2);
57 FOR(j, 3) geo_assert(n[j] > 1e-20);
58 FOR(i, 3)FOR(j, 3) res(i, j) = B(i, j) / n[j];
59 return res;
60 }
61
62 /**************************************************************************************************/
63
64 mat3 rotx(double angle) {
65 double c = cos(angle);
66 double s = sin(angle);
67 mat3 res = mat3_from_coeffs(
68 1,0,0,
69 0,c,-s,
70 0,s,c
71 );
72 return res;
73 }
74
75 mat3 roty(double angle) {
76 double c = cos(angle);
77 double s = sin(angle);
78 mat3 res = mat3_from_coeffs(
79 c, 0, s,
80 0, 1, 0,
81 -s, 0, c
82 );
83 return res;
84 }
85
86 mat3 rotz(double angle) {
87 double c = cos(angle);
88 double s = sin(angle);
89 mat3 res = mat3_from_coeffs(
90 c, -s, 0,
91 s, c, 0,
92 0, 0, 1
93 );
94 return res;
95 }
96
97 // non optimized version is "return rotz(xyz[2]) *roty(xyz[1]) *rotx(xyz[0]);"
98 mat3 euler_to_mat3(vec3 xyz) {
99 double ca = cos(xyz[0]), sa = sin(xyz[0]);
100 double cb = cos(xyz[1]), sb = sin(xyz[1]);
101 double cg = cos(xyz[2]), sg = sin(xyz[2]);
102 mat3 res = mat3_from_coeffs(
103 cb*cg, cg*sa*sb - ca*sg, ca*cg*sb + sa*sg,
104 cb*sg, sa*sb*sg + ca*cg, ca*sb*sg - cg*sa,
105 -sb, cb*sa, ca*cb
106 );
107 return res;
108 }
109
110 vec3 mat3_to_euler(const mat3& r) {//http://www.staff.city.ac.uk/~sbbh653/publications/euler.pdf
111 vec3 res;
112 if (std::abs(std::abs(r(2, 0)) - 1) > 1e-5) {
113 res[1] = -asin(r(2, 0));
114 res[0] = atan2(r(2, 1), r(2, 2));
115 res[2] = atan2(r(1, 0), r(0, 0));
116 } else {
117 res[2] = 0;
118 if (std::abs(r(2, 0) + 1) < 1e-5) {
119 res[1] = M_PI / 2.;
120 res[0] = atan2(r(0, 1), r(0, 2));
121 } else {
122 res[1] = -M_PI / 2.;
123 res[0] = atan2(-r(0, 1), -r(0, 2));
124 }
125 }
126 return res;
127 }
128
129
130 /***********************************************************************************************************************************/
131
132 //void generate_AxisPermutations_init_code() {
133 // mat3 r90z = mat3_from_coeffs(0, -1, 0, 1, 0, 0, 0, 0, 1);
134 // FOR(inv, 2) FOR(perm, 3) FOR(rotz, 4) {
135 // mat3 m;
136 // m.load_identity();
137 // if (inv == 1) m = mat3_from_coeffs(0, 0, -1, 0, -1, 0, -1, 0, 0);
138
139 // FOR(p, perm) FOR(d, 3) {
140 // double tmp = m(d, 0);
141 // m(d, 0) = m(d, 1);
142 // m(d, 1) = m(d, 2);
143 // m(d, 2) = tmp;
144 // }
145 // FOR(r, rotz) m = r90z*m;
146 // FOR(i, 3)FOR(j, 3) m(i, j) = std::floor(m(i, j) + 0.5);
147 // AxisPermutations[12 * inv + 4 * perm + rotz] = m;
148 // }
149 // FOR(i, 24)FOR(j, 24) if ((AxisPermutations[i] * AxisPermutations[j]).is_identity()) AxisPermutations_inv[i] = j;
150
151
152 // std::cerr << "static mat3 AxisPermutations[24] = { ";
153 // FOR(i, 24) {
154 // double* ptr = AxisPermutations[i].data();
155 // std::cerr << "mat3_from_coeffs(";
156 // std::cerr << ptr[0];
157 // FOR(d, 8) std::cerr << "," << ptr[d + 1];
158 // if (i<23)std::cerr << ")," << ((i % 4) ? "" : "\n");
159 // else std::cerr << ")};\n";
160 // }
161
162 // std::cerr << "static int AxisPermutations_inv[24] = { ";
163 // FOR(i, 24) {
164 // if (i<23)std::cerr << AxisPermutations_inv[i] << ",";
165 // else std::cerr << AxisPermutations_inv[i] << "};\n";
166 // }
167 //};
168
169 static mat3 AxisPermutations[24] = {
170 mat3_from_coeffs(1,0,0,0,1,0,0,0,1),
171 mat3_from_coeffs(0,-1,0,1,0,0,0,0,1),mat3_from_coeffs(-1,0,0,0,-1,0,0,0,1),mat3_from_coeffs(0,1,0,-1,0,0,0,0,1),mat3_from_coeffs(0,0,1,1,0,0,0,1,0),
172 mat3_from_coeffs(-1,0,0,0,0,1,0,1,0),mat3_from_coeffs(0,0,-1,-1,0,0,0,1,0),mat3_from_coeffs(1,0,0,0,0,-1,0,1,0),mat3_from_coeffs(0,1,0,0,0,1,1,0,0),
173 mat3_from_coeffs(0,0,-1,0,1,0,1,0,0),mat3_from_coeffs(0,-1,0,0,0,-1,1,0,0),mat3_from_coeffs(0,0,1,0,-1,0,1,0,0),mat3_from_coeffs(0,0,-1,0,-1,0,-1,0,0),
174 mat3_from_coeffs(0,1,0,0,0,-1,-1,0,0),mat3_from_coeffs(0,0,1,0,1,0,-1,0,0),mat3_from_coeffs(0,-1,0,0,0,1,-1,0,0),mat3_from_coeffs(0,-1,0,-1,0,0,0,0,-1),
175 mat3_from_coeffs(1,0,0,0,-1,0,0,0,-1),mat3_from_coeffs(0,1,0,1,0,0,0,0,-1),mat3_from_coeffs(-1,0,0,0,1,0,0,0,-1),mat3_from_coeffs(-1,0,0,0,0,-1,0,-1,0),
176 mat3_from_coeffs(0,0,1,-1,0,0,0,-1,0),mat3_from_coeffs(1,0,0,0,0,1,0,-1,0),mat3_from_coeffs(0,0,-1,1,0,0,0,-1,0)
177 };
178
179 static index_t AxisPermutations_inv[24] = { 0,3,2,1,8,5,15,22,4,14,21,11,12,23,9,6,16,17,18,19,20,10,7,13 };
180
181 void AxisPermutation::aligns_B_wrt_ref(mat3 ref, mat3 B) {
182 ref= normalize_columns(ref);
183 B = normalize_columns(B);
184 index_t best_i = 0;
185 double best_score = 1e20;
186 FOR(i, 24) {
187 double score = Frobenius_norm(B*AxisPermutations[i]-ref);
188 if (score < best_score) {
189 best_i = i;
190 best_score = score;
191 }
192 }
193 mid = best_i;
194 }
195
196 void AxisPermutation::make_col2_equal_to_z(mat3 B, vec3 z) {
197 B = normalize_columns(B);
198 index_t best_i = 0;
199 double best_score = 1e20;
200 FOR(i, 24) {
201 double score = (col(B*AxisPermutations[i],2) - z).length2();
202 if (score < best_score) {
203 best_i = i;
204 best_score = score;
205 }
206 }
207 mid = best_i;
208 }
209
210 const mat3& AxisPermutation::get_mat() const {
211 return AxisPermutations[mid];
212 }
213
214 AxisPermutation AxisPermutation::inverse() {
215 return AxisPermutation(AxisPermutations_inv[mid]);
216 }
217
218 /***********************************************************************************************************************************/
219
220 void Frame::make_z_equal_to(vec3 z) {
221 z = normalize(z);
222 vec3 x(1, 0, 0);
223 vec3 y = cross(z, x);
224 if (y.length2() < .1) {
225 x = vec3(0, 1, 0);
226 y = cross(z, x);
227 }
228 y = normalize(y);
229 x = cross(y, z);
230 FOR(d, 3) r(d, 0) = x[d];
231 FOR(d, 3) r(d, 1) = y[d];
232 FOR(d, 3) r(d, 2) = z[d];
233 }
234
235 mat3 Frame::average_frame(vector<mat3>& data) {
236 SphericalHarmonicL4 sum;
237 FOR(i, data.size()) {
238 SphericalHarmonicL4 nv;
239 nv[4] = std::sqrt(7. / 12.);
240 nv[8] = std::sqrt(5. / 12.);
241 nv.euler_rot(mat3_to_euler(data[i]));
242 sum = sum + nv;
243 }
244 sum = sum*(1. / sum.norm());
245 return sum.project_mat3();
246 }
247
248 mat3 Frame::representative_frame(vector<vec3>& bunch_of_vectors, vector<double>& w) {
249 SphericalHarmonicL4 sum;
250 FOR(i,bunch_of_vectors.size()) {
251 vec3 n = normalize(bunch_of_vectors[i]);
252 mat3 r;
253 Frame(r).make_z_equal_to(n);
254 SphericalHarmonicL4 nv;
255 nv[4] = std::sqrt(7. / 12.);
256 nv.euler_rot(mat3_to_euler(r));
257 nv = nv * w[i];
258 sum = sum + nv;
259 }
260 sum = sum*(1. / sum.norm());
261 return sum.project_mat3();
262 }
263
264 mat3 Frame::representative_frame(vector<vec3>& bunch_of_vectors) {
265 vector<double> w(bunch_of_vectors.size(), 1);
266 return representative_frame(bunch_of_vectors, w);
267 }
268
269 /***********************************************************************************************************************************/
270
271 AxisPermutation Rij(Mesh* m, Attribute<mat3>& B, index_t i, index_t j) {
272 if (i > j) return Rij(m, B, j, i).inverse(); // façon obscure de rendre le bazar symmetrique ?
273 AxisPermutation permut;
274 permut.aligns_B_wrt_ref(B[i], B[j]);
275 return permut;
276 }
277
278 bool triangle_is_frame_singular(Mesh* m, Attribute<mat3>& B, index_t c, index_t cf) {
279 mat3 ac_rot;
280 ac_rot.load_identity();
281 FOR(e, 3) ac_rot = Rij(m, B, m->cells.facet_vertex(c, cf, e), m->cells.facet_vertex(c, cf, next_mod(e, 3))).get_mat()*ac_rot;
282 return !is_identity_auvp(ac_rot);
283 }
284
285 bool triangle_is_frame_singular___give_stable_direction(Mesh* m, int& stable_dir_index, Attribute<mat3>& B, index_t c, index_t cf, index_t cfv) {
286 mat3 ac_rot,id3D;
287 stable_dir_index = -1;
288 ac_rot.load_identity();
289 FOR(e, 3) ac_rot = Rij(m, B, m->cells.facet_vertex(c, cf, (e+ cfv)%3), m->cells.facet_vertex(c, cf, (e + cfv+1) % 3)).get_mat()*ac_rot;
290 if (is_identity_auvp(ac_rot)) return false;
291 FOR(ax, 3){
292 double sum = 0;
293 FOR(d, 3) sum += std::abs(ac_rot(d, ax) - id3D(d, ax));
294 if (sum<1e-10) stable_dir_index = int(ax);
295 }
296 return true;
297 }
298 bool triangle_is_frame_singular___give_stable_direction(Mesh* m, vec3& stable_dir_geom, Attribute<mat3>& B, index_t c, index_t cf, index_t cfv) {
299 int stable_dir_index;
300 if (!triangle_is_frame_singular___give_stable_direction(m, stable_dir_index, B, c, cf,cfv)) return false;
301 stable_dir_geom = vec3(0, 0, 0);
302 if (stable_dir_index == -1) return true;
303 FOR(d, 3) stable_dir_geom[d] = B[m->cells.facet_vertex(c, cf, cfv)](d, index_t(stable_dir_index));
304 stable_dir_geom = normalize(stable_dir_geom);
305 return true;
306 }
307
308 }
309