Blender V5.0
mesh_evaluate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_mesh_types.h"
14#include "DNA_meshdata_types.h"
15
16#include "BLI_array_utils.hh"
17#include "BLI_index_range.hh"
18#include "BLI_math_geom.h"
19#include "BLI_span.hh"
20#include "BLI_utildefines.h"
21#include "BLI_virtual_array.hh"
22
23#include "BKE_attribute.hh"
24#include "BKE_mesh.hh"
25
26using blender::float3;
27using blender::int2;
30using blender::Span;
31using blender::VArray;
32
33/* -------------------------------------------------------------------- */
36
37namespace blender::bke::mesh {
38
39static float3 face_center_calc_ngon(const Span<float3> vert_positions, const Span<int> face_verts)
40{
41 const float w = 1.0f / float(face_verts.size());
42
43 float3 center(0);
44 for (const int i : face_verts.index_range()) {
45 center += vert_positions[face_verts[i]] * w;
46 }
47 return center;
48}
49
50float3 face_center_calc(const Span<float3> vert_positions, const Span<int> face_verts)
51{
52 if (face_verts.size() == 3) {
53 float3 center;
54 mid_v3_v3v3v3(center,
55 vert_positions[face_verts[0]],
56 vert_positions[face_verts[1]],
57 vert_positions[face_verts[2]]);
58 return center;
59 }
60 if (face_verts.size() == 4) {
61 float3 center;
62 mid_v3_v3v3v3v3(center,
63 vert_positions[face_verts[0]],
64 vert_positions[face_verts[1]],
65 vert_positions[face_verts[2]],
66 vert_positions[face_verts[3]]);
67 return center;
68 }
69 return face_center_calc_ngon(vert_positions, face_verts);
70}
71
72float face_area_calc(const Span<float3> vert_positions, const Span<int> face_verts)
73{
74 if (face_verts.size() == 3) {
75 return area_tri_v3(vert_positions[face_verts[0]],
76 vert_positions[face_verts[1]],
77 vert_positions[face_verts[2]]);
78 }
79 Array<float3, 32> coords(face_verts.size());
80 for (const int i : face_verts.index_range()) {
81 coords[i] = vert_positions[face_verts[i]];
82 }
83 return area_poly_v3((const float (*)[3])coords.data(), face_verts.size());
84}
85
86} // namespace blender::bke::mesh
87
88float BKE_mesh_calc_area(const Mesh *mesh)
89{
90 const Span<float3> positions = mesh->vert_positions();
91 const blender::OffsetIndices faces = mesh->faces();
92 const Span<int> corner_verts = mesh->corner_verts();
93
94 float total_area = 0.0f;
95 for (const int i : faces.index_range()) {
96 total_area += blender::bke::mesh::face_area_calc(positions, corner_verts.slice(faces[i]));
97 }
98 return total_area;
99}
100
101static float UNUSED_FUNCTION(mesh_calc_face_volume_centroid)(const int *face_verts,
102 const int face_size,
103 const float (*positions)[3],
104 float r_cent[3])
105{
106 const float *v_pivot, *v_step1;
107 float total_volume = 0.0f;
108
109 zero_v3(r_cent);
110
111 v_pivot = positions[face_verts[0]];
112 v_step1 = positions[face_verts[1]];
113
114 for (int i = 2; i < face_size; i++) {
115 const float *v_step2 = positions[face_verts[i]];
116
117 /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
118 * of the triangle and the origin as the fourth vertex */
119 const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
120 total_volume += tetra_volume;
121
122 /* Calculate the centroid of the tetrahedron formed by the 3 vertices
123 * of the triangle and the origin as the fourth vertex.
124 * The centroid is simply the average of the 4 vertices.
125 *
126 * Note that the vector is 4x the actual centroid
127 * so the division can be done once at the end. */
128 for (uint j = 0; j < 3; j++) {
129 r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
130 }
131
132 v_step1 = v_step2;
133 }
134
135 return total_volume;
136}
137
138namespace blender::bke::mesh {
139
146 const Span<int> face_verts,
147 const float3 &reference_center,
148 float r_cent[3])
149{
150 /* See: mesh_calc_face_volume_centroid for comments. */
151 float v_pivot[3], v_step1[3];
152 float total_volume = 0.0f;
153 zero_v3(r_cent);
154 sub_v3_v3v3(v_pivot, positions[face_verts[0]], reference_center);
155 sub_v3_v3v3(v_step1, positions[face_verts[1]], reference_center);
156 for (int i = 2; i < face_verts.size(); i++) {
157 float v_step2[3];
158 sub_v3_v3v3(v_step2, positions[face_verts[i]], reference_center);
159 const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
160 total_volume += tetra_volume;
161 for (uint j = 0; j < 3; j++) {
162 r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
163 }
164 copy_v3_v3(v_step1, v_step2);
165 }
166 return total_volume;
167}
168
175static float face_area_centroid_calc(const Span<float3> positions,
176 const Span<int> face_verts,
177 float r_cent[3])
178{
179 float total_area = 0.0f;
180 float v1[3], v2[3], v3[3], tri_cent[3];
181
182 const float3 normal = blender::bke::mesh::face_normal_calc(positions, face_verts);
183
184 copy_v3_v3(v1, positions[face_verts[0]]);
185 copy_v3_v3(v2, positions[face_verts[1]]);
186
187 zero_v3(r_cent);
188
189 for (int i = 2; i < face_verts.size(); i++) {
190 copy_v3_v3(v3, positions[face_verts[i]]);
191
192 float tri_area = area_tri_signed_v3(v1, v2, v3, normal);
193 total_area += tri_area;
194
195 mid_v3_v3v3v3(tri_cent, v1, v2, v3);
196 madd_v3_v3fl(r_cent, tri_cent, tri_area);
197
198 copy_v3_v3(v2, v3);
199 }
200
201 mul_v3_fl(r_cent, 1.0f / total_area);
202
203 return total_area;
204}
205
206void face_angles_calc(const Span<float3> vert_positions,
207 const Span<int> face_verts,
208 MutableSpan<float> angles)
209{
210 float nor_prev[3];
211 float nor_next[3];
212
213 int i_this = face_verts.size() - 1;
214 int i_next = 0;
215
217 nor_prev, vert_positions[face_verts[i_this - 1]], vert_positions[face_verts[i_this]]);
218 normalize_v3(nor_prev);
219
220 while (i_next < face_verts.size()) {
221 sub_v3_v3v3(nor_next, vert_positions[face_verts[i_this]], vert_positions[face_verts[i_next]]);
222 normalize_v3(nor_next);
223 angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
224
225 /* step */
226 copy_v3_v3(nor_prev, nor_next);
227 i_this = i_next;
228 i_next++;
229 }
230}
231
232} // namespace blender::bke::mesh
233
235
236/* -------------------------------------------------------------------- */
239
240bool BKE_mesh_center_median(const Mesh *mesh, float r_cent[3])
241{
242 float3 center = blender::array_utils::compute_sum<float3>(mesh->vert_positions());
243
244 /* otherwise we get NAN for 0 verts */
245 if (mesh->verts_num) {
246 mul_v3_fl(center, 1.0 / float(mesh->verts_num));
247 }
248
249 copy_v3_v3(r_cent, center);
250
251 return (mesh->verts_num != 0);
252}
253
254bool BKE_mesh_center_median_from_faces(const Mesh *mesh, float r_cent[3])
255{
256 int tot = 0;
257 const Span<float3> positions = mesh->vert_positions();
258 const blender::OffsetIndices faces = mesh->faces();
259 const Span<int> corner_verts = mesh->corner_verts();
260 zero_v3(r_cent);
261 for (const int i : faces.index_range()) {
262 for (const int vert : corner_verts.slice(faces[i])) {
263 add_v3_v3(r_cent, positions[vert]);
264 }
265 tot += faces[i].size();
266 }
267 /* otherwise we get NAN for 0 verts */
268 if (mesh->faces_num) {
269 mul_v3_fl(r_cent, 1.0f / float(tot));
270 }
271 return (mesh->faces_num != 0);
272}
273
274bool BKE_mesh_center_of_surface(const Mesh *mesh, float r_cent[3])
275{
276 float face_area;
277 float total_area = 0.0f;
278 float face_cent[3];
279 const Span<float3> positions = mesh->vert_positions();
280 const blender::OffsetIndices faces = mesh->faces();
281 const Span<int> corner_verts = mesh->corner_verts();
282
283 zero_v3(r_cent);
284
285 /* calculate a weighted average of face centroids */
286 for (const int i : faces.index_range()) {
288 positions, corner_verts.slice(faces[i]), face_cent);
289
290 madd_v3_v3fl(r_cent, face_cent, face_area);
291 total_area += face_area;
292 }
293 /* otherwise we get NAN for 0 faces */
294 if (mesh->faces_num) {
295 mul_v3_fl(r_cent, 1.0f / total_area);
296 }
297
298 /* zero area faces cause this, fallback to median */
299 if (UNLIKELY(!is_finite_v3(r_cent))) {
300 return BKE_mesh_center_median(mesh, r_cent);
301 }
302
303 return (mesh->faces_num != 0);
304}
305
306bool BKE_mesh_center_of_volume(const Mesh *mesh, float r_cent[3])
307{
308 float face_volume;
309 float total_volume = 0.0f;
310 float face_cent[3];
311 const Span<float3> positions = mesh->vert_positions();
312 const blender::OffsetIndices faces = mesh->faces();
313 const Span<int> corner_verts = mesh->corner_verts();
314
315 /* Use an initial center to avoid numeric instability of geometry far away from the center. */
316 float init_cent[3];
317 const bool init_cent_result = BKE_mesh_center_median_from_faces(mesh, init_cent);
318
319 zero_v3(r_cent);
320
321 /* calculate a weighted average of polyhedron centroids */
322 for (const int i : faces.index_range()) {
324 positions, corner_verts.slice(faces[i]), init_cent, face_cent);
325
326 /* face_cent is already volume-weighted, so no need to multiply by the volume */
327 add_v3_v3(r_cent, face_cent);
328 total_volume += face_volume;
329 }
330 /* otherwise we get NAN for 0 faces */
331 if (total_volume != 0.0f) {
332 /* multiply by 0.25 to get the correct centroid */
333 /* no need to divide volume by 6 as the centroid is weighted by 6x the volume,
334 * so it all cancels out. */
335 mul_v3_fl(r_cent, 0.25f / total_volume);
336 }
337
338 /* this can happen for non-manifold objects, fallback to median */
339 if (UNLIKELY(!is_finite_v3(r_cent))) {
340 copy_v3_v3(r_cent, init_cent);
341 return init_cent_result;
342 }
343 add_v3_v3(r_cent, init_cent);
344 return (mesh->faces_num != 0);
345}
346
348
349/* -------------------------------------------------------------------- */
352
353static bool mesh_calc_center_centroid_ex(const float (*positions)[3],
354 int /*mverts_num*/,
355 const blender::int3 *corner_tris,
356 int corner_tris_num,
357 const int *corner_verts,
358 float r_center[3])
359{
360
361 zero_v3(r_center);
362
363 if (corner_tris_num == 0) {
364 return false;
365 }
366
367 float totweight = 0.0f;
368 int i;
369 for (i = 0; i < corner_tris_num; i++) {
370 const float *v1 = positions[corner_verts[corner_tris[i][0]]];
371 const float *v2 = positions[corner_verts[corner_tris[i][1]]];
372 const float *v3 = positions[corner_verts[corner_tris[i][2]]];
373 float area;
374
375 area = area_tri_v3(v1, v2, v3);
376 madd_v3_v3fl(r_center, v1, area);
377 madd_v3_v3fl(r_center, v2, area);
378 madd_v3_v3fl(r_center, v3, area);
379 totweight += area;
380 }
381 if (totweight == 0.0f) {
382 return false;
383 }
384
385 mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
386
387 return true;
388}
389
390void BKE_mesh_calc_volume(const float (*vert_positions)[3],
391 const int mverts_num,
392 const blender::int3 *corner_tris,
393 const int corner_tris_num,
394 const int *corner_verts,
395 float *r_volume,
396 float r_center[3])
397{
398 float center[3];
399 float totvol;
400 int i;
401
402 if (r_volume) {
403 *r_volume = 0.0f;
404 }
405 if (r_center) {
406 zero_v3(r_center);
407 }
408
409 if (corner_tris_num == 0) {
410 return;
411 }
412
414 vert_positions, mverts_num, corner_tris, corner_tris_num, corner_verts, center))
415 {
416 return;
417 }
418
419 totvol = 0.0f;
420
421 for (i = 0; i < corner_tris_num; i++) {
422 const float *v1 = vert_positions[corner_verts[corner_tris[i][0]]];
423 const float *v2 = vert_positions[corner_verts[corner_tris[i][1]]];
424 const float *v3 = vert_positions[corner_verts[corner_tris[i][2]]];
425 float vol;
426
427 vol = volume_tetrahedron_signed_v3(center, v1, v2, v3);
428 if (r_volume) {
429 totvol += vol;
430 }
431 if (r_center) {
432 /* averaging factor 1/3 is applied in the end */
433 madd_v3_v3fl(r_center, v1, vol);
434 madd_v3_v3fl(r_center, v2, vol);
435 madd_v3_v3fl(r_center, v3, vol);
436 }
437 }
438
439 /* NOTE: Depending on arbitrary centroid position,
440 * totvol can become negative even for a valid mesh.
441 * The true value is always the positive value.
442 */
443 if (r_volume) {
444 *r_volume = fabsf(totvol);
445 }
446 if (r_center) {
447 /* NOTE: Factor 1/3 is applied once for all vertices here.
448 * This also automatically negates the vector if totvol is negative.
449 */
450 if (totvol != 0.0f) {
451 mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
452 }
453 }
454}
455
457
458/* -------------------------------------------------------------------- */
461
462void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
463{
464 if (UNLIKELY(!md->totdisp || !md->disps)) {
465 return;
466 }
467
468 const int sides = int(sqrt(md->totdisp));
469 float (*co)[3] = md->disps;
470
471 for (int x = 0; x < sides; x++) {
472 float *co_a, *co_b;
473
474 for (int y = 0; y < x; y++) {
475 co_a = co[y * sides + x];
476 co_b = co[x * sides + y];
477
478 swap_v3_v3(co_a, co_b);
479 std::swap(co_a[0], co_a[1]);
480 std::swap(co_b[0], co_b[1]);
481
482 if (use_loop_mdisp_flip) {
483 co_a[2] *= -1.0f;
484 co_b[2] *= -1.0f;
485 }
486 }
487
488 co_a = co[x * sides + x];
489
490 std::swap(co_a[0], co_a[1]);
491
492 if (use_loop_mdisp_flip) {
493 co_a[2] *= -1.0f;
494 }
495 }
496}
497
499
500/* -------------------------------------------------------------------- */
503
504namespace blender::bke {
505
507 const Span<bool> hide_vert,
508 MutableSpan<bool> hide_edge)
509{
510 using namespace blender;
511 threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
512 for (const int i : range) {
513 hide_edge[i] = hide_vert[edges[i][0]] || hide_vert[edges[i][1]];
514 }
515 });
516}
517
519 const Span<int> corner_verts,
520 const Span<bool> hide_vert,
521 MutableSpan<bool> hide_poly)
522{
523 using namespace blender;
524 threading::parallel_for(faces.index_range(), 4096, [&](const IndexRange range) {
525 for (const int i : range) {
526 const Span<int> face_verts = corner_verts.slice(faces[i]);
527 hide_poly[i] = std::any_of(
528 face_verts.begin(), face_verts.end(), [&](const int vert) { return hide_vert[vert]; });
529 }
530 });
531}
532
534{
535 MutableAttributeAccessor attributes = mesh.attributes_for_write();
536
537 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
538 ".hide_vert", AttrDomain::Point, false);
539 if (hide_vert.is_single() && !hide_vert.get_internal_single()) {
540 attributes.remove(".hide_edge");
541 attributes.remove(".hide_poly");
542 return;
543 }
544 const VArraySpan<bool> hide_vert_span{hide_vert};
545
547 ".hide_edge", AttrDomain::Edge);
549 ".hide_poly", AttrDomain::Face);
550
551 mesh_edge_hide_from_vert(mesh.edges(), hide_vert_span, hide_edge.span);
552 mesh_face_hide_from_vert(mesh.faces(), mesh.corner_verts(), hide_vert_span, hide_poly.span);
553
554 hide_edge.finish();
555 hide_poly.finish();
556}
557
559{
560 MutableAttributeAccessor attributes = mesh.attributes_for_write();
561
562 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
563 ".hide_poly", AttrDomain::Face, false);
564 if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
565 attributes.remove(".hide_vert");
566 attributes.remove(".hide_edge");
567 return;
568 }
569 const VArraySpan<bool> hide_poly_span{hide_poly};
570 const OffsetIndices faces = mesh.faces();
571 const Span<int> corner_verts = mesh.corner_verts();
572 const Span<int> corner_edges = mesh.corner_edges();
574 ".hide_vert", AttrDomain::Point);
576 ".hide_edge", AttrDomain::Edge);
577
578 /* Hide all edges or vertices connected to hidden polygons. */
579 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
580 for (const int i : range) {
581 if (hide_poly_span[i]) {
582 hide_vert.span.fill_indices(corner_verts.slice(faces[i]), true);
583 hide_edge.span.fill_indices(corner_edges.slice(faces[i]), true);
584 }
585 }
586 });
587 /* Unhide vertices and edges connected to visible polygons. */
588 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
589 for (const int i : range) {
590 if (!hide_poly_span[i]) {
591 hide_vert.span.fill_indices(corner_verts.slice(faces[i]), false);
592 hide_edge.span.fill_indices(corner_edges.slice(faces[i]), false);
593 }
594 }
595 });
596
597 hide_vert.finish();
598 hide_edge.finish();
599}
600
602
603/* -------------------------------------------------------------------- */
606
608{
609 MutableAttributeAccessor attributes = mesh.attributes_for_write();
610 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
611 ".select_poly", AttrDomain::Face, false);
612 if (select_poly.is_single() && !select_poly.get_internal_single()) {
613 attributes.remove(".select_vert");
614 attributes.remove(".select_edge");
615 return;
616 }
618 ".select_vert", AttrDomain::Point);
620 ".select_edge", AttrDomain::Edge);
621
622 /* Use generic domain interpolation to read the face attribute on the other domains.
623 * Assume selected faces are not hidden and none of their vertices/edges are hidden. */
624 array_utils::copy(*attributes.lookup_or_default<bool>(".select_poly", AttrDomain::Point, false),
625 select_vert.span);
626 array_utils::copy(*attributes.lookup_or_default<bool>(".select_poly", AttrDomain::Edge, false),
627 select_edge.span);
628
629 select_vert.finish();
630 select_edge.finish();
631}
632
634{
635 MutableAttributeAccessor attributes = mesh.attributes_for_write();
636 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
637 ".select_vert", AttrDomain::Point, false);
638 if (select_vert.is_single() && !select_vert.get_internal_single()) {
639 attributes.remove(".select_edge");
640 attributes.remove(".select_poly");
641 return;
642 }
644 ".select_edge", AttrDomain::Edge);
646 ".select_poly", AttrDomain::Face);
647 {
648 IndexMaskMemory memory;
649 const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
650 ".hide_edge", AttrDomain::Edge, false);
652 *attributes.lookup_or_default<bool>(".select_vert", AttrDomain::Edge, false),
653 IndexMask::from_bools(hide_edge, memory).complement(hide_edge.index_range(), memory),
654 select_edge.span);
655 }
656 {
657 IndexMaskMemory memory;
658 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
659 ".hide_poly", AttrDomain::Face, false);
661 *attributes.lookup_or_default<bool>(".select_vert", AttrDomain::Face, false),
662 IndexMask::from_bools(hide_poly, memory).complement(hide_poly.index_range(), memory),
663 select_poly.span);
664 }
665 select_edge.finish();
666 select_poly.finish();
667}
668
670{
671 MutableAttributeAccessor attributes = mesh.attributes_for_write();
672 const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
673 ".select_edge", AttrDomain::Point, false);
674 if (select_edge.is_single() && !select_edge.get_internal_single()) {
675 attributes.remove(".select_vert");
676 attributes.remove(".select_poly");
677 return;
678 }
680 ".select_vert", AttrDomain::Point);
682 ".select_poly", AttrDomain::Face);
683 {
684 IndexMaskMemory memory;
685 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
686 ".hide_vert", AttrDomain::Point, false);
688 *attributes.lookup_or_default<bool>(".select_edge", AttrDomain::Point, false),
689 IndexMask::from_bools(hide_vert, memory).complement(hide_vert.index_range(), memory),
690 select_vert.span);
691 }
692 {
693 IndexMaskMemory memory;
694 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
695 ".hide_poly", AttrDomain::Face, false);
697 *attributes.lookup_or_default<bool>(".select_edge", AttrDomain::Face, false),
698 IndexMask::from_bools(hide_poly, memory).complement(hide_poly.index_range(), memory),
699 select_poly.span);
700 }
701 select_vert.finish();
702 select_poly.finish();
703}
704
705} // namespace blender::bke
706
708
709/* -------------------------------------------------------------------- */
712
713void BKE_mesh_calc_relative_deform(const int *face_offsets,
714 const int faces_num,
715 const int *corner_verts,
716 const int totvert,
717
718 const float (*vert_cos_src)[3],
719 const float (*vert_cos_dst)[3],
720
721 const float (*vert_cos_org)[3],
722 float (*vert_cos_new)[3])
723{
724 const blender::OffsetIndices<int> faces({face_offsets, faces_num + 1});
725
726 int *vert_accum = MEM_calloc_arrayN<int>(totvert, __func__);
727
728 memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * size_t(totvert));
729
730 for (const int i : faces.index_range()) {
731 const blender::IndexRange face = faces[i];
732 const int *face_verts = &corner_verts[face.start()];
733
734 for (int j = 0; j < face.size(); j++) {
735 const int v_prev = face_verts[(face.size() + (j - 1)) % face.size()];
736 const int v_curr = face_verts[j];
737 const int v_next = face_verts[(j + 1) % face.size()];
738
739 float tvec[3];
740
742 vert_cos_dst[v_curr],
743 vert_cos_org[v_prev],
744 vert_cos_org[v_curr],
745 vert_cos_org[v_next],
746 vert_cos_src[v_prev],
747 vert_cos_src[v_curr],
748 vert_cos_src[v_next]);
749
750 add_v3_v3(vert_cos_new[v_curr], tvec);
751 vert_accum[v_curr] += 1;
752 }
753 }
754
755 for (int i = 0; i < totvert; i++) {
756 if (vert_accum[i]) {
757 mul_v3_fl(vert_cos_new[i], 1.0f / float(vert_accum[i]));
758 }
759 else {
760 copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
761 }
762 }
763
764 MEM_freeN(vert_accum);
765}
766
float area_poly_v3(const float verts[][3], unsigned int nr)
Definition math_geom.cc:133
void transform_point_by_tri_v3(float pt_tar[3], float const pt_src[3], const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float normal[3])
Definition math_geom.cc:115
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:263
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:100
float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:251
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE bool is_finite_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3])
unsigned int uint
#define UNUSED_FUNCTION(x)
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const T * data() const
Definition BLI_array.hh:312
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr int64_t size() const
constexpr int64_t start() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
IndexRange index_range() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
nullptr float
#define sqrt
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
void BKE_mesh_calc_relative_deform(const int *face_offsets, const int faces_num, const int *corner_verts, const int totvert, const float(*vert_cos_src)[3], const float(*vert_cos_dst)[3], const float(*vert_cos_org)[3], float(*vert_cos_new)[3])
bool BKE_mesh_center_of_surface(const Mesh *mesh, float r_cent[3])
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
void BKE_mesh_calc_volume(const float(*vert_positions)[3], const int mverts_num, const blender::int3 *corner_tris, const int corner_tris_num, const int *corner_verts, float *r_volume, float r_center[3])
static float UNUSED_FUNCTION mesh_calc_face_volume_centroid(const int *face_verts, const int face_size, const float(*positions)[3], float r_cent[3])
float BKE_mesh_calc_area(const Mesh *mesh)
static bool mesh_calc_center_centroid_ex(const float(*positions)[3], int, const blender::int3 *corner_tris, int corner_tris_num, const int *corner_verts, float r_center[3])
bool BKE_mesh_center_median(const Mesh *mesh, float r_cent[3])
bool BKE_mesh_center_median_from_faces(const Mesh *mesh, float r_cent[3])
bool BKE_mesh_center_of_volume(const Mesh *mesh, float r_cent[3])
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
T compute_sum(const Span< T > data)
void face_angles_calc(Span< float3 > vert_positions, Span< int > face_verts, MutableSpan< float > angles)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float3 face_center_calc_ngon(const Span< float3 > vert_positions, const Span< int > face_verts)
float face_area_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float face_area_centroid_calc(const Span< float3 > positions, const Span< int > face_verts, float r_cent[3])
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float mesh_calc_face_volume_centroid_with_reference_center(const Span< float3 > positions, const Span< int > face_verts, const float3 &reference_center, float r_cent[3])
void mesh_select_vert_flush(Mesh &mesh)
void mesh_face_hide_from_vert(OffsetIndices< int > faces, Span< int > corner_verts, Span< bool > hide_vert, MutableSpan< bool > hide_poly)
void mesh_hide_vert_flush(Mesh &mesh)
void mesh_hide_face_flush(Mesh &mesh)
void mesh_select_edge_flush(Mesh &mesh)
void mesh_edge_hide_from_vert(Span< int2 > edges, Span< bool > hide_vert, MutableSpan< bool > hide_edge)
void mesh_select_face_flush(Mesh &mesh)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
#define fabsf
float(* disps)[3]
int faces_num
int verts_num
i
Definition text_draw.cc:230