From 70ccbebc8f14a65795474bfac8d33c8cf5d22af4 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sat, 24 May 2008 04:23:25 -0800 Subject: [PATCH] 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] --- graphicswin.cpp | 3 +- mesh.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++--- polygon.h | 7 ++- 3 files changed, 146 insertions(+), 10 deletions(-) diff --git a/graphicswin.cpp b/graphicswin.cpp index 6faa47fc..86362533 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -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(); diff --git a/mesh.cpp b/mesh.cpp index 996f3de5..ef1fd728 100644 --- a/mesh.cpp +++ b/mesh.cpp @@ -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; +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; +} + +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++) { - ret = ret->Insert(&(m->l.elem[i]), NULL, false, false); + 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++; } } - return ret; + 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); } } } diff --git a/polygon.h b/polygon.h index 5871c3de..13dcfac6 100644 --- a/polygon.h +++ b/polygon.h @@ -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 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