Blender V2.61 - r43446

editmesh_loop.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2004 by Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /*
00034 
00035 editmesh_loop: tools with own drawing subloops, select, knife, subdiv
00036 
00037 */
00038 
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <math.h>
00042 
00043 #include "MEM_guardedalloc.h"
00044 
00045 
00046 #include "DNA_object_types.h"
00047 #include "DNA_scene_types.h"
00048 #include "DNA_screen_types.h"
00049 
00050 #include "BLI_blenlib.h"
00051 #include "BLI_math.h"
00052 #include "BLI_utildefines.h"
00053 #include "BLI_editVert.h"
00054 #include "BLI_ghash.h"
00055 
00056 #include "BKE_context.h"
00057 #include "BKE_depsgraph.h"
00058 #include "BKE_mesh.h"
00059 #include "BKE_array_mallocn.h"
00060 
00061 #include "PIL_time.h"
00062 
00063 #include "BIF_gl.h"
00064 
00065 #include "RNA_access.h"
00066 #include "RNA_define.h"
00067 
00068 #include "WM_api.h"
00069 #include "WM_types.h"
00070 
00071 #include "ED_mesh.h"
00072 #include "ED_view3d.h"
00073 
00074 #include "mesh_intern.h"
00075 
00076 /* **** XXX ******** */
00077 static void error(const char *UNUSED(arg)) {}
00078 /* **** XXX ******** */
00079 
00080 #if 0 /* UNUSED 2.5 */
00081 static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines)
00082 {
00083     EditEdge *eed;
00084     EditFace *efa;
00085     EditVert *v[2][2];
00086     float co[2][3];
00087     int looking= 1,i;
00088     
00089     /* in eed->f1 we put the valence (amount of faces in edge) */
00090     /* in eed->f2 we put tagged flag as correct loop */
00091     /* in efa->f1 we put tagged flag as correct to select */
00092 
00093     for(eed= em->edges.first; eed; eed= eed->next) {
00094         eed->f1= 0;
00095         eed->f2= 0;
00096     }
00097     for(efa= em->faces.first; efa; efa= efa->next) {
00098         efa->f1= 0;
00099         if(efa->h==0) {
00100             efa->e1->f1++;
00101             efa->e2->f1++;
00102             efa->e3->f1++;
00103             if(efa->e4) efa->e4->f1++;
00104         }
00105     }
00106     
00107     // tag startedge OK
00108     startedge->f2= 1;
00109     
00110     while(looking) {
00111         looking= 0;
00112         
00113         for(efa= em->faces.first; efa; efa= efa->next) {
00114             if(efa->e4 && efa->f1==0 && efa->h == 0) {  // not done quad
00115                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
00116 
00117                     // if edge tagged, select opposing edge and mark face ok
00118                     if(efa->e1->f2) {
00119                         efa->e3->f2= 1;
00120                         efa->f1= 1;
00121                         looking= 1;
00122                     }
00123                     else if(efa->e2->f2) {
00124                         efa->e4->f2= 1;
00125                         efa->f1= 1;
00126                         looking= 1;
00127                     }
00128                     if(efa->e3->f2) {
00129                         efa->e1->f2= 1;
00130                         efa->f1= 1;
00131                         looking= 1;
00132                     }
00133                     if(efa->e4->f2) {
00134                         efa->e2->f2= 1;
00135                         efa->f1= 1;
00136                         looking= 1;
00137                     }
00138                 }
00139             }
00140         }
00141     }
00142     
00143     if(previewlines > 0 && select == 0){
00144 // XXX          persp(PERSP_VIEW);
00145 // XXX          glPushMatrix();
00146 // XXX          mymultmatrix(obedit->obmat);
00147 
00148             for(efa= em->faces.first; efa; efa= efa->next) {
00149                 if(efa->v4 == NULL) {  continue; }
00150                 if(efa->h == 0){
00151                     if(efa->e1->f2 == 1){
00152                         if(efa->e1->h == 1 || efa->e3->h == 1 )
00153                             continue;
00154                         
00155                         v[0][0] = efa->v1;
00156                         v[0][1] = efa->v2;
00157                         v[1][0] = efa->v4;
00158                         v[1][1] = efa->v3;
00159                     } else if(efa->e2->f2 == 1){
00160                         if(efa->e2->h == 1 || efa->e4->h == 1)
00161                             continue;
00162                         v[0][0] = efa->v2;
00163                         v[0][1] = efa->v3;
00164                         v[1][0] = efa->v1;
00165                         v[1][1] = efa->v4;                  
00166                     } else { continue; }
00167                                           
00168                     for(i=1;i<=previewlines;i++){
00169                         co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
00170                         co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
00171                         co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
00172 
00173                         co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
00174                         co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
00175                         co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];                    
00176                         glColor3ub(255, 0, 255);
00177                         glBegin(GL_LINES);  
00178                         glVertex3f(co[0][0],co[0][1],co[0][2]);
00179                         glVertex3f(co[1][0],co[1][1],co[1][2]);
00180                         glEnd();
00181                     }
00182                 }
00183             }
00184             glPopMatrix();   
00185     } else {    
00186     
00187     /* (de)select the edges */
00188         for(eed= em->edges.first; eed; eed= eed->next) {
00189         if(eed->f2) EM_select_edge(eed, select);
00190         }
00191     }
00192 }
00193 
00194 static void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
00195 {
00196     ViewContext vc; // XXX
00197     EditEdge *nearest=NULL, *eed;
00198     float fac;
00199     int keys = 0, holdnum=0, selectmode, dist;
00200     int mvalo[2] = {0, 0}, mval[2] = {0, 0};
00201     short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
00202     short hasHidden = 0;
00203     char msg[128];
00204     
00205     selectmode = em->selectmode;
00206         
00207     if(em->selectmode & SCE_SELECT_FACE){
00208         em->selectmode =  SCE_SELECT_EDGE;
00209         EM_selectmode_set(em);    
00210     }
00211     
00212     
00213     BIF_undo_push("Loopcut Begin");
00214     while(choosing && !cancel){
00215 // XXX      getmouseco_areawin(mval);
00216         if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
00217             mvalo[0] = mval[0];
00218             mvalo[1] = mval[1];
00219             dist= 50;
00220             nearest = findnearestedge(&vc, &dist);  // returns actual distance in dist
00221 //          scrarea_do_windraw(curarea);    // after findnearestedge, backbuf!
00222 
00223             BLI_snprintf(msg, sizeof(msg),"Number of Cuts: %d (S)mooth: %s", numcuts, smooth ? "on":"off");
00224             
00225 //          headerprint(msg);
00226             /* Need to figure preview */
00227             if(nearest){
00228                 edgering_sel(em, nearest, 0, numcuts);
00229              }   
00230 // XXX          screen_swapbuffers();
00231             
00232         /* backbuffer refresh for non-apples (no aux) */
00233 #ifndef __APPLE__
00234 // XXX          if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
00235 //              backdrawview3d(0);
00236 //          }
00237 #endif
00238         }
00239         else PIL_sleep_ms(10);  // idle
00240         
00241         
00242         while(qtest()) 
00243         {
00244             val=0;
00245 // XXX          event= extern_qread(&val);
00246             if(val && (event ==  MOUSEX || event == MOUSEY)){ ; } 
00247             else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
00248             {
00249                 if(event == MIDDLEMOUSE){
00250                     cuthalf = 1;
00251                 }
00252                 if (nearest==NULL)
00253                     cancel = 1;
00254                 choosing=0;
00255                 mvalo[0] = -1;
00256             }
00257             else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
00258             {
00259                 choosing=0;
00260                 cancel = 1;
00261                 mvalo[0] = -1;
00262             }
00263             else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
00264             {
00265                 numcuts++;
00266                 mvalo[0] = -1;
00267             }
00268             else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
00269             {
00270                 if(numcuts > 1){
00271                     numcuts--;
00272                     mvalo[0] = -1;
00273                 } 
00274             }
00275             else if(val && event==SKEY)
00276             {
00277                 if(smooth){smooth=0;} 
00278                 else { smooth=1; }
00279                 mvalo[0] = -1;
00280             }
00281             
00282             else if(val){
00283                 holdnum = -1;
00284                 switch(event){
00285                     case PAD9:
00286                     case NINEKEY:
00287                         holdnum = 9; break;
00288                     case PAD8:
00289                     case EIGHTKEY:
00290                         holdnum = 8;break;
00291                     case PAD7:
00292                     case SEVENKEY:
00293                         holdnum = 7;break;
00294                     case PAD6:
00295                     case SIXKEY:
00296                         holdnum = 6;break;
00297                     case PAD5:
00298                     case FIVEKEY:
00299                         holdnum = 5;break;
00300                     case PAD4:
00301                     case FOURKEY:
00302                         holdnum = 4;break;
00303                     case PAD3:
00304                     case THREEKEY:
00305                         holdnum = 3; break;
00306                     case PAD2:
00307                     case TWOKEY:
00308                         holdnum = 2;break;
00309                     case PAD1:
00310                     case ONEKEY:
00311                         holdnum = 1; break;
00312                     case PAD0:
00313                     case ZEROKEY:
00314                         holdnum = 0;break;  
00315                     case BACKSPACEKEY:
00316                         holdnum = -2;break;         
00317                 }
00318                 if(holdnum >= 0 && numcuts*10 < 130){
00319                     if(keys == 0){  // first level numeric entry
00320                             if(holdnum > 0){
00321                                     numcuts = holdnum;
00322                                     keys++;     
00323                             }
00324                     } else if(keys > 0){//highrt level numeric entry
00325                             numcuts *= 10;
00326                             numcuts += holdnum;
00327                             keys++;     
00328                     }
00329                 } else if (holdnum == -2){// backspace
00330                     if (keys > 1){
00331                         numcuts /= 10;      
00332                         keys--;
00333                     } else {
00334                         numcuts=1;
00335                         keys = 0;
00336                     }
00337                 }
00338                 mvalo[0] = -1;
00339                 break;
00340             }  // End Numeric Entry                     
00341         }  //End while(qtest())
00342     }   // End Choosing
00343 
00344     if(cancel){
00345         return;   
00346     }
00347     /* clean selection */
00348     for(eed=em->edges.first; eed; eed = eed->next){
00349         EM_select_edge(eed,0);
00350     }
00351     /* select edge ring */
00352     edgering_sel(em, nearest, 1, 0);
00353     
00354     /* now cut the loops */
00355     if(smooth){
00356         fac= 1.0f;
00357 // XXX      if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
00358         fac= 0.292f*fac;            
00359         esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts, SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
00360     } else {
00361         esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
00362     }
00363     /* if this was a single cut, enter edgeslide mode */
00364     if(numcuts == 1 && hasHidden == 0){
00365         if(cuthalf)
00366             EdgeSlide(em, op, 1,0.0);
00367         else {
00368             if(EdgeSlide(em, op, 0,0.0) == -1){
00369                 BIF_undo();
00370             }
00371         }
00372     }
00373     
00374     if(em->selectmode !=  selectmode){
00375         em->selectmode = selectmode;
00376         EM_selectmode_set(em);
00377     }   
00378     
00379 //  DAG_id_tag_update(obedit->data, 0);
00380     return;
00381 }
00382 #endif
00383 
00384 /* *************** LOOP SELECT ************* */
00385 #if 0
00386 static short edgeFaces(EditMesh *em, EditEdge *e)
00387 {
00388     EditFace *search=NULL;
00389     short count = 0;
00390     
00391     search = em->faces.first;
00392     while(search){
00393         if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e)) 
00394             count++;
00395         search = search->next;
00396     }
00397     return count;   
00398 }
00399 #endif
00400 
00401 
00402 
00403 /*   ***************** TRAIL ************************
00404 
00405 Read a trail of mouse coords and return them as an array of CutCurve structs
00406 len returns number of mouse coords read before commiting with RETKEY   
00407 It is up to the caller to free the block when done with it,
00408 
00409 XXX Is only used here, so local inside this file (ton)
00410  */
00411 
00412 #define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
00413 #define TRAIL_FREEHAND 2
00414 #define TRAIL_MIXED    3 /* (1|2) */
00415 #define TRAIL_AUTO     4 
00416 #define TRAIL_MIDPOINTS 8
00417 
00418 typedef struct CutCurve {
00419     float  x; 
00420     float  y;
00421 } CutCurve;
00422 
00423 
00424 /* ******************************************************************** */
00425 /* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
00426     drawn by user.
00427     
00428     Currently mapped to KKey when in MeshEdit mode.
00429     Usage:
00430         Hit Shift K, Select Centers or Exact
00431         Hold LMB down to draw path, hit RETKEY.
00432         ESC cancels as expected.
00433    
00434     Contributed by Robert Wenzlaff (Det. Thorn).
00435 
00436     2.5 revamp:
00437     - non modal (no menu before cutting)
00438     - exit on mouse release
00439     - polygon/segment drawing can become handled by WM cb later
00440 
00441 */
00442 
00443 #define KNIFE_EXACT     1
00444 #define KNIFE_MIDPOINT  2
00445 #define KNIFE_MULTICUT  3
00446 
00447 static EnumPropertyItem knife_items[]= {
00448     {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
00449     {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
00450     {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
00451     {0, NULL, 0, NULL, NULL}
00452 };
00453 
00454 /* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
00455 
00456 static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
00457 {
00458 #define MAXSLOPE 100000
00459     float  x11, y11, x12=0, y12=0, x2max, x2min, y2max;
00460     float  y2min, dist, lastdist=0, xdiff2, xdiff1;
00461     float  m1, b1, m2, b2, x21, x22, y21, y22, xi;
00462     float  yi, x1min, x1max, y1max, y1min, perc=0; 
00463     float  *scr;
00464     float  threshold;
00465     int  i;
00466     
00467     threshold = 0.000001; /*tolerance for vertex intersection*/
00468     // XXX  threshold = scene->toolsettings->select_thresh / 100;
00469     
00470     /* Get screen coords of verts */
00471     scr = BLI_ghash_lookup(gh, e->v1);
00472     x21=scr[0];
00473     y21=scr[1];
00474     
00475     scr = BLI_ghash_lookup(gh, e->v2);
00476     x22=scr[0];
00477     y22=scr[1];
00478     
00479     xdiff2=(x22-x21);  
00480     if (xdiff2) {
00481         m2=(y22-y21)/xdiff2;
00482         b2= ((x22*y21)-(x21*y22))/xdiff2;
00483     }
00484     else {
00485         m2=MAXSLOPE;  /* Verticle slope  */
00486         b2=x22;      
00487     }
00488     
00489     /*check for *exact* vertex intersection first*/
00490     if(mode!=KNIFE_MULTICUT){
00491         for (i=0; i<len; i++){
00492             if (i>0){
00493                 x11=x12;
00494                 y11=y12;
00495             }
00496             else {
00497                 x11=c[i].x;
00498                 y11=c[i].y;
00499             }
00500             x12=c[i].x;
00501             y12=c[i].y;
00502             
00503             /*test e->v1*/
00504             if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
00505                 e->v1->f1 = 1;
00506                 perc = 0;
00507                 return(perc);
00508             }
00509             /*test e->v2*/
00510             else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
00511                 e->v2->f1 = 1;
00512                 perc = 0;
00513                 return(perc);
00514             }
00515         }
00516     }
00517     
00518     /*now check for edge interesect (may produce vertex intersection as well)*/
00519     for (i=0; i<len; i++){
00520         if (i>0){
00521             x11=x12;
00522             y11=y12;
00523         }
00524         else {
00525             x11=c[i].x;
00526             y11=c[i].y;
00527         }
00528         x12=c[i].x;
00529         y12=c[i].y;
00530         
00531         /* Perp. Distance from point to line */
00532         if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
00533             /* change in sign.  Skip extra math */  
00534         else dist=x22-x12;  
00535         
00536         if (i==0) lastdist=dist;
00537         
00538         /* if dist changes sign, and intersect point in edge's Bound Box*/
00539         if ((lastdist*dist)<=0){
00540             xdiff1=(x12-x11); /* Equation of line between last 2 points */
00541             if (xdiff1){
00542                 m1=(y12-y11)/xdiff1;
00543                 b1= ((x12*y11)-(x11*y12))/xdiff1;
00544             }
00545             else{
00546                 m1=MAXSLOPE;
00547                 b1=x12;
00548             }
00549             x2max=MAX2(x21,x22)+0.001f; /* prevent missed edges   */
00550             x2min=MIN2(x21,x22)-0.001f; /* due to round off error */
00551             y2max=MAX2(y21,y22)+0.001f;
00552             y2min=MIN2(y21,y22)-0.001f;
00553             
00554             /* Found an intersect,  calc intersect point */
00555             if (m1==m2){ /* co-incident lines */
00556                 /* cut at 50% of overlap area*/
00557                 x1max=MAX2(x11, x12);
00558                 x1min=MIN2(x11, x12);
00559                 xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0f;
00560                 
00561                 y1max=MAX2(y11, y12);
00562                 y1min=MIN2(y11, y12);
00563                 yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0f;
00564             }           
00565             else if (m2==MAXSLOPE){ 
00566                 xi=x22;
00567                 yi=m1*x22+b1;
00568             }
00569             else if (m1==MAXSLOPE){ 
00570                 xi=x12;
00571                 yi=m2*x12+b2;
00572             }
00573             else {
00574                 xi=(b1-b2)/(m2-m1);
00575                 yi=(b1*m2-m1*b2)/(m2-m1);
00576             }
00577             
00578             /* Intersect inside bounding box of edge?*/
00579             if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
00580                 /*test for vertex intersect that may be 'close enough'*/
00581                 if(mode!=KNIFE_MULTICUT){
00582                     if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
00583                         if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
00584                             e->v1->f1 = 1;
00585                             perc = 0;
00586                             break;
00587                         }
00588                     }
00589                     if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
00590                         if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
00591                             e->v2->f1 = 1;
00592                             perc = 0;
00593                             break;
00594                         }
00595                     }
00596                 }
00597                 if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi-x21)/(x22-x21);
00598                 else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
00599                 //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
00600                 
00601                 break;
00602             }
00603         }   
00604         lastdist=dist;
00605     }
00606     return(perc);
00607 } 
00608 
00609 /* for multicut */
00610 #define MAX_CUTS 256
00611 
00612 /* for amount of edges */
00613 #define MAX_CUT_EDGES 1024
00614 
00615 static int knife_cut_exec(bContext *C, wmOperator *op)
00616 {
00617     Object *obedit= CTX_data_edit_object(C);
00618     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
00619     ARegion *ar= CTX_wm_region(C);
00620     EditEdge *eed;
00621     EditVert *eve;
00622     CutCurve curve[MAX_CUT_EDGES];
00623     struct GHash *gh;
00624     float isect=0.0;
00625     float  *scr, co[4];
00626     int len=0;
00627     short numcuts= RNA_int_get(op->ptr, "num_cuts"); 
00628     short mode= RNA_enum_get(op->ptr, "type");
00629 //  int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
00630     
00631     /* edit-object needed for matrix, and ar->regiondata for projections to work */
00632     if (ELEM3(NULL, obedit, ar, ar->regiondata))
00633         return OPERATOR_CANCELLED;
00634     
00635     if (EM_nvertices_selected(em) < 2) {
00636         error("No edges are selected to operate on");
00637         BKE_mesh_end_editmesh(obedit->data, em);
00638         return OPERATOR_CANCELLED;
00639     }
00640 
00641     /* get the cut curve */
00642     RNA_BEGIN(op->ptr, itemptr, "path") {
00643         
00644         RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
00645         len++;
00646         if(len>= MAX_CUT_EDGES) break;
00647     }
00648     RNA_END;
00649     
00650     if(len<2) {
00651         BKE_mesh_end_editmesh(obedit->data, em);
00652         return OPERATOR_CANCELLED;
00653     }
00654 
00655     /*store percentage of edge cut for KNIFE_EXACT here.*/
00656     for(eed=em->edges.first; eed; eed= eed->next) 
00657         eed->tmp.fp = 0.0; 
00658     
00659     /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
00660     gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife_cut_exec gh");
00661     for(eve=em->verts.first; eve; eve=eve->next){
00662         scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
00663         VECCOPY(co, eve->co);
00664         co[3]= 1.0;
00665         mul_m4_v4(obedit->obmat, co);
00666         project_float(ar, co, scr);
00667         BLI_ghash_insert(gh, eve, scr);
00668         eve->f1 = 0; /*store vertex intersection flag here*/
00669     
00670     }
00671     
00672     eed= em->edges.first;       
00673     while(eed) {    
00674         if( eed->v1->f & eed->v2->f & SELECT ){     // NOTE: uses vertex select, subdiv doesnt do edges yet
00675             isect= seg_intersect(eed, curve, len, mode, gh);
00676             if (isect!=0.0f) eed->f2= 1;
00677             else eed->f2=0;
00678             eed->tmp.fp= isect;
00679         }
00680         else {
00681             eed->f2=0;
00682             eed->f1=0;
00683         }
00684         eed= eed->next;
00685     }
00686     
00687     if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
00688     else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
00689     else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
00690 
00691     eed=em->edges.first;
00692     while(eed){
00693         eed->f2=0;
00694         eed->f1=0;
00695         eed=eed->next;
00696     }   
00697     
00698     BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
00699     
00700     BKE_mesh_end_editmesh(obedit->data, em);
00701 
00702     DAG_id_tag_update(obedit->data, 0);
00703     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00704 
00705     return OPERATOR_FINISHED;
00706 }
00707 
00708 
00709 void MESH_OT_knife_cut(wmOperatorType *ot)
00710 {
00711     PropertyRNA *prop;
00712     
00713     ot->name= "Knife Cut";
00714     ot->description= "Cut selected edges and faces into parts";
00715     ot->idname= "MESH_OT_knife_cut";
00716     
00717     ot->invoke= WM_gesture_lines_invoke;
00718     ot->modal= WM_gesture_lines_modal;
00719     ot->exec= knife_cut_exec;
00720     ot->cancel= WM_gesture_lines_cancel;
00721     
00722     ot->poll= EM_view3d_poll;
00723     
00724     /* flags */
00725     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00726     
00727     RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
00728     prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
00729     RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
00730     RNA_def_int(ot->srna, "num_cuts", 1, 1, MAX_CUTS, "Number of Cuts", "Only for Multi-Cut", 1, MAX_CUTS);
00731     // doesn't work atm.. RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
00732     
00733     /* internal */
00734     RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
00735 }
00736 
00737 /* ******************************************************* */
00738