Blender V2.61 - r43446

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  *
00007  * ***** BEGIN GPL LICENSE BLOCK *****
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  * about this.  
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software Foundation,
00022  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00023  *
00024  * The Original Code is Copyright (C) 2004 Blender Foundation.
00025  * All rights reserved.
00026  *
00027  * The Original Code is: all of this file.
00028  *
00029  * Contributor(s): Geoffrey Bantle.
00030  *
00031  * ***** END GPL LICENSE BLOCK *****
00032  */
00033 
00039 #include "MEM_guardedalloc.h"
00040 #include "BLI_listbase.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 }