All pastes #256513 Raw Edit

Someone

public text v1 · immutable
#256513 ·published 2006-11-24 09:45 UTC
rendered paste body
static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit){
	
	/*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
	float	measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff,
			edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff,
			minarea, maxarea, areaA, areaB;
	
	/*First Test: Normal difference*/
	CalcNormFloat(v1->co, v2->co, v3->co, noA1);
	CalcNormFloat(v1->co, v3->co, v4->co, noA2);
	
	if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
	else normalADiff = VecAngle2(noA1, noA2);
		//if(!normalADiff) normalADiff = 179;
	CalcNormFloat(v2->co, v3->co, v4->co, noB1);
	CalcNormFloat(v4->co, v1->co, v2->co, noB2);
	
	if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
	else normalBDiff = VecAngle2(noB1, noB2);
		//if(!normalBDiff) normalBDiff = 179;
	
	measure += (normalADiff/360) + (normalBDiff/360);
	if(measure > limit) return measure;
	
	/*Second test: Colinearity*/
	VecSubf(edgeVec1, v1->co, v2->co);
	VecSubf(edgeVec2, v2->co, v3->co);
	VecSubf(edgeVec3, v3->co, v4->co);
	VecSubf(edgeVec4, v4->co, v1->co);
	
	diff = 0.0;
	
	diff = (
		fabs(VecAngle2(edgeVec1, edgeVec2) - 90) +
		fabs(VecAngle2(edgeVec2, edgeVec3) - 90) + 
		fabs(VecAngle2(edgeVec3, edgeVec4) - 90) + 
		fabs(VecAngle2(edgeVec4, edgeVec1) - 90)) / 360;
	//if(!diff) return 0.0;
	
	measure +=  diff;
	if(measure > limit) return measure;

	/*Third test: Concavity*/
	areaA = AreaT3Dfl(v1->co, v2->co, v3->co) + AreaT3Dfl(v1->co, v3->co, v4->co);
	areaB = AreaT3Dfl(v2->co, v3->co, v4->co) + AreaT3Dfl(v4->co, v1->co, v2->co);
	
	if(areaA <= areaB) minarea = areaA;
	else minarea = areaB;
	
	if(areaA >= areaB) maxarea = areaA;
	else maxarea = areaB;
	
	if(!maxarea) measure += 1;
	else measure += (1 - (minarea / maxarea));

	return measure;
}

#define T2QUV_LIMIT 0.005
#define T2QCOL_LIMIT 3
/*Bitflags for delimters on face compare*/
#define T2QCMPUV  1
#define T2QCMPVCOL 2
static int compareFaceAttribs(EditFace *f1, EditFace *f2, int flag) 
{
	/*Test to see if two faces with custom data match within a certain limit*/
	EditVert *va, *vb;
	int i, j;
	MTFace *tf1, *tf2;
	unsigned int *col1, *col2;

	tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE);
	tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE);

	col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL);
	col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL);
	
	if(flag & T2QCMPUV){
		if(tf1 == NULL || tf2 == NULL) return 1;
		else if(tf1->tpage == NULL && tf2->tpage == NULL)
			return 1;
		else if(tf1->tpage != tf2->tpage)
			return 0;
	}
	if(flag & T2QCMPVCOL)
		if(!col1 || !col2) return 1;

	i = 0;
	va = f1->v1;
	while(i < 4 && va != NULL){
		j = 0;
		vb = f2->v1;
		while(j < 4 && vb != NULL){
			if(va == vb){
				if(flag & T2QCMPUV){
					if( !(tf1->uv[i][0] + T2QUV_LIMIT > tf2->uv[j][0] && tf1->uv[i][0] - T2QUV_LIMIT < tf2->uv[j][0] &&
						tf1->uv[i][1] + T2QUV_LIMIT > tf2->uv[j][1] && tf1->uv[i][1] - T2QUV_LIMIT < tf2->uv[j][1]))
						return 0;
				}
				if(flag & T2QCMPVCOL){
					char *v1, *v2;
					v1 = (char *)&(col1[i]);
					v2 = (char *)&(col2[j]);
		
					if(!(v1[1] + T2QCOL_LIMIT > v2[1] && v1[1] - T2QCOL_LIMIT < v2[1] &&
						v1[2] + T2QCOL_LIMIT > v2[2] && v1[2] - T2QCOL_LIMIT < v2[2] &&
						v1[3] + T2QCOL_LIMIT > v2[3] && v1[3] - T2QCOL_LIMIT < v2[3]))
						return 0;
				}
			}
			j++;
			vb++;
		}
		i++;
		va++;
	}
	return 1;
}	
	
static int fplcmp(const void *v1, const void *v2)
{
	const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
	
	if( e1->crease > e2->crease) return 1;
	else if( e1->crease < e2->crease) return -1;
	
	return 0;
}

