This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/bmesh/operators/join_triangles.c

388 lines
9.5 KiB
C
Raw Normal View History

2012-02-06 06:10:11 +00:00
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
#include "BKE_customdata.h"
#include "DNA_listBase.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include <string.h>
#include "BKE_utildefines.h"
#include "BKE_mesh.h"
#include "BKE_global.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BLI_editVert.h"
#include "mesh_intern.h"
#include "ED_mesh.h"
#include "BLI_math.h"
#include "BLI_array.h"
#include "BLI_edgehash.h"
#include "BLI_heap.h"
#include "bmesh.h"
#include "bmesh_operators_private.h" /* own include */
/*
* JOIN_TRIANGLES.C
*
* utility bmesh operators, e.g. transform,
* translate, rotate, scale, etc.
*
*/
/* Bitflags for edges */
2010-02-18 10:09:52 +00:00
#define T2QDELETE 1
#define T2QCOMPLEX 2
#define T2QJOIN 4
/* assumes edges are validated before reaching this poin */
2011-03-20 16:30:39 +00:00
static float measure_facepair(BMesh *UNUSED(bm), BMVert *v1, BMVert *v2,
BMVert *v3, BMVert *v4, float limit)
{
/* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would mak */
/* Note: this is more complicated than it needs to be and should be cleaned up.. */
2010-02-18 10:09:52 +00:00
float n1[3], n2[3], measure = 0.0f, angle1, angle2, diff;
float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3];
float minarea, maxarea, areaA, areaB;
/* First Test: Normal differenc */
normal_tri_v3(n1, v1->co, v2->co, v3->co);
normal_tri_v3(n2, v1->co, v3->co, v4->co);
2012-02-05 15:55:28 +00:00
if (n1[0] == n2[0] && n1[1] == n2[1] && n1[2] == n2[2]) angle1 = 0.0f;
2010-02-18 10:09:52 +00:00
else angle1 = angle_v3v3(n1, n2);
normal_tri_v3(n1, v2->co, v3->co, v4->co);
normal_tri_v3(n2, v4->co, v1->co, v2->co);
2012-02-05 15:55:28 +00:00
if (n1[0] == n2[0] && n1[1] == n2[1] && n1[2] == n2[2]) angle2 = 0.0f;
2010-02-18 10:09:52 +00:00
else angle2 = angle_v3v3(n1, n2);
measure += (angle1 + angle2) * 0.5f;
2012-02-07 01:46:47 +00:00
if (measure > limit) {
return measure;
}
/* Second test: Colinearit */
sub_v3_v3v3(edgeVec1, v1->co, v2->co);
sub_v3_v3v3(edgeVec2, v2->co, v3->co);
sub_v3_v3v3(edgeVec3, v3->co, v4->co);
sub_v3_v3v3(edgeVec4, v4->co, v1->co);
/* a completely skinny face is 'pi' after halving */
diff = 0.25f * (
fabsf(angle_v3v3(edgeVec1, edgeVec2) - (float)M_PI_2) +
fabsf(angle_v3v3(edgeVec2, edgeVec3) - (float)M_PI_2) +
fabsf(angle_v3v3(edgeVec3, edgeVec4) - (float)M_PI_2) +
fabsf(angle_v3v3(edgeVec4, edgeVec1) - (float)M_PI_2));
2012-02-05 15:55:28 +00:00
if (!diff) return 0.0;
measure += diff;
2012-02-07 01:46:47 +00:00
if (measure > limit) {
return measure;
}
/* Third test: Concavit */
areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co);
areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co);
2012-02-05 15:55:28 +00:00
if (areaA <= areaB) minarea = areaA;
else minarea = areaB;
2012-02-05 15:55:28 +00:00
if (areaA >= areaB) maxarea = areaA;
else maxarea = areaB;
2012-02-05 15:55:28 +00:00
if (!maxarea) measure += 1;
else measure += (1 - (minarea / maxarea));
return measure;
}
#define T2QUV_LIMIT 0.005f
#define T2QCOL_LIMIT 3
2010-02-18 10:09:52 +00:00
static int compareFaceAttribs(BMesh *bm, BMEdge *e, int douvs, int dovcols)
{
MTexPoly *tp1, *tp2;
MLoopCol *lcol1, *lcol2, *lcol3, *lcol4;
MLoopUV *luv1, *luv2, *luv3, *luv4;
2010-02-18 10:09:52 +00:00
BMLoop *l1, *l2, *l3, *l4;
int mergeok_uvs = !douvs, mergeok_vcols = !dovcols;
2010-02-18 10:09:52 +00:00
l1 = e->l;
2011-09-12 15:10:59 +00:00
l3 = e->l->radial_next;
/* match up loops on each side of an edge corrusponding to each ver */
2010-02-18 10:09:52 +00:00
if (l1->v == l3->v) {
2011-09-12 15:10:59 +00:00
l2 = l1->next;
l4 = l2->next;
2012-02-05 15:55:28 +00:00
}
else {
2011-09-12 15:10:59 +00:00
l2 = l1->next;
2010-02-18 10:09:52 +00:00
l4 = l3;
2011-09-12 15:10:59 +00:00
l3 = l4->next;
2010-02-18 10:09:52 +00:00
}
lcol1 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
lcol2 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
lcol3 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
lcol4 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
luv1 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
luv2 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
luv3 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
luv4 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
tp1 = CustomData_bmesh_get(&bm->pdata, l1->f->head.data, CD_MTEXPOLY);
tp2 = CustomData_bmesh_get(&bm->pdata, l2->f->head.data, CD_MTEXPOLY);
if (!lcol1)
mergeok_vcols = 1;
if (!luv1)
mergeok_uvs = 1;
/* compare faceedges for each face attribute. Additional per face attributes can be added late */
2010-02-18 10:09:52 +00:00
/* do VCOL */
2012-02-05 15:55:28 +00:00
if (lcol1 && dovcols) {
char *cols[4] = {(char *)lcol1, (char *)lcol2, (char *)lcol3, (char *)lcol4};
2010-02-18 10:09:52 +00:00
int i;
for (i = 0; i < 3; i++) {
if (cols[0][i] + T2QCOL_LIMIT < cols[2][i] - T2QCOL_LIMIT)
2010-02-18 10:09:52 +00:00
break;
if (cols[1][i] + T2QCOL_LIMIT < cols[3][i] - T2QCOL_LIMIT)
2010-02-18 10:09:52 +00:00
break;
}
if (i == 3)
mergeok_vcols = 1;
}
/* do UV */
2010-02-18 10:09:52 +00:00
if (luv1 && douvs) {
if (tp1->tpage != tp2->tpage); /* do nothin */
2010-02-18 10:09:52 +00:00
else {
int i;
2012-02-05 15:55:28 +00:00
for (i = 0; i < 2; i++) {
if (luv1->uv[0] + T2QUV_LIMIT > luv3->uv[0] && luv1->uv[0] - T2QUV_LIMIT < luv3->uv[0] &&
2010-02-18 10:09:52 +00:00
luv1->uv[1] + T2QUV_LIMIT > luv3->uv[1] && luv1->uv[1] - T2QUV_LIMIT < luv3->uv[1])
{
2012-02-05 15:55:28 +00:00
if (luv2->uv[0] + T2QUV_LIMIT > luv4->uv[0] && luv2->uv[0] - T2QUV_LIMIT < luv4->uv[0] &&
2010-02-18 10:09:52 +00:00
luv2->uv[1] + T2QUV_LIMIT > luv4->uv[1] && luv2->uv[1] - T2QUV_LIMIT < luv4->uv[1])
{
mergeok_uvs = 1;
}
}
}
}
}
2012-02-07 01:46:47 +00:00
if (douvs == mergeok_uvs && dovcols == mergeok_vcols) {
return TRUE;
}
return FALSE;
2010-02-18 10:09:52 +00:00
}
typedef struct JoinEdge {
float weight;
BMEdge *e;
} JoinEdge;
#define EDGE_MARK 1
#define EDGE_CHOSEN 2
#define FACE_MARK 1
#define FACE_INPUT 2
static int fplcmp(const void *v1, const void *v2)
{
const JoinEdge *e1 = (JoinEdge *)v1, *e2 = (JoinEdge *)v2;
2010-02-18 10:09:52 +00:00
2012-02-05 15:55:28 +00:00
if (e1->weight > e2->weight) return 1;
else if (e1->weight < e2->weight) return -1;
2010-02-18 10:09:52 +00:00
return 0;
}
void bmesh_jointriangles_exec(BMesh *bm, BMOperator *op)
{
2010-02-18 10:09:52 +00:00
BMIter iter, liter;
BMOIter siter;
BMFace *f1, *f2;
BMLoop *l;
BMEdge *e;
BLI_array_declare(jedges);
JoinEdge *jedges = NULL;
int dosharp = BMO_Get_Int(op, "compare_sharp"), douvs = BMO_Get_Int(op, "compare_uvs");
int dovcols = BMO_Get_Int(op, "compare_vcols"), domat = BMO_Get_Int(op, "compare_materials");
float limit = BMO_Get_Float(op, "limit");
2010-02-18 10:09:52 +00:00
int i, totedge;
/* flag all edges of all input face */
2010-02-18 10:09:52 +00:00
BMO_ITER(f1, &siter, bm, op, "faces", BM_FACE) {
BMO_SetFlag(bm, f1, FACE_INPUT);
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f1) {
BMO_SetFlag(bm, l->e, EDGE_MARK);
}
}
/* unflag edges that are invalid; e.g. aren't surrounded by triangle */
2010-02-18 10:09:52 +00:00
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
if (!BMO_TestFlag(bm, e, EDGE_MARK))
continue;
if (BM_Edge_FaceCount(e) < 2) {
BMO_ClearFlag(bm, e, EDGE_MARK);
continue;
}
f1 = e->l->f;
2011-09-12 15:10:59 +00:00
f2 = e->l->radial_next->f;
2010-02-18 10:09:52 +00:00
if (f1->len != 3 || f2->len != 3) {
BMO_ClearFlag(bm, e, EDGE_MARK);
continue;
}
if (!BMO_TestFlag(bm, f1, FACE_INPUT) || !BMO_TestFlag(bm, f2, FACE_INPUT)) {
BMO_ClearFlag(bm, e, EDGE_MARK);
continue;
}
}
i = 0;
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
BMVert *v1, *v2, *v3, *v4;
BMFace *f1, *f2;
float measure;
if (!BMO_TestFlag(bm, e, EDGE_MARK))
continue;
f1 = e->l->f;
2011-09-12 15:10:59 +00:00
f2 = e->l->radial_next->f;
2010-02-18 10:09:52 +00:00
v1 = e->l->v;
2011-09-12 15:10:59 +00:00
v2 = e->l->prev->v;
v3 = e->l->next->v;
v4 = e->l->radial_next->prev->v;
2010-02-18 10:09:52 +00:00
if (dosharp && BM_TestHFlag(e, BM_SHARP))
continue;
if ((douvs || dovcols) && compareFaceAttribs(bm, e, douvs, dovcols))
continue;
if (domat && f1->mat_nr != f2->mat_nr)
continue;
measure = measure_facepair(bm, v1, v2, v3, v4, limit);
2012-02-05 15:55:28 +00:00
if (measure < limit) {
2010-02-18 10:09:52 +00:00
BLI_array_growone(jedges);
jedges[i].e = e;
jedges[i].weight = measure;
2010-02-18 10:09:52 +00:00
i++;
}
}
if (!jedges)
return;
qsort(jedges, BLI_array_count(jedges), sizeof(JoinEdge), fplcmp);
totedge = BLI_array_count(jedges);
for (i = 0; i < totedge; i++) {
2010-02-18 10:09:52 +00:00
BMFace *f1, *f2;
e = jedges[i].e;
f1 = e->l->f;
2011-09-12 15:10:59 +00:00
f2 = e->l->radial_next->f;
2010-02-18 10:09:52 +00:00
if (BMO_TestFlag(bm, f1, FACE_MARK) || BMO_TestFlag(bm, f2, FACE_MARK))
continue;
BMO_SetFlag(bm, f1, FACE_MARK);
BMO_SetFlag(bm, f2, FACE_MARK);
BMO_SetFlag(bm, e, EDGE_CHOSEN);
}
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
if (!BMO_TestFlag(bm, e, EDGE_CHOSEN))
continue;
f1 = e->l->f;
2011-09-12 15:10:59 +00:00
f2 = e->l->radial_next->f;
2010-02-18 10:09:52 +00:00
BM_Join_TwoFaces(bm, f1, f2, e);
2010-02-18 10:09:52 +00:00
}
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
if (BMO_TestFlag(bm, e, EDGE_MARK)) {
/* ok, this edge wasn't merged, check if it's
2012-02-06 06:03:46 +00:00
* in a 2-tri-pair island, and if so merg */
2010-02-18 10:09:52 +00:00
f1 = e->l->f;
2011-09-12 15:10:59 +00:00
f2 = e->l->radial_next->f;
2010-02-18 10:09:52 +00:00
if (f1->len != 3 || f2->len != 3)
continue;
for (i = 0; i < 2; i++) {
2010-02-18 10:09:52 +00:00
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, i ? f2 : f1) {
if (l->e != e && BMO_TestFlag(bm, l->e, EDGE_MARK)) {
2010-02-18 10:09:52 +00:00
break;
}
2010-02-18 10:09:52 +00:00
}
/* if l isn't NULL, we broke out of the loo */
if (l) {
2010-02-18 10:09:52 +00:00
break;
}
2010-02-18 10:09:52 +00:00
}
/* if i isn't 2, we broke out of that loo */
if (i != 2) {
2010-02-18 10:09:52 +00:00
continue;
}
BM_Join_TwoFaces(bm, f1, f2, e);
2010-02-18 10:09:52 +00:00
}
}
BLI_array_free(jedges);
}