Refactor insertion into BSP tree.
Before this commit, inserting into BSP tree could easily overflow the stack because we allocate very large stack frames and, on convex geometries (e.g. a sphere), the BSP tree degenerates into a "BSP list", thus requiring one large stack frame per triangle. This can be reproduced by exporting a 2d shaded view of sphere. After this commit, the stack frames only contan a pointer to a supplementary data structure, and moreover it only allocates its fields on demand, conserving heap memory as well. As a side effect, an arbitrary classifier limit of 50 vertices is removed.pull/36/merge
parent
d37f53e190
commit
7681f6df74
496
src/bsp.cpp
496
src/bsp.cpp
|
@ -125,9 +125,268 @@ alt:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SBsp3::InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, int n,
|
class BspUtil {
|
||||||
SMesh *instead)
|
public:
|
||||||
{
|
SBsp3 *bsp;
|
||||||
|
|
||||||
|
size_t onc;
|
||||||
|
size_t posc;
|
||||||
|
size_t negc;
|
||||||
|
bool *isPos;
|
||||||
|
bool *isNeg;
|
||||||
|
bool *isOn;
|
||||||
|
|
||||||
|
// triangle operations
|
||||||
|
STriangle *tr;
|
||||||
|
STriangle *btri; // also as alone
|
||||||
|
STriangle *ctri;
|
||||||
|
|
||||||
|
// convex operations
|
||||||
|
Vector *on;
|
||||||
|
size_t npos;
|
||||||
|
size_t nneg;
|
||||||
|
Vector *vpos; // also as quad
|
||||||
|
Vector *vneg;
|
||||||
|
|
||||||
|
static BspUtil *Alloc() {
|
||||||
|
return (BspUtil *)AllocTemporary(sizeof(BspUtil));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocOn() {
|
||||||
|
on = (Vector *)AllocTemporary(sizeof(Vector) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocTriangle() {
|
||||||
|
btri = (STriangle *)AllocTemporary(sizeof(STriangle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocTriangles() {
|
||||||
|
btri = (STriangle *)AllocTemporary(sizeof(STriangle) * 2);
|
||||||
|
ctri = &btri[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocQuad() {
|
||||||
|
vpos = (Vector *)AllocTemporary(sizeof(Vector) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocClassify(size_t size) {
|
||||||
|
// Allocate a one big piece is faster than a small ones.
|
||||||
|
isPos = (bool *)AllocTemporary(sizeof(bool) * size * 3);
|
||||||
|
isNeg = &isPos[size];
|
||||||
|
isOn = &isNeg[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocVertices(size_t size) {
|
||||||
|
vpos = (Vector *)AllocTemporary(sizeof(Vector) * size * 2);
|
||||||
|
vneg = &vpos[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassifyTriangle(STriangle *tri, SBsp3 *node) {
|
||||||
|
tr = tri;
|
||||||
|
bsp = node;
|
||||||
|
onc = 0;
|
||||||
|
posc = 0;
|
||||||
|
negc = 0;
|
||||||
|
|
||||||
|
AllocClassify(3);
|
||||||
|
|
||||||
|
double dt[3] = { (tr->a).Dot(bsp->n), (tr->b).Dot(bsp->n), (tr->c).Dot(bsp->n) };
|
||||||
|
double d = bsp->d;
|
||||||
|
// Count vertices in the plane
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
if(dt[i] > d + LENGTH_EPS) {
|
||||||
|
posc++;
|
||||||
|
isPos[i] = true;
|
||||||
|
} else if(dt[i] < d - LENGTH_EPS) {
|
||||||
|
negc++;
|
||||||
|
isNeg[i] = true;
|
||||||
|
} else {
|
||||||
|
onc++;
|
||||||
|
isOn[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassifyConvex(Vector *vertex, size_t cnt, SBsp3 *node, bool insertEdge) {
|
||||||
|
bsp = node;
|
||||||
|
onc = 0;
|
||||||
|
posc = 0;
|
||||||
|
negc = 0;
|
||||||
|
|
||||||
|
AllocClassify(cnt);
|
||||||
|
AllocOn();
|
||||||
|
|
||||||
|
for(size_t i = 0; i < cnt; i++) {
|
||||||
|
double dt = bsp->n.Dot(vertex[i]);
|
||||||
|
isPos[i] = isNeg[i] = isOn[i] = false;
|
||||||
|
if(fabs(dt - bsp->d) < LENGTH_EPS) {
|
||||||
|
isOn[i] = true;
|
||||||
|
if(onc < 2) {
|
||||||
|
on[onc] = vertex[i];
|
||||||
|
}
|
||||||
|
onc++;
|
||||||
|
} else if(dt > bsp->d) {
|
||||||
|
isPos[i] = true;
|
||||||
|
posc++;
|
||||||
|
} else {
|
||||||
|
isNeg[i] = true;
|
||||||
|
negc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onc != 2 && onc != 1 && onc != 0) return false;
|
||||||
|
if(onc == 2) {
|
||||||
|
if(insertEdge) {
|
||||||
|
Vector e01 = (vertex[1]).Minus(vertex[0]);
|
||||||
|
Vector e12 = (vertex[2]).Minus(vertex[1]);
|
||||||
|
Vector out = e01.Cross(e12);
|
||||||
|
SEdge se = SEdge::From(on[0], on[1]);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassifyConvexVertices(Vector *vertex, size_t cnt, bool insertEdges) {
|
||||||
|
Vector inter[2];
|
||||||
|
int inters = 0;
|
||||||
|
|
||||||
|
npos = 0;
|
||||||
|
nneg = 0;
|
||||||
|
|
||||||
|
// Enlarge vertices list to consider two intersections
|
||||||
|
AllocVertices(cnt + 4);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < cnt; i++) {
|
||||||
|
size_t ip = WRAP((i + 1), cnt);
|
||||||
|
|
||||||
|
if(isPos[i]) {
|
||||||
|
vpos[npos++] = vertex[i];
|
||||||
|
}
|
||||||
|
if(isNeg[i]) {
|
||||||
|
vneg[nneg++] = vertex[i];
|
||||||
|
}
|
||||||
|
if(isOn[i]) {
|
||||||
|
vneg[nneg++] = vertex[i];
|
||||||
|
vpos[npos++] = vertex[i];
|
||||||
|
}
|
||||||
|
if((isPos[i] && isNeg[ip]) || (isNeg[i] && isPos[ip])) {
|
||||||
|
Vector vi = bsp->IntersectionWith(vertex[i], vertex[ip]);
|
||||||
|
vpos[npos++] = vi;
|
||||||
|
vneg[nneg++] = vi;
|
||||||
|
|
||||||
|
if(inters >= 2) return false; // triangulate: XXX shouldn't happen but does
|
||||||
|
inter[inters++] = vi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ssassert(npos <= cnt + 1 && nneg <= cnt + 1, "Impossible");
|
||||||
|
|
||||||
|
if(insertEdges) {
|
||||||
|
Vector e01 = (vertex[1]).Minus(vertex[0]);
|
||||||
|
Vector e12 = (vertex[2]).Minus(vertex[1]);
|
||||||
|
Vector out = e01.Cross(e12);
|
||||||
|
if(inters == 2) {
|
||||||
|
SEdge se = SEdge::From(inter[0], inter[1]);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
||||||
|
} else if(inters == 1 && onc == 1) {
|
||||||
|
SEdge se = SEdge::From(inter[0], on[0]);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
||||||
|
} else if(inters == 0 && onc == 2) {
|
||||||
|
// We already handled this on-plane existing edge
|
||||||
|
} else {
|
||||||
|
return false; //triangulate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nneg < 3 || npos < 3) return false; // triangulate; // XXX
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessEdgeInsert() {
|
||||||
|
ssassert(onc == 2, "Impossible");
|
||||||
|
|
||||||
|
Vector a, b;
|
||||||
|
if (!isOn[0]) { a = tr->b; b = tr->c; }
|
||||||
|
else if(!isOn[1]) { a = tr->c; b = tr->a; }
|
||||||
|
else if(!isOn[2]) { a = tr->a; b = tr->b; }
|
||||||
|
else ssassert(false, "Impossible");
|
||||||
|
|
||||||
|
SEdge se = SEdge::From(a, b);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, tr->Normal());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SplitIntoTwoTriangles(bool insertEdge) {
|
||||||
|
ssassert(posc == 1 && negc == 1 && onc == 1, "Impossible");
|
||||||
|
|
||||||
|
bool bpos;
|
||||||
|
Vector a, b, c;
|
||||||
|
|
||||||
|
// Standardize so that a is on the plane
|
||||||
|
if (isOn[0]) { a = tr->a; b = tr->b; c = tr->c; bpos = isPos[1];
|
||||||
|
} else if(isOn[1]) { a = tr->b; b = tr->c; c = tr->a; bpos = isPos[2];
|
||||||
|
} else if(isOn[2]) { a = tr->c; b = tr->a; c = tr->b; bpos = isPos[0];
|
||||||
|
} else ssassert(false, "Impossible");
|
||||||
|
|
||||||
|
AllocTriangles();
|
||||||
|
Vector bPc = bsp->IntersectionWith(b, c);
|
||||||
|
*btri = STriangle::From(tr->meta, a, b, bPc);
|
||||||
|
*ctri = STriangle::From(tr->meta, c, a, bPc);
|
||||||
|
|
||||||
|
if(insertEdge) {
|
||||||
|
SEdge se = SEdge::From(a, bPc);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, tr->Normal());
|
||||||
|
}
|
||||||
|
|
||||||
|
return bpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SplitIntoTwoPieces(bool insertEdge) {
|
||||||
|
Vector a, b, c;
|
||||||
|
if(posc == 2 && negc == 1) {
|
||||||
|
// Standardize so that a is on one side, and b and c are on the other.
|
||||||
|
if (isNeg[0]) { a = tr->a; b = tr->b; c = tr->c;
|
||||||
|
} else if(isNeg[1]) { a = tr->b; b = tr->c; c = tr->a;
|
||||||
|
} else if(isNeg[2]) { a = tr->c; b = tr->a; c = tr->b;
|
||||||
|
} else ssassert(false, "Impossible");
|
||||||
|
} else if(posc == 1 && negc == 2) {
|
||||||
|
if (isPos[0]) { a = tr->a; b = tr->b; c = tr->c;
|
||||||
|
} else if(isPos[1]) { a = tr->b; b = tr->c; c = tr->a;
|
||||||
|
} else if(isPos[2]) { a = tr->c; b = tr->a; c = tr->b;
|
||||||
|
} else ssassert(false, "Impossible");
|
||||||
|
} else ssassert(false, "Impossible");
|
||||||
|
|
||||||
|
Vector aPb = bsp->IntersectionWith(a, b);
|
||||||
|
Vector cPa = bsp->IntersectionWith(c, a);
|
||||||
|
AllocTriangle();
|
||||||
|
AllocQuad();
|
||||||
|
|
||||||
|
*btri = STriangle::From(tr->meta, a, aPb, cPa);
|
||||||
|
|
||||||
|
vpos[0] = aPb;
|
||||||
|
vpos[1] = b;
|
||||||
|
vpos[2] = c;
|
||||||
|
vpos[3] = cPa;
|
||||||
|
|
||||||
|
if(insertEdge) {
|
||||||
|
SEdge se = SEdge::From(aPb, cPa);
|
||||||
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, btri->Normal());
|
||||||
|
}
|
||||||
|
|
||||||
|
return posc == 2 && negc == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SBsp3 *Triangulate(SBsp3 *bsp, const STriMeta &meta, Vector *vertex,
|
||||||
|
size_t cnt, SMesh *instead) {
|
||||||
|
for(size_t i = 0; i < cnt - 2; i++) {
|
||||||
|
STriangle tr = STriangle::From(meta, vertex[0], vertex[i + 1], vertex[i + 2]);
|
||||||
|
bsp = SBsp3::InsertOrCreate(bsp, &tr, instead);
|
||||||
|
}
|
||||||
|
return bsp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SBsp3::InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, size_t n,
|
||||||
|
SMesh *instead) {
|
||||||
switch(how) {
|
switch(how) {
|
||||||
case BspClass::POS:
|
case BspClass::POS:
|
||||||
if(pos) {
|
if(pos) {
|
||||||
|
@ -145,124 +404,35 @@ void SBsp3::InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, int n,
|
||||||
|
|
||||||
default: ssassert(false, "Unexpected BSP insert type");
|
default: ssassert(false, "Unexpected BSP insert type");
|
||||||
}
|
}
|
||||||
int i;
|
|
||||||
for(i = 0; i < n - 2; i++) {
|
for(size_t i = 0; i < n - 2; i++) {
|
||||||
STriangle tr = STriangle::From(meta,
|
STriangle tr = STriangle::From(meta,
|
||||||
vertex[0], vertex[i+1], vertex[i+2]);
|
vertex[0], vertex[i+1], vertex[i+2]);
|
||||||
InsertHow(how, &tr, instead);
|
InsertHow(how, &tr, instead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SBsp3 *SBsp3::InsertConvex(STriMeta meta, Vector *vertex, int cnt,
|
SBsp3 *SBsp3::InsertConvex(STriMeta meta, Vector *vertex, size_t cnt, SMesh *instead) {
|
||||||
SMesh *instead)
|
BspUtil *u = BspUtil::Alloc();
|
||||||
{
|
if(u->ClassifyConvex(vertex, cnt, this, !instead)) {
|
||||||
Vector e01 = (vertex[1]).Minus(vertex[0]);
|
if(u->posc == 0) {
|
||||||
Vector e12 = (vertex[2]).Minus(vertex[1]);
|
InsertConvexHow(BspClass::NEG, meta, vertex, cnt, instead);
|
||||||
Vector out = e01.Cross(e12);
|
return this;
|
||||||
|
}
|
||||||
#define MAX_VERTICES 50
|
if(u->negc == 0) {
|
||||||
if(cnt+1 >= MAX_VERTICES) goto triangulate;
|
InsertConvexHow(BspClass::POS, meta, vertex, cnt, instead);
|
||||||
|
return this;
|
||||||
int i;
|
|
||||||
Vector on[2];
|
|
||||||
bool isPos[MAX_VERTICES];
|
|
||||||
bool isNeg[MAX_VERTICES];
|
|
||||||
bool isOn[MAX_VERTICES];
|
|
||||||
int posc, negc, onc; posc = negc = onc = 0;
|
|
||||||
for(i = 0; i < cnt; i++) {
|
|
||||||
double dt = n.Dot(vertex[i]);
|
|
||||||
isPos[i] = isNeg[i] = isOn[i] = false;
|
|
||||||
if(fabs(dt - d) < LENGTH_EPS) {
|
|
||||||
isOn[i] = true;
|
|
||||||
if(onc < 2) {
|
|
||||||
on[onc] = vertex[i];
|
|
||||||
}
|
|
||||||
onc++;
|
|
||||||
} else if(dt > d) {
|
|
||||||
isPos[i] = true;
|
|
||||||
posc++;
|
|
||||||
} else {
|
|
||||||
isNeg[i] = true;
|
|
||||||
negc++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(onc != 2 && onc != 1 && onc != 0) goto triangulate;
|
|
||||||
|
|
||||||
if(onc == 2) {
|
if(u->ClassifyConvexVertices(vertex, cnt, !instead)) {
|
||||||
if(!instead) {
|
InsertConvexHow(BspClass::NEG, meta, u->vneg, u->nneg, instead);
|
||||||
SEdge se = SEdge::From(on[0], on[1]);
|
InsertConvexHow(BspClass::POS, meta, u->vpos, u->npos, instead);
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, out);
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(posc == 0) {
|
|
||||||
InsertConvexHow(BspClass::NEG, meta, vertex, cnt, instead);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
if(negc == 0) {
|
|
||||||
InsertConvexHow(BspClass::POS, meta, vertex, cnt, instead);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector vpos[MAX_VERTICES];
|
|
||||||
Vector vneg[MAX_VERTICES];
|
|
||||||
int npos, nneg; npos = nneg = 0;
|
|
||||||
|
|
||||||
Vector inter[2];
|
|
||||||
int inters; inters = 0;
|
|
||||||
|
|
||||||
for(i = 0; i < cnt; i++) {
|
|
||||||
int ip = WRAP((i + 1), cnt);
|
|
||||||
|
|
||||||
if(isPos[i]) {
|
|
||||||
vpos[npos++] = vertex[i];
|
|
||||||
}
|
|
||||||
if(isNeg[i]) {
|
|
||||||
vneg[nneg++] = vertex[i];
|
|
||||||
}
|
|
||||||
if(isOn[i]) {
|
|
||||||
vneg[nneg++] = vertex[i];
|
|
||||||
vpos[npos++] = vertex[i];
|
|
||||||
}
|
|
||||||
if((isPos[i] && isNeg[ip]) || (isNeg[i] && isPos[ip])) {
|
|
||||||
Vector vi = IntersectionWith(vertex[i], vertex[ip]);
|
|
||||||
vpos[npos++] = vi;
|
|
||||||
vneg[nneg++] = vi;
|
|
||||||
|
|
||||||
if(inters >= 2) goto triangulate; // XXX shouldn't happen but does
|
|
||||||
inter[inters++] = vi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(npos > cnt + 1 || nneg > cnt + 1) ssassert(false, "Impossible");
|
|
||||||
|
|
||||||
if(!instead) {
|
|
||||||
if(inters == 2) {
|
|
||||||
SEdge se = SEdge::From(inter[0], inter[1]);
|
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, out);
|
|
||||||
} else if(inters == 1 && onc == 1) {
|
|
||||||
SEdge se = SEdge::From(inter[0], on[0]);
|
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, out);
|
|
||||||
} else if(inters == 0 && onc == 2) {
|
|
||||||
// We already handled this on-plane existing edge
|
|
||||||
} else {
|
|
||||||
goto triangulate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(nneg < 3 || npos < 3) goto triangulate; // XXX
|
|
||||||
|
|
||||||
InsertConvexHow(BspClass::NEG, meta, vneg, nneg, instead);
|
|
||||||
InsertConvexHow(BspClass::POS, meta, vpos, npos, instead);
|
|
||||||
return this;
|
|
||||||
|
|
||||||
triangulate:
|
|
||||||
// We don't handle the special case for this; do it as triangles
|
// We don't handle the special case for this; do it as triangles
|
||||||
SBsp3 *r = this;
|
return BspUtil::Triangulate(this, meta, vertex, cnt, instead);
|
||||||
for(i = 0; i < cnt - 2; i++) {
|
|
||||||
STriangle tr = STriangle::From(meta,
|
|
||||||
vertex[0], vertex[i+1], vertex[i+2]);
|
|
||||||
r = InsertOrCreate(r, &tr, instead);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SBsp3 *SBsp3::InsertOrCreate(SBsp3 *where, STriangle *tr, SMesh *instead) {
|
SBsp3 *SBsp3::InsertOrCreate(SBsp3 *where, STriangle *tr, SMesh *instead) {
|
||||||
|
@ -288,45 +458,22 @@ SBsp3 *SBsp3::InsertOrCreate(SBsp3 *where, STriangle *tr, SMesh *instead) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SBsp3::Insert(STriangle *tr, SMesh *instead) {
|
void SBsp3::Insert(STriangle *tr, SMesh *instead) {
|
||||||
double dt[3] = { (tr->a).Dot(n), (tr->b).Dot(n), (tr->c).Dot(n) };
|
BspUtil *u = BspUtil::Alloc();
|
||||||
|
u->ClassifyTriangle(tr, this);
|
||||||
int inc = 0, posc = 0, negc = 0;
|
|
||||||
bool isPos[3] = {}, isNeg[3] = {}, isOn[3] = {};
|
|
||||||
// Count vertices in the plane
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
if(fabs(dt[i] - d) < LENGTH_EPS) {
|
|
||||||
inc++;
|
|
||||||
isOn[i] = true;
|
|
||||||
} else if(dt[i] > d) {
|
|
||||||
posc++;
|
|
||||||
isPos[i] = true;
|
|
||||||
} else {
|
|
||||||
negc++;
|
|
||||||
isNeg[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All vertices in-plane
|
// All vertices in-plane
|
||||||
if(inc == 3) {
|
if(u->onc == 3) {
|
||||||
InsertHow(BspClass::COPLANAR, tr, instead);
|
InsertHow(BspClass::COPLANAR, tr, instead);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No split required
|
// No split required
|
||||||
if(posc == 0 || negc == 0) {
|
if(u->posc == 0 || u->negc == 0) {
|
||||||
if(inc == 2) {
|
if(!instead && u->onc == 2) {
|
||||||
Vector a, b;
|
u->ProcessEdgeInsert();
|
||||||
if (!isOn[0]) { a = tr->b; b = tr->c; }
|
|
||||||
else if(!isOn[1]) { a = tr->c; b = tr->a; }
|
|
||||||
else if(!isOn[2]) { a = tr->a; b = tr->b; }
|
|
||||||
else ssassert(false, "Impossible");
|
|
||||||
if(!instead) {
|
|
||||||
SEdge se = SEdge::From(a, b);
|
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, tr->Normal());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(posc > 0) {
|
if(u->posc > 0) {
|
||||||
InsertHow(BspClass::POS, tr, instead);
|
InsertHow(BspClass::POS, tr, instead);
|
||||||
} else {
|
} else {
|
||||||
InsertHow(BspClass::NEG, tr, instead);
|
InsertHow(BspClass::NEG, tr, instead);
|
||||||
|
@ -334,74 +481,29 @@ void SBsp3::Insert(STriangle *tr, SMesh *instead) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The polygon must be split into two pieces, one above, one below.
|
// The polygon must be split into two triangles, one above, one below.
|
||||||
Vector a, b, c;
|
if(u->posc == 1 && u->negc == 1 && u->onc == 1) {
|
||||||
|
if(u->SplitIntoTwoTriangles(!instead)) {
|
||||||
if(posc == 1 && negc == 1 && inc == 1) {
|
InsertHow(BspClass::POS, u->btri, instead);
|
||||||
bool bpos;
|
InsertHow(BspClass::NEG, u->ctri, instead);
|
||||||
// Standardize so that a is on the plane
|
|
||||||
if (isOn[0]) { a = tr->a; b = tr->b; c = tr->c; bpos = isPos[1];
|
|
||||||
} else if(isOn[1]) { a = tr->b; b = tr->c; c = tr->a; bpos = isPos[2];
|
|
||||||
} else if(isOn[2]) { a = tr->c; b = tr->a; c = tr->b; bpos = isPos[0];
|
|
||||||
} else ssassert(false, "Impossible");
|
|
||||||
|
|
||||||
Vector bPc = IntersectionWith(b, c);
|
|
||||||
STriangle btri = STriangle::From(tr->meta, a, b, bPc);
|
|
||||||
STriangle ctri = STriangle::From(tr->meta, c, a, bPc);
|
|
||||||
|
|
||||||
if(bpos) {
|
|
||||||
InsertHow(BspClass::POS, &btri, instead);
|
|
||||||
InsertHow(BspClass::NEG, &ctri, instead);
|
|
||||||
} else {
|
} else {
|
||||||
InsertHow(BspClass::POS, &ctri, instead);
|
InsertHow(BspClass::POS, u->ctri, instead);
|
||||||
InsertHow(BspClass::NEG, &btri, instead);
|
InsertHow(BspClass::NEG, u->btri, instead);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!instead) {
|
|
||||||
SEdge se = SEdge::From(a, bPc);
|
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, tr->Normal());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(posc == 2 && negc == 1) {
|
// The polygon must be split into two pieces: a triangle and a quad.
|
||||||
// Standardize so that a is on one side, and b and c are on the other.
|
if(u->SplitIntoTwoPieces(!instead)) {
|
||||||
if (isNeg[0]) { a = tr->a; b = tr->b; c = tr->c;
|
InsertConvexHow(BspClass::POS, tr->meta, u->vpos, 4, instead);
|
||||||
} else if(isNeg[1]) { a = tr->b; b = tr->c; c = tr->a;
|
InsertHow(BspClass::NEG, u->btri, instead);
|
||||||
} else if(isNeg[2]) { a = tr->c; b = tr->a; c = tr->b;
|
|
||||||
} else ssassert(false, "Impossible");
|
|
||||||
|
|
||||||
} else if(posc == 1 && negc == 2) {
|
|
||||||
if (isPos[0]) { a = tr->a; b = tr->b; c = tr->c;
|
|
||||||
} else if(isPos[1]) { a = tr->b; b = tr->c; c = tr->a;
|
|
||||||
} else if(isPos[2]) { a = tr->c; b = tr->a; c = tr->b;
|
|
||||||
} else ssassert(false, "Impossible");
|
|
||||||
} else ssassert(false, "Impossible");
|
|
||||||
|
|
||||||
Vector aPb = IntersectionWith(a, b);
|
|
||||||
Vector cPa = IntersectionWith(c, a);
|
|
||||||
|
|
||||||
STriangle alone = STriangle::From(tr->meta, a, aPb, cPa);
|
|
||||||
Vector quad[4] = { aPb, b, c, cPa };
|
|
||||||
|
|
||||||
if(posc == 2 && negc == 1) {
|
|
||||||
InsertConvexHow(BspClass::POS, tr->meta, quad, 4, instead);
|
|
||||||
InsertHow(BspClass::NEG, &alone, instead);
|
|
||||||
} else {
|
} else {
|
||||||
InsertConvexHow(BspClass::NEG, tr->meta, quad, 4, instead);
|
InsertConvexHow(BspClass::NEG, tr->meta, u->vpos, 4, instead);
|
||||||
InsertHow(BspClass::POS, &alone, instead);
|
InsertHow(BspClass::POS, u->btri, instead);
|
||||||
}
|
}
|
||||||
if(!instead) {
|
|
||||||
SEdge se = SEdge::From(aPb, cPa);
|
|
||||||
edges = SBsp2::InsertOrCreateEdge(edges, &se, n, alone.Normal());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SBsp3::GenerateInPaintOrder(SMesh *m) const {
|
void SBsp3::GenerateInPaintOrder(SMesh *m) const {
|
||||||
|
|
||||||
// Doesn't matter which branch we take if the normal has zero z
|
// Doesn't matter which branch we take if the normal has zero z
|
||||||
// component, so don't need a separate case for that.
|
// component, so don't need a separate case for that.
|
||||||
if(n.z < 0) {
|
if(n.z < 0) {
|
||||||
|
|
|
@ -236,9 +236,9 @@ public:
|
||||||
void Insert(STriangle *str, SMesh *instead);
|
void Insert(STriangle *str, SMesh *instead);
|
||||||
static SBsp3 *InsertOrCreate(SBsp3 *where, STriangle *str, SMesh *instead);
|
static SBsp3 *InsertOrCreate(SBsp3 *where, STriangle *str, SMesh *instead);
|
||||||
|
|
||||||
void InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, int n,
|
void InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, size_t n,
|
||||||
SMesh *instead);
|
SMesh *instead);
|
||||||
SBsp3 *InsertConvex(STriMeta meta, Vector *vertex, int n, SMesh *instead);
|
SBsp3 *InsertConvex(STriMeta meta, Vector *vertex, size_t n, SMesh *instead);
|
||||||
|
|
||||||
void InsertInPlane(bool pos2, STriangle *tr, SMesh *m);
|
void InsertInPlane(bool pos2, STriangle *tr, SMesh *m);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue