Shift-G (select similar) is now bmeshafied for edge select mode.

The patch was by Wael El Oraiby.  Commit of patch #19257.
This commit is contained in:
Joseph Eagar
2009-08-28 09:36:31 +00:00
parent 6dd345a323
commit 989dde4707
8 changed files with 406 additions and 32 deletions

View File

@@ -107,7 +107,8 @@ struct BMEditMesh;
#define SUB_ELEMS_FACE 50
/*
note: all mface interfaces now officially operate on tesselated data.
Note: all mface interfaces now officially operate on tesselated data.
Also, the mface origindex layer indexes mpolys, not mfaces.
*/
/*DM Iterators. For now, first implement face iterators.

View File

@@ -46,6 +46,8 @@
#include "BKE_utildefines.h"
#include "BKE_tessmesh.h"
#include "BLI_editVert.h"
#include "BLI_scanfill.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
@@ -482,7 +484,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
}
}
static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
{
cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
@@ -781,9 +783,6 @@ static void cdDM_foreachMappedFaceCenter(
MVert *mv = cddm->mvert;
MPoly *mf = cddm->mpoly;
MLoop *ml = cddm->mloop;
float (*cents)[3];
float (*nors)[3];
int *flens;
int i, j, orig, *index;
int maxf=0;
@@ -820,6 +819,132 @@ static void cdDM_foreachMappedFaceCenter(
}
void cddm_loops_to_corners(CustomData *fdata, CustomData *ldata,
CustomData *pdata, int lindex[3], int findex,
int polyindex, int numTex, int numCol)
{
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j;
for(i=0; i < numTex; i++){
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
texface->tpage = texpoly->tpage;
texface->flag = texpoly->flag;
texface->transp = texpoly->transp;
texface->mode = texpoly->mode;
texface->tile = texpoly->tile;
texface->unwrap = texpoly->unwrap;
for (j=0; j<3; j++) {
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i);
texface->uv[j][0] = mloopuv->uv[0];
texface->uv[j][1] = mloopuv->uv[1];
}
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
for (j=0; j<3; j++) {
mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i);
mcol[j].r = mloopcol->r;
mcol[j].g = mloopcol->g;
mcol[j].b = mloopcol->b;
mcol[j].a = mloopcol->a;
}
}
}
static void cdDM_recalcTesselation(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
MPoly *mp;
MLoop *ml;
MFace *mf = NULL;
V_DECLARE(mf);
EditVert *v, *lastv, *firstv;
EditFace *f;
V_DECLARE(origIndex);
int i, j, k, lindex[3], *origIndex = NULL, *polyorigIndex;
int numTex, numCol;
numTex = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
numCol = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL);
k = 0;
mp = cddm->mpoly;
polyorigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
for (i=0; i<dm->numPolyData; i++, mp++) {
ml = cddm->mloop + mp->loopstart;
firstv = NULL;
lastv = NULL;
for (j=0; j<mp->totloop; j++, ml++) {
v = BLI_addfillvert(cddm->mvert[ml->v].co);
if (polyorigIndex)
v->f1 = polyorigIndex[i];
else
v->f1 = i;
v->f2 = mp->loopstart + j;
if (lastv)
BLI_addfilledge(lastv, v);
if (!firstv)
firstv = v;
lastv = v;
}
BLI_addfilledge(firstv, v);
BLI_edgefill(0, 0);
for (f=fillfacebase.first; f; f=f->next) {
V_GROW(mf);
V_GROW(origIndex);
/*these are loop indices, they'll be transformed
into vert indices later.*/
mf[k].v1 = f->v1->f2;
mf[k].v2 = f->v2->f2;
mf[k].v3 = f->v3->f2;
origIndex[k] = f->v1->f1;
k++;
}
BLI_end_edgefill();
}
memset(&dm->faceData, 0, sizeof(CustomData));
dm->numFaceData = k;
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mf, dm->numFaceData);
CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_ASSIGN, origIndex, dm->numFaceData);
CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, dm->numFaceData);
/*set convienence pointer*/
cddm->mface = mf;
for (i=0; i<dm->numFaceData; i++, mf++) {
lindex[0] = mf->v1;
lindex[1] = mf->v2;
lindex[2] = mf->v3;
/*transform loop indices to vert indices*/
mf->v1 = cddm->mloop[mf->v1].v;
mf->v2 = cddm->mloop[mf->v2].v;
mf->v3 = cddm->mloop[mf->v3].v;
cddm_loops_to_corners(&dm->faceData, &dm->loopData, &dm->polyData,
lindex, i, origIndex[i], numTex, numCol);
}
}
static void cdDM_release(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
@@ -858,6 +983,9 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
dm->getTessFaceDataArray = DM_get_tessface_data_layer;
//doesn't work yet for all cases
//dm->recalcTesselation = cdDM_recalcTesselation;
dm->getVertCos = cdDM_getVertCos;
dm->getVertCo = cdDM_getVertCo;
@@ -929,7 +1057,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
dm->deformedOnly = 1;
@@ -940,8 +1067,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
mesh->totvert);
CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
mesh->totedge);
CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
mesh->totface);
CustomData_merge(&mesh->ldata, &dm->loopData, mask, alloctype,
mesh->totloop);
CustomData_merge(&mesh->pdata, &dm->polyData, mask, alloctype,
@@ -949,7 +1074,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
@@ -961,14 +1085,14 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
for(i = 0; i < mesh->totedge; ++i, ++index)
*index = i;
index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
for(i = 0; i < mesh->totface; ++i, ++index)
*index = i;
index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
for(i = 0; i < mesh->totpoly; ++i, ++index)
*index = i;
/*recalculates mfaces and sets the mface origindex layer
to index mypolys.*/
cdDM_recalcTesselation((DerivedMesh*)cddm);
return dm;
}

