Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/src/editmesh_tools.c563
1 files changed, 493 insertions, 70 deletions
diff --git a/source/blender/src/editmesh_tools.c b/source/blender/src/editmesh_tools.c
index 090323fff83..dac812e5c77 100644
--- a/source/blender/src/editmesh_tools.c
+++ b/source/blender/src/editmesh_tools.c
@@ -3360,102 +3360,525 @@ void beauty_fill(void)
}
-/* ******************** FLIP EDGE ************************************* */
+/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
+/*move these macros to a header file along with notes on how they should be used*/
+#define FILL_FACEVERTS(face, arr) { arr[0] = face->v1; arr[1] = face->v2; arr[2] = face->v3; arr[3] = face->v4; arr[4] = NULL;}
+#define FILL_FACEEDGES(face, arr) { arr[0] = face->e1; arr[1] = face->e2; arr[2] = face->e3; arr[3] = face->e4; arr[4] = NULL;}
-#define FACE_MARKCLEAR(f) (f->f1 = 1)
+typedef struct FacePairL{
+ EditFace *face1, *face2;
+ EditVert *f1free, *f2free;
+ float measure;
+} FacePairL;
-void join_triangles(void)
+static int fplcmp(const void *v1, const void *v2)
{
- EditMesh *em = G.editMesh;
- EditVert *v1, *v2, *v3, *v4;
- EditFace *efa, *w;
- EVPTuple *efaar;
- EVPtr *efaa;
- EditEdge *eed, *nexted;
- int totedge, ok;
- float *uv[4];
- unsigned int col[4];
+ const FacePairL *fpl1=(*((EditEdge**)v1))->tmp.p, *fpl2=(*((EditEdge**)v2))->tmp.p;
+
+ if( fpl1->measure > fpl2->measure) return 1;
+ else if( fpl1->measure < fpl2->measure) return -1;
+
+ return 0;
+}
- EM_selectmode_flush(); // makes sure in selectmode 'face' the edges of selected faces are selected too
+static float isfaceCoLin(float fake[4][3]){
- totedge = count_selected_edges(em->edges.first);
- if(totedge==0) return;
+ float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff;
+
+ VecSubf(edgeVec1, fake[0], fake[1]);
+ VecSubf(edgeVec2, fake[1], fake[2]);
+ VecSubf(edgeVec3, fake[2], fake[3]);
+ VecSubf(edgeVec4, fake[3], fake[0]);
+
+ 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; //what? this makes no sense
+
+ return diff;
+}
- efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "jointris");
+static float isfaceNoDiff(float fake[4][3])
+{
+ float noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff;
+
+ CalcNormFloat(fake[0], fake[1], fake[2], noA1);
+ CalcNormFloat(fake[0], fake[2], fake[3], 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; not sure about this bit
+ }
+
+ CalcNormFloat(fake[1], fake[2], fake[3], noB1);
+ CalcNormFloat(fake[3], fake[0], fake[1], 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; not sure about this bit
+ }
+ return (normalADiff/360) + (normalBDiff/360);
+}
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
- if (G.f & G_DEBUG) {
- printf("Edges selected: %d\n", ok);
- }
+static float isfaceConcave(float fake[4][3])
+{
+ float minarea, maxarea, areaA, areaB;
+
+ areaA = AreaT3Dfl(fake[0], fake[1], fake[2]) + AreaT3Dfl(fake[0], fake[2], fake[3]);
+ areaB = AreaT3Dfl(fake[1], fake[2], fake[3]) + AreaT3Dfl(fake[3], fake[0], fake[1]);
+
+ if(areaA <= areaB) minarea = areaA;
+ else if(areaB < areaA) minarea = areaB;
+
+ if(areaA >= areaB) maxarea = areaA;
+ else if(areaB > areaA) maxarea = areaB;
+
+ if(!maxarea) return 1;
+ else return 1 - (minarea / maxarea);
+}
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- if(eed->f2==2) { /* points to 2 faces */
-
- efaa= (EVPtr *) eed->tmp.p;
-
- /* don't do it if flagged */
+static int measureFacePair(EditEdge *eed, float limit)
+{
+ EditVert *faceVerts[5];
+ FacePairL *fp = eed->tmp.p;
+ EditFace *face1 = fp->face1, *face2 = fp->face2;
+ float fake[4][3];
+ int v1free, v2free;
+
+ FILL_FACEVERTS(face2, faceVerts);
+
+ face1->v1->f1 = 0;
+ face1->v2->f1 = 1;
+ face1->v3->f1 = 2;
+
+ face2->v1->f1 = 0;
+ face2->v2->f1 = 1;
+ face2->v3->f1 = 2;
+
+ v1free = fp->f1free->f1;
+ v2free = fp->f2free->f1;
+
+ /*v1 is only one that dosn't vary*/
+ VECCOPY(fake[0], face1->v1->co);
+ VECCOPY(fake[1], face1->v2->co);
+ VECCOPY(fake[2], face1->v3->co);
+ switch(v1free){
+ case 0:
+ /*move fake[2] to fake[3]*/
+ VECCOPY(fake[3], fake[2]);
+ /*copy v2free to fake[2]*/
+ VECCOPY(fake[2], faceVerts[v2free]->co);
+ break;
+ case 1:
+ /*copy v2free to fake[3]*/
+ VECCOPY(fake[3], faceVerts[v2free]->co);
+ break;
+ case 2:
+ /*copy fake[2] to fake[3], then fake[1] to fake[2]*/
+ VECCOPY(fake[3], fake[2]);
+ VECCOPY(fake[2], fake[1]);
+ /*copy v2free to fake[1]*/
+ VECCOPY(fake[1], faceVerts[v2free]->co);
+ break;
+ }
+
+ fp->measure+= isfaceNoDiff(fake)/3;
+ if(fp->measure > limit) return 0;
+ fp->measure+= isfaceCoLin(fake)/3;
+ if(fp->measure > limit) return 0;
+ fp->measure+= isfaceConcave(fake)/3;
+ if(fp->measure > limit) return 0;
+
+ return 1;
+}
- ok= 1;
- efa= efaa[0];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- efa= efaa[1];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
-
- if(ok) {
- /* test convex */
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, uv, col);
+static int compare2(float v1[2], float v2[2], float limit)
+{
+ if( v1[0] + limit > v2[0] && v1[0] - limit < v2[0] &&
+ v1[1] + limit > v2[1] && v1[1] - limit < v2[1])
+ return 1;
+ return 0;
+}
-/*
- 4-----3 4-----3
- |\ | | |
- | \ 1 | | |
- | \ | -> | |
- | 0 \ | | |
- | \| | |
- 1-----2 1-----2
-*/
- /* make new faces */
- if(v1 && v2 && v3 && v4) {
- if( convex(v1->co, v2->co, v3->co, v4->co) ) {
- if(exist_face(v1, v2, v3, v4)==0) {
- w = addfacelist(v1, v2, v3, v4, efaa[0], NULL); /* seam edge may get broken */
- w->f= efaa[0]->f; /* copy selection flag */
- untag_edges(w);
+static int compare3(unsigned int RGB1, unsigned int RGB2, unsigned int limit)
+{
+ char v1[3], v2[3];
+ memcpy(v1, &RGB1, 4);
+ memcpy(v2, &RGB2, 4);
+
+ if( v1[1] + limit > v2[1] && v1[1] - limit < v2[1] &&
+ v1[2] + limit > v2[2] && v1[2] - limit < v2[2] &&
+ v1[3] + limit > v2[3] && v1[3] - limit < v2[3])
+ return 1;
+ return 0;
+}
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[1]);
- UVCOPY(w->tf.uv[2], uv[2]);
- UVCOPY(w->tf.uv[3], uv[3]);
+#define UV_LIMIT 0.005
+static int compareFaceUV(EditFace *f1, EditFace *f2)
+{
+ EditVert **faceVert1, **faceVert2, *faceVerts1[5], *faceVerts2[5];
+ int i1, i2;
+
+ if(f1->tf.tpage == NULL && f2->tf.tpage == NULL)
+ return 1;
+ else if(f1->tf.tpage != f2->tf.tpage)
+ return 0;
+
+ FILL_FACEVERTS(f1, faceVerts1);
+ FILL_FACEVERTS(f2, faceVerts2);
+
+ faceVert1 = faceVerts1;
+ i1 = 0;
+ while(*faceVert1){
+ faceVert2 = faceVerts2;
+ i2 = 0;
+ while(*faceVert2){
+ if( *faceVert1 == *faceVert2){
+ if(!compare2(f1->tf.uv[i1], f2->tf.uv[i2], UV_LIMIT))
+ return 0;
+ }
+ i2++;
+ faceVert2++;
+ }
+ i1++;
+ faceVert1++;
+ }
+ return 1;
+}
+
+#define COL_LIMIT 3
+static int compareFaceCol(EditFace *f1, EditFace *f2)
+{
+ EditVert **faceVert1, **faceVert2, *faceVerts1[5], *faceVerts2[5];
+ int i1, i2;
+
+ FILL_FACEVERTS(f1, faceVerts1);
+ FILL_FACEVERTS(f2, faceVerts2);
+
+ faceVert1 = faceVerts1;
+ i1 = 0;
+ while(*faceVert1){
+ faceVert2 = faceVerts2;
+ i2 = 0;
+ while(*faceVert2){
+ if( *faceVert1 == *faceVert2){
+ if(!compare3(f1->tf.col[i1], f2->tf.col[i2], COL_LIMIT))
+ return 0;
+ }
+ i2++;
+ faceVert2++;
+ }
+ i1++;
+ faceVert1++;
+ }
+ return 1;
+}
+
+static void meshJoinFaces(EditEdge *joined)
+{
+ FacePairL *fpl = joined->tmp.p;
+ EditFace *face1, *face2, *efa;
+ EditVert *v1free, *v2free;
+ int i;
+
+
+ face1 = fpl->face1;
+ face2 = fpl->face2;
+ v1free = fpl->f1free;
+ v2free = fpl->f2free;
+
+
+
+ face1->v1->f1 = 0;
+ face1->v2->f1 = 1;
+ face1->v3->f1 = 2;
+
+ face2->v1->f1 = 0;
+ face2->v2->f1 = 1;
+ face2->v3->f1 = 2;
+
+
+ switch(v1free->f1){
+ case 0:
+ i = 2;
+ break;
+ case 1:
+ i = 3;
+ break;
+ case 2:
+ i = 1;
+ break;
+ }
+
+ switch(i){
+ case 2:
+ /*this is really lazy...*/
+ efa = addfacelist(face1->v1, face1->v2, v2free, face1->v3, face1, NULL);
+ efa->tf.uv[0][0] = face1->tf.uv[0][0];
+ efa->tf.uv[0][1] = face1->tf.uv[0][1];
+ efa->tf.col[0] = face1->tf.col[0];
+
+ efa->tf.uv[1][0] = face1->tf.uv[1][0];
+ efa->tf.uv[1][1] = face1->tf.uv[1][1];
+ efa->tf.col[1] = face1->tf.col[1];
+
+ efa->tf.uv[2][0] = face2->tf.uv[v2free->f1][0];
+ efa->tf.uv[2][1] = face2->tf.uv[v2free->f1][1];
+ efa->tf.col[2] = face2->tf.col[v2free->f1];
+
+ efa->tf.uv[3][0] = face1->tf.uv[2][0];
+ efa->tf.uv[3][1] = face1->tf.uv[2][1];
+ efa->tf.col[3] = face1->tf.col[2];
+ break;
+ case 3:
+ efa = addfacelist(face1->v1, face1->v2, face1->v3, v2free, face1, NULL);
+ efa->tf.uv[0][0] = face1->tf.uv[0][0];
+ efa->tf.uv[0][1] = face1->tf.uv[0][1];
+ efa->tf.col[0] = face1->tf.col[0];
+
+ efa->tf.uv[1][0] = face1->tf.uv[1][0];
+ efa->tf.uv[1][1] = face1->tf.uv[1][1];
+ efa->tf.col[1] = face1->tf.col[1];
+
+ efa->tf.uv[2][0] = face1->tf.uv[2][0];
+ efa->tf.uv[2][1] = face1->tf.uv[2][1];
+ efa->tf.col[2] = face1->tf.col[2];
+
+ efa->tf.uv[3][0] = face2->tf.uv[v2free->f1][0];
+ efa->tf.uv[3][1] = face2->tf.uv[v2free->f1][1];
+ efa->tf.col[3] = face1->tf.col[v2free->f1];
+ break;
+ case 1:
+ efa = addfacelist(face1->v1, v2free, face1->v2, face1->v3, face1, NULL);
+ efa->tf.uv[0][0] = face1->tf.uv[0][0];
+ efa->tf.uv[0][1] = face1->tf.uv[0][1];
+ efa->tf.col[0] = face1->tf.col[0];
+
+ efa->tf.uv[1][0] = face2->tf.uv[v2free->f1][0];
+ efa->tf.uv[1][1] = face2->tf.uv[v2free->f1][1];
+ efa->tf.col[1] = face2->tf.col[v2free->f1];
+
+ efa->tf.uv[2][0] = face1->tf.uv[1][0];
+ efa->tf.uv[2][1] = face1->tf.uv[1][1];
+ efa->tf.col[2] = face1->tf.col[1];
+
+ efa->tf.uv[3][0] = face1->tf.uv[2][0];
+ efa->tf.uv[3][1] = face1->tf.uv[2][1];
+ efa->tf.col[3] = face1->tf.col[2];
+ break;
+ }
+
+ EM_select_face(efa,1);
+ /*flag for removal*/
+ joined->f1 = 1;
+ face1->f1 = 1;
+ face2->f1 = 1;
+}
- memcpy(w->tf.col, col, sizeof(w->tf.col));
+void join_triangles(void)
+{
+ EditMesh *em=G.editMesh;
+ EditFace *efa;
+ EditEdge *eed, **faceEdge, *faceEdges[5], **edsortblock, **edb;
+ EditVert **faceVert1, *faceVerts1[5], **faceVert2, *faceVerts2[5];
+ float limit = 25;
+ int i, paircount, joincount, totFacePairLs, respectvcol = 1, respectuv = 1, match, matchar[3];
+ FacePairL *fpl1;
+
+ waitcursor(1);
+
+ for(efa=em->faces.first; efa; efa=efa->next){
+ efa->f1 = 0;
+ efa->tmp.v = NULL;
+ }
+ for(eed=em->edges.first; eed; eed=eed->next){
+ eed->f1 = 0;
+ eed->f2 = 0;
+ eed->tmp.p = NULL;
+ }
+
+ /*store number of faces coincident on each edge*/
+ for(efa=em->faces.first; efa; efa=efa->next){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4)
+ efa->e4->f1++;
+ }
+
+ /*mark faces we are interested in*/
+ for(efa=em->faces.first; efa; efa=efa->next){
+ if(efa->f&SELECT && (!efa->v4) && (!efa->h)) efa->f1 = 1;
+ }
+
+ /*allocate FacePairL structs for each edge*/
+ totFacePairLs = 0;
+ for(efa=em->faces.first; efa; efa=efa->next){
+ if(efa->f1){
+ FILL_FACEEDGES(efa,faceEdges);
+ faceEdge = faceEdges;
+ while(*faceEdge){
+ if( (*faceEdge)->f1 == 2 && (*faceEdge)->tmp.p == NULL){
+ (*faceEdge)->tmp.p = MEM_callocN(sizeof(FacePairL), "Tri2Quad FacePair");
+ totFacePairLs++;
+ }
+ faceEdge++;
+ }
+ }
+ }
+
+ /*populate FacePairL structs*/
+ for(efa=em->faces.first; efa; efa=efa->next){
+ if(efa->f1){
+ FILL_FACEEDGES(efa,faceEdges);
+ faceEdge = faceEdges;
+ i=0;
+ while(*faceEdge){
+ if( (*faceEdge)->tmp.p){
+ fpl1 = (*faceEdge)->tmp.p;
+ /*get rid of duplicated code!*/
+ if(fpl1->face1){
+ /*do fpl1->face2*/
+ fpl1->face2 = efa;
+ switch(i)
+ {
+ case 0:
+ fpl1->f2free = efa->v3;
+ break;
+ case 1:
+ fpl1->f2free = efa->v1;
+ break;
+ case 2:
+ fpl1->f2free = efa->v2;
+ break;
}
- /* tag as to-be-removed */
- FACE_MARKCLEAR(efaa[0]);
- FACE_MARKCLEAR(efaa[1]);
- eed->f1 = 1;
- } /* endif test convex */
+ }
+ else{
+ /*do fpl1->face1*/
+ fpl1->face1 = efa;
+ switch(i)
+ {
+ case 0:
+ fpl1->f1free = efa->v3;
+ break;
+ case 1:
+ fpl1->f1free = efa->v1;
+ break;
+ case 2:
+ fpl1->f1free = efa->v2;
+ }
+
+ }
}
+ faceEdge++;
+ i++;
}
}
- eed= nexted;
}
- free_tagged_edgelist(em->edges.first);
+
+ paircount = 0;
+ /*Test FacePairLs for inclusion of the associated edge in sort array */
+ for(eed=em->edges.first; eed; eed=eed->next){
+ EditFace *f1, *f2;
+ EditVert *f1free, *f2free;
+
+ if(eed->tmp.p){
+ f1 = ((FacePairL*)(eed->tmp.p))->face1;
+ f1free = ((FacePairL*)(eed->tmp.p))->f1free;
+ f2 = ((FacePairL*)(eed->tmp.p))->face2;
+ f2free = ((FacePairL*)(eed->tmp.p))->f2free;
+
+ /*test for two editfaces with same vertices but different order. Should never happen but does sometimes!*/
+ FILL_FACEVERTS(f1,faceVerts1);
+ FILL_FACEVERTS(f2,faceVerts2);
+ faceVert1 = faceVerts1;
+ i = 0;
+ while(*faceVert1){
+ match = 0;
+ faceVert2 = faceVerts2;
+ while(*faceVert2){
+ if(*faceVert2 == *faceVert1){
+ match = 1;
+ break;
+ }
+ else faceVert2++;
+ }
+
+ matchar[i] = match;
+ faceVert1++;
+ i++;
+ }
+
+ if(!(matchar[0] == 1 && matchar[1] == 1 && matchar[2] == 1)){
+ if(f1 && f2){
+ /*do tests to disqualify potential face pairs from the sort.*/
+ if(f1->mat_nr != f2->mat_nr); /*do nothing*/
+ else if(eed->sharp); /*do nothing*/
+ else if(respectuv && !compareFaceUV(f1, f2) ); /*do nothing*/
+ else if(respectvcol && !compareFaceCol(f1, f2) ); /*do nothing*/
+ else{
+ eed->f2 = measureFacePair(eed, (float)limit);
+ if(eed->f2) paircount += 1;
+ }
+ }
+ }
+ }
+ }
+
+ edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * paircount, "Face Pairs quicksort Array");
+ for(eed = em->edges.first; eed; eed=eed->next){
+ if(eed->f2){
+ *edb = eed;
+ edb++;
+ }
+ }
+
+ //eed->f1 and efa->f1 used by free_taggeed_edge/facelist
+ for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(efa = em->faces.first; efa; efa=efa->next) efa->f1 = 0;
+ /*quicksort according to FacePairL->measure*/
+ qsort(edsortblock, paircount, sizeof(EditEdge*), fplcmp);
+
+ joincount = 0;
+ for(edb=edsortblock, i=0; i < paircount; edb++, i++){
+ fpl1 = (*edb)->tmp.p;
+ if( !(fpl1->face1->f1) && !(fpl1->face2->f1) ){
+ joincount++;
+ meshJoinFaces(*edb);
+ }
+ }
+
+ if(joincount) notice("Created %i new quads /n", joincount);
+ else notice("nothing done");
+
free_tagged_facelist(em->faces.first);
-
- MEM_freeN(efaar);
+ MEM_freeN(edsortblock);
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->tmp.p) MEM_freeN(eed->tmp.p);
+ }
+ free_tagged_edgelist(em->edges.first);
+ EM_selectmode_flush();
+ countall();
allqueue(REDRAWVIEW3D, 0);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
-#ifdef WITH_VERSE
+ #ifdef WITH_VERSE
if(G.editMesh->vnode)
sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
-#endif
+ #endif
BIF_undo_push("Convert Triangles to Quads");
+ waitcursor(0);
}
+/* ******************** END TRIANGLE TO QUAD ************************************* */
+
+#define FACE_MARKCLEAR(f) (f->f1 = 1)
/* quick hack, basically a copy of beauty_fill */
void edge_flip(void)