Blender  V2.59
BME_eulers.c
Go to the documentation of this file.
00001 /*
00002  * BME_eulers.c    jan 2007
00003  *
00004  *      BMesh Euler construction API.
00005  *
00006  * $Id: BME_eulers.c 35247 2011-02-27 20:40:57Z jesterking $
00007  *
00008  * ***** BEGIN GPL LICENSE BLOCK *****
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License
00012  * as published by the Free Software Foundation; either version 2
00013  * of the License, or (at your option) any later version.
00014  * about this.  
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00024  *
00025  * The Original Code is Copyright (C) 2004 Blender Foundation.
00026  * All rights reserved.
00027  *
00028  * The Original Code is: all of this file.
00029  *
00030  * Contributor(s): Geoffrey Bantle.
00031  *
00032  * ***** END GPL LICENSE BLOCK *****
00033  */
00034 
00040 #include "MEM_guardedalloc.h"
00041 #include "BLI_utildefines.h"
00042 
00043 #include "bmesh_private.h"
00044 
00045 /*********************************************************
00046  *                    "Euler API"                        *
00047  *                                                       *
00048  *                                                       *
00049  *       Primitive construction operators for mesh tools.    *
00050  *                                                       *
00051  **********************************************************/
00052 
00053 
00054 /*
00055         The functions in this file represent the 'primitive' or 'atomic' operators that
00056         mesh tools use to manipulate the topology of the structure.* The purpose of these
00057         functions is to provide a trusted set of operators to manipulate the mesh topology
00058         and which can also be combined together like building blocks to create more 
00059         sophisticated tools. It needs to be stressed that NO manipulation of an existing 
00060         mesh structure should be done outside of these functions.
00061         
00062         In the BMesh system, each euler is named by an ancronym which describes what it actually does.
00063         Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
00064         through a Euler's logical inverse you can 'undo' an operation. (Special note should
00065         be taken of BME_loop_reverse, which is its own inverse).
00066                 
00067         BME_MF/KF: Make Face and Kill Face
00068         BME_ME/KE: Make Edge and Kill Edge
00069         BME_MV/KV: Make Vert and Kill Vert
00070         BME_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
00071         BME_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
00072         BME_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
00073         
00074         Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
00075         Each Euler operator has a detailed explanation of what is does in the comments preceding its 
00076         code. 
00077 
00078    *The term "Euler Operator" is actually a misnomer when referring to a non-manifold 
00079         data structure. Its use is in keeping with the convention established by others.
00080 
00081         TODO:
00082         -Finish inserting 'strict' validation in all Eulers
00083 */
00084 
00085 void *BME_exit(char *s) {
00086         if (s) printf("%s\n",s);
00087         return NULL;
00088 }
00089 
00090 #define RETCLEAR(bm) {bm->rval->v = bm->rval->e = bm->rval->f = bm->rva->l = NULL;}
00091 /*MAKE Eulers*/
00092 
00104 BME_Vert *BME_MV(BME_Mesh *bm, float *vec){
00105         BME_Vert *v = BME_addvertlist(bm, NULL);        
00106         VECCOPY(v->co,vec);
00107         return v;
00108 }
00109 
00124 BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){
00125         BME_Edge *e=NULL;
00126         BME_CycleNode *d1=NULL, *d2=NULL;
00127         int valance1=0, valance2=0, edok;
00128         
00129         /*edge must be between two distinct vertices...*/
00130         if(v1 == v2) return NULL;
00131         
00132         #ifndef BME_FASTEULER
00133         /*count valance of v1*/
00134         if(v1->edge){ 
00135                 d1 = BME_disk_getpointer(v1->edge,v1);
00136                 if(d1) valance1 = BME_cycle_length(d1);
00137                 else BME_error();
00138         }
00139         if(v2->edge){
00140                 d2 = BME_disk_getpointer(v2->edge,v2);
00141                 if(d2) valance2 = BME_cycle_length(d2);
00142                 else BME_error();
00143         }
00144         #endif
00145         
00146         /*go ahead and add*/
00147         e = BME_addedgelist(bm, v1, v2, NULL);
00148         BME_disk_append_edge(e, e->v1);
00149         BME_disk_append_edge(e, e->v2);
00150         
00151         #ifndef BME_FASTEULER
00152         /*verify disk cycle lengths*/
00153         d1 = BME_disk_getpointer(e, e->v1);
00154         edok = BME_cycle_validate(valance1+1, d1);
00155         if(!edok) BME_error();
00156         d2 = BME_disk_getpointer(e, e->v2);
00157         edok = BME_cycle_validate(valance2+1, d2);
00158         if(!edok) BME_error();
00159         
00160         /*verify that edge actually made it into the cycle*/
00161         edok = BME_disk_hasedge(v1, e);
00162         if(!edok) BME_error();
00163         edok = BME_disk_hasedge(v2, e);
00164         if(!edok) BME_error();
00165         #endif
00166         return e;
00167 }
00168 
00169 
00170 
00186 #define MF_CANDIDATE    1
00187 #define MF_VISITED              2
00188 #define MF_TAKEN                4 
00189 
00190 BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len)
00191 {
00192         BME_Poly *f = NULL;
00193         BME_Edge *curedge;
00194         BME_Vert *curvert, *tv, **vlist;
00195         int i, j, done, cont, edok;
00196         
00197         if(len < 2) return NULL;
00198         
00199         /*make sure that v1 and v2 are in elist[0]*/
00200         if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return NULL;
00201         
00202         /*clear euler flags*/
00203         for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0;
00204         for(i=0;i<len;i++){
00205                 elist[i]->eflag1 |= MF_CANDIDATE;
00206                 
00207                 /*if elist[i] has a loop, count its radial length*/
00208                 if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial));
00209                 else elist[i]->eflag2 = 0;
00210         }
00211         
00212         /*      For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
00213                 Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
00214                 that elist contains a finite number of seperate closed loops.
00215         */
00216         for(i=0; i<len; i++){
00217                 edok = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
00218                 if(edok != 2) return NULL;
00219                 edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
00220                 if(edok != 2) return NULL;
00221         }
00222         
00223         /*set start edge, start vert and target vert for our loop traversal*/
00224         curedge = elist[0];
00225         tv = v1;
00226         curvert = v2;
00227         
00228         if(bm->vtarlen < len){
00229                 MEM_freeN(bm->vtar);
00230                 bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh Vert pointer array");
00231                 bm->vtarlen = len;
00232         }
00233         /*insert tv into vlist since its the first vertex in face*/
00234         i=0;
00235         vlist=bm->vtar;
00236         vlist[i] = tv;
00237 
00238         /*      Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't 
00239                 been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
00240                 edge, loop until we find TV. We know TV is reachable because of test we did earlier.
00241         */
00242         done=0;
00243         while(!done){
00244                 /*add curvert to vlist*/
00245                 /*insert some error cheking here for overflows*/
00246                 i++;
00247                 vlist[i] = curvert;
00248                 
00249                 /*mark curedge as visited*/
00250                 curedge->eflag1 |= MF_VISITED;
00251                 
00252                 /*find next edge and vert*/
00253                 curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
00254                 curvert = BME_edge_getothervert(curedge, curvert);
00255                 if(curvert == tv){
00256                         curedge->eflag1 |= MF_VISITED;
00257                         done=1;
00258                 }
00259         }
00260 
00261         /*      Verify that all edges have been visited It's possible that we did reach tv 
00262                 from sv, but that several unconnected loops were passed in via elist.
00263         */
00264         cont=1;
00265         for(i=0; i<len; i++){
00266                 if((elist[i]->eflag1 & MF_VISITED) == 0) cont = 0;
00267         }
00268         
00269         /*if we get this far, its ok to allocate the face and add the loops*/
00270         if(cont){
00271                 BME_Loop *l;
00272                 BME_Edge *e;
00273                 f = BME_addpolylist(bm, NULL);
00274                 f->len = len;
00275                 for(i=0;i<len;i++){
00276                         curvert = vlist[i];
00277                         l = BME_create_loop(bm,curvert,NULL,f,NULL);
00278                         if(!(f->loopbase)) f->loopbase = l;
00279                         BME_cycle_append(f->loopbase, l);
00280                 }
00281                 
00282                 /*take care of edge pointers and radial cycle*/
00283                 for(i=0, l = f->loopbase; i<len; i++, l=l->next){
00284                         e = NULL;
00285                         if(l == f->loopbase) e = elist[0]; /*first edge*/
00286                         
00287                         else{/*search elist for others*/
00288                                 for(j=1; j<len; j++){
00289                                         edok = BME_verts_in_edge(l->v, l->next->v, elist[j]);
00290                                         if(edok){ 
00291                                                 e = elist[j];
00292                                                 break;
00293                                         }
00294                                 }
00295                         }
00296                         l->e = e; /*set pointer*/
00297                         BME_radial_append(e, l); /*append into radial*/
00298                 }
00299 
00300                 f->len = len;
00301                 
00302                 /*Validation Loop cycle*/
00303                 edok = BME_cycle_validate(len, f->loopbase);
00304                 if(!edok) BME_error();
00305                 for(i=0, l = f->loopbase; i<len; i++, l=l->next){
00306                         /*validate loop vert pointers*/
00307                         edok = BME_verts_in_edge(l->v, l->next->v, l->e);
00308                         if(!edok) BME_error();
00309                         /*validate the radial cycle of each edge*/
00310                         edok = BME_cycle_length(&(l->radial));
00311                         if(edok != (l->e->eflag2 + 1)) BME_error();
00312                 }
00313         }
00314         return f;
00315 }
00316 
00317 /* KILL Eulers */
00318 
00330 int BME_KV(BME_Mesh *bm, BME_Vert *v){
00331         if(v->edge == NULL){ 
00332                 BLI_remlink(&(bm->verts), v);
00333                 BME_free_vert(bm,v);
00334                 return 1;
00335         }
00336         return 0;
00337 }
00338 
00350 int BME_KE(BME_Mesh *bm, BME_Edge *e){
00351         int edok;
00352         
00353         /*Make sure that no faces!*/
00354         if(e->loop == NULL){
00355                 BME_disk_remove_edge(e, e->v1);
00356                 BME_disk_remove_edge(e, e->v2);
00357                 
00358                 /*verify that edge out of disk*/
00359                 edok = BME_disk_hasedge(e->v1, e);
00360                 if(edok) BME_error();
00361                 edok = BME_disk_hasedge(e->v2, e);
00362                 if(edok) BME_error();
00363                 
00364                 /*remove and deallocate*/
00365                 BLI_remlink(&(bm->edges), e);
00366                 BME_free_edge(bm, e);
00367                 return 1;
00368         }
00369         return 0;
00370 }
00371 
00384 int BME_KF(BME_Mesh *bm, BME_Poly *bply){
00385         BME_Loop *newbase,*oldbase, *curloop;
00386         int i,len=0;
00387         
00388         /*add validation to make sure that radial cycle is cleaned up ok*/
00389         /*deal with radial cycle first*/
00390         len = BME_cycle_length(bply->loopbase);
00391         for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next) 
00392                 BME_radial_remove_loop(curloop, curloop->e);
00393         
00394         /*now deallocate the editloops*/
00395         for(i=0; i < len; i++){
00396                 newbase = bply->loopbase->next;
00397                 oldbase = bply->loopbase;
00398                 BME_cycle_remove(oldbase, oldbase);
00399                 BME_free_loop(bm, oldbase);
00400                 bply->loopbase = newbase;
00401         }
00402         
00403         BLI_remlink(&(bm->polys), bply);
00404         BME_free_poly(bm, bply);
00405         return 1;
00406 }
00407 
00408 /*SPLIT Eulers*/
00409 
00425 BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
00426         BME_Vert *nv, *ov;
00427         BME_CycleNode *diskbase;
00428         BME_Edge *ne;
00429         int i, edok, valance1=0, valance2=0;
00430         
00431         if(BME_vert_in_edge(e,tv) == 0) return NULL;
00432         ov = BME_edge_getothervert(e,tv);
00433         //v2 = tv;
00434 
00435         /*count valance of v1*/
00436         diskbase = BME_disk_getpointer(e, ov);
00437         valance1 = BME_cycle_length(diskbase);
00438         /*count valance of v2*/
00439         diskbase = BME_disk_getpointer(e, tv);
00440         valance2 = BME_cycle_length(diskbase);
00441         
00442         nv = BME_addvertlist(bm, tv);
00443         ne = BME_addedgelist(bm, nv, tv, e);
00444         
00445         //e->v2 = nv;
00446         /*remove e from v2's disk cycle*/
00447         BME_disk_remove_edge(e, tv);
00448         /*swap out tv for nv in e*/
00449         BME_edge_swapverts(e, tv, nv);
00450         /*add e to nv's disk cycle*/
00451         BME_disk_append_edge(e, nv);
00452         /*add ne to nv's disk cycle*/
00453         BME_disk_append_edge(ne, nv);
00454         /*add ne to tv's disk cycle*/
00455         BME_disk_append_edge(ne, tv);
00456         /*verify disk cycles*/
00457         diskbase = BME_disk_getpointer(ov->edge,ov);
00458         edok = BME_cycle_validate(valance1, diskbase);
00459         if(!edok) BME_error();
00460         diskbase = BME_disk_getpointer(tv->edge,tv);
00461         edok = BME_cycle_validate(valance2, diskbase);
00462         if(!edok) BME_error();
00463         diskbase = BME_disk_getpointer(nv->edge,nv);
00464         edok = BME_cycle_validate(2, diskbase);
00465         if(!edok) BME_error();
00466         
00467         /*Split the radial cycle if present*/
00468         if(e->loop){
00469                 BME_Loop *nl,*l;
00470                 BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
00471                 int radlen = BME_cycle_length(&(e->loop->radial));
00472                 /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
00473                 while(e->loop){
00474                         l=e->loop;
00475                         l->f->len++;
00476                         BME_radial_remove_loop(l,e);
00477                         
00478                         nl = BME_create_loop(bm,NULL,NULL,l->f,l);
00479                         nl->prev = l;
00480                         nl->next = l->next;
00481                         nl->prev->next = nl;
00482                         nl->next->prev = nl;
00483                         nl->v = nv;
00484                         
00485                         /*assign the correct edge to the correct loop*/
00486                         if(BME_verts_in_edge(nl->v, nl->next->v, e)){
00487                                 nl->e = e;
00488                                 l->e = ne;
00489                                 
00490                                 /*append l into ne's rad cycle*/
00491                                 if(!radNEBase){
00492                                         radNEBase = &(l->radial);
00493                                         radNEBase->next = NULL;
00494                                         radNEBase->prev = NULL;
00495                                 }
00496                                 
00497                                 if(!radEBase){
00498                                         radEBase = &(nl->radial);
00499                                         radEBase->next = NULL;
00500                                         radEBase->prev = NULL;
00501                                 }
00502                                 
00503                                 BME_cycle_append(radEBase,&(nl->radial));
00504                                 BME_cycle_append(radNEBase,&(l->radial));
00505                                         
00506                         }
00507                         else if(BME_verts_in_edge(nl->v,nl->next->v,ne)){
00508                                 nl->e = ne;
00509                                 l->e = e;
00510                                 
00511                                 if(!radNEBase){
00512                                         radNEBase = &(nl->radial);
00513                                         radNEBase->next = NULL;
00514                                         radNEBase->prev = NULL;
00515                                 }
00516                                 if(!radEBase){
00517                                         radEBase = &(l->radial);
00518                                         radEBase->next = NULL;
00519                                         radEBase->prev = NULL;
00520                                 }
00521                                 BME_cycle_append(radEBase,&(l->radial));
00522                                 BME_cycle_append(radNEBase,&(nl->radial));
00523                         }
00524                                         
00525                 }
00526                 
00527                 e->loop = radEBase->data;
00528                 ne->loop = radNEBase->data;
00529                 
00530                 /*verify length of radial cycle*/
00531                 edok = BME_cycle_validate(radlen,&(e->loop->radial));
00532                 if(!edok) BME_error();
00533                 edok = BME_cycle_validate(radlen,&(ne->loop->radial));
00534                 if(!edok) BME_error();
00535                 
00536                 /*verify loop->v and loop->next->v pointers for e*/
00537                 for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){
00538                         if(!(l->e == e)) BME_error();
00539                         if(!(l->radial.data == l)) BME_error();
00540                         if(l->prev->e != ne && l->next->e != ne) BME_error();
00541                         edok = BME_verts_in_edge(l->v, l->next->v, e);
00542                         if(!edok) BME_error();
00543                         if(l->v == l->next->v) BME_error();
00544                         if(l->e == l->next->e) BME_error();
00545                         /*verify loop cycle for kloop->f*/
00546                         edok = BME_cycle_validate(l->f->len, l->f->loopbase);
00547                         if(!edok) BME_error();
00548                 }
00549                 /*verify loop->v and loop->next->v pointers for ne*/
00550                 for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){
00551                         if(!(l->e == ne)) BME_error();
00552                         if(!(l->radial.data == l)) BME_error();
00553                         if(l->prev->e != e && l->next->e != e) BME_error();
00554                         edok = BME_verts_in_edge(l->v, l->next->v, ne);
00555                         if(!edok) BME_error();
00556                         if(l->v == l->next->v) BME_error();
00557                         if(l->e == l->next->e) BME_error();
00558                         /*verify loop cycle for kloop->f. Redundant*/
00559                         edok = BME_cycle_validate(l->f->len, l->f->loopbase);
00560                         if(!edok) BME_error();
00561                 }
00562         }
00563         
00564         if(re) *re = ne;
00565         return nv;
00566 }
00567 
00595 BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){
00596 
00597         BME_Poly *f2;
00598         BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
00599         BME_Edge *e;
00600         int i, len, f1len, f2len;
00601         
00602         
00603         /*verify that v1 and v2 are in face.*/
00604         len = BME_cycle_length(f->loopbase);
00605         for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){
00606                 if(curloop->v == v1) v1loop = curloop;
00607                 else if(curloop->v == v2) v2loop = curloop;
00608         }
00609         
00610         if(!v1loop || !v2loop) return NULL;
00611         
00612         /*allocate new edge between v1 and v2*/
00613         e = BME_addedgelist(bm, v1, v2,NULL);
00614         BME_disk_append_edge(e, v1);
00615         BME_disk_append_edge(e, v2);
00616         
00617         f2 = BME_addpolylist(bm,f);
00618         f1loop = BME_create_loop(bm,v2,e,f,v2loop);
00619         f2loop = BME_create_loop(bm,v1,e,f2,v1loop);
00620         
00621         f1loop->prev = v2loop->prev;
00622         f2loop->prev = v1loop->prev;
00623         v2loop->prev->next = f1loop;
00624         v1loop->prev->next = f2loop;
00625         
00626         f1loop->next = v1loop;
00627         f2loop->next = v2loop;
00628         v1loop->prev = f1loop;
00629         v2loop->prev = f2loop;
00630         
00631         f2->loopbase = f2loop;
00632         f->loopbase = f1loop;
00633         
00634         /*validate both loops*/
00635         /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
00636         
00637         /*go through all of f2's loops and make sure they point to it properly.*/
00638         f2len = BME_cycle_length(f2->loopbase);
00639         for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2;
00640         
00641         /*link up the new loops into the new edges radial*/
00642         BME_radial_append(e, f1loop);
00643         BME_radial_append(e, f2loop);
00644         
00645         
00646         f2->len = f2len;
00647         
00648         f1len = BME_cycle_length(f->loopbase);
00649         f->len = f1len;
00650         
00651         if(rl) *rl = f2loop;
00652         return f2;
00653 }
00654 
00655 
00687 int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
00688 {
00689         BME_Edge *oe;
00690         BME_Vert *ov, *tv;
00691         BME_CycleNode *diskbase;
00692         BME_Loop *killoop,*nextl;
00693         int len,radlen=0, halt = 0, i, valance1, valance2,edok;
00694         
00695         if(BME_vert_in_edge(ke,kv) == 0) return 0;
00696         diskbase = BME_disk_getpointer(kv->edge, kv);
00697         len = BME_cycle_length(diskbase);
00698         
00699         if(len == 2){
00700                 oe = BME_disk_nextedge(ke, kv);
00701                 tv = BME_edge_getothervert(ke, kv);
00702                 ov = BME_edge_getothervert(oe, kv);             
00703                 halt = BME_verts_in_edge(kv, tv, oe); //check for double edges
00704                 
00705                 if(halt) return 0;
00706                 else{
00707                         
00708                         /*For verification later, count valance of ov and tv*/
00709                         diskbase = BME_disk_getpointer(ov->edge, ov);
00710                         valance1 = BME_cycle_length(diskbase);
00711                         diskbase = BME_disk_getpointer(tv->edge, tv);
00712                         valance2 = BME_cycle_length(diskbase);
00713                         
00714                         /*remove oe from kv's disk cycle*/
00715                         BME_disk_remove_edge(oe,kv);
00716                         /*relink oe->kv to be oe->tv*/
00717                         BME_edge_swapverts(oe, kv, tv);
00718                         /*append oe to tv's disk cycle*/
00719                         BME_disk_append_edge(oe, tv);
00720                         /*remove ke from tv's disk cycle*/
00721                         BME_disk_remove_edge(ke, tv);
00722                 
00723                         
00724 
00725                         /*deal with radial cycle of ke*/
00726                         if(ke->loop){
00727                                 /*first step, fix the neighboring loops of all loops in ke's radial cycle*/
00728                                 radlen = BME_cycle_length(&(ke->loop->radial));
00729                                 for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){
00730                                         /*relink loops and fix vertex pointer*/
00731                                         killoop->next->prev = killoop->prev;
00732                                         killoop->prev->next = killoop->next;
00733                                         if(killoop->next->v == kv) killoop->next->v = tv;
00734                                         
00735                                         /*fix len attribute of face*/
00736                                         killoop->f->len--;
00737                                         if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next;
00738                                 }
00739                                 /*second step, remove all the hanging loops attached to ke*/
00740                                 killoop = ke->loop;
00741                                 radlen = BME_cycle_length(&(ke->loop->radial));
00742                                 /*make sure we have enough room in bm->lpar*/
00743                                 if(bm->lparlen < radlen){
00744                                         MEM_freeN(bm->lpar);
00745                                         bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array");
00746                                         bm->lparlen = bm->lparlen * radlen;
00747                                 }
00748                                 /*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/
00749                                 i=0;
00750                                 while(i<radlen){
00751                                         bm->lpar[i] = killoop;
00752                                         killoop = killoop->radial.next->data;
00753                                         i++;
00754                                 }
00755                                 i=0;
00756                                 while(i<radlen){
00757                                         BME_free_loop(bm,bm->lpar[i]);
00758                                         i++;
00759                                 }
00760                                 /*Validate radial cycle of oe*/
00761                                 edok = BME_cycle_validate(radlen,&(oe->loop->radial));
00762                                 
00763                         }
00764                         
00765 
00766                         /*Validate disk cycles*/
00767                         diskbase = BME_disk_getpointer(ov->edge,ov);
00768                         edok = BME_cycle_validate(valance1, diskbase);
00769                         if(!edok) BME_error();
00770                         diskbase = BME_disk_getpointer(tv->edge,tv);
00771                         edok = BME_cycle_validate(valance2, diskbase);
00772                         if(!edok) BME_error();
00773                         
00774                         /*Validate loop cycle of all faces attached to oe*/
00775                         for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
00776                                 edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase);
00777                                 if(!edok) BME_error();
00778                         }
00779                         /*deallocate edge*/
00780                         BLI_remlink(&(bm->edges), ke);
00781                         BME_free_edge(bm, ke);
00782                         /*deallocate vertex*/
00783                         BLI_remlink(&(bm->verts), kv);
00784                         BME_free_vert(bm, kv);  
00785                         return 1;
00786                 }
00787         }
00788         return 0;
00789 }
00790 
00791 
00807 int BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){
00808         BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext;
00809         int i, j, edok, len = 0;
00810 
00811         len = BME_cycle_length(l);
00812         if(bm->edarlen < len){
00813                 MEM_freeN(bm->edar);
00814                 bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array");
00815                 bm->edarlen = len;
00816         }
00817         
00818         for(i=0, curloop = l; i< len; i++, curloop=curloop->next){
00819                 curloop->e->eflag1 = 0;
00820                 curloop->e->eflag2 = BME_cycle_length(&curloop->radial);
00821                 BME_radial_remove_loop(curloop, curloop->e);
00822                 /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
00823                 curloop->radial.next = curloop->radial.prev = NULL;
00824                 bm->edar[i] = curloop->e;
00825         }
00826         
00827         /*actually reverse the loop. This belongs in BME_cycle_reverse!*/
00828         for(i=0, curloop = l; i < len; i++){
00829                 oldnext = curloop->next;
00830                 oldprev = curloop->prev;
00831                 curloop->next = oldprev;
00832                 curloop->prev = oldnext;
00833                 curloop = oldnext;
00834         }
00835 
00836         if(len == 2){ //two edged face
00837                 //do some verification here!
00838                 l->e = bm->edar[1];
00839                 l->next->e = bm->edar[0];
00840         }
00841         else{
00842                 for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
00843                         edok = 0;
00844                         for(j=0; j < len; j++){
00845                                 edok = BME_verts_in_edge(curloop->v, curloop->next->v, bm->edar[j]);
00846                                 if(edok){
00847                                         curloop->e = bm->edar[j];
00848                                         break;
00849                                 }
00850                         }
00851                 }
00852         }
00853         /*rebuild radial*/
00854         for(i=0, curloop = l; i < len; i++, curloop = curloop->next) BME_radial_append(curloop->e, curloop);
00855         
00856         /*validate radial*/
00857         for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
00858                 edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial));
00859                 if(!edok){
00860                         BME_error();
00861                 }
00862         }
00863         return 1;
00864 }
00865 
00898 BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
00899 {
00900         
00901         BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL;
00902         int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok;
00903         
00904         if(f1 == f2) return NULL; //can't join a face to itself
00905         /*verify that e is in both f1 and f2*/
00906         f1len = BME_cycle_length(f1->loopbase);
00907         f2len = BME_cycle_length(f2->loopbase);
00908         for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){
00909                 if(curloop->e == e){ 
00910                         f1loop = curloop;
00911                         break;
00912                 }
00913         }
00914         for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){
00915                 if(curloop->e==e){
00916                         f2loop = curloop;
00917                         break;
00918                 }
00919         }
00920         if(!(f1loop && f2loop)) return NULL;
00921         
00922         /*validate that edge is 2-manifold edge*/
00923         radlen = BME_cycle_length(&(f1loop->radial));
00924         if(radlen != 2) return NULL;
00925 
00926         /*validate direction of f2's loop cycle is compatible.*/
00927         if(f1loop->v == f2loop->v) return NULL;
00928         
00929         /*
00930                 Finally validate that for each face, each vertex has another edge in its disk cycle that is 
00931                 not e, and not shared.
00932         */
00933         if(BME_radial_find_face(f1loop->next->e,f2)) return NULL;
00934         if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL;
00935         if(BME_radial_find_face(f2loop->next->e,f1)) return NULL;
00936         if(BME_radial_find_face(f2loop->prev->e,f1)) return NULL;
00937         
00938         /*join the two loops*/
00939         f1loop->prev->next = f2loop->next;
00940         f2loop->next->prev = f1loop->prev;
00941         
00942         f1loop->next->prev = f2loop->prev;
00943         f2loop->prev->next = f1loop->next;
00944         
00945         /*if f1loop was baseloop, give f1loop->next the base.*/
00946         if(f1->loopbase == f1loop) f1->loopbase = f1loop->next;
00947         
00948         /*validate the new loop*/
00949         loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase);
00950         if(!loopok) BME_error();
00951         
00952         /*make sure each loop points to the proper face*/
00953         newlen = BME_cycle_length(f1->loopbase);
00954         for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1;
00955         
00956         f1->len = newlen;
00957         
00958         edok = BME_cycle_validate(f1->len, f1->loopbase);
00959         if(!edok) BME_error();
00960         
00961         /*remove edge from the disk cycle of its two vertices.*/
00962         BME_disk_remove_edge(f1loop->e, f1loop->e->v1);
00963         BME_disk_remove_edge(f1loop->e, f1loop->e->v2);
00964         
00965         /*deallocate edge and its two loops as well as f2*/
00966         BLI_remlink(&(bm->edges), f1loop->e);
00967         BLI_remlink(&(bm->polys), f2);
00968         BME_free_edge(bm, f1loop->e);
00969         BME_free_loop(bm, f1loop);
00970         BME_free_loop(bm, f2loop);
00971         BME_free_poly(bm, f2);  
00972         return f1;
00973 }