diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 781ebd32318..9f4d0f8dcc1 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1828,6 +1828,7 @@ class VIEW3D_MT_edit_mesh(Menu): layout.operator("mesh.symmetrize") layout.operator("mesh.symmetry_snap") + layout.operator("mesh.bisect") layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...") layout.separator() diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 877e62a01f4..a6202b01ea4 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4435,6 +4435,133 @@ void MESH_OT_convex_hull(wmOperatorType *ot) } #endif + +static int mesh_bisect_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + + /* both can be NULL, fallbacks values are used */ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMOperator bmop; + float plane_co[3]; + float plane_no[3]; + float imat[4][4]; + + const float thresh = RNA_float_get(op->ptr, "threshold"); + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); + const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); + + PropertyRNA *prop; + + prop = RNA_struct_find_property(op->ptr, "plane_co"); + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, plane_co); + } + else { + copy_v3_v3(plane_co, give_cursor(scene, v3d)); + RNA_property_float_set_array(op->ptr, prop, plane_co); + } + + prop = RNA_struct_find_property(op->ptr, "plane_no"); + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, plane_no); + } + else { + if (rv3d) { + copy_v3_v3(plane_no, rv3d->viewinv[1]); + } + else { + /* fallback... */ + plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f; + } + RNA_property_float_set_array(op->ptr, prop, plane_no); + } + + invert_m4_m4(imat, obedit->obmat); + mul_m4_v3(imat, plane_co); + mul_mat3_m4_v3(imat, plane_no); + normalize_v3(plane_no); + + EDBM_op_init(em, &bmop, op, + "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", + BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer); + BMO_op_exec(bm, &bmop); + + if (use_fill) { + float normal_fill[3]; + BMOperator bmop_fill; + BMOperator bmop_attr; + + normalize_v3_v3(normal_fill, plane_no); + if (clear_outer == true && clear_inner == false) { + negate_v3(normal_fill); + } + + /* Fill */ + BMO_op_initf( + bm, &bmop_fill, op->flag, + "triangle_fill edges=%S normal=%v use_dissolve=%b", + &bmop, "geom_cut.out", normal_fill, true); + BMO_op_exec(bm, &bmop_fill); + + /* Copy Attributes */ + BMO_op_initf(bm, &bmop_attr, op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + &bmop_fill, "geom.out", false, true); + BMO_op_exec(bm, &bmop_attr); + BMO_op_finish(bm, &bmop_attr); + BMO_op_finish(bm, &bmop_fill); + } + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + return OPERATOR_CANCELLED; + } + else { + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + return OPERATOR_FINISHED; + } +} + +void MESH_OT_bisect(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bisect"; + ot->description = "Enforce symmetry (both form and topological) across an axis"; + ot->idname = "MESH_OT_bisect"; + + /* api callbacks */ + ot->exec = mesh_bisect_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + + prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut"); + RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane"); + RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry infront of the plane"); + + RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1); + +} + static int mesh_symmetrize_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 1dcc0e64183..be9243dc7ef 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -171,6 +171,7 @@ void MESH_OT_edge_split(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); void MESH_OT_wireframe(struct wmOperatorType *ot); void MESH_OT_convex_hull(struct wmOperatorType *ot); +void MESH_OT_bisect(struct wmOperatorType *ot); void MESH_OT_symmetrize(struct wmOperatorType *ot); void MESH_OT_symmetry_snap(struct wmOperatorType *ot); void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index b5352fb35f4..c98ad13acf6 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -175,6 +175,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_convex_hull); #endif + WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap);