connect verts now does geometric tests to perform valid splits. it also supports multiple splits in a face, going around the face boundary in a loop and performing splits.

This commit is contained in:
Joseph Eagar
2009-03-14 13:16:35 +00:00
parent 168847fe79
commit 302e796270
7 changed files with 278 additions and 96 deletions

View File

@@ -113,6 +113,8 @@
#define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);}
#define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
#define VECSUB2D(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
#define VECMUL(v1, fac) {v1[0] *= fac; v1[1] *= fac; v1[2] *= fac;}
#define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
#define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}

View File

@@ -52,8 +52,9 @@ code, that never (or almost never) directly inspects the underlying structure.
The API includes iterators, including many useful topological iterators;
walkers, which walk over a mesh, without the risk of hitting the recursion
limit; operators, which are logical, reusable mesh modules; topological
"euler" functions, which are used for topological manipulations; and some
(not yet finished) geometric utility functions.
modification functions (like split face, join faces, etc), which are used for
topological manipulations; and some (not yet finished) geometric utility
functions.
some definitions:

View File

@@ -79,4 +79,11 @@ int BM_Edge_Share_Faces(struct BMEdge *e1, struct BMEdge *e2);
/*checks if a face is valid in the data structure*/
int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err);
/*each pair of loops defines a new edge, a split. this function goes
through and sets pairs that are geometrically invalid to null. a
split is invalid, if it forms a concave angle or it intersects other
edges in the face.*/
void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len);
#endif

View File

@@ -275,7 +275,7 @@ BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl,
BMFace *nf;
nf = bmesh_sfme(bm,f,v1,v2,nl);
BM_Copy_Attributes(bm, bm, f, nf);
if (nf) BM_Copy_Attributes(bm, bm, f, nf);
return nf;
}

View File

