pytessel 1.2.0__cp310-cp310-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pytessel might be problematic. Click here for more details.

pytessel/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .pytessel import PyTessel
2
+
3
+ from ._version import __version__
pytessel/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "1.2.2"
@@ -0,0 +1,561 @@
1
+ /**************************************************************************
2
+ * *
3
+ * Author: Ivo Filot <ivo@ivofilot.nl> *
4
+ * *
5
+ * PyTessel is free software: *
6
+ * you can redistribute it and/or modify it under the terms of the *
7
+ * GNU General Public License as published by the Free Software *
8
+ * Foundation, either version 3 of the License, or (at your option) *
9
+ * any later version. *
10
+ * *
11
+ * PyTessel is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty *
13
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * See the GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program. If not, see http://www.gnu.org/licenses/. *
18
+ * *
19
+ **************************************************************************/
20
+
21
+ #include "isosurface.h"
22
+
23
+ /**************
24
+ * CUBE *
25
+ **************/
26
+
27
+ /*
28
+ * z
29
+ * |
30
+ * 4------5
31
+ * /| /|
32
+ * 7-|----6 |
33
+ * | 0----|-1--- y (j)
34
+ * |/ |/
35
+ * 3 ---- 2
36
+ * /
37
+ * x (i)
38
+ *
39
+ */
40
+
41
+ Cube::Cube(unsigned int _i, unsigned int _j, unsigned int _k, const ScalarField &_vp) {
42
+
43
+ this->i = _i;
44
+ this->j = _j;
45
+ this->k = _k;
46
+ this->cubidx = 0;
47
+
48
+ values[0] = _vp.get_value(_i, _j, _k);
49
+ values[1] = _vp.get_value(_i, _j+1, _k);
50
+ values[2] = _vp.get_value(_i+1, _j+1, _k);
51
+ values[3] = _vp.get_value(_i+1, _j, _k);
52
+
53
+ values[4] = _vp.get_value(_i, _j, _k+1);
54
+ values[5] = _vp.get_value(_i, _j+1, _k+1);
55
+ values[6] = _vp.get_value(_i+1, _j+1, _k+1);
56
+ values[7] = _vp.get_value(_i+1, _j, _k+1);
57
+ }
58
+
59
+ void Cube::set_cube_index(float _isovalue) {
60
+ if (this->values[0] < _isovalue) this->cubidx |= (1 << 0);
61
+ if (this->values[1] < _isovalue) this->cubidx |= (1 << 1);
62
+ if (this->values[2] < _isovalue) this->cubidx |= (1 << 2);
63
+ if (this->values[3] < _isovalue) this->cubidx |= (1 << 3);
64
+ if (this->values[4] < _isovalue) this->cubidx |= (1 << 4);
65
+ if (this->values[5] < _isovalue) this->cubidx |= (1 << 5);
66
+ if (this->values[6] < _isovalue) this->cubidx |= (1 << 6);
67
+ if (this->values[7] < _isovalue) this->cubidx |= (1 << 7);
68
+ }
69
+
70
+ unsigned int Cube::get_cube_index() const {
71
+ return this->cubidx;
72
+ }
73
+
74
+ float Cube::get_value_from_vertex(unsigned int _p) const {
75
+ return this->values[_p];
76
+ }
77
+
78
+ Vec3 Cube::get_position_from_vertex(unsigned int _p) const {
79
+ Vec3 c;
80
+ if(_p == 0) {
81
+ c.x = (float)this->i;
82
+ c.y = (float)this->j;
83
+ c.z = (float)this->k;
84
+ } else if(_p == 1) {
85
+ c.x = (float)this->i;
86
+ c.y = (float)this->j+1;
87
+ c.z = (float)this->k;
88
+ } else if(_p == 2) {
89
+ c.x = (float)this->i+1;
90
+ c.y = (float)this->j+1;
91
+ c.z = (float)this->k;
92
+ } else if(_p == 3) {
93
+ c.x = (float)this->i+1;
94
+ c.y = (float)this->j;
95
+ c.z = (float)this->k;
96
+ } else if(_p == 4) {
97
+ c.x = (float)this->i;
98
+ c.y = (float)this->j;
99
+ c.z = (float)this->k+1;
100
+ } else if(_p == 5) {
101
+ c.x = (float)this->i;
102
+ c.y = (float)this->j+1;
103
+ c.z = (float)this->k+1;
104
+ } else if(_p == 6) {
105
+ c.x = (float)this->i+1;
106
+ c.y = (float)this->j+1;
107
+ c.z = (float)this->k+1;
108
+ } else if(_p == 7) {
109
+ c.x = (float)this->i+1;
110
+ c.y = (float)this->j;
111
+ c.z = (float)this->k+1;
112
+ } else {
113
+ c.x = 0;
114
+ c.y = 0;
115
+ c.z = 0;
116
+ }
117
+
118
+ return c;
119
+ }
120
+
121
+ /*********************
122
+ * TETRAHEDRON *
123
+ *********************/
124
+
125
+ Tetrahedron::Tetrahedron(unsigned int _i, unsigned int _j, unsigned int _k,
126
+ const ScalarField &_vp, unsigned int _pos) {
127
+ this->i = _i;
128
+ this->j = _j;
129
+ this->k = _k;
130
+ this->tetidx = 0;
131
+
132
+ /*
133
+ * z
134
+ * |
135
+ * 4------5
136
+ * /| /|
137
+ * 7-|----6 |
138
+ * | 0----|-1--- y (j)
139
+ * |/ |/
140
+ * 3 ---- 2
141
+ * /
142
+ * x (i)
143
+ *
144
+ */
145
+
146
+ switch(_pos) {
147
+ case 0: // 0 2 3 7
148
+ values[0] = _vp.get_value(_i , _j , _k);
149
+ values[1] = _vp.get_value(_i+1, _j+1, _k);
150
+ values[2] = _vp.get_value(_i+1, _j , _k);
151
+ values[3] = _vp.get_value(_i+1, _j , _k+1);
152
+ pos[0].x = _i ; pos[0].y = _j ; pos[0].z = _k ;
153
+ pos[1].x = _i+1 ; pos[1].y = _j+1 ; pos[1].z = _k ;
154
+ pos[2].x = _i+1 ; pos[2].y = _j ; pos[2].z = _k ;
155
+ pos[3].x = _i+1 ; pos[3].y = _j ; pos[3].z = _k+1 ;
156
+ break;
157
+ case 1: // 0 2 6 7
158
+ values[0] = _vp.get_value(_i, _j, _k);
159
+ values[1] = _vp.get_value(_i+1, _j+1, _k);
160
+ values[2] = _vp.get_value(_i+1, _j+1, _k+1);
161
+ values[3] = _vp.get_value(_i+1, _j , _k+1);
162
+ pos[0].x = _i ; pos[0].y = _j ; pos[0].z = _k ;
163
+ pos[1].x = _i+1 ; pos[1].y = _j+1 ; pos[1].z = _k ;
164
+ pos[2].x = _i+1 ; pos[2].y = _j+1 ; pos[2].z = _k+1 ;
165
+ pos[3].x = _i+1 ; pos[3].y = _j ; pos[3].z = _k+1 ;
166
+ break;
167
+ case 2: // 0 4 6 7
168
+ values[0] = _vp.get_value(_i, _j, _k);
169
+ values[1] = _vp.get_value(_i, _j, _k+1);
170
+ values[2] = _vp.get_value(_i+1, _j+1, _k+1);
171
+ values[3] = _vp.get_value(_i+1, _j , _k+1);
172
+ pos[0].x = _i ; pos[0].y = _j ; pos[0].z = _k ;
173
+ pos[1].x = _i ; pos[1].y = _j ; pos[1].z = _k+1 ;
174
+ pos[2].x = _i+1 ; pos[2].y = _j+1 ; pos[2].z = _k+1 ;
175
+ pos[3].x = _i+1 ; pos[3].y = _j ; pos[3].z = _k+1 ;
176
+ break;
177
+ case 3: // 0 6 1 2
178
+ values[0] = _vp.get_value(_i, _j, _k);
179
+ values[1] = _vp.get_value(_i+1, _j+1, _k+1);
180
+ values[2] = _vp.get_value(_i, _j+1, _k);
181
+ values[3] = _vp.get_value(_i+1, _j+1, _k);
182
+ pos[0].x = _i ; pos[0].y = _j ; pos[0].z = _k ;
183
+ pos[1].x = _i+1 ; pos[1].y = _j+1 ; pos[1].z = _k+1 ;
184
+ pos[2].x = _i ; pos[2].y = _j+1 ; pos[2].z = _k ;
185
+ pos[3].x = _i+1 ; pos[3].y = _j+1 ; pos[3].z = _k ;
186
+ break;
187
+ case 4: // 0 6 1 4
188
+ values[0] = _vp.get_value(_i, _j, _k);
189
+ values[1] = _vp.get_value(_i+1, _j+1, _k+1);
190
+ values[2] = _vp.get_value(_i, _j+1, _k);
191
+ values[3] = _vp.get_value(_i, _j, _k+1);
192
+ pos[0].x = _i ; pos[0].y = _j ; pos[0].z = _k ;
193
+ pos[1].x = _i+1 ; pos[1].y = _j+1 ; pos[1].z = _k+1 ;
194
+ pos[2].x = _i ; pos[2].y = _j+1 ; pos[2].z = _k ;
195
+ pos[3].x = _i ; pos[3].y = _j ; pos[3].z = _k+1 ;
196
+ break;
197
+ case 5: // 5 6 1 4
198
+ values[0] = _vp.get_value(_i, _j+1, _k+1);
199
+ values[1] = _vp.get_value(_i+1, _j+1, _k+1);
200
+ values[2] = _vp.get_value(_i, _j+1, _k);
201
+ values[3] = _vp.get_value(_i, _j, _k+1);
202
+ pos[0].x = _i ; pos[0].y = _j+1 ; pos[0].z = _k+1 ;
203
+ pos[1].x = _i+1 ; pos[1].y = _j+1 ; pos[1].z = _k+1 ;
204
+ pos[2].x = _i ; pos[2].y = _j+1 ; pos[2].z = _k ;
205
+ pos[3].x = _i ; pos[3].y = _j ; pos[3].z = _k+1 ;
206
+ break;
207
+ default:
208
+ exit(-1);
209
+ }
210
+ }
211
+
212
+ void Tetrahedron::set_tetrahedron_index(float _isovalue) {
213
+ if (this->values[0] < _isovalue) this->tetidx |= (1 << 0);
214
+ if (this->values[1] < _isovalue) this->tetidx |= (1 << 1);
215
+ if (this->values[2] < _isovalue) this->tetidx |= (1 << 2);
216
+ if (this->values[3] < _isovalue) this->tetidx |= (1 << 3);
217
+ }
218
+
219
+ unsigned int Tetrahedron::get_tetrahedron_index() const {
220
+ return this->tetidx;
221
+ }
222
+
223
+ float Tetrahedron::get_value_from_vertex(unsigned int _p) const {
224
+ return this->values[_p];
225
+ }
226
+
227
+ const Vec3& Tetrahedron::get_position_from_vertex(unsigned int _p) const {
228
+ return pos[_p];
229
+ }
230
+
231
+ /**************
232
+ * TRIANGLE *
233
+ **************/
234
+
235
+ Triangle::Triangle(const Vec3 &_p1, const Vec3 &_p2, const Vec3 &_p3) {
236
+ this->p1 = _p1;
237
+ this->p2 = _p2;
238
+ this->p3 = _p3;
239
+ }
240
+
241
+ void Triangle::transform_to_real(const ScalarField &_vp) {
242
+ p1 = _vp.grid_to_realspace(p1.x, p1.y, p1.z);
243
+ p2 = _vp.grid_to_realspace(p2.x, p2.y, p2.z);
244
+ p3 = _vp.grid_to_realspace(p3.x, p3.y, p3.z);
245
+ }
246
+
247
+ float Triangle::get_x(unsigned int i) const {
248
+ switch(i) {
249
+ case 0:
250
+ return p1.x;
251
+ case 1:
252
+ return p2.x;
253
+ case 2:
254
+ return p3.x;
255
+ default:
256
+ return p1.x;
257
+ }
258
+ }
259
+
260
+ float Triangle::get_y(unsigned int i) const {
261
+ switch(i) {
262
+ case 0:
263
+ return p1.y;
264
+ case 1:
265
+ return p2.y;
266
+ case 2:
267
+ return p3.y;
268
+ default:
269
+ return p1.y;
270
+ }
271
+ }
272
+
273
+ float Triangle::get_z(unsigned int i) const {
274
+ switch(i) {
275
+ case 0:
276
+ return p1.z;
277
+ case 1:
278
+ return p2.z;
279
+ case 2:
280
+ return p3.z;
281
+ default:
282
+ return p1.z;
283
+ }
284
+ }
285
+
286
+ /**************
287
+ * ISOSURFACE *
288
+ **************/
289
+
290
+ /**
291
+ * @brief default constructor
292
+ *
293
+ * @param _sf pointer to ScalarField object
294
+ */
295
+ IsoSurface::IsoSurface(const std::shared_ptr<ScalarField>& _vp) :
296
+ vp_ptr(_vp) {
297
+ this->isovalue = 0;
298
+ this->vp_ptr->copy_grid_dimensions(this->grid_dimensions);
299
+ }
300
+
301
+ /**
302
+ * @brief generate isosurface using marching cubes algorithm
303
+ *
304
+ * @param[in] _isovalue The isovalue
305
+ */
306
+ void IsoSurface::marching_cubes(float _isovalue) {
307
+ this->isovalue = _isovalue;
308
+ this->sample_grid_with_cubes(_isovalue);
309
+ this->construct_triangles_from_cubes(_isovalue);
310
+
311
+ #pragma omp parallel for
312
+ for(unsigned int i=0; i < this->triangles.size(); i++) {
313
+ triangles[i].transform_to_real(*this->vp_ptr);
314
+ }
315
+ }
316
+
317
+ /**
318
+ * @brief generate isosurface using marching tetrahedra algorithm
319
+ *
320
+ * @param[in] _isovalue The isovalue
321
+ */
322
+ void IsoSurface::marching_tetrahedra(float _isovalue) {
323
+ this->isovalue = _isovalue;
324
+ this->sample_grid_with_tetrahedra(_isovalue);
325
+ this->construct_triangles_from_tetrahedra(_isovalue);
326
+ for(std::vector<Triangle>::iterator it = triangles.begin();
327
+ it != triangles.end(); ++it) {
328
+ it->transform_to_real(*this->vp_ptr);
329
+ }
330
+ }
331
+
332
+ /**
333
+ * @brief Gets the triangles pointer.
334
+ *
335
+ * @return The triangles pointer.
336
+ */
337
+ const std::vector<Triangle>* IsoSurface::get_triangles_ptr() const {
338
+ return &this->triangles;
339
+ }
340
+
341
+ void IsoSurface::sample_grid_with_cubes(float _isovalue) {
342
+ std::mutex push_back_mutex;
343
+
344
+ #pragma omp parallel for schedule(dynamic)
345
+ for(unsigned int i = 0; i < this->grid_dimensions[2] - 1; i++) {
346
+ for(unsigned int j = 0; j < this->grid_dimensions[1] - 1; j++) {
347
+ for(unsigned int k = 0; k < this->grid_dimensions[0] - 1; k++) {
348
+ Cube cub(k, j, i, *this->vp_ptr);
349
+ cub.set_cube_index(_isovalue);
350
+ if(!(cub.get_cube_index() == (unsigned int)0 ||
351
+ cub.get_cube_index() == (unsigned int)255)) {
352
+ push_back_mutex.lock();
353
+ this->cube_table.push_back(cub);
354
+ push_back_mutex.unlock();
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
360
+
361
+ void IsoSurface::sample_grid_with_tetrahedra(float _isovalue) {
362
+ for(unsigned int i = 0; i < this->grid_dimensions[2] - 1; i++) {
363
+ for(unsigned int j = 0; j < this->grid_dimensions[1] - 1; j++) {
364
+ for(unsigned int k = 0; k < this->grid_dimensions[0] - 1; k++) {
365
+ for(unsigned int l=0; l<6; l++) {
366
+ Tetrahedron tet(k, j, i, *this->vp_ptr, l);
367
+ tet.set_tetrahedron_index(_isovalue);
368
+ if(!(tet.get_tetrahedron_index() == (unsigned int)0 ||
369
+ tet.get_tetrahedron_index() == (unsigned int)15)) {
370
+ this->tetrahedra_table.push_back(tet);
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ void IsoSurface::construct_triangles_from_cubes(float _isovalue) {
379
+ std::mutex push_back_mutex;
380
+
381
+ #pragma omp parallel for schedule(dynamic)
382
+ for(unsigned int i=0; i < cube_table.size(); i++) {
383
+
384
+ uint8_t cubeindex = cube_table[i].get_cube_index();
385
+ Vec3 vertices_list[12];
386
+
387
+ /* Find the vertices where the surface intersects the cube, perform
388
+ an interpolation of 2 (Vec3) coordinates and 2 values and the isovalue,
389
+ return one (Vec3) coordinate as the result */
390
+ if (edge_table[cubeindex] & (1 << 0))
391
+ vertices_list[0] =
392
+ this->interpolate_from_cubes(cube_table[i], 0, 1, _isovalue);
393
+ if (edge_table[cubeindex] & (1 << 1))
394
+ vertices_list[1] =
395
+ this->interpolate_from_cubes(cube_table[i], 1, 2, _isovalue);
396
+ if (edge_table[cubeindex] & (1 << 2))
397
+ vertices_list[2] =
398
+ this->interpolate_from_cubes(cube_table[i], 2, 3, _isovalue);
399
+ if (edge_table[cubeindex] & (1 << 3))
400
+ vertices_list[3] =
401
+ this->interpolate_from_cubes(cube_table[i], 3, 0, _isovalue);
402
+ if (edge_table[cubeindex] & (1 << 4))
403
+ vertices_list[4] =
404
+ this->interpolate_from_cubes(cube_table[i], 4, 5, _isovalue);
405
+ if (edge_table[cubeindex] & (1 << 5))
406
+ vertices_list[5] =
407
+ this->interpolate_from_cubes(cube_table[i], 5, 6, _isovalue);
408
+ if (edge_table[cubeindex] & (1 << 6))
409
+ vertices_list[6] =
410
+ this->interpolate_from_cubes(cube_table[i], 6, 7, _isovalue);
411
+ if (edge_table[cubeindex] & (1 << 7))
412
+ vertices_list[7] =
413
+ this->interpolate_from_cubes(cube_table[i], 7, 4, _isovalue);
414
+ if (edge_table[cubeindex] & (1 << 8))
415
+ vertices_list[8] =
416
+ this->interpolate_from_cubes(cube_table[i], 0, 4, _isovalue);
417
+ if (edge_table[cubeindex] & (1 << 9))
418
+ vertices_list[9] =
419
+ this->interpolate_from_cubes(cube_table[i], 1, 5, _isovalue);
420
+ if (edge_table[cubeindex] & (1 << 10))
421
+ vertices_list[10] =
422
+ this->interpolate_from_cubes(cube_table[i], 2, 6, _isovalue);
423
+ if (edge_table[cubeindex] & (1 << 11))
424
+ vertices_list[11] =
425
+ this->interpolate_from_cubes(cube_table[i], 3, 7, _isovalue);
426
+
427
+ /* finally construct the triangles using the triangle table */
428
+ for(unsigned int i=0; triangle_table[cubeindex][i] != -1; i += 3) {
429
+ Triangle triangle(
430
+ vertices_list[triangle_table[cubeindex][i]],
431
+ vertices_list[triangle_table[cubeindex][i+1]],
432
+ vertices_list[triangle_table[cubeindex][i+2]]);
433
+ /* push the triangle to the list */
434
+ push_back_mutex.lock();
435
+ this->triangles.push_back(triangle);
436
+ push_back_mutex.unlock();
437
+ }
438
+ }
439
+ }
440
+
441
+ void IsoSurface::construct_triangles_from_tetrahedra(float _isovalue) {
442
+ for(unsigned int i=0; i < tetrahedra_table.size(); i++) {
443
+
444
+ unsigned int tetidx = tetrahedra_table[i].get_tetrahedron_index();
445
+ Vec3 p[3];
446
+
447
+ switch(tetidx) {
448
+ case 0x0E:
449
+ case 0x01:
450
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 1, _isovalue);
451
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 2, _isovalue);
452
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 3, _isovalue);
453
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
454
+ break;
455
+ case 0x0D:
456
+ case 0x02:
457
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 0, _isovalue);
458
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 3, _isovalue);
459
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 2, _isovalue);
460
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
461
+ break;
462
+ case 0x0C:
463
+ case 0x03:
464
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 3, _isovalue);
465
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 2, _isovalue);
466
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 3, _isovalue);
467
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
468
+
469
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 2, _isovalue);
470
+ this->triangles.push_back(Triangle(p[2], p[0], p[1]));
471
+
472
+ break;
473
+ case 0x0B:
474
+ case 0x04:
475
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 2, 0, _isovalue);
476
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 2, 1, _isovalue);
477
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 2, 3, _isovalue);
478
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
479
+ break;
480
+ case 0x0A:
481
+ case 0x05:
482
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 1, _isovalue);
483
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 2, 3, _isovalue);
484
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 3, _isovalue);
485
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
486
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 2, _isovalue);
487
+ this->triangles.push_back(Triangle(p[0], p[2], p[1]));
488
+ break;
489
+ case 0x09:
490
+ case 0x06:
491
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 1, _isovalue);
492
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 1, 3, _isovalue);
493
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 2, 3, _isovalue);
494
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
495
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 0, 2, _isovalue);
496
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
497
+ break;
498
+ case 0x07:
499
+ case 0x08:
500
+ p[0] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 3, 0, _isovalue);
501
+ p[1] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 3, 2, _isovalue);
502
+ p[2] = this->interpolate_from_tetrahedra(tetrahedra_table[i], 3, 1, _isovalue);
503
+ this->triangles.push_back(Triangle(p[0], p[1], p[2]));
504
+ break;
505
+ }
506
+ }
507
+ }
508
+
509
+ Vec3 IsoSurface::interpolate_from_cubes(const Cube &_cub, unsigned int _p1,
510
+ unsigned int _p2, float _isovalue) {
511
+ float v1 = _cub.get_value_from_vertex(_p1);
512
+ float v2 = _cub.get_value_from_vertex(_p2);
513
+
514
+ Vec3 p1 = _cub.get_position_from_vertex(_p1);
515
+ Vec3 p2 = _cub.get_position_from_vertex(_p2);
516
+
517
+ Vec3 p;
518
+ float mu;
519
+
520
+ if(std::abs(_isovalue-v1) < PRECISION_LIMIT)
521
+ return p1;
522
+ if(std::abs(_isovalue-v2) < PRECISION_LIMIT)
523
+ return p2;
524
+ if(std::abs(v1-v2) < PRECISION_LIMIT)
525
+ return p1;
526
+
527
+ mu = (_isovalue - v1) / (v2 - v1);
528
+
529
+ p.x = p1.x + mu * (p2.x - p1.x);
530
+ p.y = p1.y + mu * (p2.y - p1.y);
531
+ p.z = p1.z + mu * (p2.z - p1.z);
532
+
533
+ return p;
534
+ }
535
+
536
+ Vec3 IsoSurface::interpolate_from_tetrahedra(const Tetrahedron &_tet,
537
+ unsigned int _p1, unsigned int _p2, float _isovalue) {
538
+ float v1 = _tet.get_value_from_vertex(_p1);
539
+ float v2 = _tet.get_value_from_vertex(_p2);
540
+
541
+ Vec3 p1 = _tet.get_position_from_vertex(_p1);
542
+ Vec3 p2 = _tet.get_position_from_vertex(_p2);
543
+
544
+ Vec3 p;
545
+ float mu;
546
+
547
+ if(std::abs(_isovalue-v1) < PRECISION_LIMIT)
548
+ return p1;
549
+ if(std::abs(_isovalue-v2) < PRECISION_LIMIT)
550
+ return p2;
551
+ if(std::abs(v1-v2) < PRECISION_LIMIT)
552
+ return p1;
553
+
554
+ mu = (_isovalue - v1) / (v2 - v1);
555
+
556
+ p.x = p1.x + mu * (p2.x - p1.x);
557
+ p.y = p1.y + mu * (p2.y - p1.y);
558
+ p.z = p1.z + mu * (p2.z - p1.z);
559
+
560
+ return p;
561
+ }