Index: source/blender/bmesh/bmesh_operators.h =================================================================== --- source/blender/bmesh/bmesh_operators.h (revision 22703) +++ source/blender/bmesh/bmesh_operators.h (working copy) @@ -22,6 +22,7 @@ SUBD_STRAIGHT_CUT, }; +/* similar face selection slot values */ enum { SIMFACE_MATERIAL = 201, SIMFACE_IMAGE, @@ -31,6 +32,17 @@ SIMFACE_COPLANAR, }; +/* similar edge selection slot values */ +enum { + SIMEDGE_LENGTH = 101, + SIMEDGE_DIR, + SIMEDGE_FACE, + SIMEDGE_FACE_ANGLE, + SIMEDGE_CREASE, + SIMEDGE_SEAM, + SIMEDGE_SHARP, +}; + extern BMOpDefine *opdefines[]; extern int bmesh_total_ops; Index: source/blender/bmesh/intern/bmesh_opdefines.c =================================================================== --- source/blender/bmesh/intern/bmesh_opdefines.c (revision 22703) +++ source/blender/bmesh/intern/bmesh_opdefines.c (working copy) @@ -629,6 +629,22 @@ 0 }; +/* + Similar edges select + + Select similar edges (length, direction, edge, seam,....). +*/ +BMOpDefine def_similaredges = { + "similaredges", + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /* input edges */ + {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, /* output edges */ + {BMOP_OPSLOT_INT, "type"}, /* type of selection */ + {BMOP_OPSLOT_FLT, "thresh"}, /* threshold of selection */ + {0} /*null-terminating sentinel*/}, + bmesh_similaredges_exec, + 0 +}; + BMOpDefine *opdefines[] = { &def_splitop, &def_dupeop, @@ -670,6 +686,7 @@ &def_pointmerge, &def_collapse, &def_similarfaces, + &def_similaredges, }; int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*)); Index: source/blender/bmesh/intern/bmesh_operators_private.h =================================================================== --- source/blender/bmesh/intern/bmesh_operators_private.h (revision 22703) +++ source/blender/bmesh/intern/bmesh_operators_private.h (working copy) @@ -47,5 +47,5 @@ void bmesh_pointmerge_exec(BMesh *bm, BMOperator *op); void bmesh_collapse_exec(BMesh *bm, BMOperator *op); void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op); - +void bmesh_similaredges_exec(BMesh *bm, BMOperator *op); #endif Index: source/blender/bmesh/operators/utils.c =================================================================== --- source/blender/bmesh/operators/utils.c (revision 22703) +++ source/blender/bmesh/operators/utils.c (working copy) @@ -501,7 +501,7 @@ BMIter fm_iter; BMFace *fs, *fm; BMOIter fs_iter; - int num_tex, num_sels = 0, num_total = 0, i = 0, idx = 0; + int num_sels = 0, num_total = 0, i = 0, idx = 0; float angle = 0.0f; tmp_face_ext *f_ext = NULL; int *indices = NULL; @@ -543,7 +543,7 @@ ** Save us some computation burden: In case of perimeter/area/coplanar selection we compute ** only once. */ - if( type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE ) { + if( type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE ) { for( i = 0; i < num_total; i++ ) { switch( type ) { case SIMFACE_PERIMETER: @@ -579,11 +579,9 @@ } /* now select the rest (if any) */ - //BM_ITER(fm, &fm_iter, bm, BM_FACES_OF_MESH, NULL) { for( i = 0; i < num_total; i++ ) { fm = f_ext[i].f; - if (!BMO_TestFlag(bm, fm, FACE_MARK)) { - //BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) { + if( !BMO_TestFlag(bm, fm, FACE_MARK) && !BM_TestHFlag(fm, BM_HIDDEN) ) { int cont = 1; for( idx = 0; idx < num_sels && cont == 1; idx++ ) { fs = f_ext[indices[idx]].f; @@ -644,3 +642,200 @@ /* transfer all marked faces to the output slot */ BMO_Flag_To_Slot(bm, op, "faceout", FACE_MARK, BM_FACE); } + +/****************************************************************************** +** Similar Edges +******************************************************************************/ +#define EDGE_MARK 1 + +/* +** compute the angle of an edge (i.e. the angle between two faces) +*/ +static float edge_angle(BMesh *bm, BMEdge *e) +{ + BMIter fiter; + BMFace *f; + int num_faces = 0; + float n1[3], n2[3]; + float angle = 0.0f; + + BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) { + if( num_faces == 0 ) { + n1[0] = f->no[0]; + n1[1] = f->no[1]; + n1[2] = f->no[2]; + num_faces++; + } else { + n2[0] = f->no[0]; + n2[1] = f->no[1]; + n2[2] = f->no[2]; + num_faces++; + } + } + + angle = VecAngle2(n1, n2) / 180.0; + + return angle; +} +/* +** extra edge information +*/ +typedef struct tmp_edge_ext { + BMEdge *e; + union { + float dir[3]; + float angle; /* angle between the faces*/ + }; + + union { + float length; /* edge length */ + int faces; /* faces count */ + }; +} tmp_edge_ext; + +/* +** select similar edges: the choices are in the enum in source/blender/bmesh/bmesh_operators.h +** choices are length, direction, face, ... +*/ +void bmesh_similaredges_exec(BMesh *bm, BMOperator *op) +{ + BMOIter es_iter; /* selected edges iterator */ + BMIter em_iter; /* mesh edges iterator */ + BMEdge *es; /* selected edge */ + BMEdge *em; /* mesh edge */ + int idx = 0, i = 0, f = 0; + int *indices = NULL; + tmp_edge_ext *e_ext = NULL; + float *angles = NULL; + float angle; + + int num_sels = 0, num_total = 0; + int type = BMO_Get_Int(op, "type"); + float thresh = BMO_Get_Float(op, "thresh"); + + num_total = BM_Count_Element(bm, BM_EDGE); + + /* iterate through all selected edges and mark them */ + BMO_ITER(es, &es_iter, bm, op, "edges", BM_EDGE) { + BMO_SetFlag(bm, es, EDGE_MARK); + num_sels++; + } + + /* allocate memory for the selected edges indices and for all temporary edges */ + indices = (int*)malloc(sizeof(int) * num_sels); + e_ext = (tmp_edge_ext*)malloc(sizeof(tmp_edge_ext) * num_total); + + /* loop through all the edges and fill the edges/indices structure */ + BM_ITER(em, &em_iter, bm, BM_EDGES_OF_MESH, NULL) { + e_ext[i].e = em; + if (BMO_TestFlag(bm, em, EDGE_MARK)) { + indices[idx] = i; + idx++; + } + i++; + } + + /* save us some computation time by doing heavy computation once */ + if( type == SIMEDGE_LENGTH || type == SIMEDGE_FACE || type == SIMEDGE_DIR || + type == SIMEDGE_FACE_ANGLE ) { + for( i = 0; i < num_total; i++ ) { + switch( type ) { + case SIMEDGE_LENGTH: /* compute the length of the edge */ + e_ext[i].length = VecLenf(e_ext[i].e->v1->co, e_ext[i].e->v2->co); + break; + + case SIMEDGE_DIR: /* compute the direction */ + VecSubf(e_ext[i].dir, e_ext[i].e->v1->co, e_ext[i].e->v2->co); + break; + + case SIMEDGE_FACE: /* count the faces around the edge */ + e_ext[i].faces = BM_Edge_FaceCount(e_ext[i].e); + break; + + case SIMEDGE_FACE_ANGLE: + e_ext[i].faces = BM_Edge_FaceCount(e_ext[i].e); + if( e_ext[i].faces == 2 ) + e_ext[i].angle = edge_angle(bm, e_ext[i].e); + break; + } + } + } + + /* select the edges if any */ + for( i = 0; i < num_total; i++ ) { + em = e_ext[i].e; + if( !BMO_TestFlag(bm, em, EDGE_MARK) && !BM_TestHFlag(em, BM_HIDDEN) ) { + int cont = 1; + for( idx = 0; idx < num_sels && cont == 1; idx++ ) { + es = e_ext[indices[idx]].e; + switch( type ) { + case SIMEDGE_LENGTH: + if( fabs(e_ext[i].length - e_ext[indices[idx]].length) <= thresh ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + + case SIMEDGE_DIR: + /* compute the angle between the two edges */ + angle = VecAngle2(e_ext[i].dir, e_ext[indices[idx]].dir); + + if( angle > 90.0 ) /* use the smallest angle between the edges */ + angle = fabs(angle - 180.0f); + + if( angle / 90.0 <= thresh ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + + case SIMEDGE_FACE: + if( e_ext[i].faces == e_ext[indices[idx]].faces ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + + case SIMEDGE_FACE_ANGLE: + if( e_ext[i].faces == 2 ) { + if( e_ext[indices[idx]].faces == 2 ) { + if( fabs(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + } + } else cont = 0; + break; + + case SIMEDGE_CREASE: + if( fabs(em->crease - es->crease) <= thresh ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + + case SIMEDGE_SEAM: + if( BM_TestHFlag(em, BM_SEAM) == BM_TestHFlag(es, BM_SEAM) ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + + case SIMEDGE_SHARP: + if( BM_TestHFlag(em, BM_SHARP) == BM_TestHFlag(es, BM_SHARP) ) { + BMO_SetFlag(bm, em, EDGE_MARK); + cont = 0; + } + break; + } + } + } + } + + free(e_ext); + free(indices); + + /* transfer all marked edges to the output slot */ + BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_MARK, BM_EDGE); +} + Index: source/blender/editors/mesh/bmesh_select.c =================================================================== --- source/blender/editors/mesh/bmesh_select.c (revision 22703) +++ source/blender/editors/mesh/bmesh_select.c (working copy) @@ -699,18 +699,10 @@ /* EDGE GROUP */ -#define SIMEDGE_LENGTH 101 -#define SIMEDGE_DIR 102 -#define SIMEDGE_FACE 103 -#define SIMEDGE_FACE_ANGLE 104 -#define SIMEDGE_CREASE 105 -#define SIMEDGE_SEAM 106 -#define SIMEDGE_SHARP 107 - static EnumPropertyItem prop_simedge_types[] = { {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, - {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""}, + {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""}, {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""}, {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""}, {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""}, @@ -920,6 +912,38 @@ /* wrap the above function but do selection flushing edge to face */ static int similar_edge_select_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* get the type from RNA */ + int type = RNA_enum_get(op->ptr, "type"); + + float thresh = scene->toolsettings->select_thresh; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_clear_flag_all(em, BM_SELECT); + + /* select the output */ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + /* dependencies graph and notification stuff */ + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob); + + /* we succeeded */ + return OPERATOR_FINISHED; #if 0 Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C);