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:
@@ -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);}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user