/*Bitflags for edges.*/
#define T2QDELETE	1
#define T2QCOMPLEX	2
#define T2QSIMPLE	4
void join_triangles(void)
{
	EditMesh *em=G.editMesh;
	EditVert *v1, *v2, *v3, *v4, *eve;
	EditEdge *eed, **edsortblock = NULL, **edb = NULL;
	EditFace *efa;
	EVPTuple *efaar = NULL;
	EVPtr *efaa = NULL;
	float *creases = NULL;
	float limit = G.scene->toolsettings->select_thresh * 10; /*Used to set tolerance*/
	int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
	
	/*test for multi-resolution data*/
	if(multires_test()) return;
	
	/*if we take a long time on very dense meshes we want waitcursor to display*/
	waitcursor(1);
	
	totseledge = count_selected_edges(em->edges.first);
	if(totseledge==0) return;
	
	/*abusing crease value to store weights for edge pairs. Nasty*/
	for(eed=em->edges.first; eed; eed=eed->next) totedge++;
	if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array"); 
	for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
		creases[i] = eed->crease; 
		eed->crease = 0.0;
	}
	
	/*clear temp flags*/
	for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0;
	for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0;
	for(efa=em->edges.first; efa; efa=efa->next) efa->f1 = 0;

	/*For every 2 manifold edge, create pointers to its two faces.*/
	efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad");
	ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
	
	if(ok){
		/*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/  
		for(efa=em->faces.first; efa; efa=efa->next) efa->tmp.l = 0;
		for(eed=em->edges.first; eed; eed=eed->next){
			if(eed->tmp.p){
				efaa= (EVPtr *) eed->tmp.p;
				if(efaa[0]) efaa[0]->tmp.l++;
				if(efaa[1]) efaa[1]->tmp.l++;
			}
		}
		complexedges = 0;
		for(eed=em->edges.first; eed; eed=eed->next){
			if(eed->tmp.p){
				efaa= (EVPtr *) eed->tmp.p;
				if(efaa[0] && efaa[1]){
					v1 = v2 = v3 = v4 = NULL;
					givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
					if(v1 && v2 && v3 && v4){
						/*test if simple island first. This mimics 2.42 behaviour and the tests are more restrictive.*/
						if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){
							eed->f1 |= T2QSIMPLE;
							if( convex(v1->co, v2->co, v3->co, v4->co) ) {
								/*mark joined faces/edges for deletion*/
								efaa[0]->f1 = 1;
								efaa[1]->f1 = 1;
								eed->f1 |= T2QDELETE;
							}
						}
						else{ /*its part of a 'complex' island, tests are different*/
							if(efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
							else if(eed->sharp); /*do nothing*/
							else{
								ok = compareFaceAttribs(efaa[0], efaa[1], T2QCMPUV|T2QCMPVCOL);
								if(ok){
									measure = measure_facepair(v1, v2, v3, v4, limit);
									if(measure < limit){
										complexedges++;
										eed->f1 |= T2QCOMPLEX;
										eed->crease = measure; /*we dont mark edges for join YET*/
									}
								}
							}
						}
					}
				}
			}
		}
		
		/*Quicksort the complex edges and mark the most appropriate ones for deletion*/
		if(complexedges){
			edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
			for(eed = em->edges.first; eed; eed=eed->next){
				if(eed->f1 & T2QCOMPLEX){
					*edb = eed;
					edb++;
				}
			}
			qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp);
			/*now go through and mark the edges who get the highest weighting*/
			for(edb=edsortblock, i=0; i < complexedges; edb++, i++){ 
				efaa = (EVPtr *)((*edb)->tmp.p);
				if( !(efaa[0]->f1) && !(efaa[1]->f1) ){
					v1 = v2 = v3 = v4 = NULL;
					givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
					if(v1 && v2 && v3 && v4){
						/*mark elements for deletion later*/
						efaa[0]->f1 = 1;
						efaa[1]->f1 = 1;
						(*edb)->f1 |= T2QDELETE;
					}
				}
			}
		}
		/*finally go through all edges marked for deletion and join their faces*/ 
		for(eed=em->edges.first; eed; eed=eed->next){
			if(eed->f1 & T2QDELETE){
				efaa= (EVPtr *)eed->tmp.p;
				v1 = v2 = v3 = v4 = NULL;
				givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
				if(exist_face(v1, v2, v3, v4)==0) {
					efa = EM_face_from_faces(efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
					EM_select_face(efa,1);
				}
			}
		}
	}
	
	/*free data and cleanup*/
	if(creases){
		for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i]; 
		MEM_freeN(creases);
	}
	for(eed=em->edges.first; eed; eed=eed->next){
		if(eed->f1 & T2QDELETE) eed->f1 = 1;
		else eed->f1 = 0;
	}
	free_tagged_facelist(em->faces.first);
	free_tagged_edgelist(em->edges.first);
	if(efaar) MEM_freeN(efaar);
	if(edsortblock) MEM_freeN(edsortblock);
		
	EM_selectmode_flush();
	countall();
	allqueue(REDRAWVIEW3D, 0);
	DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
	#ifdef WITH_VERSE
	if(G.editMesh->vnode)
		sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
	#endif
	waitcursor(0);
	BIF_undo_push("Convert Triangles to Quads");
}