Some ugly hacks; discard zero-area triangles, randomize the

triangle list before adding to the BSP, and check if a point in
plane lies in multiple triangles and choose the one with the
biggest normal magnitude (i.e., area) when testing normal
direction.

[git-p4: depot-paths = "//depot/solvespace/": change = 1745]
solver
Jonathan Westhues 2008-05-25 22:23:05 -08:00
parent d750344653
commit 727ac126fb
3 changed files with 57 additions and 12 deletions

View File

@ -1105,7 +1105,7 @@ void GraphicsWindow::Paint(int w, int h) {
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glScaled(scale*2.0/w, scale*2.0/h, scale*1.0/10000); glScaled(scale*2.0/w, scale*2.0/h, scale*1.0/100000);
double tx = projRight.Dot(offset); double tx = projRight.Dot(offset);
double ty = projUp.Dot(offset); double ty = projUp.Dot(offset);

View File

@ -51,7 +51,7 @@ void SMesh::GetBounding(Vector *vmax, Vector *vmin) {
void SMesh::Simplify(int start) { void SMesh::Simplify(int start) {
#define MAX_TRIANGLES 500 #define MAX_TRIANGLES 500
if(l.n - start > MAX_TRIANGLES) return; if(l.n - start > MAX_TRIANGLES) oops();
STriangle tout[MAX_TRIANGLES]; STriangle tout[MAX_TRIANGLES];
int toutc = 0; int toutc = 0;
@ -63,10 +63,16 @@ void SMesh::Simplify(int start) {
int i, j; int i, j;
for(i = start; i < l.n; i++) { for(i = start; i < l.n; i++) {
l.elem[i].tag = 0; STriangle *tr = &(l.elem[i]);
if((tr->Normal()).Magnitude() < LENGTH_EPS*LENGTH_EPS) {
tr->tag = 1;
} else {
tr->tag = 0;
}
} }
for(;;) { for(;;) {
bool didAdd;
convc = 0; convc = 0;
for(i = start; i < l.n; i++) { for(i = start; i < l.n; i++) {
STriangle *tr = &(l.elem[i]); STriangle *tr = &(l.elem[i]);
@ -83,7 +89,6 @@ void SMesh::Simplify(int start) {
} }
if(i >= l.n) break; if(i >= l.n) break;
bool didAdd;
do { do {
didAdd = false; didAdd = false;
@ -141,11 +146,27 @@ void SMesh::Simplify(int start) {
} }
} while(didAdd); } while(didAdd);
// I need to debug why this is required; sometimes the above code
// still generates a convex polygon
for(i = 0; i < convc; i++) {
Vector a = conv[WRAP((i-1), convc)],
b = conv[i],
c = conv[WRAP((i+1), convc)];
Vector ab = b.Minus(a);
Vector bc = c.Minus(b);
double bDot = (ab.Cross(bc)).Dot(n);
bDot /= min(ab.Magnitude(), bc.Magnitude());
if(bDot < 0) return;
}
for(i = 0; i < convc - 2; i++) { for(i = 0; i < convc - 2; i++) {
STriangle tr = { 0, conv[0], conv[i+1], conv[i+2] }; STriangle tr = { 0, conv[0], conv[i+1], conv[i+2] };
if((tr.Normal()).Magnitude() > LENGTH_EPS*LENGTH_EPS) {
tout[toutc++] = tr; tout[toutc++] = tr;
} }
} }
}
l.n = start0; l.n = start0;
for(i = 0; i < toutc; i++) { for(i = 0; i < toutc; i++) {
@ -169,7 +190,7 @@ void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) {
AddTriangle(st->a, st->b, st->c); AddTriangle(st->a, st->b, st->c);
} }
} }
if(l.n - pn > 4) { if(l.n - pn > 1) {
Simplify(pn); Simplify(pn);
} }
} }
@ -210,9 +231,25 @@ SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
SBsp3 *SBsp3::FromMesh(SMesh *m) { SBsp3 *SBsp3::FromMesh(SMesh *m) {
SBsp3 *bsp3 = NULL; SBsp3 *bsp3 = NULL;
int i; int i;
SMesh mc; ZERO(&mc);
for(i = 0; i < m->l.n; i++) { for(i = 0; i < m->l.n; i++) {
bsp3 = bsp3->Insert(&(m->l.elem[i]), NULL); mc.AddTriangle(&(m->l.elem[i]));
} }
srand(0); // Let's be deterministic, at least!
int n = mc.l.n;
while(n > 1) {
int k = rand() % n;
n--;
SWAP(STriangle, mc.l.elem[k], mc.l.elem[n]);
}
for(i = 0; i < mc.l.n; i++) {
bsp3 = bsp3->Insert(&(mc.l.elem[i]), NULL);
}
mc.Clear();
return bsp3; return bsp3;
} }
@ -230,13 +267,21 @@ void SBsp3::InsertInPlane(bool pos2, STriangle *tr, SMesh *m) {
bool onFace = false; bool onFace = false;
bool sameNormal; bool sameNormal;
double maxNormalMag = -1;
Vector lln, trn = tr->Normal();
SBsp3 *ll = this; SBsp3 *ll = this;
while(ll) { while(ll) {
if((ll->tri).ContainsPoint(tc)) { if((ll->tri).ContainsPoint(tc)) {
onFace = true; onFace = true;
sameNormal = (tr->Normal()).Dot((ll->tri).Normal()) > 0; // If the mesh contains almost-zero-area triangles, and we're
break; // just on the edge of one of those, then don't trust its normal.
lln = (ll->tri).Normal();
if(lln.Magnitude() > maxNormalMag) {
sameNormal = trn.Dot(lln) > 0;
maxNormalMag = lln.Magnitude();
}
} }
ll = ll->more; ll = ll->more;
} }

View File

@ -299,10 +299,10 @@ Vector Vector::ScaledBy(double v) {
Vector Vector::WithMagnitude(double v) { Vector Vector::WithMagnitude(double v) {
double m = Magnitude(); double m = Magnitude();
if(m < LENGTH_EPS) { if(m == 0) {
return MakeFrom(v, 0, 0); return MakeFrom(v, 0, 0);
} else { } else {
return ScaledBy(v/Magnitude()); return ScaledBy(v/m);
} }
} }