BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){ BME_Edge *e=NULL; BME_CycleNode *d1=NULL, *d2=NULL; int valance1=0, valance2=0, edok; /*edge must be between two distinct vertices...*/ if(v1 == v2) return NULL; #ifndef BME_FASTEULER /*count valance of v1*/ if(v1->edge){ d1 = BME_disk_getpointer(v1->edge,v1); if(d1) valance1 = BME_cycle_length(d1); else BME_error(); } if(v2->edge){ d2 = BME_disk_getpointer(v2->edge,v2); if(d2) valance2 = BME_cycle_length(d2); else BME_error(); } #endif /*go ahead and add*/ e = BME_addedgelist(bm, v1, v2, NULL); BME_disk_append_edge(e, e->v1); BME_disk_append_edge(e, e->v2); #ifndef BME_FASTEULER /*verify disk cycle lengths*/ d1 = BME_disk_getpointer(e, e->v1); edok = BME_cycle_validate(valance1+1, d1); if(!edok) BME_error(); d2 = BME_disk_getpointer(e, e->v2); edok = BME_cycle_validate(valance2+1, d2); if(!edok) BME_error(); /*verify that edge actually made it into the cycle*/ edok = BME_disk_hasedge(v1, e); if(!edok) BME_error(); edok = BME_disk_hasedge(v2, e); if(!edok) BME_error(); #endif return e; }
/** * BME_JEKV * * JOIN EDGE KILL VERT: * Takes a an edge and pointer to one of its vertices and collapses * the edge on that vertex. * * Before: OE KE * ------- ------- * | || | * OV KV TV * * * After: OE * --------------- * | | * OV TV * * * Restrictions: * KV is a vertex that must have a valance of exactly two. Furthermore * both edges in KV's disk cycle (OE and KE) must be unique (no double * edges). * * It should also be noted that this euler has the possibility of creating * faces with just 2 edges. It is up to the caller to decide what to do with * these faces. * * Returns - * 1 for success, 0 for failure. */ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv) { BME_Edge *oe; BME_Vert *ov, *tv; BME_CycleNode *diskbase; BME_Loop *killoop,*nextl; int len,radlen=0, halt = 0, i, valance1, valance2,edok; if(BME_vert_in_edge(ke,kv) == 0) return 0; diskbase = BME_disk_getpointer(kv->edge, kv); len = BME_cycle_length(diskbase); if(len == 2){ oe = BME_disk_nextedge(ke, kv); tv = BME_edge_getothervert(ke, kv); ov = BME_edge_getothervert(oe, kv); halt = BME_verts_in_edge(kv, tv, oe); //check for double edges if(halt) return 0; else{ /*For verification later, count valance of ov and tv*/ diskbase = BME_disk_getpointer(ov->edge, ov); valance1 = BME_cycle_length(diskbase); diskbase = BME_disk_getpointer(tv->edge, tv); valance2 = BME_cycle_length(diskbase); /*remove oe from kv's disk cycle*/ BME_disk_remove_edge(oe,kv); /*relink oe->kv to be oe->tv*/ BME_edge_swapverts(oe, kv, tv); /*append oe to tv's disk cycle*/ BME_disk_append_edge(oe, tv); /*remove ke from tv's disk cycle*/ BME_disk_remove_edge(ke, tv); /*deal with radial cycle of ke*/ if(ke->loop){ /*first step, fix the neighboring loops of all loops in ke's radial cycle*/ radlen = BME_cycle_length(&(ke->loop->radial)); for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){ /*relink loops and fix vertex pointer*/ killoop->next->prev = killoop->prev; killoop->prev->next = killoop->next; if(killoop->next->v == kv) killoop->next->v = tv; /*fix len attribute of face*/ killoop->f->len--; if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next; } /*second step, remove all the hanging loops attached to ke*/ killoop = ke->loop; radlen = BME_cycle_length(&(ke->loop->radial)); /*make sure we have enough room in bm->lpar*/ if(bm->lparlen < radlen){ MEM_freeN(bm->lpar); bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array"); bm->lparlen = bm->lparlen * radlen; } /*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/ i=0; while(i<radlen){ bm->lpar[i] = killoop; killoop = killoop->radial.next->data; i++; } i=0; while(i<radlen){ BME_free_loop(bm,bm->lpar[i]); i++; } /*Validate radial cycle of oe*/ edok = BME_cycle_validate(radlen,&(oe->loop->radial)); } /*Validate disk cycles*/ diskbase = BME_disk_getpointer(ov->edge,ov); edok = BME_cycle_validate(valance1, diskbase); if(!edok) BME_error(); diskbase = BME_disk_getpointer(tv->edge,tv); edok = BME_cycle_validate(valance2, diskbase); if(!edok) BME_error(); /*Validate loop cycle of all faces attached to oe*/ for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){ edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase); if(!edok) BME_error(); } /*deallocate edge*/ BLI_remlink(&(bm->edges), ke); BME_free_edge(bm, ke); /*deallocate vertex*/ BLI_remlink(&(bm->verts), kv); BME_free_vert(bm, kv); return 1; } } return 0; }
BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){ BME_Vert *nv, *ov; BME_CycleNode *diskbase; BME_Edge *ne; int i, edok, valance1=0, valance2=0; if(BME_vert_in_edge(e,tv) == 0) return NULL; ov = BME_edge_getothervert(e,tv); //v2 = tv; /*count valance of v1*/ diskbase = BME_disk_getpointer(e, ov); valance1 = BME_cycle_length(diskbase); /*count valance of v2*/ diskbase = BME_disk_getpointer(e, tv); valance2 = BME_cycle_length(diskbase); nv = BME_addvertlist(bm, tv); ne = BME_addedgelist(bm, nv, tv, e); //e->v2 = nv; /*remove e from v2's disk cycle*/ BME_disk_remove_edge(e, tv); /*swap out tv for nv in e*/ BME_edge_swapverts(e, tv, nv); /*add e to nv's disk cycle*/ BME_disk_append_edge(e, nv); /*add ne to nv's disk cycle*/ BME_disk_append_edge(ne, nv); /*add ne to tv's disk cycle*/ BME_disk_append_edge(ne, tv); /*verify disk cycles*/ diskbase = BME_disk_getpointer(ov->edge,ov); edok = BME_cycle_validate(valance1, diskbase); if(!edok) BME_error(); diskbase = BME_disk_getpointer(tv->edge,tv); edok = BME_cycle_validate(valance2, diskbase); if(!edok) BME_error(); diskbase = BME_disk_getpointer(nv->edge,nv); edok = BME_cycle_validate(2, diskbase); if(!edok) BME_error(); /*Split the radial cycle if present*/ if(e->loop){ BME_Loop *nl,*l; BME_CycleNode *radEBase=NULL, *radNEBase=NULL; int radlen = BME_cycle_length(&(e->loop->radial)); /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/ while(e->loop){ l=e->loop; l->f->len++; BME_radial_remove_loop(l,e); nl = BME_create_loop(bm,NULL,NULL,l->f,l); nl->prev = l; nl->next = l->next; nl->prev->next = nl; nl->next->prev = nl; nl->v = nv; /*assign the correct edge to the correct loop*/ if(BME_verts_in_edge(nl->v, nl->next->v, e)){ nl->e = e; l->e = ne; /*append l into ne's rad cycle*/ if(!radNEBase){ radNEBase = &(l->radial); radNEBase->next = NULL; radNEBase->prev = NULL; } if(!radEBase){ radEBase = &(nl->radial); radEBase->next = NULL; radEBase->prev = NULL; } BME_cycle_append(radEBase,&(nl->radial)); BME_cycle_append(radNEBase,&(l->radial)); } else if(BME_verts_in_edge(nl->v,nl->next->v,ne)){ nl->e = ne; l->e = e; if(!radNEBase){ radNEBase = &(nl->radial); radNEBase->next = NULL; radNEBase->prev = NULL; } if(!radEBase){ radEBase = &(l->radial); radEBase->next = NULL; radEBase->prev = NULL; } BME_cycle_append(radEBase,&(l->radial)); BME_cycle_append(radNEBase,&(nl->radial)); } } e->loop = radEBase->data; ne->loop = radNEBase->data; /*verify length of radial cycle*/ edok = BME_cycle_validate(radlen,&(e->loop->radial)); if(!edok) BME_error(); edok = BME_cycle_validate(radlen,&(ne->loop->radial)); if(!edok) BME_error(); /*verify loop->v and loop->next->v pointers for e*/ for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){ if(!(l->e == e)) BME_error(); if(!(l->radial.data == l)) BME_error(); if(l->prev->e != ne && l->next->e != ne) BME_error(); edok = BME_verts_in_edge(l->v, l->next->v, e); if(!edok) BME_error(); if(l->v == l->next->v) BME_error(); if(l->e == l->next->e) BME_error(); /*verify loop cycle for kloop->f*/ edok = BME_cycle_validate(l->f->len, l->f->loopbase); if(!edok) BME_error(); } /*verify loop->v and loop->next->v pointers for ne*/ for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){ if(!(l->e == ne)) BME_error(); if(!(l->radial.data == l)) BME_error(); if(l->prev->e != e && l->next->e != e) BME_error(); edok = BME_verts_in_edge(l->v, l->next->v, ne); if(!edok) BME_error(); if(l->v == l->next->v) BME_error(); if(l->e == l->next->e) BME_error(); /*verify loop cycle for kloop->f. Redundant*/ edok = BME_cycle_validate(l->f->len, l->f->loopbase); if(!edok) BME_error(); } } if(re) *re = ne; return nv; }
int BME_validate_mesh(struct BME_Mesh *bm, int halt) { BME_Vert *v; BME_Edge *e; BME_Poly *f; BME_Loop *l; BME_CycleNode *diskbase; int i, ok; /*Simple edge verification*/ for(e=bm->edges.first; e; e=e->next){ if(e->v1 == e->v2) VHALT(halt); /*validate e->d1.data and e->d2.data*/ if(e->d1.data != e || e->d2.data != e) VHALT(halt); /*validate e->loop->e*/ if(e->loop){ if(e->loop->e != e) VHALT(halt); } } /*calculate disk cycle lengths*/ for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0; for(e=bm->edges.first; e; e=e->next){ e->v1->tflag1++; e->v2->tflag1++; } /*Validate vertices and disk cycle*/ for(v=bm->verts.first; v; v=v->next){ /*validate v->edge pointer*/ if(v->tflag1){ if(v->edge){ ok = BME_vert_in_edge(v->edge,v); if(!ok) VHALT(halt); /*validate length of disk cycle*/ diskbase = BME_disk_getpointer(v->edge, v); ok = BME_cycle_validate(v->tflag1, diskbase); if(!ok) VHALT(halt); /*validate that each edge in disk cycle contains V*/ for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){ ok = BME_vert_in_edge(e, v); if(!ok) VHALT(halt); } } else VHALT(halt); } } /*validate edges*/ for(e=bm->edges.first; e; e=e->next){ /*seperate these into BME_disk_hasedge (takes pointer to edge)*/ /*search v1 disk cycle for edge*/ ok = BME_disk_hasedge(e->v1,e); if(!ok) VHALT(halt); /*search v2 disk cycle for edge*/ ok = BME_disk_hasedge(e->v2,e); if(!ok) VHALT(halt); } for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces /*Validate the loop cycle integrity.*/ for(f=bm->polys.first; f; f=f->next){ ok = BME_cycle_length(f->loopbase); if(ok > 1){ f->tflag1 = ok; } else VHALT(halt); for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){ /*verify loop->v pointers*/ ok = BME_verts_in_edge(l->v, l->next->v, l->e); if(!ok) VHALT(halt); /*verify radial node data pointer*/ if(l->radial.data != l) VHALT(halt); /*validate l->e->loop poitner*/ if(l->e->loop == NULL) VHALT(halt); /*validate l->f pointer*/ if(l->f != f) VHALT(halt); /*see if l->e->loop is actually in radial cycle*/ l->e->tflag2++; } } /*validate length of radial cycle*/ for(e=bm->edges.first; e; e=e->next){ if(e->loop){ ok = BME_cycle_validate(e->tflag2,&(e->loop->radial)); if(!ok) VHALT(halt); } } /*validate that EIDs are within range... if not indicates corrupted mem*/ /*if we get this far, pretty safe to return 1*/ return 1; }
/** * BME_bevel_initialize * * Prepare the mesh for beveling: * * Sets the tflag1's of the mesh elements based on the options passed. * * Returns - * A BME_Mesh pointer to the BMesh passed as a parameter. */ static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defgrp_index), float angle, BME_TransData_Head *td) { BME_Vert *v; BME_Edge *e; BME_Poly *f; BME_TransData *vtd; MDeformVert *dvert; MDeformWeight *dw; int len; float weight, threshold; /* vert pass */ for (v=bm->verts.first; v; v=v->next) { dvert = NULL; dw = NULL; v->tflag1 = BME_BEVEL_ORIG; /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if * the vert is manifold (or is shared by only two edges - wire bevel) * BME_BEVEL_SELECT is passed and the vert has v->flag&SELECT or * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight * BME_BEVEL_ANGLE is not passed * BME_BEVEL_EWEIGHT is not passed */ /* originally coded, a vertex gets tagged with BME_BEVEL_NONMAN in this pass if * the vert is loose, shared by multiple regions, or is shared by wire edges * note: verts belonging to edges of open meshes are not tagged with BME_BEVEL_NONMAN */ /* originally coded, a vertex gets a transform weight set in this pass if * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight */ /* get disk cycle length */ if (v->edge == NULL) { len = 0; } else { len = BME_cycle_length(BME_disk_getpointer(v->edge,v)); /* we'll assign a default transform data to every vert (except the loose ones) */ vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL); } /* check for non-manifold vert */ if (BME_is_nonmanifold_vert(bm,v)) { v->tflag1 |= BME_BEVEL_NONMAN; } /* BME_BEVEL_BEVEL tests */ if ((v->tflag1 & BME_BEVEL_NONMAN) == 0 || len == 2) { /* either manifold vert, or wire vert */ if (((options & BME_BEVEL_SELECT) && (v->flag & SELECT)) || ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT)) /* use weights for verts */ || ((options & BME_BEVEL_ANGLE) == 0 && (options & BME_BEVEL_SELECT) == 0 && (options & BME_BEVEL_WEIGHT) == 0)) { if (options & BME_BEVEL_WEIGHT) { /* do vert weight stuff */ //~ dvert = CustomData_em_get(&bm->vdata,v->data,CD_MDEFORMVERT); //~ if (!dvert) continue; //~ for (i = 0; i < dvert->totweight; ++i) { //~ if(dvert->dw[i].def_nr == defgrp_index) { //~ dw = &dvert->dw[i]; //~ break; //~ } //~ } //~ if (!dw || dw->weight == 0.0) continue; if (v->bweight == 0.0) continue; vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, v->bweight, -1, NULL); v->tflag1 |= BME_BEVEL_BEVEL; } else { vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, 1.0, -1, NULL); v->tflag1 |= BME_BEVEL_BEVEL; } } } } /* edge pass */ threshold = (float)cos((angle + 0.001) * M_PI / 180.0); for (e=bm->edges.first; e; e=e->next) { e->tflag1 = BME_BEVEL_ORIG; weight = 0.0; /* originally coded, an edge gets tagged with BME_BEVEL_BEVEL in this pass if * BME_BEVEL_VERT is not set * the edge is manifold (shared by exactly two faces) * BME_BEVEL_SELECT is passed and the edge has e->flag&SELECT or * BME_BEVEL_EWEIGHT is passed, and the edge has the crease set or * BME_BEVEL_ANGLE is passed, and the edge is sharp enough * BME_BEVEL_VWEIGHT is passed, and both verts are set for bevel */ /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if * the vert belongs to the edge * the vert is not tagged with BME_BEVEL_NONMAN * the edge is eligible for bevel (even if BME_BEVEL_VERT is set, or the edge is shared by less than 2 faces) */ /* originally coded, a vertex gets a transform weight set in this pass if * the vert belongs to the edge * the edge has a weight */ /* note: edge weights are cumulative at the verts, * i.e. the vert's weight is the average of the weights of its weighted edges */ if (e->loop == NULL) { len = 0; e->v1->tflag1 |= BME_BEVEL_NONMAN; e->v2->tflag1 |= BME_BEVEL_NONMAN; } else { len = BME_cycle_length(&(e->loop->radial)); } if (len > 2) { /* non-manifold edge of the worst kind */ continue; } if ((options & BME_BEVEL_SELECT) && (e->flag & SELECT)) { weight = 1.0; /* stupid editmode doesn't always flush selections, or something */ e->v1->flag |= SELECT; e->v2->flag |= SELECT; } else if ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT) == 0) { weight = e->bweight; } else if (options & BME_BEVEL_ANGLE) { if ((e->v1->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v1) < threshold) { e->tflag1 |= BME_BEVEL_BEVEL; e->v1->tflag1 |= BME_BEVEL_BEVEL; BME_bevel_add_vweight(td, bm, e->v1, 1.0, 1.0, options); } else { BME_bevel_add_vweight(td, bm, e->v1, 0.0, 1.0, options); } if ((e->v2->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v2) < threshold) { e->tflag1 |= BME_BEVEL_BEVEL; e->v2->tflag1 |= BME_BEVEL_BEVEL; BME_bevel_add_vweight(td, bm, e->v2, 1.0, 1.0, options); } else { BME_bevel_add_vweight(td, bm, e->v2, 0.0, 1.0, options); } } //~ else if ((options & BME_BEVEL_VWEIGHT) && (options & BME_BEVEL_VERT) == 0) { //~ if ((e->v1->tflag1 & BME_BEVEL_BEVEL) && (e->v2->tflag1 & BME_BEVEL_BEVEL)) { //~ e->tflag1 |= BME_BEVEL_BEVEL; //~ } //~ } else if ((options & BME_BEVEL_SELECT) == 0 && (options & BME_BEVEL_VERT) == 0) { weight = 1.0; } if (weight > 0.0) { e->tflag1 |= BME_BEVEL_BEVEL; BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options); BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options); } if (len != 2 || options & BME_BEVEL_VERT) { e->tflag1 &= ~BME_BEVEL_BEVEL; } } /* face pass */ for (f=bm->polys.first; f; f=f->next) f->tflag1 = BME_BEVEL_ORIG; /*clean up edges with 2 faces that share more than one edge*/ for (e=bm->edges.first; e; e=e->next){ if(e->tflag1 & BME_BEVEL_BEVEL){ int count = 0; count = BME_face_sharededges(e->loop->f, ((BME_Loop*)e->loop->radial.next->data)->f); if(count > 1){ e->tflag1 &= ~BME_BEVEL_BEVEL; } } } return bm; }
static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int UNUSED(defgrp_index), BME_TransData_Head *td) { BME_Vert *v, *nv; BME_Edge *e, *oe; BME_Loop *l, *l2; BME_Poly *f; unsigned int i, len; for (f=bm->polys.first; f; f=f->next) { if(f->tflag1 & BME_BEVEL_ORIG) { BME_bevel_poly(bm,f,value,options,td); } } /* here we will loop through all the verts to clean up the left over geometry */ /* crazy idea. when res == 0, don't remove the original geometry */ for (v = bm->verts.first; v; /* we may kill v, so increment in-loop */) { nv = v->next; if ((v->tflag1 & BME_BEVEL_NONMAN) && (v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG)) { v = BME_bevel_wire(bm, v, value, res, options, td); } else if (res && ((v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG))) { int count = 0; /* first, make sure we're not sitting on an edge to be removed */ oe = v->edge; e = BME_disk_nextedge(oe,v); while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) { e = BME_disk_nextedge(e,v); if (e == oe) { //printf("Something's wrong! We can't remove every edge here!\n"); break; } } /* look for original edges, and remove them */ oe = e; while ( (e = BME_disk_next_edgeflag(oe, v, 0, BME_BEVEL_ORIG | BME_BEVEL_BEVEL)) ) { count++; /* join the faces (we'll split them later) */ f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e); if (!f){ //printf("Non-manifold geometry not getting tagged right?\n"); } } /*need to do double check *before* you bevel to make sure that manifold edges are for two faces that share only *one* edge to make sure it doesnt hang here!*/ /* all original edges marked to be beveled have been removed; * now we need to link up the edges for this "corner" */ len = BME_cycle_length(BME_disk_getpointer(v->edge, v)); for (i=0,e=v->edge; i < len; i++,e=BME_disk_nextedge(e,v)) { l = e->loop; l2 = l->radial.next->data; if (l->v != v) l = l->next; if (l2->v != v) l2 = l2->next; /* look for faces that have had the original edges removed via JFKE */ if (l->f->len > 3) { BME_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */ if (len > 2) { l->e->tflag1 |= BME_BEVEL_BEVEL; } } if (l2->f->len > 3) { BME_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */ if (len > 2) { l->e->tflag1 |= BME_BEVEL_BEVEL; } } } bmesh_dissolve_disk(bm, v); } v = nv; } return bm; }