Blender V5.0
bmesh_polygon.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include "DNA_modifier_types.h"
13
14#include "BLI_alloca.h"
15#include "BLI_linklist.h"
16#include "BLI_math_base.hh"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_vector.h"
20#include "BLI_math_vector.hh"
21#include "BLI_memarena.h"
22#include "BLI_polyfill_2d.h"
24
25#include "bmesh.hh"
26#include "bmesh_tools.hh"
27
28#include "BKE_customdata.hh"
29
31
32using blender::float2;
33using blender::float3;
34using blender::Span;
35
39static float angle_signed_v2v2_pos(const float v1[2], const float v2[2])
40{
41 const float angle = angle_signed_v2v2(v1, v2);
42 if (angle < 0.0f) {
43 return angle + (M_PI * 2);
44 }
45 return angle;
46}
47
53static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
54{
55 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
56 BMLoop *l_iter = l_first;
57 const float *v_prev = l_first->prev->v->co;
58 const float *v_curr = l_first->v->co;
59
60 zero_v3(n);
61
62 /* Newell's Method */
63 do {
64 add_newell_cross_v3_v3v3(n, v_prev, v_curr);
65
66 l_iter = l_iter->next;
67 v_prev = v_curr;
68 v_curr = l_iter->v->co;
69
70 } while (l_iter != l_first);
71
72 return normalize_v3(n);
73}
74
82 float r_no[3],
83 const Span<float3> vertexCos)
84{
85 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
86 BMLoop *l_iter = l_first;
87 const float *v_prev = vertexCos[BM_elem_index_get(l_first->prev->v)];
88 const float *v_curr = vertexCos[BM_elem_index_get(l_first->v)];
89
90 zero_v3(r_no);
91
92 /* Newell's Method */
93 do {
94 add_newell_cross_v3_v3v3(r_no, v_prev, v_curr);
95
96 l_iter = l_iter->next;
97 v_prev = v_curr;
98 v_curr = vertexCos[BM_elem_index_get(l_iter->v)];
99 } while (l_iter != l_first);
100
101 return normalize_v3(r_no);
102}
103
108 const BMFace *f, float r_cent[3], const blender::Span<blender::float3> vert_positions)
109{
110 const BMLoop *l_first, *l_iter;
111
112 zero_v3(r_cent);
113
114 /* Newell's Method */
115 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
116 do {
117 add_v3_v3(r_cent, vert_positions[BM_elem_index_get(l_iter->v)]);
118 } while ((l_iter = l_iter->next) != l_first);
119 mul_v3_fl(r_cent, 1.0f / f->len);
120}
121
123 const bool use_fixed_quad,
124 BMLoop **r_loops,
125 uint (*r_index)[3])
126{
127 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
128 BMLoop *l_iter;
129
130 if (f->len == 3) {
131 *r_loops++ = (l_iter = l_first);
132 *r_loops++ = (l_iter = l_iter->next);
133 *r_loops++ = (l_iter->next);
134
135 r_index[0][0] = 0;
136 r_index[0][1] = 1;
137 r_index[0][2] = 2;
138 }
139 else if (f->len == 4 && use_fixed_quad) {
140 *r_loops++ = (l_iter = l_first);
141 *r_loops++ = (l_iter = l_iter->next);
142 *r_loops++ = (l_iter = l_iter->next);
143 *r_loops++ = (l_iter->next);
144
145 r_index[0][0] = 0;
146 r_index[0][1] = 1;
147 r_index[0][2] = 2;
148
149 r_index[1][0] = 0;
150 r_index[1][1] = 2;
151 r_index[1][2] = 3;
152 }
153 else {
154 float axis_mat[3][3];
155 float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
156 int j;
157
158 axis_dominant_v3_to_m3_negate(axis_mat, f->no);
159
160 j = 0;
161 l_iter = l_first;
162 do {
163 mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co);
164 r_loops[j] = l_iter;
165 j++;
166 } while ((l_iter = l_iter->next) != l_first);
167
168 /* complete the loop */
169 BLI_polyfill_calc(projverts, f->len, 1, r_index);
170 }
171}
172
173void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
174{
175 const BMLoop *ltri[3];
176
177 if (f->len == 3) {
178 const BMLoop *l = BM_FACE_FIRST_LOOP(f);
179 ARRAY_SET_ITEMS(ltri, l, l->next, l->prev);
180 }
181 else {
182 /* tessellation here seems overkill when in many cases this will be the center,
183 * but without this we can't be sure the point is inside a concave face. */
184 const int tottri = f->len - 2;
185 BMLoop **loops = BLI_array_alloca(loops, f->len);
186 uint(*index)[3] = BLI_array_alloca(index, tottri);
187 int j;
188 int j_best = 0; /* use as fallback when unset */
189 float area_best = -1.0f;
190
191 BM_face_calc_tessellation(f, false, loops, index);
192
193 for (j = 0; j < tottri; j++) {
194 const float *p1 = loops[index[j][0]]->v->co;
195 const float *p2 = loops[index[j][1]]->v->co;
196 const float *p3 = loops[index[j][2]]->v->co;
197 const float area = area_squared_tri_v3(p1, p2, p3);
198 if (area > area_best) {
199 j_best = j;
200 area_best = area;
201 }
202 }
203
205 ltri, loops[index[j_best][0]], loops[index[j_best][1]], loops[index[j_best][2]]);
206 }
207
208 mid_v3_v3v3v3(r_co, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co);
209}
210
212{
213 /* inline 'area_poly_v3' logic, avoid creating a temp array */
214 const BMLoop *l_iter, *l_first;
215 float n[3];
216
217 zero_v3(n);
218 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
219 do {
220 add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co);
221 } while ((l_iter = l_iter->next) != l_first);
222 return len_v3(n) * 0.5f;
223}
224
225float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
226{
227 /* inline 'area_poly_v3' logic, avoid creating a temp array */
228 const BMLoop *l_iter, *l_first;
229 float co[3];
230 float n[3];
231
232 zero_v3(n);
233 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
234 mul_v3_m3v3(co, mat3, l_iter->v->co);
235 do {
236 float co_next[3];
237 mul_v3_m3v3(co_next, mat3, l_iter->next->v->co);
238 add_newell_cross_v3_v3v3(n, co, co_next);
239 copy_v3_v3(co, co_next);
240 } while ((l_iter = l_iter->next) != l_first);
241 return len_v3(n) * 0.5f;
242}
243
244float BM_face_calc_area_uv_signed(const BMFace *f, int cd_loop_uv_offset)
245{
246 /* inline 'area_poly_v2' logic, avoid creating a temp array */
247 const BMLoop *l_iter, *l_first;
248
249 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
250 /* Green's theorem applied to area of a polygon.
251 * TODO: `cross` should be of type `double` to reduce rounding error. */
252 float cross = 0.0f;
253 do {
254 const float *luv = BM_ELEM_CD_GET_FLOAT_P(l_iter, cd_loop_uv_offset);
255 const float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l_iter->next, cd_loop_uv_offset);
256 cross += (luv_next[0] - luv[0]) * (luv_next[1] + luv[1]);
257 } while ((l_iter = l_iter->next) != l_first);
258 return cross * 0.5f;
259}
260
261float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
262{
263 return fabsf(BM_face_calc_area_uv_signed(f, cd_loop_uv_offset));
264}
265
267{
268 const BMLoop *l_iter, *l_first;
269 float perimeter = 0.0f;
270
271 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
272 do {
273 perimeter += len_v3v3(l_iter->v->co, l_iter->next->v->co);
274 } while ((l_iter = l_iter->next) != l_first);
275
276 return perimeter;
277}
278
279float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
280{
281 const BMLoop *l_iter, *l_first;
282 float co[3];
283 float perimeter = 0.0f;
284
285 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
286 mul_v3_m3v3(co, mat3, l_iter->v->co);
287 do {
288 float co_next[3];
289 mul_v3_m3v3(co_next, mat3, l_iter->next->v->co);
290 perimeter += len_v3v3(co, co_next);
291 copy_v3_v3(co, co_next);
292 } while ((l_iter = l_iter->next) != l_first);
293
294 return perimeter;
295}
296
303{
304/* find the most 'unique' loop, (greatest difference to others) */
305#if 1
306 /* Optimized version that avoids `sqrt`. */
307 float difs[3];
308 for (int i_prev = 1, i_curr = 2, i_next = 0; i_next < 3; i_prev = i_curr, i_curr = i_next++) {
309 const float *co = verts[i_curr]->co;
310 const float *co_other[2] = {verts[i_prev]->co, verts[i_next]->co};
311 float proj_dir[3];
312 mid_v3_v3v3(proj_dir, co_other[0], co_other[1]);
313 sub_v3_v3(proj_dir, co);
314
315 float proj_pair[2][3];
316 project_v3_v3v3(proj_pair[0], co_other[0], proj_dir);
317 project_v3_v3v3(proj_pair[1], co_other[1], proj_dir);
318 difs[i_next] = len_squared_v3v3(proj_pair[0], proj_pair[1]);
319 }
320#else
321 const float lens[3] = {
322 len_v3v3(verts[0]->co, verts[1]->co),
323 len_v3v3(verts[1]->co, verts[2]->co),
324 len_v3v3(verts[2]->co, verts[0]->co),
325 };
326 const float difs[3] = {
327 fabsf(lens[1] - lens[2]),
328 fabsf(lens[2] - lens[0]),
329 fabsf(lens[0] - lens[1]),
330 };
331#endif
332
333 int order[3] = {0, 1, 2};
334 axis_sort_v3(difs, order);
335
336 return order[0];
337}
338
340{
341 const int index = bm_vert_tri_find_unique_edge(verts);
342 const int index_next = (index + 1) % 3;
343
344 sub_v3_v3v3(r_tangent, verts[index]->co, verts[index_next]->co);
345 normalize_v3(r_tangent);
346}
347
349 float r_tangent_a[3],
350 float r_tangent_b[3])
351{
352 const int index = bm_vert_tri_find_unique_edge(verts);
353 const int index_next = (index + 1) % 3;
354 const int index_prev = (index_next + 1) % 3;
355
356 sub_v3_v3v3(r_tangent_a, verts[index]->co, verts[index_next]->co);
357 normalize_v3(r_tangent_a);
358
359 /* Pick the adjacent loop that is least co-linear. */
360 float vec_prev[3], vec_next[3];
361 float tmp_prev[3], tmp_next[3];
362
363 sub_v3_v3v3(vec_prev, verts[index_prev]->co, verts[index]->co);
364 sub_v3_v3v3(vec_next, verts[index_next]->co, verts[index_prev]->co);
365
366 cross_v3_v3v3(tmp_prev, r_tangent_a, vec_prev);
367 cross_v3_v3v3(tmp_next, r_tangent_a, vec_next);
368
369 normalize_v3_v3(r_tangent_b,
370 len_squared_v3(tmp_next) > len_squared_v3(tmp_prev) ? vec_next : vec_prev);
371}
372
374{
375 const int index = bm_vert_tri_find_unique_edge(verts);
376
377 const float *v_a = verts[index]->co;
378 const float *v_b = verts[(index + 1) % 3]->co;
379 const float *v_other = verts[(index + 2) % 3]->co;
380
381 mid_v3_v3v3(r_tangent, v_a, v_b);
382 sub_v3_v3v3(r_tangent, v_other, r_tangent);
383
384 normalize_v3(r_tangent);
385}
386
387void BM_face_calc_tangent_from_edge(const BMFace *f, float r_tangent[3])
388{
389 const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
390
391 sub_v3_v3v3(r_tangent, l_long->v->co, l_long->next->v->co);
392
393 normalize_v3(r_tangent);
394}
395
396static void bm_face_calc_tangent_from_quad_edge_pair(const BMFace *f, float r_tangent[3])
397{
398 BMVert *verts[4];
399 float vec[3], vec_a[3], vec_b[3];
400
402
403 sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co);
404 sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co);
405 add_v3_v3v3(r_tangent, vec_a, vec_b);
406
407 sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co);
408 sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co);
409 add_v3_v3v3(vec, vec_a, vec_b);
410 /* use the longest edge length */
411 if (len_squared_v3(r_tangent) < len_squared_v3(vec)) {
412 copy_v3_v3(r_tangent, vec);
413 }
414 normalize_v3(r_tangent);
415}
416
418 float r_tangent_a[3],
419 float r_tangent_b[3])
420{
421 BLI_assert(f->len == 4);
422 BMVert *verts[4];
423 float vec_a[3], vec_b[3];
424
426
427 sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co);
428 sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co);
429 add_v3_v3v3(r_tangent_a, vec_a, vec_b);
430
431 sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co);
432 sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co);
433 add_v3_v3v3(r_tangent_b, vec_a, vec_b);
434
435 /* `r_tangent_a` always gets the longest edge. */
436 if (normalize_v3(r_tangent_a) < normalize_v3(r_tangent_b)) {
437 swap_v3_v3(r_tangent_a, r_tangent_b);
438 }
439}
440
442 float r_tangent_a[3],
443 float r_tangent_b[3])
444{
445 const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
446
447 sub_v3_v3v3(r_tangent_a, l_long->v->co, l_long->next->v->co);
448 normalize_v3(r_tangent_a);
449
450 /* Pick the adjacent loop that is least co-linear. */
451 float vec_prev[3], vec_next[3];
452 float tmp_prev[3], tmp_next[3];
453
454 sub_v3_v3v3(vec_prev, l_long->prev->v->co, l_long->v->co);
455 sub_v3_v3v3(vec_next, l_long->next->v->co, l_long->next->next->v->co);
456
457 cross_v3_v3v3(tmp_prev, r_tangent_a, vec_prev);
458 cross_v3_v3v3(tmp_next, r_tangent_a, vec_next);
459
460 normalize_v3_v3(r_tangent_b,
461 len_squared_v3(tmp_next) > len_squared_v3(tmp_prev) ? vec_next : vec_prev);
462}
463
464void BM_face_calc_tangent_from_edge_pair(const BMFace *f, float r_tangent[3])
465{
466 if (f->len == 3) {
467 BMVert *verts[3];
468
470
472 }
473 else if (f->len == 4) {
474 /* Use longest edge pair */
475 float r_tangent_dummy[3];
476 bm_face_calc_tangent_pair_from_quad_edge_pair(f, r_tangent, r_tangent_dummy);
477 }
478 else {
479 /* For ngons use two longest disconnected edges */
481 BMLoop *l_long_other = nullptr;
482
483 float len_max_sq = 0.0f;
484 float vec_a[3], vec_b[3];
485
486 BMLoop *l_iter = l_long->prev->prev;
487 BMLoop *l_last = l_long->next;
488
489 do {
490 const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co);
491 if (len_sq >= len_max_sq) {
492 l_long_other = l_iter;
493 len_max_sq = len_sq;
494 }
495 } while ((l_iter = l_iter->prev) != l_last);
496
497 sub_v3_v3v3(vec_a, l_long->next->v->co, l_long->v->co);
498 sub_v3_v3v3(vec_b, l_long_other->v->co, l_long_other->next->v->co);
499 add_v3_v3v3(r_tangent, vec_a, vec_b);
500
501 /* Edges may not be opposite side of the ngon,
502 * this could cause problems for ngons with multiple-aligned edges of the same length.
503 * Fall back to longest edge. */
504 if (UNLIKELY(normalize_v3(r_tangent) == 0.0f)) {
505 normalize_v3_v3(r_tangent, vec_a);
506 }
507 }
508}
509
510void BM_face_calc_tangent_from_edge_diagonal(const BMFace *f, float r_tangent[3])
511{
512 BMLoop *l_iter, *l_first;
513
514 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
515
516 /* In case of degenerate faces. */
517 zero_v3(r_tangent);
518
519 /* WARNING: O(n^2) loop here, take care! */
520 float dist_max_sq = 0.0f;
521 do {
522 BMLoop *l_iter_other = l_iter->next;
523 BMLoop *l_iter_last = l_iter->prev;
524 do {
525 BLI_assert(!ELEM(l_iter->v, l_iter_other->v, l_iter_other->next->v));
526 float co_other[3], vec[3];
528 co_other, l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co);
529 sub_v3_v3v3(vec, l_iter->v->co, co_other);
530
531 const float dist_sq = len_squared_v3(vec);
532 if (dist_sq > dist_max_sq) {
533 dist_max_sq = dist_sq;
534 copy_v3_v3(r_tangent, vec);
535 }
536 } while ((l_iter_other = l_iter_other->next) != l_iter_last);
537 } while ((l_iter = l_iter->next) != l_first);
538
539 normalize_v3(r_tangent);
540}
541
542void BM_face_calc_tangent_from_vert_diagonal(const BMFace *f, float r_tangent[3])
543{
544 BMLoop *l_iter, *l_first;
545
546 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
547
548 /* In case of degenerate faces. */
549 zero_v3(r_tangent);
550
551 /* WARNING: O(n^2) loop here, take care! */
552 float dist_max_sq = 0.0f;
553 do {
554 BMLoop *l_iter_other = l_iter->next;
555 do {
556 float vec[3];
557 sub_v3_v3v3(vec, l_iter->v->co, l_iter_other->v->co);
558
559 const float dist_sq = len_squared_v3(vec);
560 if (dist_sq > dist_max_sq) {
561 dist_max_sq = dist_sq;
562 copy_v3_v3(r_tangent, vec);
563 }
564 } while ((l_iter_other = l_iter_other->next) != l_iter);
565 } while ((l_iter = l_iter->next) != l_first);
566
567 normalize_v3(r_tangent);
568}
569
570void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
571{
572 if (f->len == 3) {
573 /* most 'unique' edge of a triangle */
574 BMVert *verts[3];
577 }
578 else if (f->len == 4) {
579 /* longest edge pair of a quad */
581 }
582 else {
583 /* longest edge of an ngon */
584 BM_face_calc_tangent_from_edge(f, r_tangent);
585 }
586}
587
588void BM_face_calc_tangent_pair_auto(const BMFace *f, float r_tangent_a[3], float r_tangent_b[3])
589{
590 if (f->len == 3) {
591 /* most 'unique' edge of a triangle */
592 BMVert *verts[3];
594 BM_vert_tri_calc_tangent_pair_from_edge(verts, r_tangent_a, r_tangent_b);
595 }
596 else if (f->len == 4) {
597 /* longest edge pair of a quad */
598 bm_face_calc_tangent_pair_from_quad_edge_pair(f, r_tangent_a, r_tangent_b);
599 }
600 else {
601 /* longest edge of an ngon */
602 BM_face_calc_tangent_pair_from_edge(f, r_tangent_a, r_tangent_b);
603 }
604}
605
606void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
607{
608 const BMLoop *l_iter, *l_first;
609 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
610 do {
611 minmax_v3v3_v3(min, max, l_iter->v->co);
612 } while ((l_iter = l_iter->next) != l_first);
613}
614
615void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
616{
617 const BMLoop *l_iter, *l_first;
618 float min[3], max[3];
619
621
622 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
623 do {
624 minmax_v3v3_v3(min, max, l_iter->v->co);
625 } while ((l_iter = l_iter->next) != l_first);
626
627 mid_v3_v3v3(r_cent, min, max);
628}
629
631 const BMFace *f,
632 float r_cent[3],
633 const blender::Span<blender::float3> vert_positions)
634{
635 /* must have valid index data */
636 BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
637 (void)bm;
638
639 const BMLoop *l_iter, *l_first;
640 float min[3], max[3];
641
643
644 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
645 do {
646 minmax_v3v3_v3(min, max, vert_positions[BM_elem_index_get(l_iter->v)]);
647 } while ((l_iter = l_iter->next) != l_first);
648
649 mid_v3_v3v3(r_cent, min, max);
650}
651
652void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
653{
654 const BMLoop *l_iter, *l_first;
655
656 zero_v3(r_cent);
657
658 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
659 do {
660 add_v3_v3(r_cent, l_iter->v->co);
661 } while ((l_iter = l_iter->next) != l_first);
662 mul_v3_fl(r_cent, 1.0f / float(f->len));
663}
664
665void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
666{
667 const BMLoop *l_iter;
668 const BMLoop *l_first;
669 float totw = 0.0f;
670 float w_prev;
671
672 zero_v3(r_cent);
673
674 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
675 w_prev = BM_edge_calc_length(l_iter->prev->e);
676 do {
677 const float w_curr = BM_edge_calc_length(l_iter->e);
678 const float w = (w_curr + w_prev);
679 madd_v3_v3fl(r_cent, l_iter->v->co, w);
680 totw += w;
681 w_prev = w_curr;
682 } while ((l_iter = l_iter->next) != l_first);
683
684 if (totw != 0.0f) {
685 mul_v3_fl(r_cent, 1.0f / totw);
686 }
687}
688
689void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
690{
691 float mat[3][3];
692 float co[3];
693 uint i;
694
695 co[2] = 0.0f;
696
697 axis_dominant_v3_to_m3(mat, normal);
698 for (i = 0; i < nverts; i++) {
699 mul_v2_m3v3(co, mat, verts[i]);
700 copy_v3_v3(verts[i], co);
701 }
702}
703
705{
706 BMIter iter;
707 BMFace *f;
708
709 BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
711 }
712
715}
716
717static void bm_loop_normal_accum(const BMLoop *l, float no[3])
718{
719 float vec1[3], vec2[3], fac;
720
721 /* Same calculation used in BM_mesh_normals_update */
722 sub_v3_v3v3(vec1, l->v->co, l->prev->v->co);
723 sub_v3_v3v3(vec2, l->next->v->co, l->v->co);
724 normalize_v3(vec1);
725 normalize_v3(vec2);
726
727 fac = blender::math::safe_acos_approx(-dot_v3v3(vec1, vec2));
728
729 madd_v3_v3fl(no, l->f->no, fac);
730}
731
732bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
733{
734 int len = 0;
735
736 zero_v3(r_no);
737
738 if (v->e) {
739 const BMEdge *e = v->e;
740 do {
741 if (e->l) {
742 const BMLoop *l = e->l;
743 do {
744 if (l->v == v) {
745 if (BM_elem_flag_test(l->f, hflag)) {
746 bm_loop_normal_accum(l, r_no);
747 len++;
748 }
749 }
750 } while ((l = l->radial_next) != e->l);
751 }
752 } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
753 }
754
755 if (len) {
756 normalize_v3(r_no);
757 return true;
758 }
759 return false;
760}
761
762bool BM_vert_calc_normal(const BMVert *v, float r_no[3])
763{
764 int len = 0;
765
766 zero_v3(r_no);
767
768 if (v->e) {
769 const BMEdge *e = v->e;
770 do {
771 if (e->l) {
772 const BMLoop *l = e->l;
773 do {
774 if (l->v == v) {
775 bm_loop_normal_accum(l, r_no);
776 len++;
777 }
778 } while ((l = l->radial_next) != e->l);
779 }
780 } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
781 }
782
783 if (len) {
784 normalize_v3(r_no);
785 return true;
786 }
787 return false;
788}
789
791{
792 int len = 0;
793
794 zero_v3(v->no);
795
796 if (v->e) {
797 const BMEdge *e = v->e;
798 do {
799 if (e->l) {
800 const BMLoop *l = e->l;
801 do {
802 if (l->v == v) {
805 len++;
806 }
807 } while ((l = l->radial_next) != e->l);
808 }
809 } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
810 }
811
812 if (len) {
813 normalize_v3(v->no);
814 }
815}
816
821
822float BM_face_calc_normal(const BMFace *f, float r_no[3])
823{
824 BMLoop *l;
825
826 /* common cases first */
827 switch (f->len) {
828 case 4: {
829 const float *co1 = (l = BM_FACE_FIRST_LOOP(f))->v->co;
830 const float *co2 = (l = l->next)->v->co;
831 const float *co3 = (l = l->next)->v->co;
832 const float *co4 = (l->next)->v->co;
833
834 return normal_quad_v3(r_no, co1, co2, co3, co4);
835 }
836 case 3: {
837 const float *co1 = (l = BM_FACE_FIRST_LOOP(f))->v->co;
838 const float *co2 = (l = l->next)->v->co;
839 const float *co3 = (l->next)->v->co;
840
841 return normal_tri_v3(r_no, co1, co2, co3);
842 }
843 default: {
844 return bm_face_calc_poly_normal(f, r_no);
845 }
846 }
847}
849{
850 BM_face_calc_normal(f, f->no);
851}
852
854 const BMFace *f,
855 float r_no[3],
856 const Span<float3> vertexCos)
857{
858 BMLoop *l;
859
860 /* must have valid index data */
861 BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
862 (void)bm;
863
864 /* common cases first */
865 switch (f->len) {
866 case 4: {
867 const float *co1 = vertexCos[BM_elem_index_get((l = BM_FACE_FIRST_LOOP(f))->v)];
868 const float *co2 = vertexCos[BM_elem_index_get((l = l->next)->v)];
869 const float *co3 = vertexCos[BM_elem_index_get((l = l->next)->v)];
870 const float *co4 = vertexCos[BM_elem_index_get((l->next)->v)];
871
872 return normal_quad_v3(r_no, co1, co2, co3, co4);
873 }
874 case 3: {
875 const float *co1 = vertexCos[BM_elem_index_get((l = BM_FACE_FIRST_LOOP(f))->v)];
876 const float *co2 = vertexCos[BM_elem_index_get((l = l->next)->v)];
877 const float *co3 = vertexCos[BM_elem_index_get((l->next)->v)];
878
879 return normal_tri_v3(r_no, co1, co2, co3);
880 }
881 default: {
882 return bm_face_calc_poly_normal_vertex_cos(f, r_no, vertexCos);
883 }
884 }
885}
886
888 BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
889{
890 const float varr_len_inv = 1.0f / float(varr_len);
891
892 /* Get the center point and collect vector array since we loop over these a lot. */
893 float center[3] = {0.0f, 0.0f, 0.0f};
894 for (int i = 0; i < varr_len; i++) {
895 madd_v3_v3fl(center, varr[i]->co, varr_len_inv);
896 }
897
898 /* Find the 'co_a' point from center. */
899 int co_a_index = 0;
900 const float *co_a = nullptr;
901 {
902 float dist_sq_max = -1.0f;
903 for (int i = 0; i < varr_len; i++) {
904 const float dist_sq_test = len_squared_v3v3(varr[i]->co, center);
905 if (!(dist_sq_test <= dist_sq_max)) {
906 co_a = varr[i]->co;
907 co_a_index = i;
908 dist_sq_max = dist_sq_test;
909 }
910 }
911 }
912
913 float dir_a[3];
914 sub_v3_v3v3(dir_a, co_a, center);
915 normalize_v3(dir_a);
916
917 const float *co_b = nullptr;
918 float dir_b[3] = {0.0f, 0.0f, 0.0f};
919 {
920 float dist_sq_max = -1.0f;
921 for (int i = 0; i < varr_len; i++) {
922 if (varr[i]->co == co_a) {
923 continue;
924 }
925 float dir_test[3];
926 sub_v3_v3v3(dir_test, varr[i]->co, center);
927 project_plane_normalized_v3_v3v3(dir_test, dir_test, dir_a);
928 const float dist_sq_test = len_squared_v3(dir_test);
929 if (!(dist_sq_test <= dist_sq_max)) {
930 co_b = varr[i]->co;
931 dist_sq_max = dist_sq_test;
932 copy_v3_v3(dir_b, dir_test);
933 }
934 }
935 }
936
937 if (varr_len <= 3) {
938 normal_tri_v3(r_normal, center, co_a, co_b);
939 goto finally;
940 }
941
942 {
943 normalize_v3(dir_b);
944
945 const float *co_a_opposite = nullptr;
946 const float *co_b_opposite = nullptr;
947
948 {
949 float dot_a_min = FLT_MAX;
950 float dot_b_min = FLT_MAX;
951 for (int i = 0; i < varr_len; i++) {
952 const float *co_test = varr[i]->co;
953 float dot_test;
954
955 if (co_test != co_a) {
956 dot_test = dot_v3v3(dir_a, co_test);
957 if (dot_test < dot_a_min) {
958 dot_a_min = dot_test;
959 co_a_opposite = co_test;
960 }
961 }
962
963 if (co_test != co_b) {
964 dot_test = dot_v3v3(dir_b, co_test);
965 if (dot_test < dot_b_min) {
966 dot_b_min = dot_test;
967 co_b_opposite = co_test;
968 }
969 }
970 }
971 }
972
973 normal_quad_v3(r_normal, co_a, co_b, co_a_opposite, co_b_opposite);
974 }
975
976finally:
977 if (r_center != nullptr) {
978 copy_v3_v3(r_center, center);
979 }
980 if (r_index_tangent != nullptr) {
981 *r_index_tangent = co_a_index;
982 }
983}
984
985void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3])
986{
987 BM_verts_calc_normal_from_cloud_ex(varr, varr_len, r_normal, nullptr, nullptr);
988}
989
990float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
991{
992 const float *v_prev, *v_curr;
993
994 /* Newell's Method */
995 const BMLoop *l_iter = l_first;
996 const BMLoop *l_term = l_last->next;
997
998 zero_v3(r_no);
999
1000 v_prev = l_last->v->co;
1001 do {
1002 v_curr = l_iter->v->co;
1003 add_newell_cross_v3_v3v3(r_no, v_prev, v_curr);
1004 v_prev = v_curr;
1005 } while ((l_iter = l_iter->next) != l_term);
1006
1007 return normalize_v3(r_no);
1008}
1009
1011 const BMFace *f,
1012 float r_cent[3],
1013 const blender::Span<blender::float3> vert_positions)
1014{
1015 /* must have valid index data */
1016 BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
1017 (void)bm;
1018
1019 bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vert_positions);
1020}
1021
1023 BMFace *f,
1024 const int cd_loop_mdisp_offset,
1025 const bool use_loop_mdisp_flip)
1026{
1027 bmesh_kernel_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
1028 negate_v3(f->no);
1029}
1030
1032{
1033 const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
1034 BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
1035}
1036
1037bool BM_face_point_inside_test(const BMFace *f, const float co[3])
1038{
1039 float axis_mat[3][3];
1040 float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
1041
1042 float co_2d[2];
1043 BMLoop *l_iter;
1044 int i;
1045
1047
1048 axis_dominant_v3_to_m3(axis_mat, f->no);
1049
1050 mul_v2_m3v3(co_2d, axis_mat, co);
1051
1052 for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
1053 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
1054 }
1055
1056 return isect_point_poly_v2(co_2d, projverts, f->len);
1057}
1058
1060 BMFace *f,
1061 BMFace **r_faces_new,
1062 int *r_faces_new_tot,
1063 BMEdge **r_edges_new,
1064 int *r_edges_new_tot,
1065 LinkNode **r_faces_double,
1066 const int quad_method,
1067 const int ngon_method,
1068 const bool use_tag,
1069 /* use for ngons only! */
1070 MemArena *pf_arena,
1071
1072 /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
1073 Heap *pf_heap)
1074{
1075 const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
1076 const bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY);
1077 BMLoop *l_first, *l_new;
1078 BMFace *f_new;
1079 int nf_i = 0;
1080 int ne_i = 0;
1081
1083
1084 /* ensure both are valid or nullptr */
1085 BLI_assert((r_faces_new == nullptr) == (r_faces_new_tot == nullptr));
1086
1087 BLI_assert(f->len > 3);
1088
1089 {
1090 BMLoop **loops = BLI_array_alloca(loops, f->len);
1091 uint(*tris)[3] = BLI_array_alloca(tris, f->len);
1092 const int totfilltri = f->len - 2;
1093 const int last_tri = f->len - 3;
1094 int i;
1095 /* for mdisps */
1096 float f_center[3];
1097
1098 if (f->len == 4) {
1099 /* even though we're not using BLI_polyfill, fill in 'tris' and 'loops'
1100 * so we can share code to handle face creation afterwards. */
1101 BMLoop *l_v1, *l_v2;
1102
1103 l_first = BM_FACE_FIRST_LOOP(f);
1104
1105 switch (quad_method) {
1107 l_v1 = l_first;
1108 l_v2 = l_first->next->next;
1109 break;
1110 }
1112 l_v1 = l_first->next;
1113 l_v2 = l_first->prev;
1114 break;
1115 }
1119 default: {
1120 BMLoop *l_v3, *l_v4;
1121 bool split_24;
1122
1123 l_v1 = l_first->next;
1124 l_v2 = l_first->next->next;
1125 l_v3 = l_first->prev;
1126 l_v4 = l_first;
1127
1128 if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) {
1129 float d1, d2;
1130 d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
1131 d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
1132 split_24 = ((d2 - d1) > 0.0f);
1133 }
1134 else if (quad_method == MOD_TRIANGULATE_QUAD_LONGEDGE) {
1135 float d1, d2;
1136 d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
1137 d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
1138 split_24 = ((d2 - d1) < 0.0f);
1139 }
1140 else {
1141 /* first check if the quad is concave on either diagonal */
1142 const int flip_flag = is_quad_flip_v3(
1143 l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co);
1144 if (UNLIKELY(flip_flag & (1 << 0))) {
1145 split_24 = true;
1146 }
1147 else if (UNLIKELY(flip_flag & (1 << 1))) {
1148 split_24 = false;
1149 }
1150 else {
1151 split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) >
1152 0.0f);
1153 }
1154 }
1155
1156 /* named confusingly, l_v1 is in fact the second vertex */
1157 if (split_24) {
1158 l_v1 = l_v4;
1159 // l_v2 = l_v2;
1160 }
1161 else {
1162 // l_v1 = l_v1;
1163 l_v2 = l_v3;
1164 }
1165 break;
1166 }
1167 }
1168
1169 loops[0] = l_v1;
1170 loops[1] = l_v1->next;
1171 loops[2] = l_v2;
1172 loops[3] = l_v2->next;
1173
1174 ARRAY_SET_ITEMS(tris[0], 0, 1, 2);
1175 ARRAY_SET_ITEMS(tris[1], 0, 2, 3);
1176 }
1177 else {
1178 BMLoop *l_iter;
1179 float axis_mat[3][3];
1180 float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
1181
1182 axis_dominant_v3_to_m3_negate(axis_mat, f->no);
1183
1184 for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
1185 loops[i] = l_iter;
1186 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
1187 }
1188
1189 BLI_polyfill_calc_arena(projverts, f->len, 1, tris, pf_arena);
1190
1191 if (use_beauty) {
1192 BLI_polyfill_beautify(projverts, f->len, tris, pf_arena, pf_heap);
1193 }
1194
1195 BLI_memarena_clear(pf_arena);
1196 }
1197
1198 if (cd_loop_mdisp_offset != -1) {
1199 BM_face_calc_center_median(f, f_center);
1200 }
1201
1202 /* loop over calculated triangles and create new geometry */
1203 for (i = 0; i < totfilltri; i++) {
1204 BMLoop *ltri[3] = {loops[tris[i][0]], loops[tris[i][1]], loops[tris[i][2]]};
1205
1206 BMVert *v_tri[3] = {ltri[0]->v, ltri[1]->v, ltri[2]->v};
1207
1208 f_new = BM_face_create_verts(bm, v_tri, 3, f, BM_CREATE_NOP, true);
1209 l_new = BM_FACE_FIRST_LOOP(f_new);
1210
1211 BLI_assert(v_tri[0] == l_new->v);
1212
1213 /* check for duplicate */
1214 if (l_new->radial_next != l_new) {
1215 BMLoop *l_iter = l_new->radial_next;
1216 do {
1217 if (UNLIKELY((l_iter->f->len == 3) && (l_new->prev->v == l_iter->prev->v))) {
1218 /* Check the last tri because we swap last f_new with f at the end... */
1219 BLI_linklist_prepend(r_faces_double, (i != last_tri) ? f_new : f);
1220 break;
1221 }
1222 } while ((l_iter = l_iter->radial_next) != l_new);
1223 }
1224
1225 /* copy CD data */
1226 BM_elem_attrs_copy(bm, ltri[0], l_new);
1227 BM_elem_attrs_copy(bm, ltri[1], l_new->next);
1228 BM_elem_attrs_copy(bm, ltri[2], l_new->prev);
1229
1230 /* add all but the last face which is swapped and removed (below) */
1231 if (i != last_tri) {
1232 if (use_tag) {
1234 }
1235 if (r_faces_new) {
1236 r_faces_new[nf_i++] = f_new;
1237 }
1238 }
1239
1240 if (use_tag || r_edges_new) {
1241 /* new faces loops */
1242 BMLoop *l_iter;
1243
1244 l_iter = l_first = l_new;
1245 do {
1246 BMEdge *e = l_iter->e;
1247 /* Confusing! if its not a boundary now, we know it will be later since this will be an
1248 * edge of one of the new faces which we're in the middle of creating. */
1249 bool is_new_edge = (l_iter == l_iter->radial_next);
1250
1251 if (is_new_edge) {
1252 if (use_tag) {
1254 }
1255 if (r_edges_new) {
1256 r_edges_new[ne_i++] = e;
1257 }
1258 }
1259 /* NOTE: never disable tag's. */
1260 } while ((l_iter = l_iter->next) != l_first);
1261 }
1262
1263 if (cd_loop_mdisp_offset != -1) {
1264 float f_new_center[3];
1265 BM_face_calc_center_median(f_new, f_new_center);
1266 BM_face_interp_multires_ex(bm, f_new, f, f_new_center, f_center, cd_loop_mdisp_offset);
1267 }
1268 }
1269
1270 {
1271 /* we can't delete the real face, because some of the callers expect it to remain valid.
1272 * so swap data and delete the last created tri */
1273 bmesh_face_swap_data(f, f_new);
1274 BM_face_kill(bm, f_new);
1275 }
1276 }
1277 bm->elem_index_dirty |= BM_FACE;
1278
1279 if (r_faces_new_tot) {
1280 *r_faces_new_tot = nf_i;
1281 }
1282
1283 if (r_edges_new_tot) {
1284 *r_edges_new_tot = ne_i;
1285 }
1286}
1287
1289{
1290 float center[2] = {0.0f, 0.0f};
1291 float axis_mat[3][3];
1292 float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
1293 const float *(*edgeverts)[2] = BLI_array_alloca(edgeverts, len);
1294 BMLoop *l;
1295 int i, i_prev, j;
1296
1298
1299 axis_dominant_v3_to_m3(axis_mat, f->no);
1300
1301 for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
1302 mul_v2_m3v3(projverts[i], axis_mat, l->v->co);
1303 add_v2_v2(center, projverts[i]);
1304 }
1305
1306 /* first test for completely convex face */
1307 if (is_poly_convex_v2(projverts, f->len)) {
1308 return;
1309 }
1310
1311 mul_v2_fl(center, 1.0f / f->len);
1312
1313 for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
1314 BM_elem_index_set(l, i); /* set_dirty */
1315
1316 /* center the projection for maximum accuracy */
1317 sub_v2_v2(projverts[i], center);
1318 }
1319 bm->elem_index_dirty |= BM_LOOP;
1320
1321 for (i = 0; i < len; i++) {
1322 edgeverts[i][0] = projverts[BM_elem_index_get(loops[i][0])];
1323 edgeverts[i][1] = projverts[BM_elem_index_get(loops[i][1])];
1324 }
1325 /* Check the split is inside the face, otherwise clear it.
1326 *
1327 * Ensure the edge between the two corners of the face defines a line that lies within the face.
1328 * Consider an edge that connects both tips of a crescent-moon shaped face.
1329 * In this case the edge would span the empty region and must not be considered "legal". */
1330 for (i = 0; i < len; i++) {
1331 /* Compare the angles at the loops. */
1332 BMLoop **l_pair = loops[i];
1333 const float *co_pair[2] = {
1334 projverts[BM_elem_index_get(l_pair[0])],
1335 projverts[BM_elem_index_get(l_pair[1])],
1336 };
1337
1338 /* Always allow cuts that overlap (unlikely but not an error). */
1339 if (UNLIKELY(equals_v2v2(co_pair[0], co_pair[1]))) {
1340 continue;
1341 }
1342
1343 const float2 pair_dir = blender::math::normalize(float2(co_pair[1]) - float2(co_pair[0]));
1344 for (const int side : blender::IndexRange(2)) {
1345 const float2 co = float2(co_pair[side]);
1346 BMLoop *l_prev = l_pair[side]->prev;
1347 BMLoop *l_next = l_pair[side]->next;
1348
1349 /* Account for zero length edges, not essential but they shouldn't break the calculation. */
1350 {
1351 const int limit_init = f->len - 3;
1352 int limit;
1353 limit = limit_init;
1354 while (UNLIKELY(equals_v2v2(co, projverts[BM_elem_index_get(l_prev)])) && limit-- > 0) {
1355 l_prev = l_prev->prev;
1356 }
1357 limit = limit_init;
1358 while (UNLIKELY(equals_v2v2(co, projverts[BM_elem_index_get(l_next)])) && limit-- > 0) {
1359 l_next = l_next->next;
1360 }
1361 }
1362
1363 const float2 co_prev = float2(projverts[BM_elem_index_get(l_prev)]);
1364 const float2 co_next = float2(projverts[BM_elem_index_get(l_next)]);
1365
1366 const float2 dir_other = side == 0 ? pair_dir : -pair_dir;
1367 const float2 dir_prev = blender::math::normalize(co_prev - co);
1368 const float2 dir_next = blender::math::normalize(co_next - co);
1369
1370 if (angle_signed_v2v2_pos(dir_prev, dir_other) > angle_signed_v2v2_pos(dir_prev, dir_next)) {
1371 loops[i][0] = nullptr;
1372 break;
1373 }
1374 }
1375 }
1376
1377#define EDGE_SHARE_VERT(e1, e2) \
1378 (ELEM((e1)[0], (e2)[0], (e2)[1]) || ELEM((e1)[1], (e2)[0], (e2)[1]))
1379
1380 /* do line crossing tests */
1381 for (i = 0, i_prev = f->len - 1; i < f->len; i_prev = i++) {
1382 const float *f_edge[2] = {projverts[i_prev], projverts[i]};
1383 for (j = 0; j < len; j++) {
1384 if ((loops[j][0] != nullptr) && !EDGE_SHARE_VERT(f_edge, edgeverts[j])) {
1385 if (isect_seg_seg_v2(UNPACK2(f_edge), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
1386 loops[j][0] = nullptr;
1387 }
1388 }
1389 }
1390 }
1391
1392 /* self intersect tests */
1393 for (i = 0; i < len; i++) {
1394 if (loops[i][0]) {
1395 for (j = i + 1; j < len; j++) {
1396 if ((loops[j][0] != nullptr) && !EDGE_SHARE_VERT(edgeverts[i], edgeverts[j])) {
1397 if (isect_seg_seg_v2(UNPACK2(edgeverts[i]), UNPACK2(edgeverts[j])) ==
1399 {
1400 loops[i][0] = nullptr;
1401 break;
1402 }
1403 }
1404 }
1405 }
1406 }
1407
1408#undef EDGE_SHARE_VERT
1409}
1410
1412{
1413 int i;
1414
1415 for (i = 0; i < len; i++) {
1416 BMLoop *l_a_dummy, *l_b_dummy;
1418 loops[i][0]->v, loops[i][1]->v, &l_a_dummy, &l_b_dummy, false))
1419 {
1420 loops[i][0] = nullptr;
1421 }
1422 }
1423}
1424
1426{
1428
1429 BLI_assert(f->len == 3);
1430
1431 r_verts[0] = l->v;
1432 l = l->next;
1433 r_verts[1] = l->v;
1434 l = l->next;
1435 r_verts[2] = l->v;
1436}
1437
1439{
1441
1442 BLI_assert(f->len == 4);
1443
1444 r_verts[0] = l->v;
1445 l = l->next;
1446 r_verts[1] = l->v;
1447 l = l->next;
1448 r_verts[2] = l->v;
1449 l = l->next;
1450 r_verts[3] = l->v;
1451}
1452
1454{
1456
1457 BLI_assert(f->len == 3);
1458
1459 r_loops[0] = l;
1460 l = l->next;
1461 r_loops[1] = l;
1462 l = l->next;
1463 r_loops[2] = l;
1464}
1465
1467{
1469
1470 BLI_assert(f->len == 4);
1471
1472 r_loops[0] = l;
1473 l = l->next;
1474 r_loops[1] = l;
1475 l = l->next;
1476 r_loops[2] = l;
1477 l = l->next;
1478 r_loops[3] = l;
1479}
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define M_PI
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:58
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
bool isect_point_poly_v2(const float pt[2], const float verts[][2], unsigned int nr)
float closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:387
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:107
bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
#define ISECT_LINE_LINE_CROSS
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3_v3(float r[3], const float a[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void zero_v3(float r[3])
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])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
void BLI_polyfill_calc_arena(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
void BLI_polyfill_beautify(const float(*coords)[2], unsigned int coords_num, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
unsigned int uint
#define UNPACK2(a)
#define INIT_MINMAX(min, max)
#define ARRAY_SET_ITEMS(...)
#define UNLIKELY(x)
#define ELEM(...)
@ MOD_TRIANGULATE_QUAD_SHORTEDGE
@ MOD_TRIANGULATE_QUAD_FIXED
@ MOD_TRIANGULATE_QUAD_LONGEDGE
@ MOD_TRIANGULATE_QUAD_BEAUTY
@ MOD_TRIANGULATE_QUAD_ALTERNATE
@ MOD_TRIANGULATE_NGON_BEAUTY
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
float BM_verts_calc_rotate_beauty(const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4, const short flag, const short method)
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_FLOAT_P(ele, offset)
@ BM_ELEM_TAG
@ BM_LOOP
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
void bmesh_kernel_loop_reverse(BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
Loop Reverse.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_face_interp_multires_ex(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_FACES_OF_EDGE
BMesh * bm
#define BM_FACE
#define BM_VERT
void BM_face_calc_tangent_from_vert_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
static void bm_face_calc_tangent_from_quad_edge_pair(const BMFace *f, float r_tangent[3])
void BM_face_calc_tangent_pair_from_edge(const BMFace *f, float r_tangent_a[3], float r_tangent_b[3])
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
void poly_rotate_plane(const float normal[3], float(*verts)[3], const uint nverts)
POLY ROTATE PLANE.
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f, float r_cent[3], const blender::Span< blender::float3 > vert_positions)
COMPUTE POLY CENTER (BMFace).
void BM_vert_normal_update(BMVert *v)
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
static void bm_face_calc_tangent_pair_from_quad_edge_pair(const BMFace *f, float r_tangent_a[3], float r_tangent_b[3])
void BM_face_calc_tangent_from_edge_pair(const BMFace *f, float r_tangent[3])
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3])
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
float BM_face_calc_area_uv_signed(const BMFace *f, int cd_loop_uv_offset)
bool BM_vert_calc_normal(const BMVert *v, float r_no[3])
static float angle_signed_v2v2_pos(const float v1[2], const float v2[2])
void BM_vert_tri_calc_tangent_from_edge(BMVert *verts[3], float r_tangent[3])
void BM_vert_tri_calc_tangent_pair_from_edge(BMVert *verts[3], float r_tangent_a[3], float r_tangent_b[3])
void BM_face_calc_center_bounds_vcos(const BMesh *bm, const BMFace *f, float r_cent[3], const blender::Span< blender::float3 > vert_positions)
void BM_face_normal_flip_ex(BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
Face Flip Normal.
void BM_face_normal_update(BMFace *f)
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
float BM_face_calc_normal_vcos(const BMesh *bm, const BMFace *f, float r_no[3], const Span< float3 > vertexCos)
void BM_face_normal_flip(BMesh *bm, BMFace *f)
void BM_face_calc_center_median_vcos(const BMesh *bm, const BMFace *f, float r_cent[3], const blender::Span< blender::float3 > vert_positions)
void BM_verts_calc_normal_from_cloud_ex(BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
float BM_face_calc_area(const BMFace *f)
#define EDGE_SHARE_VERT(e1, e2)
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
float BM_face_calc_normal(const BMFace *f, float r_no[3])
BMESH UPDATE FACE NORMAL.
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
void BM_face_triangulate(BMesh *bm, BMFace *f, BMFace **r_faces_new, int *r_faces_new_tot, BMEdge **r_edges_new, int *r_edges_new_tot, LinkNode **r_faces_double, const int quad_method, const int ngon_method, const bool use_tag, MemArena *pf_arena, Heap *pf_heap)
static float bm_face_calc_poly_normal_vertex_cos(const BMFace *f, float r_no[3], const Span< float3 > vertexCos)
COMPUTE POLY NORMAL (BMFace).
void BM_face_calc_tangent_from_edge(const BMFace *f, float r_tangent[3])
static void bm_loop_normal_accum(const BMLoop *l, float no[3])
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
void BM_face_calc_tessellation(const BMFace *f, const bool use_fixed_quad, BMLoop **r_loops, uint(*r_index)[3])
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
COMPUTE POLY NORMAL (BMFace).
void BM_face_calc_tangent_from_edge_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
void BM_vert_normal_update_all(BMVert *v)
void BM_face_calc_tangent_pair_auto(const BMFace *f, float r_tangent_a[3], float r_tangent_b[3])
float BM_face_calc_perimeter(const BMFace *f)
void BM_edge_normals_update(BMEdge *e)
bool BM_face_is_normal_valid(const BMFace *f)
BMFace * BM_vert_pair_share_face_by_angle(BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
BMLoop * BM_face_find_longest_loop(BMFace *f)
float BM_edge_calc_length(const BMEdge *e)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
static float verts[][3]
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
float safe_acos_approx(float x)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
#define fabsf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
float no[3]
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
float co[3]
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len