BMesh: Add API call BM_face_calc_point_in_face

Was local to knife code, but this is generally useful.
This commit is contained in:
Campbell Barton 2015-11-27 22:08:16 +11:00
parent bfaebeaee6
commit a28e014313
4 changed files with 55 additions and 45 deletions

View File

@ -150,10 +150,14 @@ static void bm_face_calc_poly_center_mean_vertex_cos(
/**
* For tools that insist on using triangles, ideally we would cache this data.
*
* \param r_loops Store face loop pointers, (f->len)
* \param r_index Store triangle triples, indices into \a r_loops, ((f->len - 2) * 3)
* \param use_fixed_quad: When true, always split quad along (0 -> 2) regardless of concave corners,
* (as done in #BM_mesh_calc_tessellation).
* \param r_loops: Store face loop pointers, (f->len)
* \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
*/
void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3])
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
BMLoop **r_loops, unsigned int (*r_index)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
@ -167,7 +171,7 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (
r_index[0][1] = 1;
r_index[0][2] = 2;
}
else if (f->len == 4) {
else if (f->len == 4 && use_fixed_quad) {
*r_loops++ = (l_iter = l_first);
*r_loops++ = (l_iter = l_iter->next);
*r_loops++ = (l_iter = l_iter->next);
@ -201,6 +205,46 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (
}
}
/**
* Return a point inside the face.
*/
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
{
const BMLoop *l_tri[3];
if (f->len == 3) {
const BMLoop *l = BM_FACE_FIRST_LOOP(f);
ARRAY_SET_ITEMS(l_tri, l, l->next, l->prev);
}
else {
/* tessellation here seems overkill when in many cases this will be the center,
* but without this we can't be sure the point is inside a concave face. */
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
int j;
int j_best = 0; /* use as fallback when unset */
float area_best = -1.0f;
BM_face_calc_tessellation(f, false, loops, index);
for (j = 0; j < tottri; j++) {
const float *p1 = loops[index[j][0]]->v->co;
const float *p2 = loops[index[j][1]]->v->co;
const float *p3 = loops[index[j][2]]->v->co;
const float area = area_squared_tri_v3(p1, p2, p3);
if (area > area_best) {
j_best = j;
area_best = area;
}
}
ARRAY_SET_ITEMS(l_tri, loops[index[j_best][0]], loops[index[j_best][1]], loops[index[j_best][2]]);
}
mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
}
/**
* get the area of the face
*/

View File

@ -34,7 +34,10 @@ struct Heap;
void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]);
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
BMLoop **r_loops, unsigned int (*r_index)[3]);
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_normal_vcos(
const BMesh *bm, const BMFace *f, float r_no[3],

View File

@ -2299,7 +2299,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol)
unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
int j;
BM_face_calc_tessellation(f, loops, index);
BM_face_calc_tessellation(f, false, loops, index);
for (j = 0; j < tottri; j++) {
const float *p1 = loops[index[j][0]]->v->co;

View File

@ -3341,43 +3341,6 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
/* Knife tool as a utility function
* that can be used for internal slicing operations */
/**
* Return a point inside the face.
*
* tessellation here seems way overkill,
* but without this its very hard to know of a point is inside the face
*/
static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3])
{
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
int j;
int j_best = 0; /* use as fallback when unset */
float area_best = -1.0f;
BM_face_calc_tessellation(f, loops, index);
for (j = 0; j < tottri; j++) {
const float *p1 = loops[index[j][0]]->v->co;
const float *p2 = loops[index[j][1]]->v->co;
const float *p3 = loops[index[j][2]]->v->co;
float area;
area = area_squared_tri_v3(p1, p2, p3);
if (area > area_best) {
j_best = j;
area_best = area;
}
}
mid_v3_v3v3v3(
r_cent,
loops[index[j_best][0]]->v->co,
loops[index[j_best][1]]->v->co,
loops[index[j_best][2]]->v->co);
}
static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
{
LinkNode *p = polys;
@ -3495,7 +3458,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
BMIter fiter;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
float cent[3], cent_ss[2];
edbm_mesh_knife_face_point(f, cent);
BM_face_calc_point_in_face(f, cent);
knife_project_v2(kcd, cent, cent_ss);
if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
@ -3531,7 +3494,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
if (found) {
float cent[3], cent_ss[2];
edbm_mesh_knife_face_point(f, cent);
BM_face_calc_point_in_face(f, cent);
knife_project_v2(kcd, cent, cent_ss);
if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) &&
edbm_mesh_knife_point_isect(polys, cent_ss))