diff --git a/polygon.cpp b/polygon.cpp index 94b082e0..cb7c18d9 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -386,8 +386,11 @@ void SPolygon::FixContourDirections(void) { int i, j; for(i = 0; i < l.n; i++) { SContour *sc = &(l.elem[i]); - if(sc->l.n < 1) continue; - Vector pt = (sc->l.elem[0]).p; + if(sc->l.n < 2) continue; + // The contours may not intersect, but they may share vertices; so + // testing a vertex for point-in-polygon may fail, but the midpoint + // of an edge is okay. + Vector pt = (((sc->l.elem[0]).p).Plus(sc->l.elem[1].p)).ScaledBy(0.5); sc->timesEnclosed = 0; bool outer = true; diff --git a/srf/boolean.cpp b/srf/boolean.cpp index 414d1d24..b1d7d8ba 100644 --- a/srf/boolean.cpp +++ b/srf/boolean.cpp @@ -426,7 +426,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent, } final.l.RemoveTagged(); -// if(I == 1) DEBUGEDGELIST(&final, &ret); +// if(I == 10) DEBUGEDGELIST(&final, &ret); // Use our reassembled edges to trim the new surface. ret.TrimFromEdgeList(&final); @@ -485,13 +485,13 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) { a->MakeIntersectionCurvesAgainst(b, this); I = 100; - if(b->surface.n == 0 || a->surface.n == 0) { + if(b->surface.n == 0 || a->surface.n == 0 || a->surface.n == 6) { // Then trim and copy the surfaces a->CopySurfacesTrimAgainst(b, this, type, true); b->CopySurfacesTrimAgainst(a, this, type, false); } else { - a->CopySurfacesTrimAgainst(b, this, type, true); I = 0; + a->CopySurfacesTrimAgainst(b, this, type, true); b->CopySurfacesTrimAgainst(a, this, type, false); } diff --git a/srf/triangulate.cpp b/srf/triangulate.cpp index 6152d360..27a8817b 100644 --- a/srf/triangulate.cpp +++ b/srf/triangulate.cpp @@ -42,9 +42,14 @@ void SPolygon::UvTriangulateInto(SMesh *m) { SContour *sc; for(sc = l.First(); sc; sc = l.NextAfter(sc)) { if(sc->timesEnclosed != 1) continue; - if(sc->l.n < 1) continue; + if(sc->l.n < 2) continue; - if(top->ContainsPointProjdToNormal(normal, sc->l.elem[0].p)) { + // Test the midpoint of an edge. Our polygon may not be self- + // intersecting, but two countours may share a vertex; so a + // vertex could be on the edge of another polygon, in which + // case ContainsPointProjdToNormal returns indeterminate. + Vector tp = ((sc->l.elem[0].p).Plus(sc->l.elem[1].p)).ScaledBy(0.5); + if(top->ContainsPointProjdToNormal(normal, tp)) { sc->tag = 2; sc->MakeEdgesInto(&el); sc->FindPointWithMinX(); @@ -180,6 +185,12 @@ bool SContour::IsEar(int bp) { tr.b = l.elem[bp].p; tr.c = l.elem[cp].p; + if((tr.a).Equals(tr.c)) { + // This is two coincident and anti-parallel edges. Zero-area, so + // won't generate a real triangle, but we certainly can clip it. + return true; + } + Vector n = Vector::From(0, 0, -1); if((tr.Normal()).Dot(n) < LENGTH_EPS) { // This vertex is reflex, or between two collinear edges; either way, @@ -222,7 +233,12 @@ void SContour::ClipEarInto(SMesh *m, int bp) { tr.a = l.elem[ap].p; tr.b = l.elem[bp].p; tr.c = l.elem[cp].p; - m->AddTriangle(&tr); + if(tr.Normal().MagSquared() < LENGTH_EPS*LENGTH_EPS) { + // A vertex with more than two edges will cause us to generate + // zero-area triangles, which must be culled. + } else { + m->AddTriangle(&tr); + } // By deleting the point at bp, we may change the ear-ness of the points // on either side. @@ -236,7 +252,17 @@ void SContour::ClipEarInto(SMesh *m, int bp) { void SContour::UvTriangulateInto(SMesh *m) { int i; - // First, calculate the ear-ness of all the points + + // Clean the original contour by removing any zero-length edges. + l.ClearTags(); + for(i = 1; i < l.n; i++) { + if((l.elem[i].p).Equals(l.elem[i-1].p)) { + l.elem[i].tag = 1; + } + } + l.RemoveTagged(); + + // Now calculate the ear-ness of each vertex for(i = 0; i < l.n; i++) { (l.elem[i]).ear = IsEar(i) ? SPoint::EAR : SPoint::NOT_EAR; }