/** * BME_SFME * * SPLIT FACE MAKE EDGE: * * Takes as input two vertices in a single face. An edge is created which divides the original face * into two distinct regions. One of the regions is assigned to the original face and it is closed off. * The second region has a new face assigned to it. * * Examples: * * Before: After: * ---------- ---------- * | | | | * | | | f1 | * v1 f1 v2 v1======v2 * | | | f2 | * | | | | * ---------- ---------- * * Note that the input vertices can be part of the same edge. This will result in a two edged face. * This is desirable for advanced construction tools and particularly essential for edge bevel. Because * of this it is up to the caller to decide what to do with the extra edge. * * Returns - * A BME_Poly pointer */ BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){ BME_Poly *f2; BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL; BME_Edge *e; int i, len, f1len, f2len; /*verify that v1 and v2 are in face.*/ len = BME_cycle_length(f->loopbase); for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){ if(curloop->v == v1) v1loop = curloop; else if(curloop->v == v2) v2loop = curloop; } if(!v1loop || !v2loop) return NULL; /*allocate new edge between v1 and v2*/ e = BME_addedgelist(bm, v1, v2,NULL); BME_disk_append_edge(e, v1); BME_disk_append_edge(e, v2); f2 = BME_addpolylist(bm,f); f1loop = BME_create_loop(bm,v2,e,f,v2loop); f2loop = BME_create_loop(bm,v1,e,f2,v1loop); f1loop->prev = v2loop->prev; f2loop->prev = v1loop->prev; v2loop->prev->next = f1loop; v1loop->prev->next = f2loop; f1loop->next = v1loop; f2loop->next = v2loop; v1loop->prev = f1loop; v2loop->prev = f2loop; f2->loopbase = f2loop; f->loopbase = f1loop; /*validate both loops*/ /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/ /*go through all of f2's loops and make sure they point to it properly.*/ f2len = BME_cycle_length(f2->loopbase); for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2; /*link up the new loops into the new edges radial*/ BME_radial_append(e, f1loop); BME_radial_append(e, f2loop); f2->len = f2len; f1len = BME_cycle_length(f->loopbase); f->len = f1len; if(rl) *rl = f2loop; return f2; }
int BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){ BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext; int i, j, edok, len = 0; len = BME_cycle_length(l); if(bm->edarlen < len){ MEM_freeN(bm->edar); bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array"); bm->edarlen = len; } for(i=0, curloop = l; i< len; i++, curloop=curloop->next){ curloop->e->eflag1 = 0; curloop->e->eflag2 = BME_cycle_length(&curloop->radial); BME_radial_remove_loop(curloop, curloop->e); /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/ curloop->radial.next = curloop->radial.prev = NULL; bm->edar[i] = curloop->e; } /*actually reverse the loop. This belongs in BME_cycle_reverse!*/ for(i=0, curloop = l; i < len; i++){ oldnext = curloop->next; oldprev = curloop->prev; curloop->next = oldprev; curloop->prev = oldnext; curloop = oldnext; } if(len == 2){ //two edged face //do some verification here! l->e = bm->edar[1]; l->next->e = bm->edar[0]; } else{ for(i=0, curloop = l; i < len; i++, curloop = curloop->next){ edok = 0; for(j=0; j < len; j++){ edok = BME_verts_in_edge(curloop->v, curloop->next->v, bm->edar[j]); if(edok){ curloop->e = bm->edar[j]; break; } } } } /*rebuild radial*/ for(i=0, curloop = l; i < len; i++, curloop = curloop->next) BME_radial_append(curloop->e, curloop); /*validate radial*/ for(i=0, curloop = l; i < len; i++, curloop = curloop->next){ edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial)); if(!edok){ BME_error(); } } return 1; }
static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){ BME_Poly *f; BME_Edge *e; int done, len; if(v->edge){ done = 0; while(!done){ done = 1; e = v->edge; /*loop the edge looking for a edge to dissolve*/ do{ f = NULL; len = BME_cycle_length(&(e->loop->radial)); if(len == 2){ f = BME_JFKE_safe(bm,e->loop->f, ((BME_Loop*)(e->loop->radial.next->data))->f, e); } if(f){ done = 0; break; } e = BME_disk_nextedge(e,v); }while(e != v->edge); } BME_collapse_vert(bm, v->edge, v, 1.0); //BME_JEKV(bm,v->edge,v); } }
static int BME_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) { BME_Edge *e, *oe; BME_Loop *l; int len, count, flag; if (v->edge == NULL) { /* loose vert */ return 1; } /* count edges while looking for non-manifold edges */ oe = v->edge; for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) { if (e->loop == NULL) { /* loose edge */ return 1; } if (BME_cycle_length(&(e->loop->radial)) > 2) { /* edge shared by more than two faces */ return 1; } } count = 1; flag = 1; e = NULL; oe = v->edge; l = oe->loop; while(e != oe) { if (l->v == v) l = l->prev; else l = l->next; e = l->e; count++; /* count the edges */ if (flag && l->radial.next->data == l) { /* we've hit the edge of an open mesh, reset once */ flag = 0; count = 1; oe = e; e = NULL; l = oe->loop; } else if (l->radial.next->data == l) { /* break the loop */ e = oe; } else { l = l->radial.next->data; } } if (count < len) { /* vert shared by multiple regions */ return 1; } return 0; }
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; }
int BME_KF(BME_Mesh *bm, BME_Poly *bply){ BME_Loop *newbase,*oldbase, *curloop; int i,len=0; /*add validation to make sure that radial cycle is cleaned up ok*/ /*deal with radial cycle first*/ len = BME_cycle_length(bply->loopbase); for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next) BME_radial_remove_loop(curloop, curloop->e); /*now deallocate the editloops*/ for(i=0; i < len; i++){ newbase = bply->loopbase->next; oldbase = bply->loopbase; BME_cycle_remove(oldbase, oldbase); BME_free_loop(bm, oldbase); bply->loopbase = newbase; } BLI_remlink(&(bm->polys), bply); BME_free_poly(bm, bply); return 1; }
DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm) { MFace *mface, *mf; MEdge *medge, *me; MVert *mvert, *mv; int *origindex; int totface,totedge,totvert,i,bmeshok,len, numTex, numCol; BME_Vert *v1=NULL; BME_Edge *e=NULL, *oe=NULL; BME_Poly *f=NULL; DerivedMesh *result; EdgeHash *edge_hash = BLI_edgehash_new(); totvert = BLI_countlist(&(bm->verts)); totedge = 0; /*we cannot have double edges in a derived mesh!*/ for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i; for(e=bm->edges.first; e; e=e->next){ oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1); if(!oe){ totedge++; BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e); e->tflag2 = 1; } else{ e->tflag2 = 0; } } /*count quads and tris*/ totface = 0; bmeshok = 1; for(f=bm->polys.first;f;f=f->next){ len = BME_cycle_length(f->loopbase); if(len == 3 || len == 4) totface++; } /*convert back to mesh*/ result = CDDM_from_template(dm,totvert,totedge,totface); CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert); CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge); CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface); CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface); numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); /*Make Verts*/ mvert = CDDM_get_verts(result); origindex = result->getVertDataArray(result, CD_ORIGINDEX); for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){ VECCOPY(mv->co,v1->co); mv->flag = (unsigned char)v1->flag; mv->bweight = (char)(255.0*v1->bweight); CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i); origindex[i] = ORIGINDEX_NONE; } medge = CDDM_get_edges(result); origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); i=0; for(e=bm->edges.first,me=medge;e;e=e->next){ if(e->tflag2){ if(e->v1->tflag1 < e->v2->tflag1){ me->v1 = e->v1->tflag1; me->v2 = e->v2->tflag1; } else{ me->v1 = e->v2->tflag1; me->v2 = e->v1->tflag1; } me->crease = (char)(255.0*e->crease); me->bweight = (char)(255.0*e->bweight); me->flag = e->flag; CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i); origindex[i] = ORIGINDEX_NONE; me++; i++; } } if(totface){ mface = CDDM_get_faces(result); origindex = result->getFaceDataArray(result, CD_ORIGINDEX); /*make faces*/ for(i=0,f=bm->polys.first;f;f=f->next){ mf = &mface[i]; len = BME_cycle_length(f->loopbase); if(len==3 || len==4){ mf->v1 = f->loopbase->v->tflag1; mf->v2 = f->loopbase->next->v->tflag1; mf->v3 = f->loopbase->next->next->v->tflag1; if(len == 4){ mf->v4 = f->loopbase->prev->v->tflag1; } /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */ if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){ test_index_face(mf, NULL, i, len); } mf->mat_nr = (unsigned char)f->mat_nr; mf->flag = (unsigned char)f->flag; CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i); BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex); origindex[i] = ORIGINDEX_NONE; i++; } } } BLI_edgehash_free(edge_hash, NULL); return result; }
/* adds the geometry in the bmesh to editMesh (does not free editMesh) * if td != NULL, the transdata will be mapped to the EditVert's co */ void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) { BME_Vert *v1; BME_Edge *e; BME_Poly *f; BME_TransData *vtd; EditVert *eve1, *eve2, *eve3, *eve4, **evlist; EditEdge *eed; EditFace *efa; int totvert, len, i, numTex, numCol; if (em == NULL) return; CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0); numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); /* convert to EditMesh */ /* make editverts */ totvert = BLI_countlist(&(bm->verts)); evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist"); for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) { v1->tflag1 = i; eve1 = NULL; //XXX addvertlist(v1->co,NULL); if (td && (vtd = BME_get_transdata(td,v1))) { vtd->loc = eve1->co; } eve1->keyindex = i; evlist[i]= eve1; eve1->f = (unsigned char)v1->flag; eve1->h = (unsigned char)v1->h; eve1->bweight = v1->bweight; CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data); } /* make edges */ for (e=bm->edges.first;e;e=e->next) { if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){ eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL); eed->crease = e->crease; eed->bweight = e->bweight; if(e->flag & ME_SEAM) eed->seam = 1; if(e->flag & ME_SHARP) eed->sharp = 1; if(e->flag & SELECT) eed->f |= SELECT; //XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(e->flag & ME_HIDE) eed->h |= 1; if(em->selectmode==SCE_SELECT_EDGE) { ; //XXX EM_select_edge(eed, eed->f & SELECT); } CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data); } } /* make faces */ for (f=bm->polys.first;f;f=f->next) { len = BME_cycle_length(f->loopbase); if (len==3 || len==4) { eve1= evlist[f->loopbase->v->tflag1]; eve2= evlist[f->loopbase->next->v->tflag1]; eve3= evlist[f->loopbase->next->next->v->tflag1]; if (len == 4) { eve4= evlist[f->loopbase->prev->v->tflag1]; } else { eve4= NULL; } efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL); efa->mat_nr = (unsigned char)f->mat_nr; efa->flag= f->flag & ~ME_HIDE; if(f->flag & ME_FACE_SEL) { efa->f |= SELECT; } if(f->flag & ME_HIDE) efa->h= 1; // XXX flag depricated // if((G.f & G_FACESELECT) && (efa->f & SELECT)) //XXX EM_select_face(efa, 1); /* flush down */ CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data); BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex); } } MEM_freeN(evlist); }
BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) { BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL; int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok; if(f1 == f2) return NULL; //can't join a face to itself /*verify that e is in both f1 and f2*/ f1len = BME_cycle_length(f1->loopbase); f2len = BME_cycle_length(f2->loopbase); for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){ if(curloop->e == e){ f1loop = curloop; break; } } for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){ if(curloop->e==e){ f2loop = curloop; break; } } if(!(f1loop && f2loop)) return NULL; /*validate that edge is 2-manifold edge*/ radlen = BME_cycle_length(&(f1loop->radial)); if(radlen != 2) return NULL; /*validate direction of f2's loop cycle is compatible.*/ if(f1loop->v == f2loop->v) return NULL; /* Finally validate that for each face, each vertex has another edge in its disk cycle that is not e, and not shared. */ if(BME_radial_find_face(f1loop->next->e,f2)) return NULL; if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL; if(BME_radial_find_face(f2loop->next->e,f1)) return NULL; if(BME_radial_find_face(f2loop->prev->e,f1)) return NULL; /*join the two loops*/ f1loop->prev->next = f2loop->next; f2loop->next->prev = f1loop->prev; f1loop->next->prev = f2loop->prev; f2loop->prev->next = f1loop->next; /*if f1loop was baseloop, give f1loop->next the base.*/ if(f1->loopbase == f1loop) f1->loopbase = f1loop->next; /*validate the new loop*/ loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase); if(!loopok) BME_error(); /*make sure each loop points to the proper face*/ newlen = BME_cycle_length(f1->loopbase); for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1; f1->len = newlen; edok = BME_cycle_validate(f1->len, f1->loopbase); if(!edok) BME_error(); /*remove edge from the disk cycle of its two vertices.*/ BME_disk_remove_edge(f1loop->e, f1loop->e->v1); BME_disk_remove_edge(f1loop->e, f1loop->e->v2); /*deallocate edge and its two loops as well as f2*/ BLI_remlink(&(bm->edges), f1loop->e); BLI_remlink(&(bm->polys), f2); BME_free_edge(bm, f1loop->e); BME_free_loop(bm, f1loop); BME_free_loop(bm, f2loop); BME_free_poly(bm, f2); return f1; }
/** * 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; }
BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len) { BME_Poly *f = NULL; BME_Edge *curedge; BME_Vert *curvert, *tv, **vlist; int i, j, done, cont, edok; if(len < 2) return NULL; /*make sure that v1 and v2 are in elist[0]*/ if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return NULL; /*clear euler flags*/ for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0; for(i=0;i<len;i++){ elist[i]->eflag1 |= MF_CANDIDATE; /*if elist[i] has a loop, count its radial length*/ if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial)); else elist[i]->eflag2 = 0; } /* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it Note that this does not gauruntee that face is a single closed loop. At best it gauruntees that elist contains a finite number of seperate closed loops. */ for(i=0; i<len; i++){ edok = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0); if(edok != 2) return NULL; edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0); if(edok != 2) return NULL; } /*set start edge, start vert and target vert for our loop traversal*/ curedge = elist[0]; tv = v1; curvert = v2; if(bm->vtarlen < len){ MEM_freeN(bm->vtar); bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh Vert pointer array"); bm->vtarlen = len; } /*insert tv into vlist since its the first vertex in face*/ i=0; vlist=bm->vtar; vlist[i] = tv; /* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE edge, loop until we find TV. We know TV is reachable because of test we did earlier. */ done=0; while(!done){ /*add curvert to vlist*/ /*insert some error cheking here for overflows*/ i++; vlist[i] = curvert; /*mark curedge as visited*/ curedge->eflag1 |= MF_VISITED; /*find next edge and vert*/ curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0); curvert = BME_edge_getothervert(curedge, curvert); if(curvert == tv){ curedge->eflag1 |= MF_VISITED; done=1; } } /* Verify that all edges have been visited It's possible that we did reach tv from sv, but that several unconnected loops were passed in via elist. */ cont=1; for(i=0; i<len; i++){ if((elist[i]->eflag1 & MF_VISITED) == 0) cont = 0; } /*if we get this far, its ok to allocate the face and add the loops*/ if(cont){ BME_Loop *l; BME_Edge *e; f = BME_addpolylist(bm, NULL); f->len = len; for(i=0;i<len;i++){ curvert = vlist[i]; l = BME_create_loop(bm,curvert,NULL,f,NULL); if(!(f->loopbase)) f->loopbase = l; BME_cycle_append(f->loopbase, l); } /*take care of edge pointers and radial cycle*/ for(i=0, l = f->loopbase; i<len; i++, l=l->next){ e = NULL; if(l == f->loopbase) e = elist[0]; /*first edge*/ else{/*search elist for others*/ for(j=1; j<len; j++){ edok = BME_verts_in_edge(l->v, l->next->v, elist[j]); if(edok){ e = elist[j]; break; } } } l->e = e; /*set pointer*/ BME_radial_append(e, l); /*append into radial*/ } f->len = len; /*Validation Loop cycle*/ edok = BME_cycle_validate(len, f->loopbase); if(!edok) BME_error(); for(i=0, l = f->loopbase; i<len; i++, l=l->next){ /*validate loop vert pointers*/ edok = BME_verts_in_edge(l->v, l->next->v, l->e); if(!edok) BME_error(); /*validate the radial cycle of each edge*/ edok = BME_cycle_length(&(l->radial)); if(edok != (l->e->eflag2 + 1)) BME_error(); } } return f; }
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; }