Add extra split planes (not coplanar with any triangle) to the BSP

while building it. That may improve performance, by building a more
balanced tree and actually reducing splitting. Not dramatic
improvements, though; half the triangles for some parts, but no
change or slightly worse for others.

[git-p4: depot-paths = "//depot/solvespace/": change = 1737]
solver
Jonathan Westhues 2008-05-24 04:23:25 -08:00
parent 4d7ffc85f9
commit 70ccbebc8f
3 changed files with 146 additions and 10 deletions

View File

@ -1195,6 +1195,7 @@ void GraphicsWindow::Paint(int w, int h) {
for(i = 0; i < ma->l.n; i++) {
pb->Insert(&(ma->l.elem[i]), &br, false, false);
}
dbp("triangles in = %d %d out = %d", ma->l.n, mb->l.n, br.l.n);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
@ -1202,7 +1203,7 @@ void GraphicsWindow::Paint(int w, int h) {
glDisable(GL_LIGHTING);
glxLockColorTo(0, 1, 0);
glEnable(GL_DEPTH_TEST);
glxDebugMesh(&br);
// glxDebugMesh(&br);
br.Clear();
FreeAllTemporary();

148
mesh.cpp
View File

@ -13,25 +13,155 @@ void SMesh::AddTriangle(Vector n, Vector a, Vector b, Vector c) {
AddTriangle(c, b, a);
}
}
void SMesh::AddTriangle(Vector a, Vector b, Vector c) {
STriangle t; ZERO(&t);
t.a = a;
t.b = b;
t.c = c;
l.Add(&t);
AddTriangle(&t);
}
void SMesh::AddTriangle(STriangle *st) {
l.Add(st);
}
void SMesh::DoBounding(Vector v, Vector *vmax, Vector *vmin) {
vmax->x = max(vmax->x, v.x);
vmax->y = max(vmax->y, v.y);
vmax->z = max(vmax->z, v.z);
vmin->x = min(vmin->x, v.x);
vmin->y = min(vmin->y, v.y);
vmin->z = min(vmin->z, v.z);
}
void SMesh::GetBounding(Vector *vmax, Vector *vmin) {
int i;
*vmin = Vector::MakeFrom( 1e12, 1e12, 1e12);
*vmax = Vector::MakeFrom(-1e12, -1e12, -1e12);
for(i = 0; i < l.n; i++) {
STriangle *st = &(l.elem[i]);
DoBounding(st->a, vmax, vmin);
DoBounding(st->b, vmax, vmin);
DoBounding(st->c, vmax, vmin);
}
}
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
SBsp3 *SBsp3::FromMesh(SMesh *m) {
int i;
SBsp3 *ret = NULL;
for(i = 0; i < m->l.n; i++) {
ret = ret->Insert(&(m->l.elem[i]), NULL, false, false);
double SBsp3::SplitFactor(int npos, int nneg, int nsplit) {
double r, ntot = npos + nneg + nsplit;
// A larger split factor is more desirable; best possible is 0.5
r = (min(npos, nneg)) / ntot;
r *= pow((npos + nneg) / ntot, 3);
return r;
}
return ret;
SBsp3 *SBsp3::ChoosePartition(SMesh *m) {
if(m->l.n < 20) return NULL;
Vector vmax, vmin;
m->GetBounding(&vmax, &vmin);
double x = (vmax.x + vmin.x)/2;
double y = (vmax.y + vmin.y)/2;
double z = (vmax.z + vmin.z)/2;
int px = 0, nx = 0, sx = 0;
int py = 0, ny = 0, sy = 0;
int pz = 0, nz = 0, sz = 0;
int i, j;
for(i = 0; i < m->l.n; i++) {
STriangle *tr = &(m->l.elem[i]);
int vx = 0, vy = 0, vz = 0;
for(j = 0; j < 3; j++) {
Vector a = (j == 0) ? tr->a : ((j == 1) ? tr->b : tr->c);
if(a.x < x) vx++;
if(a.y < y) vy++;
if(a.z < z) vz++;
}
if(vx == 3) { px++; } else if(vx == 0) { nx++; } else { sx++; }
if(vy == 3) { py++; } else if(vy == 0) { ny++; } else { sy++; }
if(vz == 3) { pz++; } else if(vz == 0) { nz++; } else { sz++; }
}
double fx = SplitFactor(px, nx, sx);
double fy = SplitFactor(py, ny, sy);
double fz = SplitFactor(pz, nz, sz);
double fmax = max(fx, max(fy, fz));
Vector nn;
double dd;
if(fmax == fx) {
nn = Vector::MakeFrom(1, 0, 0);
dd = x;
} else if(fmax == fy) {
nn = Vector::MakeFrom(0, 1, 0);
dd = y;
} else if(fmax == fz) {
nn = Vector::MakeFrom(0, 0, 1);
dd = z;
} else oops();
SBsp3 *r = Alloc();
r->n = nn;
r->d = dd;
SMesh mpos, mneg;
ZERO(&mpos); ZERO(&mneg);
for(i = 0; i < m->l.n; i++) {
STriangle *tr = &(m->l.elem[i]);
double da = (tr->a).Dot(nn);
double db = (tr->b).Dot(nn);
double dc = (tr->c).Dot(nn);
if(da > dd && db > dd && dc > dd) {
mpos.AddTriangle(tr);
}
if(da < dd && db < dd && dc < dd) {
mneg.AddTriangle(tr);
}
}
if(mpos.l.n >= m->l.n || mneg.l.n >= m->l.n) {
// We show no signs of terminating; bad.
oops();
}
r->pos = ChoosePartition(&mpos);
r->neg = ChoosePartition(&mneg);
mpos.Clear(); mneg.Clear();
return r;
}
SBsp3 *SBsp3::FromMesh(SMesh *m) {
SBsp3 *bsp3 = ChoosePartition(m);
Vector vmax, vmin;
m->GetBounding(&vmax, &vmin);
Vector adj = { 1, 1, 1 };
vmax = vmax.Plus(adj); vmin = vmin.Minus(adj);
int i;
for(i = 0; i < m->l.n; i++) {
bsp3 = bsp3->Insert(&(m->l.elem[i]), NULL, false, false);
}
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom( 1, 0, 0), vmax.x);
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom( 0, 1, 0), vmax.y);
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom( 0, 0, 1), vmax.z);
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom(-1, 0, 0), -vmin.x);
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom( 0, -1, 0), -vmin.y);
bsp3 = bsp3->InsertExtraSplit(Vector::MakeFrom( 0, 0, -1), -vmin.z);
return bsp3;
}
SBsp3 *SBsp3::InsertExtraSplit(Vector nn, double dd) {
SBsp3 *r = Alloc();
r->n = nn;
r->d = dd;
r->neg = this;
r->pos = NULL;
return r;
}
Vector SBsp3::IntersectionWith(Vector a, Vector b) {
@ -114,7 +244,7 @@ alt:
} else {
// I suppose this actually is allowed to happen, if the coplanar
// face is the leaf, and all of its neighbors are earlier in tree?
InsertInPlane(true, tr, instead, flip, cpl);
InsertInPlane(false, tr, instead, flip, cpl);
}
}
}

View File

@ -130,13 +130,15 @@ public:
SBsp2 *edges;
static SBsp3 *Alloc(void);
static double SplitFactor(int npos, int nneg, int nsplit);
static SBsp3 *ChoosePartition(SMesh *m);
SBsp3 *InsertExtraSplit(Vector nn, double dd);
static SBsp3 *FromMesh(SMesh *m);
Vector IntersectionWith(Vector a, Vector b);
static const int POS = 100, NEG = 101, COPLANAR = 200;
void InsertHow(int how, STriangle *str, SMesh *instead, bool flip,bool cpl);
SBsp3 *Insert(STriangle *str, SMesh *instead, bool flip, bool cpl);
void InsertInPlane(bool pos2, STriangle *tr, SMesh *m, bool flip, bool cpl);
@ -150,8 +152,11 @@ public:
SList<STriangle> l;
void Clear(void);
void AddTriangle(STriangle *st);
void AddTriangle(Vector a, Vector b, Vector c);
void AddTriangle(Vector n, Vector a, Vector b, Vector c);
void DoBounding(Vector v, Vector *vmax, Vector *vmin);
void GetBounding(Vector *vmax, Vector *vmin);
};
#endif