Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bmesh/tools')
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c188
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c4
2 files changed, 142 insertions, 50 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 85de065daff..e7d0fe6a0c6 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -39,12 +39,13 @@
#include "BLI_utildefines_stack.h"
#include "bmesh.h"
-#include "bmesh_bisect_plane.h" /* own include */
+#include "bmesh_bisect_plane.h" /* Own include. */
-#include "BLI_strict_flags.h" /* keep last */
+#include "BLI_strict_flags.h" /* Keep last. */
/* -------------------------------------------------------------------- */
-/* Math utils */
+/** \name Math Functions
+ * \{ */
static short plane_point_test_v3(const float plane[4],
const float co[3],
@@ -63,10 +64,15 @@ static short plane_point_test_v3(const float plane[4],
return 0;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Wrappers to hide internal data-structure abuse,
+/** \name BMesh Element Accessors
+ *
+ * Wrappers to hide internal data-structure abuse,
* later we may want to move this into some hash lookup
- * to a separate struct, but for now we can store in BMesh data */
+ * to a separate struct, but for now we can store in #BMesh data.
+ * \{ */
#define BM_VERT_DIR(v) ((short *)(&(v)->head.index))[0] /* Direction -1/0/1 */
#define BM_VERT_SKIP(v) ((short *)(&(v)->head.index))[1] /* Skip Vert 0/1 */
@@ -75,12 +81,16 @@ static short plane_point_test_v3(const float plane[4],
#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
(*((uint *)(&(v)->no[2])))
-/**
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Flag Accessors
+ *
* Hide flag access
- * (for more readable code since same flag is used differently for vert/edgeface)...
+ * (for more readable code since same flag is used differently for vert/edge-face).
*/
-/* enable when vertex is in the center and its faces have been added to the stack */
+/** Enable when vertex is in the center and its faces have been added to the stack. */
BLI_INLINE void vert_is_center_enable(BMVert *v)
{
BM_elem_flag_enable(v, BM_ELEM_TAG);
@@ -94,7 +104,13 @@ BLI_INLINE bool vert_is_center_test(BMVert *v)
return (BM_elem_flag_test(v, BM_ELEM_TAG) != 0);
}
-/* enable when the edge can be cut */
+BLI_INLINE bool vert_pair_adjacent_in_orig_face(BMVert *v_a, BMVert *v_b, const uint f_len_orig)
+{
+ const uint delta = (uint)abs((int)BM_VERT_LOOPINDEX(v_a) - (int)BM_VERT_LOOPINDEX(v_b));
+ return ELEM(delta, 1, (uint)(f_len_orig - 1));
+}
+
+/** Enable when the edge can be cut. */
BLI_INLINE void edge_is_cut_enable(BMEdge *e)
{
BM_elem_flag_enable(e, BM_ELEM_TAG);
@@ -108,7 +124,7 @@ BLI_INLINE bool edge_is_cut_test(BMEdge *e)
return (BM_elem_flag_test(e, BM_ELEM_TAG) != 0);
}
-/* enable when the faces are added to the stack */
+/** Enable when the faces are added to the stack. */
BLI_INLINE void face_in_stack_enable(BMFace *f)
{
BM_elem_flag_disable(f, BM_ELEM_TAG);
@@ -122,8 +138,11 @@ BLI_INLINE bool face_in_stack_test(BMFace *f)
return (BM_elem_flag_test(f, BM_ELEM_TAG) == 0);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* BMesh utils */
+/** \name BMesh Face Bisect
+ * \{ */
static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
{
@@ -142,32 +161,39 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
static void bm_face_bisect_verts(
BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
{
- /* unlikely more than 2 verts are needed */
+ /* Unlikely more than 2 verts are needed. */
const uint f_len_orig = (uint)f->len;
BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
STACK_DECLARE(vert_split_arr);
BMLoop *l_iter, *l_first;
bool use_dirs[3] = {false, false, false};
bool is_inside = false;
+ /* True when the face contains one or more edges with both it's vertices on the plane.
+ * When set, centered loops are walked over to check if they need to be skipped. */
+ bool face_has_center_edge = false;
STACK_INIT(vert_split_arr, f_len_orig);
l_first = BM_FACE_FIRST_LOOP(f);
- /* add plane-aligned verts to the stack
- * and check we have verts from both sides in this face,
- * ... that the face doesn't only have boundary verts on the plane for eg. */
+ /* Add plane-aligned verts to the stack and check we have verts from both sides in this face
+ * (that the face doesn't only have boundary verts on the plane for eg). */
l_iter = l_first;
do {
if (vert_is_center_test(l_iter->v)) {
BLI_assert(BM_VERT_DIR(l_iter->v) == 0);
- /* if both are -1 or 1, or both are zero:
- * don't flip 'inside' var while walking */
+ /* If both are -1 or 1, or both are zero: don't flip 'inside' var while walking. */
BM_VERT_SKIP(l_iter->v) = (((BM_VERT_DIR(l_iter->prev->v) ^ BM_VERT_DIR(l_iter->next->v))) ==
0);
STACK_PUSH(vert_split_arr, l_iter->v);
+
+ if (face_has_center_edge == false) {
+ if (vert_is_center_test(l_iter->prev->v)) {
+ face_has_center_edge = true;
+ }
+ }
}
use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true;
} while ((l_iter = l_iter->next) != l_first);
@@ -180,7 +206,7 @@ static void bm_face_bisect_verts(
l_a = BM_face_vert_share_loop(f, vert_split_arr[0]);
l_b = BM_face_vert_share_loop(f, vert_split_arr[1]);
- /* common case, just cut the face once */
+ /* Common case, just cut the face once. */
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
if (oflag_center | oflag_new) {
@@ -192,7 +218,63 @@ static void bm_face_bisect_verts(
}
}
else {
- /* less common case, _complicated_ we need to calculate how to do multiple cuts */
+ /* Less common case, _complicated_ we need to calculate how to do multiple cuts. */
+
+ uint i = 0;
+
+ /* ---- */
+ /* Check contiguous spans of centered vertices (skipping when necessary). */
+ if (face_has_center_edge) {
+
+ /* Loop indices need to be set for adjacency checks. */
+ l_iter = l_first;
+ do {
+ BM_VERT_LOOPINDEX(l_iter->v) = i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* Start out on a non-centered vertex so a span of centered vertices can be looped over
+ * without having to scan backwards as well as forwards. */
+ BMLoop *l_first_non_center = l_first;
+ while (vert_is_center_test(l_first_non_center->v)) {
+ l_first_non_center = l_first_non_center->next;
+ }
+
+ l_iter = l_first_non_center;
+ do {
+ if (BM_VERT_SKIP(l_iter->v)) {
+ continue;
+ }
+ /* No need to check the previous as the iteration starts on a non-centered vertex. */
+ if (!(vert_is_center_test(l_iter->v) && vert_is_center_test(l_iter->next->v))) {
+ continue;
+ }
+
+ /* Walk over the next loops as long as they are centered. */
+ BMLoop *l_prev = l_iter->prev;
+ BMLoop *l_next = l_iter->next->next;
+ /* No need to scan the previous vertices,
+ * these will have been dealt with in previous steps. */
+ BLI_assert(!vert_is_center_test(l_prev->v));
+ while (vert_is_center_test(l_next->v)) {
+ l_next = l_next->next;
+ }
+
+ /* Skip all vertices when the edges connected to the beginning/end
+ * of the range are on a different side of the bisecting plane. */
+ if (!(BM_VERT_DIR(l_prev->v) ^ BM_VERT_DIR(l_next->v))) {
+ BLI_assert(!vert_is_center_test(l_prev->v));
+ l_iter = l_prev->next;
+ while (l_iter != l_next) {
+ BLI_assert(vert_is_center_test(l_iter->v));
+ BM_VERT_SKIP(l_iter->v) = true;
+ l_iter = l_iter->next;
+ }
+ }
+ /* Step over the span already handled, even if skip wasn't set. */
+ l_iter = l_next->prev;
+ } while ((l_iter = l_iter->next) != l_first_non_center);
+ }
+
float(*face_verts_proj_2d)[2] = BLI_array_alloca(face_verts_proj_2d, f_len_orig);
float axis_mat[3][3];
@@ -200,15 +282,12 @@ static void bm_face_bisect_verts(
STACK_DECLARE(face_split_arr);
float sort_dir[3];
- uint i;
/* ---- */
/* Calculate the direction to sort verts in the face intersecting the plane */
- /* exact dir isn't so important,
- * just need a dir for sorting verts across face,
- * 'sort_dir' could be flipped either way, it not important, we only need to order the array
- */
+ /* The exact direction isn't important, vertices just need to be sorted across the face.
+ * (`sort_dir` could be flipped either way). */
cross_v3_v3v3(sort_dir, f->no, plane);
if (UNLIKELY(normalize_v3(sort_dir) == 0.0f)) {
/* find any 2 verts and get their direction */
@@ -219,8 +298,8 @@ static void bm_face_bisect_verts(
}
}
if (UNLIKELY(i == STACK_SIZE(vert_split_arr))) {
- /* ok, we can't do anything useful here,
- * face has no area or so, bail out, this is highly unlikely but not impossible */
+ /* Ok, we can't do anything useful here,
+ * face has no area or so, bail out, this is highly unlikely but not impossible. */
goto finally;
}
}
@@ -228,20 +307,19 @@ static void bm_face_bisect_verts(
/* ---- */
/* Calculate 2d coords to use for intersection checks */
- /* get the faces 2d coords */
+ /* Get the faces 2d coords. */
BLI_assert(BM_face_is_normal_valid(f));
axis_dominant_v3_to_m3(axis_mat, f->no);
l_iter = l_first;
i = 0;
do {
- BM_VERT_LOOPINDEX(l_iter->v) = i;
mul_v2_m3v3(face_verts_proj_2d[i], axis_mat, l_iter->v->co);
i++;
} while ((l_iter = l_iter->next) != l_first);
/* ---- */
- /* Sort the verts across the face from one side to another */
+ /* Sort the verts across the face from one side to another. */
for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
BMVert *v = vert_split_arr[i];
BM_VERT_SORTVAL(v) = dot_v3v3(sort_dir, v->co);
@@ -251,9 +329,9 @@ static void bm_face_bisect_verts(
vert_split_arr, STACK_SIZE(vert_split_arr), sizeof(*vert_split_arr), bm_vert_sortval_cb);
/* ---- */
- /* Split the face across sorted splits */
+ /* Split the face across sorted splits. */
- /* note: we don't know which face gets which splits,
+ /* NOTE: we don't know which face gets which splits,
* so at the moment we have to search all faces for the vert pair,
* while not all that nice, typically there are < 5 resulting faces,
* so its not _that_ bad. */
@@ -265,6 +343,12 @@ static void bm_face_bisect_verts(
BMVert *v_a = vert_split_arr[i];
BMVert *v_b = vert_split_arr[i + 1];
+ if (face_has_center_edge) {
+ if (vert_pair_adjacent_in_orig_face(v_a, v_b, f_len_orig)) {
+ continue;
+ }
+ }
+
if (!BM_VERT_SKIP(v_a)) {
is_inside = !is_inside;
}
@@ -275,8 +359,8 @@ static void bm_face_bisect_verts(
uint j;
for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
- /* would be nice to avoid loop lookup here,
- * but we need to know which face the verts are in */
+ /* It would be nice to avoid loop lookup here,
+ * but we need to know which face the verts are in. */
if ((l_a = BM_face_vert_share_loop(face_split_arr[j], v_a)) &&
(l_b = BM_face_vert_share_loop(face_split_arr[j], v_b))) {
found = true;
@@ -284,11 +368,10 @@ static void bm_face_bisect_verts(
}
}
- /* ideally wont happen, but it can for self intersecting faces */
+ /* Ideally wont happen, but it can for self intersecting faces. */
// BLI_assert(found == true);
- /* in fact this simple test is good enough,
- * test if the loops are adjacent */
+ /* In fact this simple test is good enough, test if the loops are adjacent. */
if (found && !BM_loop_is_adjacent(l_a, l_b)) {
BMLoop *l_new;
BMFace *f_tmp;
@@ -322,8 +405,11 @@ finally:
(void)vert_split_arr;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Main logic */
+/** \name Public BMesh Bisect Function
+ * \{ */
/**
* \param use_snap_center: Snap verts onto the plane.
@@ -350,25 +436,25 @@ void BM_mesh_bisect_plane(BMesh *bm,
BMIter iter;
if (use_tag) {
- /* build tagged edge array */
+ /* Build tagged edge array. */
BMEdge *e;
einput_len = 0;
- /* flush edge tags to verts */
+ /* Flush edge tags to verts. */
BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
- /* keep face tags as is */
+ /* Keep face tags as is. */
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
if (edge_is_cut_test(e)) {
edges_arr[einput_len++] = e;
- /* flush edge tags to verts */
+ /* Flush edge tags to verts. */
BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
- /* face tags are set by caller */
+ /* Face tags are set by caller. */
}
else {
BMEdge *e;
@@ -388,7 +474,7 @@ void BM_mesh_bisect_plane(BMesh *bm,
if (use_tag && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
vert_is_center_disable(v);
- /* these should never be accessed */
+ /* These should never be accessed. */
BM_VERT_DIR(v) = 0;
BM_VERT_DIST(v) = 0.0f;
@@ -408,11 +494,11 @@ void BM_mesh_bisect_plane(BMesh *bm,
}
}
- /* store a stack of faces to be evaluated for splitting */
+ /* Store a stack of faces to be evaluated for splitting. */
BLI_LINKSTACK_INIT(face_stack);
for (i = 0; i < einput_len; i++) {
- /* we could check edge_is_cut_test(e) but there is no point */
+ /* We could check `edge_is_cut_test(e)` but there is no point. */
BMEdge *e = edges_arr[i];
const int side[2] = {BM_VERT_DIR(e->v1), BM_VERT_DIR(e->v2)};
const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
@@ -449,8 +535,8 @@ void BM_mesh_bisect_plane(BMesh *bm,
BM_VERT_DIST(v_new) = 0.0f;
}
else if (side[0] == 0 || side[1] == 0) {
- /* check if either edge verts are aligned,
- * if so - tag and push all faces that use it into the stack */
+ /* Check if either edge verts are aligned,
+ * if so - tag and push all faces that use it into the stack. */
uint j;
BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) {
if (side[j] == 0) {
@@ -470,7 +556,7 @@ void BM_mesh_bisect_plane(BMesh *bm,
}
}
- /* if both verts are on the center - tag it */
+ /* If both verts are on the center - tag it. */
if (oflag_center) {
if (side[0] == 0 && side[1] == 0) {
BMO_edge_flag_enable(bm, e, oflag_center);
@@ -485,9 +571,11 @@ void BM_mesh_bisect_plane(BMesh *bm,
bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
}
- /* Caused by access macros: BM_VERT_DIR, BM_VERT_SKIP. */
+ /* Caused by access macros: #BM_VERT_DIR, #BM_VERT_SKIP. */
bm->elem_index_dirty |= BM_VERT;
- /* now we have all faces to split in the stack */
+ /* Now we have all faces to split in the stack. */
BLI_LINKSTACK_FREE(face_stack);
}
+
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index c176210426b..710d7f79637 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -1660,5 +1660,9 @@ bool BM_mesh_intersect(BMesh *bm,
BLI_memarena_free(s.mem_arena);
+ /* It's unlikely the selection history is useful at this point,
+ * if this is not called this array would need to be validated, see: T86799. */
+ BM_select_history_clear(bm);
+
return (has_edit_isect || has_edit_boolean);
}