View File

@@ -55,6 +55,7 @@
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_arithb.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"

View File

@@ -22,6 +22,7 @@ enum {
SUBD_STRAIGHT_CUT,
};
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,
SIMFACE_IMAGE,
@@ -31,6 +32,17 @@ enum {
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;

View File

@@ -629,6 +629,22 @@ BMOpDefine def_similarfaces = {
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 @@ BMOpDefine *opdefines[] = {
&def_pointmerge,
&def_collapse,
&def_similarfaces,
&def_similaredges,
};
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));

View File

@@ -47,5 +47,5 @@ void bmesh_collapsecon_exec(BMesh *bm, BMOperator *op);
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

View File

@@ -501,7 +501,7 @@ void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
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;
@@ -526,8 +526,8 @@ void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
}
/* allocate memory for the selected faces indices and for all temporary faces */
indices = (int*)malloc(sizeof(int) * num_sels);
f_ext = (tmp_face_ext*)malloc(sizeof(tmp_face_ext) * num_total);
indices = (int*)MEM_callocN(sizeof(int) * num_sels, "face indices util.c");
f_ext = (tmp_face_ext*)MEM_callocN(sizeof(tmp_face_ext) * num_total, "f_ext util.c");
/* loop through all the faces and fill the faces/indices structure */
BM_ITER(fm, &fm_iter, bm, BM_FACES_OF_MESH, NULL) {
@@ -543,7 +543,7 @@ void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
** 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 @@ void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
}
/* 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;
@@ -638,9 +636,206 @@ void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
}
}
free(f_ext);
free(indices);
MEM_freeN(f_ext);
MEM_freeN(indices);
/* 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 e_iter; /* mesh edges iterator */
BMEdge *es; /* selected edge */
BMEdge *e; /* 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*)MEM_callocN(sizeof(int) * num_sels, "indices util.c");
e_ext = (tmp_edge_ext*)MEM_callocN(sizeof(tmp_edge_ext) * num_total, "e_ext util.c");
/* loop through all the edges and fill the edges/indices structure */
BM_ITER(e, &e_iter, bm, BM_EDGES_OF_MESH, NULL) {
e_ext[i].e = e;
if (BMO_TestFlag(bm, e, 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++ ) {
e = e_ext[i].e;
if( !BMO_TestFlag(bm, e, EDGE_MARK) && !BM_TestHFlag(e, 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, e, 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, e, EDGE_MARK);
cont = 0;
}
break;
case SIMEDGE_FACE:
if( e_ext[i].faces == e_ext[indices[idx]].faces ) {
BMO_SetFlag(bm, e, 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, e, EDGE_MARK);
cont = 0;
}
}
} else cont = 0;
break;
case SIMEDGE_CREASE:
if( fabs(e->crease - es->crease) <= thresh ) {
BMO_SetFlag(bm, e, EDGE_MARK);
cont = 0;
}
break;
case SIMEDGE_SEAM:
if( BM_TestHFlag(e, BM_SEAM) == BM_TestHFlag(es, BM_SEAM) ) {
BMO_SetFlag(bm, e, EDGE_MARK);
cont = 0;
}
break;
case SIMEDGE_SHARP:
if( BM_TestHFlag(e, BM_SHARP) == BM_TestHFlag(es, BM_SHARP) ) {
BMO_SetFlag(bm, e, EDGE_MARK);
cont = 0;
}
break;
}
}
}
}
MEM_freeN(e_ext);
MEM_freeN(indices);
/* transfer all marked edges to the output slot */
BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_MARK, BM_EDGE);
}

View File

@@ -699,18 +699,10 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
/* 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 @@ static int similar_edge_select__internal(Scene *scene, EditMesh *em, int mode)
/* 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);