With the royal blessing of guitarGeek, I commit the sharp/flat mesh
authorChris Want <cwant@ualberta.ca>
Thu, 29 Dec 2005 23:26:48 +0000 (23:26 +0000)
committerChris Want <cwant@ualberta.ca>
Thu, 29 Dec 2005 23:26:48 +0000 (23:26 +0000)
editmode selection tools. The documentation can (currently) be
found here:

http://mediawiki.blender.org/index.php/Requests/SharpFlatSelect

source/blender/blenlib/BLI_editVert.h
source/blender/include/BIF_editmesh.h
source/blender/src/editmesh_mods.c
source/blender/src/header_view3d.c
source/blender/src/space.c
source/blender/src/toolbox.c

index 5e393570e94e6e4130a6e5af8244fee71734bd80..a11e1ebfeff1ca8fe53547e949ab79871982a00f 100644 (file)
@@ -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;
index 632509953e0688896ef156f3aa2da3e18a0cf47b..b1620ec58a6d1b461963e9cf95b159cabb48beb1 100644 (file)
@@ -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);
index 3c568266c05caef84f1ccbe5f4ea2bca252834f6..5d811950c6bab4109080d66b3ddfd87364222f34 100644 (file)
@@ -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;
index c2f83c637fd566208a8f970f3efb6597b74ed2f1..c52704e4020c7afbf38060288d2b1d5f07fadbf5 100644 (file)
@@ -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, "");
index f94a459bfadb3f5be48ea5c3e6af022d6510aab6..404d3e5bb093754acec9d0a33ffd72eeefa8f851 100644 (file)
@@ -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)
index b99535119faf92f04fc3206590c9fb7d81ab0022..61a9eb6418de79d0cd0e8cb645920d7b90161c90 100644 (file)
@@ -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},