From 0ad8644df4e93277406ac6c46adc19ecc6b56cef Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sat, 24 May 2008 15:10:00 -0800 Subject: [PATCH] As we break things against the BSP, keep an arbitrary convex polygon, not just triangles. This helps to avoid needless splitting. Also test if an entire triangle got inserted in multiple pieces; if yes, back things out, and just insert the triangle. Also remove the extra partition stuff, since it didn't seem to help consistently, and this does. Still could do some better merging, in the case where an inserted triangle does not get fully inserted, but we can find a better triangulation than what the BSP naturally gives. [git-p4: depot-paths = "//depot/solvespace/": change = 1739] --- graphicswin.cpp | 11 +- mesh.cpp | 368 ++++++++++++++++++++++++++---------------------- polygon.h | 41 ++++-- 3 files changed, 236 insertions(+), 184 deletions(-) diff --git a/graphicswin.cpp b/graphicswin.cpp index aaac850..3c48e48 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -1189,12 +1189,11 @@ void GraphicsWindow::Paint(int w, int h) { SBsp3 *pb = SBsp3::FromMesh(mb); SMesh br; ZERO(&br); - for(i = 0; i < mb->l.n; i++) { - pa->Insert(&(mb->l.elem[i]), &br, true, false); - } - for(i = 0; i < ma->l.n; i++) { - pb->Insert(&(ma->l.elem[i]), &br, false, false); - } + br.flipNormal = true; br.keepCoplanar = false; + br.AddAgainstBsp(mb, pa); + br.flipNormal = false; br.keepCoplanar = false; + br.AddAgainstBsp(ma, pb); + dbp("triangles in = %d %d out = %d", ma->l.n, mb->l.n, br.l.n); glEnable(GL_DEPTH_TEST); diff --git a/mesh.cpp b/mesh.cpp index b5fd3bf..8f69045 100644 --- a/mesh.cpp +++ b/mesh.cpp @@ -49,125 +49,37 @@ void SMesh::GetBounding(Vector *vmax, Vector *vmin) { } } +void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) { + int i; + for(i = 0; i < srcm->l.n; i++) { + STriangle *st = &(srcm->l.elem[i]); + int pn = l.n; + atLeastOneDiscarded = false; + bsp3->Insert(st, this); + if(!atLeastOneDiscarded && (l.n != (pn+1))) { + l.n = pn; + if(flipNormal) { + AddTriangle(st->c, st->b, st->a); + } else { + AddTriangle(st->a, st->b, st->c); + } + continue; + } + } +} + SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); } SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); } -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++) { - 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); - + SBsp3 *bsp3 = NULL; int i; for(i = 0; i < m->l.n; i++) { - bsp3 = bsp3->Insert(&(m->l.elem[i]), NULL, false, false); + bsp3 = bsp3->Insert(&(m->l.elem[i]), NULL); } - - 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) { double da = a.Dot(n) - d; double db = b.Dot(n) - d; @@ -177,9 +89,7 @@ Vector SBsp3::IntersectionWith(Vector a, Vector b) { return (a.ScaledBy(db/dab)).Plus(b.ScaledBy(-da/dab)); } -void SBsp3::InsertInPlane(bool pos2, STriangle *tr, - SMesh *m, bool flip, bool cpl) -{ +void SBsp3::InsertInPlane(bool pos2, STriangle *tr, SMesh *m) { Vector tc = ((tr->a).Plus(tr->b).Plus(tr->c)).ScaledBy(1.0/3); bool onFace = false; @@ -195,30 +105,27 @@ void SBsp3::InsertInPlane(bool pos2, STriangle *tr, ll = ll->more; } - if(flip) { - if(cpl) oops(); - if(!pos2 && (!onFace || !sameNormal)) { - m->AddTriangle(tr->c, tr->b, tr->a); - } + if(m->flipNormal && !pos2 && (!onFace || !sameNormal)) { + m->AddTriangle(tr->c, tr->b, tr->a); + } else if(!(m->flipNormal) && (pos2 || + (onFace && sameNormal && m->keepCoplanar))) + { + m->AddTriangle(tr->a, tr->b, tr->c); } else { - if(pos2 || (onFace && sameNormal && cpl)) { - m->AddTriangle(tr->a, tr->b, tr->c); - } + m->atLeastOneDiscarded = true; } } -void SBsp3::InsertHow(int how, STriangle *tr, - SMesh *instead, bool flip, bool cpl) -{ +void SBsp3::InsertHow(int how, STriangle *tr, SMesh *instead) { switch(how) { case POS: if(instead && !pos) goto alt; - pos = pos->Insert(tr, instead, flip, cpl); + pos = pos->Insert(tr, instead); break; case NEG: if(instead && !neg) goto alt; - neg = neg->Insert(tr, instead, flip, cpl); + neg = neg->Insert(tr, instead); break; case COPLANAR: { @@ -236,24 +143,153 @@ void SBsp3::InsertHow(int how, STriangle *tr, return; alt: - if(how == POS && !flip) { + if(how == POS && !(instead->flipNormal)) { instead->AddTriangle(tr->a, tr->b, tr->c); - } - if(how == NEG && flip) { + } else if(how == NEG && instead->flipNormal) { instead->AddTriangle(tr->c, tr->b, tr->a); - } - if(how == COPLANAR) { + } else if(how == COPLANAR) { if(edges) { - edges->InsertTriangle(tr, instead, this, flip, cpl); + edges->InsertTriangle(tr, instead, this); } 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(false, tr, instead, flip, cpl); + InsertInPlane(false, tr, instead); } + } else { + instead->atLeastOneDiscarded = true; } } -SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead, bool flip, bool cpl) { +void SBsp3::InsertConvexHow(int how, Vector *vertex, int n, SMesh *instead) { + switch(how) { + case POS: + if(pos) { + pos = pos->InsertConvex(vertex, n, instead); + return; + } + break; + + case NEG: + if(neg) { + neg = neg->InsertConvex(vertex, n, instead); + return; + } + break; + + default: oops(); + } + int i; + for(i = 0; i < n - 2; i++) { + STriangle tr = { 0, vertex[0], vertex[i+1], vertex[i+2] }; + InsertHow(how, &tr, instead); + } +} + +SBsp3 *SBsp3::InsertConvex(Vector *vertex, int cnt, SMesh *instead) { + Vector e01 = (vertex[1]).Minus(vertex[0]); + Vector e12 = (vertex[2]).Minus(vertex[1]); + Vector out = e01.Cross(e12); + + int i; + Vector on[2]; + bool *isPos = (bool *)AllocTemporary(cnt*sizeof(bool)); + bool *isNeg = (bool *)AllocTemporary(cnt*sizeof(bool)); + bool *isOn = (bool *)AllocTemporary(cnt*sizeof(bool)); + int posc = 0, negc = 0, 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(!instead) { + SEdge se = { 0, on[0], on[1] }; + edges = edges->InsertEdge(&se, n, out); + } + } + + if(posc == 0) { + InsertConvexHow(NEG, vertex, cnt, instead); + return this; + } + if(negc == 0) { + InsertConvexHow(POS, vertex, cnt, instead); + return this; + } + + Vector *vpos = (Vector *)AllocTemporary((cnt+1)*sizeof(Vector)); + Vector *vneg = (Vector *)AllocTemporary((cnt+1)*sizeof(Vector)); + int npos = 0, nneg = 0; + + Vector inter[2]; + int inters = 0; + + for(i = 0; i < cnt; i++) { + int ip = (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) oops(); + inter[inters++] = vi; + } + } + if(npos > cnt + 1 || nneg > cnt + 1) oops(); + + if(!instead) { + if(inters == 2) { + SEdge se = { 0, inter[0], inter[1] }; + edges = edges->InsertEdge(&se, n, out); + } else if(inters == 1 && onc == 1) { + SEdge se = { 0, inter[0], on[0] }; + edges = edges->InsertEdge(&se, n, out); + } else if(inters == 0 && onc == 2) { + // We already handled this on-plane existing edge + } else oops(); + } + if(nneg < 3 || npos < 3) oops(); + + InsertConvexHow(NEG, vneg, nneg, instead); + InsertConvexHow(POS, vpos, npos, instead); + return this; + +triangulate: + // We don't handle the special case for this; do it as triangles + SBsp3 *r = this; + for(i = 0; i < cnt - 2; i++) { + STriangle tr = { 0, vertex[0], vertex[i+1], vertex[i+2] }; + r = r->Insert(&tr, instead); + } + return r; +} + +SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead) { if(!this) { // Brand new node; so allocate for it, and fill us in. SBsp3 *r = Alloc(); @@ -284,7 +320,7 @@ SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead, bool flip, bool cpl) { // All vertices in-plane if(inc == 3) { - InsertHow(COPLANAR, tr, instead, flip, cpl); + InsertHow(COPLANAR, tr, instead); return this; } @@ -303,9 +339,9 @@ SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead, bool flip, bool cpl) { } if(posc > 0) { - InsertHow(POS, tr, instead, flip, cpl); + InsertHow(POS, tr, instead); } else { - InsertHow(NEG, tr, instead, flip, cpl); + InsertHow(NEG, tr, instead); } return this; } @@ -326,11 +362,11 @@ SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead, bool flip, bool cpl) { STriangle ctri = { 0, c, a, bPc }; if(bpos) { - InsertHow(POS, &btri, instead, flip, cpl); - InsertHow(NEG, &ctri, instead, flip, cpl); + InsertHow(POS, &btri, instead); + InsertHow(NEG, &ctri, instead); } else { - InsertHow(POS, &ctri, instead, flip, cpl); - InsertHow(NEG, &btri, instead, flip, cpl); + InsertHow(POS, &ctri, instead); + InsertHow(NEG, &btri, instead); } if(!instead) { @@ -359,17 +395,17 @@ SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead, bool flip, bool cpl) { Vector cPa = IntersectionWith(c, a); STriangle alone = { 0, a, aPb, cPa }; + + Vector quad[4] = { aPb, b, c, cPa }; STriangle quad1 = { 0, aPb, b, c }; STriangle quad2 = { 0, aPb, c, cPa }; if(posc == 2 && negc == 1) { - InsertHow(POS, &quad1, instead, flip, cpl); - InsertHow(POS, &quad2, instead, flip, cpl); - InsertHow(NEG, &alone, instead, flip, cpl); + InsertConvexHow(POS, quad, 4, instead); + InsertHow(NEG, &alone, instead); } else { - InsertHow(NEG, &quad1, instead, flip, cpl); - InsertHow(NEG, &quad2, instead, flip, cpl); - InsertHow(POS, &alone, instead, flip, cpl); + InsertConvexHow(NEG, quad, 4, instead); + InsertHow(POS, &alone, instead); } if(!instead) { SEdge se = { 0, aPb, cPa }; @@ -502,23 +538,21 @@ SBsp2 *SBsp2::InsertEdge(SEdge *nedge, Vector nnp, Vector out) { oops(); } -void SBsp2::InsertTriangleHow(int how, STriangle *tr, - SMesh *m, SBsp3 *bsp3, bool flip, bool cpl) -{ +void SBsp2::InsertTriangleHow(int how, STriangle *tr, SMesh *m, SBsp3 *bsp3) { switch(how) { case POS: if(pos) { - pos->InsertTriangle(tr, m, bsp3, flip, cpl); + pos->InsertTriangle(tr, m, bsp3); } else { - bsp3->InsertInPlane(true, tr, m, flip, cpl); + bsp3->InsertInPlane(true, tr, m); } break; case NEG: if(neg) { - neg->InsertTriangle(tr, m, bsp3, flip, cpl); + neg->InsertTriangle(tr, m, bsp3); } else { - bsp3->InsertInPlane(false, tr, m, flip, cpl); + bsp3->InsertInPlane(false, tr, m); } break; @@ -526,9 +560,7 @@ void SBsp2::InsertTriangleHow(int how, STriangle *tr, } } -void SBsp2::InsertTriangle(STriangle *tr, - SMesh *m, SBsp3 *bsp3, bool flip, bool cpl) -{ +void SBsp2::InsertTriangle(STriangle *tr, SMesh *m, SBsp3 *bsp3) { double dt[3] = { (tr->a).Dot(no), (tr->b).Dot(no), (tr->c).Dot(no) }; bool isPos[3], isNeg[3], isOn[3]; @@ -555,9 +587,9 @@ void SBsp2::InsertTriangle(STriangle *tr, // No split required if(posc == 0 || negc == 0) { if(posc > 0) { - InsertTriangleHow(POS, tr, m, bsp3, flip, cpl); + InsertTriangleHow(POS, tr, m, bsp3); } else { - InsertTriangleHow(NEG, tr, m, bsp3, flip, cpl); + InsertTriangleHow(NEG, tr, m, bsp3); } return; } @@ -578,11 +610,11 @@ void SBsp2::InsertTriangle(STriangle *tr, STriangle ctri = { 0, c, a, bPc }; if(bpos) { - InsertTriangleHow(POS, &btri, m, bsp3, flip, cpl); - InsertTriangleHow(NEG, &ctri, m, bsp3, flip, cpl); + InsertTriangleHow(POS, &btri, m, bsp3); + InsertTriangleHow(NEG, &ctri, m, bsp3); } else { - InsertTriangleHow(POS, &ctri, m, bsp3, flip, cpl); - InsertTriangleHow(NEG, &btri, m, bsp3, flip, cpl); + InsertTriangleHow(POS, &ctri, m, bsp3); + InsertTriangleHow(NEG, &btri, m, bsp3); } return; @@ -610,13 +642,13 @@ void SBsp2::InsertTriangle(STriangle *tr, STriangle quad2 = { 0, aPb, c, cPa }; if(posc == 2 && negc == 1) { - InsertTriangleHow(POS, &quad1, m, bsp3, flip, cpl); - InsertTriangleHow(POS, &quad2, m, bsp3, flip, cpl); - InsertTriangleHow(NEG, &alone, m, bsp3, flip, cpl); + InsertTriangleHow(POS, &quad1, m, bsp3); + InsertTriangleHow(POS, &quad2, m, bsp3); + InsertTriangleHow(NEG, &alone, m, bsp3); } else { - InsertTriangleHow(NEG, &quad1, m, bsp3, flip, cpl); - InsertTriangleHow(NEG, &quad2, m, bsp3, flip, cpl); - InsertTriangleHow(POS, &alone, m, bsp3, flip, cpl); + InsertTriangleHow(NEG, &quad1, m, bsp3); + InsertTriangleHow(NEG, &quad2, m, bsp3); + InsertTriangleHow(POS, &alone, m, bsp3); } return; diff --git a/polygon.h b/polygon.h index 13dcfac..280bee3 100644 --- a/polygon.h +++ b/polygon.h @@ -33,6 +33,23 @@ public: elem = NULL; n = elemsAllocated = 0; } + + void RemoveTagged(void) { + int src, dest; + dest = 0; + for(src = 0; src < n; src++) { + if(elem[src].tag) { + // this item should be deleted + } else { + if(src != dest) { + elem[dest] = elem[src]; + } + dest++; + } + } + n = dest; + // and elemsAllocated is untouched, because we didn't resize + } }; class SEdge { @@ -105,10 +122,8 @@ public: SBsp2 *more; static const int POS = 100, NEG = 101, COPLANAR = 200; - void InsertTriangleHow(int how, STriangle *tr, - SMesh *m, SBsp3 *bsp3, bool flip, bool cpl); - void InsertTriangle(STriangle *tr, - SMesh *m, SBsp3 *bsp3, bool flip, bool cpl); + void InsertTriangleHow(int how, STriangle *tr, SMesh *m, SBsp3 *bsp3); + void InsertTriangle(STriangle *tr, SMesh *m, SBsp3 *bsp3); Vector IntersectionWith(Vector a, Vector b); SBsp2 *InsertEdge(SEdge *nedge, Vector nnp, Vector out); static SBsp2 *Alloc(void); @@ -130,18 +145,18 @@ 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 InsertHow(int how, STriangle *str, SMesh *instead); + SBsp3 *Insert(STriangle *str, SMesh *instead); - void InsertInPlane(bool pos2, STriangle *tr, SMesh *m, bool flip, bool cpl); + void InsertConvexHow(int how, Vector *vertex, int n, SMesh *instead); + SBsp3 *InsertConvex(Vector *vertex, int n, SMesh *instead); + + void InsertInPlane(bool pos2, STriangle *tr, SMesh *m); void DebugDraw(void); }; @@ -151,12 +166,18 @@ class SMesh { public: SList l; + bool flipNormal; + bool keepCoplanar; + bool atLeastOneDiscarded; + 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); + + void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3); }; #endif