42#define USE_NET_ISLAND_CONNECT
110 params.calc_looptris =
true;
111 params.calc_normals =
true;
112 params.is_destructive =
true;
141 int (*test_fn)(
BMFace *,
void *);
142 bool use_separate_all =
false;
143 bool use_separate_cut =
false;
152 const bool exact =
false;
168 switch (separate_mode) {
170 use_separate_all =
true;
173 if (use_self ==
false) {
174 use_separate_cut =
true;
179 use_separate_all =
true;
190 for (
Object *obedit : objects) {
198 int nshapes = use_self ? 1 : 2;
224 if (use_separate_cut) {
237 if (isect_len == objects.
size()) {
252 row = &layout->
row(
false);
255 row = &layout->
row(
false);
259 row = &layout->
row(
false);
271 {
ISECT_SEL,
"SELECT", 0,
"Self Intersect",
"Self intersect selected faces"},
275 "Selected/Unselected",
276 "Intersect selected with unselected faces"},
277 {0,
nullptr, 0,
nullptr,
nullptr},
286 "Cut into geometry keeping each side separate (Selected/Unselected only)"},
288 {0,
nullptr, 0,
nullptr,
nullptr},
296 "Simple solver with good performance, without support for overlapping geometry"},
301 "Slower solver with the best results for coplanar faces"},
302 {0,
nullptr, 0,
nullptr,
nullptr},
306 ot->name =
"Intersect (Knife)";
307 ot->description =
"Cut an intersection into faces";
308 ot->idname =
"MESH_OT_intersect";
320 ot->srna,
"threshold", 0.000001f, 0.0, 0.01,
"Merge Threshold",
"", 0.0, 0.001);
323 isect_intersect_solver_items,
326 "Which Intersect solver to use");
352 const bool use_exact =
false;
355 int (*test_fn)(
BMFace *,
void *);
364 for (
Object *obedit : objects) {
373 em->
bm, em->
looptris, test_fn,
nullptr, 2, use_self,
true,
false, boolean_operation);
397 if (isect_len == objects.
size()) {
413 row = &layout->
row(
false);
417 row = &layout->
row(
false);
434 {0,
nullptr, 0,
nullptr,
nullptr},
439 {
ISECT_SOLVER_EXACT,
"EXACT", 0,
"Exact",
"Exact solver, slower, handles more cases"},
440 {0,
nullptr, 0,
nullptr,
nullptr},
444 ot->name =
"Intersect (Boolean)";
445 ot->description =
"Cut solid geometry from selected to unselected";
446 ot->idname =
"MESH_OT_intersect_boolean";
456 isect_boolean_operation_items,
459 "Which boolean operation to apply");
464 "Use with difference intersection to swap which side is kept");
466 ot->srna,
"use_self",
false,
"Self Intersection",
"Do self-union or self-intersection");
468 ot->srna,
"threshold", 0.000001f, 0.0, 0.01,
"Merge Threshold",
"", 0.0, 0.001);
471 isect_boolean_solver_items,
474 "Which Boolean solver to use");
519 }
while ((l_iter = l_iter->
next) != l_first);
533 edge_net_temp_buf->
append(e_next);
545 edge_net_temp_buf->
clear();
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))
940#ifdef USE_NET_ISLAND_CONNECT
951 params.calc_looptris =
true;
952 params.calc_normals =
true;
953 params.is_destructive =
true;
956#ifdef USE_NET_ISLAND_CONNECT
1005 for (
int j = 0; j < 2; j++) {
1006 BMVert *v_pivot = (&
e->v1)[j];
1010 float v_pivot_co[3];
1013 e, f, v_pivot,
bm->ftable,
bm->totface, v_pivot_co, &v_pivot_fac);
1031 }
while ((e_link = e_link->
next));
1058 params.calc_looptris =
true;
1059 params.calc_normals =
true;
1060 params.is_destructive =
true;
1073 ot->name =
"Weld Edges into Faces";
1074 ot->description =
"Weld loose edges into faces (splitting them into new faces)";
1075 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)
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)
bool EDBM_uvselect_clear(BMEditMesh *em)
void EDBM_selectmode_flush(BMEditMesh *em)
bool ED_operator_editmesh(bContext *C)
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 append(const T &value)
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 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 bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag, Vector< BMEdge *, 128 > *edge_net_temp_buf)
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 use_property_decorate_set(bool is_sep)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & row(bool align)
void use_property_split_set(bool value)
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