@@ -99,6 +99,11 @@ static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
double n[3] = {0.0, 0.0, 0.0}, l;
int i;
/*this fixes some weird numerical error*/
verts[0][0] += 0.0001f;
verts[0][1] += 0.0001f;
verts[0][2] += 0.0001f;
for(i = 0; i < nverts; i++){
u = verts[i];
v = verts[(i+1) % nverts];
@@ -133,9 +138,9 @@ static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
n[1] /= l;
n[2] /= l;
normal[0] = n[0];
normal[1] = n[1];
normal[2] = n[2];
normal[0] = (float) n[0];
normal[1] = (float) n[1];
normal[2] = (float) n[2];
}
/*
@@ -249,78 +254,40 @@ void compute_poly_plane(float (*verts)[3], int nverts)
the list that bridges a concave region of the face or intersects
any of the faces's edges.
*/
static void shrink_edge(float *v1, float *v2, float fac)
static void shrink_edged(double *v1, double *v2, double fac)
{
double mid[3];
VECADD(mid, v1, v2);
VECMUL(mid, 0.5);
VECSUB(v1, v1, mid);
VECSUB(v2, v2, mid);
VECMUL(v1, fac);
VECMUL(v2, fac);
VECADD(v1, v1, mid);
VECADD(v2, v2, mid);
}
static void shrink_edgef(float *v1, float *v2, float fac)
{
float mid[3];
VecAddf(mid, v1, v2);
VecMulf(mid, 0.5f);
VECADD(mid, v1, v2);
VECMUL(mid, 0.5);
VecSubf(v1, v1, mid);
VecSubf(v2, v2, mid);
VECSUB(v1, v1, mid);
VECSUB(v2, v2, mid);
VecMulf(v1, fac);
VecMulf(v2, fac);
VecAddf(v1, v1, mid);
VecAddf(v2, v2, mid);
VECMUL(v1, fac);
VECMUL(v2, fac);
VECADD(v1, v1, mid);
VECADD(v2, v2, mid);
}
#if 0
void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop (*loops)[2], int len)
{
BMIter iter;
BMLoop *l;
float v1[3], v2[3], no[3], *p1, *p2;
float projectverts[100][3];
float edgevertsstack[100][2][3];
float (*projverts)[3] = projectverts;
float (*edgeverts)[2][3] = edgevertsstack;
int i, nvert, j;
if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb");
if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb");
i = 0;
l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
for (; l; l=BMIter_Step(&iter)) {
VECCOPY(projverts[i], l->v->co);
i++;
}
for (i=0; i<len; i++) {
VECCOPY(v1, loops[i][0]->v->co);
VECCOPY(v2, loops[i][0]->v->co);
shrink_edge(v1, v2, 0.9999f);
VECCOPY(edgeverts[i][0], v1);
VECCOPY(edgeverts[i][1], v2);
}
compute_poly_normal(no, projverts, f->len);
poly_rotate_plane(no, projverts, f->len);
poly_rotate_plane(no, edgeverts, len);
for (i=0; i<len; i++) {
if (convexangle(
}
for (i=0; i<f->len; i++) {
for (j=0; j<len; j++) {
p1 = projverts[i];
p2 = projverts[(i+1)%f->len];
if (convexangle(
if (linecrosses(p1, p2,
}
}
if (projverts != projectverts) MEM_freeN(projverts);
if (edgeverts != edgevertsstack) MEM_freeN(edgeverts);
}
#endif
/*
* POLY ROTATE PLANE
*
@@ -337,8 +304,6 @@ void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts)
double angle;
int i;
compute_poly_normal(normal, verts, nverts);
Crossf(axis, up, normal);
axis[0] *= -1;
axis[1] *= -1;
@@ -512,6 +477,48 @@ int linecrosses(double *v1, double *v2, double *v3, double *v4)
return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
}
int windingf(float *a, float *b, float *c)
{
float v1[3], v2[3], v[3];
VECSUB(v1, b, a);
VECSUB(v2, b, c);
v1[2] = 0;
v2[2] = 0;
Normalize(v1);
Normalize(v2);
Crossf(v, v1, v2);
/*!! (turns nonzero into 1) is likely not necassary,
since '>' I *think* should always
return 0 or 1, but I'm not totally sure. . .*/
return !!(v[2] > 0);
}
/* detects if two line segments cross each other (intersects).
note, there could be more winding cases then there needs to be. */
int linecrossesf(float *v1, float *v2, float *v3, float *v4)
{
int w1, w2, w3, w4, w5;
/*w1 = winding(v1, v3, v4);
w2 = winding(v2, v3, v4);
w3 = winding(v3, v1, v2);
w4 = winding(v4, v1, v2);
return (w1 == w2) && (w3 == w4);*/
w1 = windingf(v1, v3, v2);
w2 = windingf(v2, v4, v1);
w3 = !windingf(v1, v2, v3);
w4 = windingf(v3, v2, v4);
w5 = !windingf(v3, v1, v4);
return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
}
int goodline(float (*projectverts)[3], BMFace *f, int v1i,
int v2i, int v3i, int nvert) {
BMLoop *l = f->loopbase;
@@ -528,7 +535,7 @@ int goodline(float (*projectverts)[3], BMFace *f, int v1i,
do {
i = l->v->head.eflag2;
if (i == v1i || i == v2i || i == v3i) {
l = l->head.next;
l = (BMLoop*)l->head.next;
continue;
}
@@ -539,7 +546,7 @@ int goodline(float (*projectverts)[3], BMFace *f, int v1i,
if (point_in_triangle(v1, v2, v3, pv1)) return 0;
if (point_in_triangle(v3, v2, v1, pv1)) return 0;
l = l->head.next;
l = (BMLoop*)l->head.next;
} while (l != f->loopbase);
return 1;
}
@@ -617,7 +624,6 @@ void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
int newedgeflag, int newfaceflag)
{
int i, done, nvert;
float no[3];
BMLoop *l, *newl, *nextloop;
BMVert *v;
@@ -633,11 +639,6 @@ void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
///bmesh_update_face_normal(bm, f, projectverts);
/*this fixes some weird numerical error*/
projectverts[0][0] += 0.0001f;
projectverts[0][1] += 0.0001f;
projectverts[0][2] += 0.0001f;
compute_poly_normal(f->no, projectverts, f->len);
poly_rotate_plane(f->no, projectverts, i);
@@ -696,3 +697,129 @@ void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
}
}
}
#if 1
/*each pair of loops defines a new edge, a split. this function goes
through and sets pairs that are geometrically invalid to null. a
split is invalid, if it forms a concave angle or it intersects other
edges in the face, or it intersects another split. in the case of
intersecting splits, only the first of the set of intersecting
splits survives.*/
void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
BMIter iter;
BMLoop *l;
float v1[3], v2[3], v3[3], v4[3], no[3], mid[3], *p1, *p2, *p3, *p4;
float out[3] = {-234324.0f, -234324.0f, 0.0f};
float projectverts[100][3];
float edgevertsstack[200][3];
float (*projverts)[3] = projectverts;
float (*edgeverts)[3] = edgevertsstack;
int i, j, a=0, clen;
if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb");
if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb");
i = 0;
l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
for (; l; l=BMIter_Step(&iter)) {
l->head.eflag2 = i;
VECCOPY(projverts[i], l->v->co);
i++;
}
for (i=0; i<len; i++) {
VECCOPY(v1, loops[i][0]->v->co);
VECCOPY(v2, loops[i][1]->v->co);
shrink_edgef(v1, v2, 0.9999f);
VECCOPY(edgeverts[a], v1);
a++;
VECCOPY(edgeverts[a], v2);
a++;
}
compute_poly_normal(no, projverts, f->len);
poly_rotate_plane(no, projverts, f->len);
poly_rotate_plane(no, edgeverts, len*2);
for (i=0; i<f->len; i++) {
p1 = projverts[i];
out[0] = MAX2(out[0], p1[0]) + 0.01;
out[1] = MAX2(out[1], p1[1]) + 0.01;
out[2] = 0.0f;
p1[2] = 0.0f;
}
/*do convexity test*/
for (i=0; i<len; i++) {
l = (BMLoop*)loops[i][0];
VECCOPY(v2, edgeverts[i*2]);
l = (BMLoop*)loops[i][1];
VECCOPY(v3, edgeverts[i*2+1]);
VecAddf(mid, v2, v3);
VecMulf(mid, 0.5f);
clen = 0;
for (j=0; j<f->len; j++) {
p1 = projverts[j];
p2 = projverts[(j+1)%f->len];
VECCOPY(v1, p1);
VECCOPY(v2, p2);
shrink_edgef(v1, v2, 1.001f);
if (linecrossesf(p1, p2, mid, out)) clen++;
else if (linecrossesf(p2, p1, out, mid)) clen++;
else if (linecrossesf(p1, p2, out, mid)) clen++;
}
if (clen%2 == 0) {
loops[i][0] = NULL;
}
}
/*do line crossing tests*/
for (i=0; i<f->len; i++) {
p1 = projverts[i];
p2 = projverts[(i+1)%f->len];
for (j=0; j<len; j++) {
if (!loops[j][0]) continue;
l = loops[j][0];
VECCOPY(v1, edgeverts[j*2]);
l = loops[j][1];
VECCOPY(v2, edgeverts[j*2+1]);
if (linecrossesf(p1, p2, v1, v2) ||
linecrossesf(p2, p1, v2, v1))
{
loops[j][0] = NULL;
}
}
}
for (i=0; i<len; i++) {
for (j=0; j<len; j++) {
if (j != i) continue;
if (!loops[i][0]) continue;
if (!loops[j][0]) continue;
p1 = edgeverts[i*2];
p2 = edgeverts[i*2+1];
p3 = edgeverts[j*2];
p4 = edgeverts[j*2+1];
if (linecrossesf(p1, p2, p3, p4)) loops[i][0]=NULL;
}
}
if (projverts != projectverts) MEM_freeN(projverts);
if (edgeverts != edgevertsstack) MEM_freeN(edgeverts);
}
#endif

View File

@@ -8,52 +8,97 @@
#include "BLI_arithb.h"
#include <stdio.h>
#include <string.h>
#define VERT_INPUT 1
#define EDGE_OUT 1
#define FACE_NEW 2
void connectverts_exec(BMesh *bm, BMOperator *op)
{
BMIter iter, liter;
BMFace *f, *nf;
BMEdge *e;
BMLoop **loops = NULL, *lastl = NULL;
V_DECLARE(loops);
BMLoop *l, *nl;
BMVert *v1, *v2;
int ok;
BMVert *v1, *v2, **verts = NULL;
V_DECLARE(verts);
int i;
BMO_Flag_Buffer(bm, op, BM_CONVERTS_VERTIN, VERT_INPUT);
for (f=BMIter_New(&iter, bm, BM_FACES, NULL); f; f=BMIter_Step(&iter)){
V_RESET(loops);
V_RESET(verts);
if (BMO_TestFlag(bm, f, FACE_NEW)) continue;
l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
v1 = v2 = NULL;
ok = 0;
lastl = NULL;
for (; l; l=BMIter_Step(&liter)) {
if (BMO_TestFlag(bm, l->v, VERT_INPUT)) {
if (v1==NULL) v1 = l->v;
else if (v2==NULL) {
if (((BMLoop*)l->head.prev)->v != v1
&& ((BMLoop*)l->head.next)->v!=v1) {
v2 = l->v;
ok = 1;
}
} else ok = 0;
if (!lastl) {
lastl = l;
continue;
}
if (lastl != l->head.prev && lastl !=
l->head.next)
{
V_GROW(loops);
loops[V_COUNT(loops)-1] = lastl;
V_GROW(loops);
loops[V_COUNT(loops)-1] = l;
lastl = l;
}
}
}
if (ok) {
if (V_COUNT(loops) == 0) continue;
if (V_COUNT(loops) > 2) {
V_GROW(loops);
loops[V_COUNT(loops)-1] = loops[V_COUNT(loops)-2];
nf = BM_Split_Face(bm, f, v1, v2, &nl, NULL);
V_GROW(loops);
loops[V_COUNT(loops)-1] = loops[0];
}
BM_LegalSplits(bm, f, loops, V_COUNT(loops)/2);
for (i=0; i<V_COUNT(loops)/2; i++) {
if (loops[i*2]==NULL) continue;
V_GROW(verts);
verts[V_COUNT(verts)-1] = loops[i*2]->v;
V_GROW(verts);
verts[V_COUNT(verts)-1] = loops[i*2+1]->v;
}
for (i=0; i<V_COUNT(verts)/2; i++) {
nf = BM_Split_Face(bm, f, verts[i*2],
verts[i*2+1], &nl, NULL);
f = nf;
if (!nl || !nf) {
BMO_RaiseError(bm, op,
BMERR_CONNECTVERT_FAILED, NULL);
return;
V_FREE(loops);
return;;;
}
BMO_SetFlag(bm, nf, FACE_NEW);
BMO_SetFlag(bm, nl->e, EDGE_OUT);
}
}
BMO_Flag_To_Slot(bm, op, BM_CONVERTS_EDGEOUT, EDGE_OUT, BM_EDGE);
V_FREE(loops);
V_FREE(verts);
}
int BM_ConnectVerts(EditMesh *em, int flag)

View File

@@ -93,8 +93,8 @@ void extrude_edge_context_exec(BMesh *bm, BMOperator *op)
if (BMO_InMap(bm, op, BMOP_EXFACE_EXCLUDEMAP, e)) continue;
newedge = BMO_IterMapVal(&siter);
if (!newedge) continue;
newedge = *(BMEdge**)newedge;
if (!newedge) continue;
verts[0] = e->v1;
verts[1] = e->v2;