Fix an issue with edge intersection testing: if a vertex from edge

A touches edge B, but does not share a vertex with edge B, then
that's an intersection.

Adjust the ear clipping so that it generates strip-like
triangulations, not fan-like.

And rearrange deck chairs on the bridge-finding code, which is
still pathetically slow. It may not be possible to get reasonable
performance without kd tree type acceleration.

[git-p4: depot-paths = "//depot/solvespace/": change = 1901]
solver
Jonathan Westhues 2009-01-22 02:02:46 -08:00
parent 7cf3a06274
commit 6d7954e167
4 changed files with 88 additions and 27 deletions

View File

@ -187,9 +187,19 @@ bool SEdgeList::AnyEdgeCrosses(Vector a, Vector b) {
&t, &tse);
if(skew) continue;
if(t > t_eps && t < (1 - t_eps) &&
tse > tse_eps && tse < (1 - tse_eps))
bool inOrEdge0 = (t > -t_eps) && (t < (1 + t_eps));
bool inOrEdge1 = (tse > -tse_eps) && (tse < (1 + tse_eps));
if(inOrEdge0 && inOrEdge1) {
if((se->a).Equals(a) || (se->b).Equals(a) ||
(se->a).Equals(b) || (se->b).Equals(b))
{
// Not an intersection if we share an endpoint with an edge
continue;
}
// But it's an intersection if a vertex of one edge lies on the
// inside of the other (or if they cross away from either's
// vertex).
return true;
}
}
@ -222,6 +232,16 @@ void SContour::CopyInto(SContour *dest) {
}
}
void SContour::FindPointWithMinX(void) {
SPoint *sp;
xminPt = Vector::From(1e10, 1e10, 1e10);
for(sp = l.First(); sp; sp = l.NextAfter(sp)) {
if(sp->p.x < xminPt.x) {
xminPt = sp->p;
}
}
}
Vector SContour::ComputeNormal(void) {
Vector n = Vector::From(0, 0, 0);

View File

@ -43,6 +43,7 @@ class SContour {
public:
int tag;
int timesEnclosed;
Vector xminPt;
List<SPoint> l;
void AddPoint(Vector p);
@ -54,6 +55,7 @@ public:
bool AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt);
void OffsetInto(SContour *dest, double r);
void CopyInto(SContour *dest);
void FindPointWithMinX(void);
bool IsEar(int bp);
bool BridgeToContour(SContour *sc, SEdgeList *el, List<Vector> *vl);

View File

@ -559,7 +559,7 @@ SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
STrimBy stb1 = STrimBy::EntireCurve(&ret, hc1);
// The translated curves trim the flat top and bottom surfaces.
(ret.surface.FindById(hs0))->trim.Add(&stb0);
// (ret.surface.FindById(hs0))->trim.Add(&stb0);
(ret.surface.FindById(hs1))->trim.Add(&stb1);
// The translated curves also trim the surface of extrusion.

View File

@ -3,6 +3,8 @@
void SPolygon::UvTriangulateInto(SMesh *m) {
if(l.n <= 0) return;
SDWORD in = GetMilliseconds();
normal = Vector::From(0, 0, 1);
while(l.n > 0) {
@ -45,34 +47,36 @@ void SPolygon::UvTriangulateInto(SMesh *m) {
if(top->ContainsPointProjdToNormal(normal, sc->l.elem[0].p)) {
sc->tag = 2;
sc->MakeEdgesInto(&el);
sc->FindPointWithMinX();
}
}
bool holesExist, mergedHole;
do {
holesExist = false;
mergedHole = false;
dbp("finished finding holes: %d ms", GetMilliseconds() - in);
for(;;) {
double xmin = 1e10;
SContour *scmin = NULL;
for(sc = l.First(); sc; sc = l.NextAfter(sc)) {
if(sc->tag != 2) continue;
holesExist = true;
if(merged.BridgeToContour(sc, &el, &vl)) {
// Merged it in, so we're done with it.
sc->tag = 3;
mergedHole = true;
} else {
// Looks like we can't merge it yet, but that can happen;
// we may have to merge the holes in a specific order.
if(sc->xminPt.x < xmin) {
xmin = sc->xminPt.x;
scmin = sc;
}
}
if(holesExist && !mergedHole) {
dbp("holes exist, yet couldn't merge one");
if(!scmin) break;
if(!merged.BridgeToContour(scmin, &el, &vl)) {
dbp("couldn't merge our hole");
return;
}
} while(holesExist);
dbp(" bridged to contour: %d ms", GetMilliseconds() - in);
scmin->tag = 3;
}
dbp("finished merging holes: %d ms", GetMilliseconds() - in);
merged.UvTriangulateInto(m);
dbp("finished ear clippping: %d ms", GetMilliseconds() - in);
merged.l.Clear();
el.Clear();
vl.Clear();
@ -84,10 +88,35 @@ void SPolygon::UvTriangulateInto(SMesh *m) {
bool SContour::BridgeToContour(SContour *sc,
SEdgeList *avoidEdges, List<Vector> *avoidPts)
{
int i, j;
// Start looking for a bridge on our new hole near its leftmost (min x)
// point.
int sco = 0;
for(i = 0; i < (sc->l.n - 1); i++) {
if((sc->l.elem[i].p).EqualsExactly(sc->xminPt)) {
sco = i;
}
}
// And start looking on our merged contour at whichever point is nearest
// to the leftmost point of the new segment.
int thiso = 0;
double dmin = 1e10;
for(i = 0; i < l.n; i++) {
Vector p = l.elem[i].p;
double d = (p.Minus(sc->xminPt)).MagSquared();
if(d < dmin) {
dmin = d;
thiso = i;
}
}
int thisp, scp;
Vector a, b, *f;
for(thisp = 0; thisp < l.n; thisp++) {
for(i = 0; i < l.n; i++) {
thisp = WRAP(i+thiso, l.n);
a = l.elem[thisp].p;
for(f = avoidPts->First(); f; f = avoidPts->NextAfter(f)) {
@ -95,7 +124,8 @@ bool SContour::BridgeToContour(SContour *sc,
}
if(f) continue;
for(scp = 0; scp < (sc->l.n - 1); scp++) {
for(j = 0; j < (sc->l.n - 1); j++) {
scp = WRAP(j+sco, (sc->l.n - 1));
b = sc->l.elem[scp].p;
for(f = avoidPts->First(); f; f = avoidPts->NextAfter(f)) {
@ -116,7 +146,6 @@ bool SContour::BridgeToContour(SContour *sc,
haveEdge:
SContour merged;
ZERO(&merged);
int i, j;
for(i = 0; i < l.n; i++) {
merged.AddPoint(l.elem[i].p);
if(i == thisp) {
@ -207,26 +236,36 @@ void SContour::ClipEarInto(SMesh *m, int bp) {
void SContour::UvTriangulateInto(SMesh *m) {
int i;
// First, calculate the ear-ness of all the points
for(i = 0; i < l.n; i++) {
(l.elem[i]).ear = IsEar(i) ? SPoint::EAR : SPoint::NOT_EAR;
}
bool toggle = false;
while(l.n > 3) {
// Some points may have changed ear-ness, so recalculate
for(i = 0; i < l.n; i++) {
if(l.elem[i].ear == SPoint::UNKNOWN) {
(l.elem[i]).ear = IsEar(i) ? SPoint::EAR : SPoint::NOT_EAR;
}
}
// And find a candidate ear; alternate the starting position so
// we generate strip-like triangulations instead of fan-like
int ear = -1;
toggle = !toggle;
int offset = toggle ? -1 : 0;
for(i = 0; i < l.n; i++) {
if(l.elem[i].ear == SPoint::EAR) {
ear = WRAP(i+offset, l.n);
if(l.elem[ear].ear == SPoint::EAR) {
break;
}
}
if(i >= l.n) {
if(ear < 0) {
dbp("couldn't find an ear! fail");
return;
}
ClipEarInto(m, i);
ClipEarInto(m, ear);
}
ClipEarInto(m, 0); // add the last triangle