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;
}
示例#4
0
/**
 *			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;
}
示例#5
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;
}