With the royal blessing of guitarGeek, I commit the sharp/flat mesh
editmode selection tools. The documentation can (currently) be found here: http://mediawiki.blender.org/index.php/Requests/SharpFlatSelect
This commit is contained in:
@@ -66,6 +66,7 @@ typedef struct HashEdge {
|
||||
typedef struct EditEdge
|
||||
{
|
||||
struct EditEdge *next, *prev;
|
||||
/* Note: vn is for general purpose temporary storage */
|
||||
struct EditVert *v1, *v2, *vn;
|
||||
short f1, f2; /* short, f1 is (ab)used in subdiv */
|
||||
unsigned char f, h, dir, seam;
|
||||
|
||||
@@ -134,6 +134,8 @@ extern void editmesh_align_view_to_selected(struct View3D *v3d, int axis);
|
||||
|
||||
/* Selection */
|
||||
extern void select_non_manifold(void);
|
||||
extern void select_sharp_edges(void);
|
||||
extern void select_linked_flat_faces(void);
|
||||
extern void select_faces_by_numverts(int numverts);
|
||||
extern void select_more(void);
|
||||
extern void select_less(void);
|
||||
|
||||
@@ -1506,6 +1506,264 @@ void select_faces_by_numverts(int numverts)
|
||||
BIF_undo_push("Select non-Triangles/Quads");
|
||||
}
|
||||
|
||||
void select_sharp_edges(void)
|
||||
{
|
||||
/* Find edges that have exactly two neighboring faces,
|
||||
* check the angle between those faces, and if angle is
|
||||
* small enough, select the edge
|
||||
*/
|
||||
EditMesh *em = G.editMesh;
|
||||
EditEdge *eed;
|
||||
EditFace *efa;
|
||||
EditFace **efa1;
|
||||
EditFace **efa2;
|
||||
long edgecount = 0, i, *vnptr;
|
||||
static short sharpness = 135;
|
||||
float fsharpness;
|
||||
|
||||
if(G.scene->selectmode==SCE_SELECT_FACE) {
|
||||
error("Doesn't work in face selection mode");
|
||||
return;
|
||||
}
|
||||
|
||||
if(button(&sharpness,0, 180,"Max Angle:")==0) return;
|
||||
/* if faces are at angle 'sharpness', then the face normals
|
||||
* are at angle 180.0 - 'sharpness' (convert to radians too)
|
||||
*/
|
||||
fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
|
||||
|
||||
i=0;
|
||||
/* count edges, (ab)use vn to be a long */
|
||||
eed= em->edges.first;
|
||||
while(eed) {
|
||||
edgecount++;
|
||||
vnptr = (long *) &eed->vn;
|
||||
*vnptr = i;
|
||||
eed= eed->next;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* for each edge, we want a pointer to two adjacent faces */
|
||||
efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
|
||||
"pairs of edit face pointers");
|
||||
efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
|
||||
"pairs of edit face pointers");
|
||||
|
||||
#define face_table_edge { \
|
||||
i = *vnptr; \
|
||||
if (i != -1) { \
|
||||
if (efa1[i]) { \
|
||||
if (efa2[i]) { \
|
||||
*vnptr = -1; /* bad, edge has more than two neighbors */ \
|
||||
} \
|
||||
else { \
|
||||
efa2[i] = efa; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
efa1[i] = efa; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* find the adjacent faces of each edge, we want only two */
|
||||
efa= em->faces.first;
|
||||
while(efa) {
|
||||
vnptr = (long *) &efa->e1->vn;
|
||||
face_table_edge;
|
||||
vnptr = (long *) &efa->e2->vn;
|
||||
face_table_edge;
|
||||
vnptr = (long *) &efa->e3->vn;
|
||||
face_table_edge;
|
||||
if (efa->e4) {
|
||||
vnptr = (long *) &efa->e4->vn;
|
||||
face_table_edge;
|
||||
}
|
||||
efa= efa->next;
|
||||
}
|
||||
|
||||
#undef face_table_edge
|
||||
|
||||
eed= em->edges.first;
|
||||
while(eed) {
|
||||
vnptr = (long *) &eed->vn;
|
||||
i = *vnptr;
|
||||
if (i != -1) {
|
||||
/* edge has two or less neighboring faces */
|
||||
if ( (efa1[i]) && (efa2[i]) ) {
|
||||
/* edge has exactly two neighboring faces, check angle */
|
||||
float angle;
|
||||
angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
|
||||
efa1[i]->n[1]*efa2[i]->n[1] +
|
||||
efa1[i]->n[2]*efa2[i]->n[2]);
|
||||
if (fabs(angle) >= fsharpness)
|
||||
EM_select_edge(eed, 1);
|
||||
}
|
||||
}
|
||||
|
||||
eed= eed->next;
|
||||
}
|
||||
|
||||
MEM_freeN(efa1);
|
||||
MEM_freeN(efa2);
|
||||
|
||||
countall();
|
||||
addqueue(curarea->win, REDRAW, 0);
|
||||
BIF_undo_push("Select Sharp Edges");
|
||||
}
|
||||
|
||||
void select_linked_flat_faces(void)
|
||||
{
|
||||
/* Find faces that are linked to selected faces that are
|
||||
* relatively flat (angle between faces is higher than
|
||||
* specified angle)
|
||||
*/
|
||||
EditMesh *em = G.editMesh;
|
||||
EditEdge *eed;
|
||||
EditFace *efa;
|
||||
EditFace **efa1;
|
||||
EditFace **efa2;
|
||||
long edgecount = 0, i, *vnptr, faceselcount=0, faceselcountold=0;
|
||||
static short sharpness = 135;
|
||||
float fsharpness;
|
||||
|
||||
if(G.scene->selectmode!=SCE_SELECT_FACE) {
|
||||
error("Only works in face selection mode");
|
||||
return;
|
||||
}
|
||||
|
||||
if(button(&sharpness,0, 180,"Min Angle:")==0) return;
|
||||
/* if faces are at angle 'sharpness', then the face normals
|
||||
* are at angle 180.0 - 'sharpness' (convert to radians too)
|
||||
*/
|
||||
fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
|
||||
|
||||
i=0;
|
||||
/* count edges, (ab)use vn to be a long */
|
||||
eed= em->edges.first;
|
||||
while(eed) {
|
||||
edgecount++;
|
||||
vnptr = (long *) &eed->vn;
|
||||
*vnptr = i;
|
||||
eed= eed->next;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* for each edge, we want a pointer to two adjacent faces */
|
||||
efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
|
||||
"pairs of edit face pointers");
|
||||
efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
|
||||
"pairs of edit face pointers");
|
||||
|
||||
#define face_table_edge { \
|
||||
i = *vnptr; \
|
||||
if (i != -1) { \
|
||||
if (efa1[i]) { \
|
||||
if (efa2[i]) { \
|
||||
*vnptr = -1; /* bad, edge has more than two neighbors */ \
|
||||
} \
|
||||
else { \
|
||||
efa2[i] = efa; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
efa1[i] = efa; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* find the adjacent faces of each edge, we want only two */
|
||||
efa= em->faces.first;
|
||||
while(efa) {
|
||||
vnptr = (long *) &efa->e1->vn;
|
||||
face_table_edge;
|
||||
vnptr = (long *) &efa->e2->vn;
|
||||
face_table_edge;
|
||||
vnptr = (long *) &efa->e3->vn;
|
||||
face_table_edge;
|
||||
if (efa->e4) {
|
||||
vnptr = (long *) &efa->e4->vn;
|
||||
face_table_edge;
|
||||
}
|
||||
|
||||
/* while were at it, count the selected faces */
|
||||
if (efa->f & SELECT) ++faceselcount;
|
||||
|
||||
efa= efa->next;
|
||||
}
|
||||
|
||||
#undef face_table_edge
|
||||
|
||||
eed= em->edges.first;
|
||||
while(eed) {
|
||||
vnptr = (long *) &eed->vn;
|
||||
i = *vnptr;
|
||||
if (i != -1) {
|
||||
/* edge has two or less neighboring faces */
|
||||
if ( (efa1[i]) && (efa2[i]) ) {
|
||||
/* edge has exactly two neighboring faces, check angle */
|
||||
float angle;
|
||||
angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
|
||||
efa1[i]->n[1]*efa2[i]->n[1] +
|
||||
efa1[i]->n[2]*efa2[i]->n[2]);
|
||||
/* flag sharp edges */
|
||||
if (fabs(angle) >= fsharpness)
|
||||
*vnptr = -1;
|
||||
}
|
||||
else {
|
||||
/* less than two neighbors */
|
||||
*vnptr = -1;
|
||||
}
|
||||
}
|
||||
|
||||
eed= eed->next;
|
||||
}
|
||||
|
||||
#define select_flat_neighbor { \
|
||||
i = *vnptr; \
|
||||
if (i!=-1) { \
|
||||
if (! (efa1[i]->f & SELECT) ) { \
|
||||
EM_select_face(efa1[i], 1); \
|
||||
++faceselcount; \
|
||||
} \
|
||||
if (! (efa2[i]->f & SELECT) ) { \
|
||||
EM_select_face(efa2[i], 1); \
|
||||
++faceselcount; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
while (faceselcount != faceselcountold) {
|
||||
faceselcountold = faceselcount;
|
||||
|
||||
efa= em->faces.first;
|
||||
while(efa) {
|
||||
if (efa->f & SELECT) {
|
||||
vnptr = (long *) &efa->e1->vn;
|
||||
select_flat_neighbor;
|
||||
vnptr = (long *) &efa->e2->vn;
|
||||
select_flat_neighbor;
|
||||
vnptr = (long *) &efa->e3->vn;
|
||||
select_flat_neighbor;
|
||||
if (efa->e4) {
|
||||
vnptr = (long *) &efa->e4->vn;
|
||||
select_flat_neighbor;
|
||||
}
|
||||
}
|
||||
efa= efa->next;
|
||||
}
|
||||
}
|
||||
|
||||
#undef select_flat_neighbor
|
||||
|
||||
MEM_freeN(efa1);
|
||||
MEM_freeN(efa2);
|
||||
|
||||
countall();
|
||||
addqueue(curarea->win, REDRAW, 0);
|
||||
BIF_undo_push("Select Linked Flat Faces");
|
||||
}
|
||||
|
||||
void select_non_manifold(void)
|
||||
{
|
||||
EditMesh *em = G.editMesh;
|
||||
|
||||
@@ -859,6 +859,12 @@ void do_view3d_select_meshmenu(void *arg, int event)
|
||||
case 13: /* select non-triangles/quads */
|
||||
select_faces_by_numverts(5);
|
||||
break;
|
||||
case 14: /* select less */
|
||||
select_sharp_edges();
|
||||
break;
|
||||
case 15: /* select less */
|
||||
select_linked_flat_faces();
|
||||
break;
|
||||
|
||||
}
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
@@ -887,6 +893,12 @@ static uiBlock *view3d_select_meshmenu(void *arg_unused)
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
|
||||
"Non-Manifold|Ctrl Alt Shift M",
|
||||
0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
|
||||
"Sharp Edges|Ctrl Alt Shift S",
|
||||
0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
|
||||
"Linked flat faces|Ctrl Alt Shift F",
|
||||
0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
|
||||
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
@@ -1245,6 +1245,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
edge_flip();
|
||||
else if (G.qual==0)
|
||||
addedgeface_mesh();
|
||||
else if ( G.qual ==
|
||||
(LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
|
||||
select_linked_flat_faces();
|
||||
}
|
||||
|
||||
}
|
||||
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addsegment_nurb();
|
||||
}
|
||||
@@ -1632,7 +1637,9 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
initTransform(TFM_TOSPHERE, CTX_NONE);
|
||||
Transform();
|
||||
}
|
||||
|
||||
if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
|
||||
if(G.obedit->type==OB_MESH) select_sharp_edges();
|
||||
}
|
||||
}
|
||||
else if(G.qual==LR_ALTKEY) {
|
||||
if(G.f & G_WEIGHTPAINT)
|
||||
|
||||
@@ -1700,6 +1700,8 @@ static TBitem tb_mesh_select[]= {
|
||||
{ 0, "SEPR", 0, NULL},
|
||||
{ 0, "Random...", 5, NULL},
|
||||
{ 0, "Non-Manifold|Shift Ctrl Alt M", 9, NULL},
|
||||
{ 0, "Sharp Edges|Shift Ctrl Alt S", 14, NULL},
|
||||
{ 0, "Linked Flat Faces|Shift Ctrl Alt F", 15, NULL},
|
||||
{ 0, "Triangles|Shift Ctrl Alt 3", 11, NULL},
|
||||
{ 0, "Quads|Shift Ctrl Alt 4", 12, NULL},
|
||||
{ 0, "Non-Triangles/Quads|Shift Ctrl Alt 5", 13, NULL},
|
||||
|
||||
Reference in New Issue
Block a user