new mesh bisect tool, available in the mesh menu.

cuts the mesh in half based on the cursor location and the viewport,
optionally supports filling the cut area (with uvs. vcols, etc),
and removing geometry on either side of the cut.
This commit is contained in:
Campbell Barton 2013-08-23 11:46:08 +00:00
parent e203c4c390
commit c752346cfa
4 changed files with 130 additions and 0 deletions

@ -1828,6 +1828,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.operator("mesh.symmetrize") layout.operator("mesh.symmetrize")
layout.operator("mesh.symmetry_snap") layout.operator("mesh.symmetry_snap")
layout.operator("mesh.bisect")
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...") layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
layout.separator() layout.separator()

@ -4435,6 +4435,133 @@ void MESH_OT_convex_hull(wmOperatorType *ot)
} }
#endif #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) static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
{ {
Object *obedit = CTX_data_edit_object(C); Object *obedit = CTX_data_edit_object(C);

@ -171,6 +171,7 @@ void MESH_OT_edge_split(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
void MESH_OT_wireframe(struct wmOperatorType *ot); void MESH_OT_wireframe(struct wmOperatorType *ot);
void MESH_OT_convex_hull(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_symmetrize(struct wmOperatorType *ot);
void MESH_OT_symmetry_snap(struct wmOperatorType *ot); void MESH_OT_symmetry_snap(struct wmOperatorType *ot);
void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot); void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot);

@ -175,6 +175,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_convex_hull); WM_operatortype_append(MESH_OT_convex_hull);
#endif #endif
WM_operatortype_append(MESH_OT_bisect);
WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetrize);
WM_operatortype_append(MESH_OT_symmetry_snap); WM_operatortype_append(MESH_OT_symmetry_snap);