BMesh: add utility functions

- BM_edge_uv_share_vert_check
- BM_face_uv_calc_center_median_weighted
- BM_loop_at_index_find
This commit is contained in:
Campbell Barton
2020-07-09 18:23:16 +10:00
parent 0b3bf69d3c
commit 0b8221683f
5 changed files with 113 additions and 6 deletions

View File

@@ -2377,6 +2377,26 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index)
return BLI_mempool_findelem(bm->fpool, index);
}
BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
{
BMIter iter;
BMFace *f;
int i = index;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (i < f->len) {
BMLoop *l_first, *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (i == 0) {
return l_iter;
}
} while ((l_iter = l_iter->next) != l_first);
}
i -= f->len;
}
return NULL;
}
/**
* Use lookup table when available, else use slower find functions.
*

View File

@@ -118,6 +118,7 @@ BLI_INLINE BMFace *BM_face_at_index(BMesh *bm, const int index)
BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);

View File

@@ -32,6 +32,69 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
static void uv_aspect(const BMLoop *l,
const float aspect[2],
const int cd_loop_uv_offset,
float r_uv[2])
{
const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
r_uv[0] = uv[0] * aspect[0];
r_uv[1] = uv[1] * aspect[1];
}
/**
* Typically we avoid hiding arguments,
* make this an exception since it reads poorly with so many repeated arguments.
*/
#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
/**
* Computes the UV center of a face, using the mean average weighted by edge length.
*
* See #BM_face_calc_center_median_weighted for matching spatial functionality.
*
* \param aspect: Calculate the center scaling by these values, and finally dividing.
* Since correct weighting depends on having the correct aspect.
*/
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
float r_cent[2])
{
const BMLoop *l_iter;
const BMLoop *l_first;
float totw = 0.0f;
float w_prev;
zero_v2(r_cent);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
float uv_prev[2], uv_curr[2];
UV_ASPECT(l_iter->prev, uv_prev);
UV_ASPECT(l_iter, uv_curr);
w_prev = len_v2v2(uv_prev, uv_curr);
do {
float uv_next[2];
UV_ASPECT(l_iter->next, uv_next);
const float w_curr = len_v2v2(uv_curr, uv_next);
const float w = (w_curr + w_prev);
madd_v2_v2fl(r_cent, uv_curr, w);
totw += w;
w_prev = w_curr;
copy_v2_v2(uv_curr, uv_next);
} while ((l_iter = l_iter->next) != l_first);
if (totw != 0.0f) {
mul_v2_fl(r_cent, 1.0f / (float)totw);
}
/* Reverse aspect. */
r_cent[0] /= aspect[0];
r_cent[1] /= aspect[1];
}
#undef UV_ASPECT
/**
* Calculate the UV cross product (use the sign to check the winding).
*/
@@ -69,16 +132,25 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
/**
* Check if two loops that share a vertex also have the same UV coordinates.
*/
bool BM_loop_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
{
const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset);
const MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset);
if (!equals_v2v2(luv_a->uv, luv_b->uv)) {
return false;
}
return true;
}
/**
* Check if two loops that share a vertex also have the same UV coordinates.
*/
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
if (!BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) {
return false;
}
/* No need for NULL checks, these will always succeed. */

View File

@@ -21,6 +21,18 @@
* \ingroup bmesh
*/
float BM_loop_uv_calc_edge_length_squared(const BMLoop *l,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_loop_uv_calc_edge_length(const BMLoop *l,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
float r_cent[2]) ATTR_NONNULL();
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -29,8 +41,10 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_loop_uv_share_vert_check(BMEdge *e,
BMLoop *l_a,
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_loop_uv_share_vert_check(BMLoop *l_a,
BMLoop *l_b,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();

View File

@@ -657,7 +657,7 @@ static UVRipPairs *uv_rip_pairs_from_loop(BMLoop *l_init,
BMLoop *l_other = (l_radial_iter->v == l_step->v) ? l_radial_iter :
l_radial_iter->next;
BLI_assert(l_other->v == l_step->v);
if (BM_loop_uv_share_vert_check(e_radial, l_other, l_step, cd_loop_uv_offset)) {
if (BM_edge_uv_share_vert_check(e_radial, l_other, l_step, cd_loop_uv_offset)) {
if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
BLI_SMALLSTACK_PUSH(stack, l_other);
UL(l_other)->in_stack = true;