43#define USE_NET_ISLAND_CONNECT
109 params.calc_looptris =
true;
110 params.calc_normals =
true;
111 params.is_destructive =
true;
140 int (*test_fn)(
BMFace *,
void *);
141 bool use_separate_all =
false;
142 bool use_separate_cut =
false;
151 const bool exact =
false;
167 switch (separate_mode) {
169 use_separate_all =
true;
172 if (use_self ==
false) {
173 use_separate_cut =
true;
178 use_separate_all =
true;
189 for (
Object *obedit : objects) {
197 int nshapes = use_self ? 1 : 2;
223 if (use_separate_cut) {
236 if (isect_len == objects.
size()) {
251 row = &layout->
row(
false);
254 row = &layout->
row(
false);
258 row = &layout->
row(
false);
270 {
ISECT_SEL,
"SELECT", 0,
"Self Intersect",
"Self intersect selected faces"},
274 "Selected/Unselected",
275 "Intersect selected with unselected faces"},
276 {0,
nullptr, 0,
nullptr,
nullptr},
285 "Cut into geometry keeping each side separate (Selected/Unselected only)"},
287 {0,
nullptr, 0,
nullptr,
nullptr},
295 "Simple solver with good performance, without support for overlapping geometry"},
300 "Slower solver with the best results for coplanar faces"},
301 {0,
nullptr, 0,
nullptr,
nullptr},
305 ot->name =
"Intersect (Knife)";
306 ot->description =
"Cut an intersection into faces";
307 ot->idname =
"MESH_OT_intersect";
319 ot->srna,
"threshold", 0.000001f, 0.0, 0.01,
"Merge Threshold",
"", 0.0, 0.001);
322 isect_intersect_solver_items,
325 "Which Intersect solver to use");
351 const bool use_exact =
false;
354 int (*test_fn)(
BMFace *,
void *);
363 for (
Object *obedit : objects) {
372 em->
bm, em->
looptris, test_fn,
nullptr, 2, use_self,
true,
false, boolean_operation);
396 if (isect_len == objects.
size()) {
412 row = &layout->
row(
false);
416 row = &layout->
row(
false);
433 {0,
nullptr, 0,
nullptr,
nullptr},
438 {
ISECT_SOLVER_EXACT,
"EXACT", 0,
"Exact",
"Exact solver, slower, handles more cases"},
439 {0,
nullptr, 0,
nullptr,
nullptr},
443 ot->name =
"Intersect (Boolean)";
444 ot->description =
"Cut solid geometry from selected to unselected";
445 ot->idname =
"MESH_OT_intersect_boolean";
455 isect_boolean_operation_items,
458 "Which boolean operation to apply");
463 "Use with difference intersection to swap which side is kept");
465 ot->srna,
"use_self",
false,
"Self Intersection",
"Do self-union or self-intersection");
467 ot->srna,
"threshold", 0.000001f, 0.0, 0.01,
"Merge Threshold",
"", 0.0, 0.001);
470 isect_boolean_solver_items,
473 "Which Boolean solver to use");
518 }
while ((l_iter = l_iter->
next) != l_first);
543 bm, f,
static_cast<BMEdge **
>(edge_net_temp_buf->
data), edge_net_temp_buf->
count, &face_arr);
547 for (
BMFace *face : face_arr) {
563 if (l_iter->
f != f_ignore) {
568 }
while ((l_iter = l_iter->
radial_next) != e_radial->
l);
573#ifdef USE_NET_ISLAND_CONNECT
592 ls_base->
list =
nullptr;
596 ls_base =
static_cast<LinkBase *
>(*ls_base_p);
625 int edge_arr_len = 0;
628 edge_arr[edge_arr_len++] =
static_cast<BMEdge *
>(e_link->
link);
629 e_link = e_link->
next;
633 uint edge_arr_holes_len;
642 &edge_arr_holes_len))
644 edge_arr_len = edge_arr_holes_len;
645 edge_arr = edge_arr_holes;
651 for (
int i = e_link_len;
i < edge_arr_len;
i++) {
655 if (e_link_len != edge_arr_len) {
659 for (
int i = e_link_len;
i < edge_arr_len;
i++) {
667 "Doubled face detected at " AT ". Resulting mesh may be corrupt.");
700 const int ftable_len,
701 float r_v_pivot_co[3],
702 float *r_v_pivot_fac)
705 bool found_other_self =
false;
706 int found_other_face = 0;
714 if (f_b_index == f_a_index) {
716 found_other_self =
true;
718 else if (f_b_index != -1) {
724 BMFace *f_b = ftable[f_b_index];
734 BMEdge *e_split =
nullptr;
738 if ((found_other_self ==
false) || found_other_face) {
745 float v_pivot_co_test[3];
747 CLAMP(v_pivot_fac, 0.0f, 1.0f);
751 if ((dist_test_sq < dist_best_sq) || (e_split ==
nullptr)) {
761 else if (found_other_face) {
766 int other_face_shared = 0;
767 if (l_radial_iter != l_iter) {
772 }
while ((l_radial_iter = l_radial_iter->
radial_next) != l_iter);
774 if (other_face_shared != found_other_face) {
781 dist_best_sq = dist_test_sq;
783 *r_v_pivot_fac = v_pivot_fac;
786 }
while ((l_iter = l_iter->
next) != l_first);
815 for (
Object *obedit : objects) {
819 if ((
bm->totedgesel == 0) || (
bm->totfacesel == 0)) {
882 if (loop_stack_len == 0) {
885 else if (loop_stack_len == 1) {
906 if (dot_test < dot_best) {
911 l->prev->v->co,
l->v->co, v_other->
co,
l->f->no) <
913 l->prev->v->co,
l->v->co,
l->next->v->co,
l->f->no))
941#ifdef USE_NET_ISLAND_CONNECT
952 params.calc_looptris =
true;
953 params.calc_normals =
true;
954 params.is_destructive =
true;
957#ifdef USE_NET_ISLAND_CONNECT
1006 for (
int j = 0; j < 2; j++) {
1007 BMVert *v_pivot = (&
e->v1)[j];
1011 float v_pivot_co[3];
1014 e, f, v_pivot,
bm->ftable,
bm->totface, v_pivot_co, &v_pivot_fac);
1032 }
while ((e_link = e_link->
next));
1059 params.calc_looptris =
true;
1060 params.calc_normals =
true;
1061 params.is_destructive =
true;
1074 ot->name =
"Weld Edges into Faces";
1075 ot->description =
"Weld loose edges into faces (splitting them into new faces)";
1076 ot->idname =
"MESH_OT_face_split_by_edges";
Scene * CTX_data_scene(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
struct BMFace * BKE_bmbvh_find_face_closest(const BMBVHTree *tree, const float co[3], float dist_max)
BMBVHTree * BKE_bmbvh_new(struct BMesh *bm, blender::Span< std::array< BMLoop *, 3 > > looptris, int flag, const blender::float3 *cos_cage, bool cos_cage_free)
void BKE_bmbvh_free(BMBVHTree *tree)
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_msg(a, msg)
#define BLI_buffer_append(buffer_, type_, val_)
#define BLI_buffer_declare_static(type_, name_, flag_, static_count_)
#define BLI_buffer_clear(buffer_)
#define BLI_buffer_free(name_)
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
#define GHASH_ITER(gh_iter_, ghash_)
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
BLI_LINKSTACK_*** wrapper macros for using a LinkNode to store a stack of pointers,...
#define BLI_SMALLSTACK_DECLARE(var, type)
#define BLI_SMALLSTACK_POP(var)
#define BLI_SMALLSTACK_PUSH(var, data)
#define BLI_SMALLSTACK_POP_EX(var_src, var_dst)
#define BLI_SMALLSTACK_IS_EMPTY(var)
#define BLI_SMALLSTACK_SWAP(var_a, var_b)
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[3])
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
#define BLI_stack_new(esize, descr)
#define UNUSED_VARS_NDEBUG(...)
Object is a sort of wrapper for general info.
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
void EDBM_selectmode_flush(BMEditMesh *em)
bool ED_operator_editmesh(bContext *C)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
bool BM_mesh_boolean_knife(BMesh *, blender::Span< std::array< BMLoop *, 3 > > looptris, int(*test_fn)(BMFace *, void *), void *, const int, const bool, const bool, const bool, const bool)
bool BM_mesh_boolean(BMesh *, blender::Span< std::array< BMLoop *, 3 > > looptris, int(*test_fn)(BMFace *, void *), void *, const int, const bool, const bool, const bool, const int)
#define BM_elem_cb_check_hflag_enabled_simple(type, hflag_p)
#define BM_DISK_EDGE_NEXT(e, v)
#define BM_FACE_FIRST_LOOP(p)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del, BMFace **r_double)
Join Connected Faces.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
bool BM_mesh_intersect(BMesh *bm, const blender::Span< std::array< BMLoop *, 3 > > looptris, int(*test_fn)(BMFace *f, void *user_data), void *user_data, const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect, const bool use_partial_connect, const bool use_edge_tag, const int boolean_mode, const float eps)
@ BMESH_ISECT_BOOLEAN_DIFFERENCE
@ BMESH_ISECT_BOOLEAN_UNION
@ BMESH_ISECT_BOOLEAN_ISECT
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
bool BM_face_split_edgenet_connect_islands(BMesh *bm, BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len, bool use_partial_connect, MemArena *mem_arena, BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
bool BM_face_split_edgenet(BMesh *bm, BMFace *f, BMEdge **edge_net, const int edge_net_len, blender::Vector< BMFace * > *r_face_arr)
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
float BM_edge_calc_length_squared(const BMEdge *e)
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
bool BM_vert_in_face(BMVert *v, BMFace *f)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
void MESH_OT_intersect(wmOperatorType *ot)
static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignore)
void MESH_OT_intersect_boolean(wmOperatorType *ot)
static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag, BLI_Buffer *edge_net_temp_buf)
static BMEdge * bm_face_split_edge_find(BMEdge *e_a, BMFace *f_a, BMVert *v_pivot, BMFace **ftable, const int ftable_len, float r_v_pivot_co[3], float *r_v_pivot_fac)
static void bm_face_split_by_edges_island_connect(BMesh *bm, BMFace *f, LinkNode *e_link, const int e_link_len, MemArena *mem_arena_edgenet)
static int bm_face_isect_self(BMFace *f, void *)
static void edbm_intersect_ui(bContext *, wmOperator *op)
static wmOperatorStatus edbm_intersect_exec(bContext *C, wmOperator *op)
static void ghash_insert_face_edge_link(GHash *gh, BMFace *f_key, BMEdge *e_val, MemArena *mem_arena)
static void edbm_intersect_select(BMEditMesh *em, Mesh *mesh, bool do_select)
void MESH_OT_face_split_by_edges(wmOperatorType *ot)
static int bm_face_isect_pair_swap(BMFace *f, void *)
static wmOperatorStatus edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
static void edbm_intersect_boolean_ui(bContext *, wmOperator *op)
static wmOperatorStatus edbm_face_split_by_edges_exec(bContext *C, wmOperator *)
static int bm_edge_sort_length_cb(const void *e_a_v, const void *e_b_v)
static int bm_face_isect_pair(BMFace *f, void *)
static MemArena * mem_arena
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
blender::Array< std::array< BMLoop *, 3 > > looptris
struct BMLoop * radial_next
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct ReportList * reports