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; }
static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int UNUSED(options), BME_TransData_Head *td) { BME_Vert *ov1, *ov2, *v1, *v2; ov1 = BME_edge_getothervert(v->edge, v); ov2 = BME_edge_getothervert(BME_disk_nextedge(v->edge, v), v); /* split the edges */ v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td); v1->tflag1 |= BME_BEVEL_NONMAN; v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td); v2->tflag1 |= BME_BEVEL_NONMAN; if (value > 0.5) { BME_bevel_set_max(v1,ov1,value,td); BME_bevel_set_max(v2,ov2,value,td); } /* remove the original vert */ if (res) { BME_JEKV(bm,v->edge,v); } return v1; }
/** * 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; }
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_split_edge() is the main math work-house; its responsibilities are: * using the vert and the loop passed, get or make the split vert, set its coordinates * and transform properties, and set the max limits. * Finally, return the split vert. */ static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) { BME_TransData *vtd, *vtd1, *vtd2; BME_Vert *sv, *v2, *v3, *ov; BME_Loop *lv1, *lv2; BME_Edge *ne, *e1, *e2; float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3]; int is_edge, forward, is_split_vert; if (l == NULL) { /* what you call operator overloading in C :) * I wanted to use the same function for both wire edges and poly loops * so... here we walk around edges to find the needed verts */ forward = 1; is_split_vert = 0; if (v->edge == NULL) { //printf("We can't split a loose vert's edge!\n"); return NULL; } e1 = v->edge; /* we just use the first two edges */ e2 = BME_disk_nextedge(v->edge, v); if (e1 == e2) { //printf("You need at least two edges to use BME_bevel_split_edge()\n"); return NULL; } v2 = BME_edge_getothervert(e1, v); v3 = BME_edge_getothervert(e2, v); if (v1 != v2 && v1 != v3) { //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n"); return NULL; } if (v1 == v2) { v2 = v3; } else { e1 = e2; } ov = BME_edge_getothervert(e1,v); sv = BME_split_edge(bm,v,e1,&ne,0); //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ sv->tflag1 |= BME_BEVEL_BEVEL; ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ BME_bevel_get_vec(vec1,v1,v,td); BME_bevel_get_vec(vec2,v2,v,td); cross_v3_v3v3(t_up_vec,vec1,vec2); normalize_v3(t_up_vec); up_vec = t_up_vec; } else { /* establish loop direction */ if (l->v == v) { forward = 1; lv1 = l->next; lv2 = l->prev; v1 = l->next->v; v2 = l->prev->v; } else if (l->next->v == v) { forward = 0; lv1 = l; lv2 = l->next->next; v1 = l->v; v2 = l->next->next->v; } else { //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n"); return NULL; } if (BME_bevel_is_split_vert(lv1)) { is_split_vert = 1; sv = v1; if (forward) v1 = l->next->next->v; else v1 = l->prev->v; } else { is_split_vert = 0; ov = BME_edge_getothervert(l->e,v); sv = BME_split_edge(bm,v,l->e,&ne,0); //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ sv->tflag1 |= BME_BEVEL_BEVEL; ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ } if (BME_bevel_is_split_vert(lv2)) { if (forward) v2 = lv2->prev->v; else v2 = lv2->next->v; } } is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */ BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */ len = len_v3(vec1); normalize_v3(vec1); vtd = BME_get_transdata(td, sv); vtd1 = BME_get_transdata(td, v); vtd2 = BME_get_transdata(td,v1); if (vtd1->loc == NULL) { /* this is a vert with data only for calculating initial weights */ if (vtd1->weight < 0) { vtd1->weight = 0; } scale = vtd1->weight/vtd1->factor; if (!vtd1->max) { vtd1->max = BME_new_transdata_float(td); *vtd1->max = -1; } } else { scale = vtd1->weight; } vtd->max = vtd1->max; if (is_edge && vtd1->loc != NULL) { maxfactor = vtd1->maxfactor; } else { maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td); if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) { maxfactor = vtd->maxfactor; } } dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2; if (is_edge || dis > maxfactor*value) { dis = maxfactor*value; } VECADDFAC(sv->co,v->co,vec1,dis); VECSUB(vec1,sv->co,vtd1->org); dis = len_v3(vec1); normalize_v3(vec1); BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max); return sv; }
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; }