From 77cace05ce781f36eb7ff9ea3ca547e5dd9096d5 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Fri, 27 Feb 2009 06:05:08 -0800 Subject: [PATCH] When clipping ears to triangulate a curved surface, clip the ear that minimizes the chord tolerance. [git-p4: depot-paths = "//depot/solvespace/": change = 1921] --- polygon.h | 4 ++-- solvespace.h | 1 + srf/ratpoly.cpp | 4 +++- srf/surface.h | 1 + srf/triangulate.cpp | 53 ++++++++++++++++++++++++++++++++++++--------- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/polygon.h b/polygon.h index feb102a..a4cd00c 100644 --- a/polygon.h +++ b/polygon.h @@ -61,7 +61,7 @@ public: bool IsEar(int bp); bool BridgeToContour(SContour *sc, SEdgeList *el, List *vl); void ClipEarInto(SMesh *m, int bp); - void UvTriangulateInto(SMesh *m); + void UvTriangulateInto(SMesh *m, SSurface *srf); }; typedef struct { @@ -88,7 +88,7 @@ public: bool IsEmpty(void); Vector AnyPoint(void); void OffsetInto(SPolygon *dest, double r); - void UvTriangulateInto(SMesh *m); + void UvTriangulateInto(SMesh *m, SSurface *srf); }; class STriangle { diff --git a/solvespace.h b/solvespace.h index 2414e14..70b1954 100644 --- a/solvespace.h +++ b/solvespace.h @@ -141,6 +141,7 @@ void vl(void); // debug function to validate heaps //================ +class SSurface; #include "dsc.h" #include "polygon.h" #include "srf/surface.h" diff --git a/srf/ratpoly.cpp b/srf/ratpoly.cpp index 89d661f..1b02b07 100644 --- a/srf/ratpoly.cpp +++ b/srf/ratpoly.cpp @@ -731,7 +731,9 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) { ZERO(&poly); if(el.AssemblePolygon(&poly, NULL, true)) { int i, start = sm->l.n; - poly.UvTriangulateInto(sm); + // Curved surfaces are triangulated in such a way as to minimize + // deviation between edges and surface; but doesn't matter for planes. + poly.UvTriangulateInto(sm, (degm == 1 && degn == 1) ? NULL : this); STriMeta meta = { face, color }; for(i = start; i < sm->l.n; i++) { diff --git a/srf/surface.h b/srf/surface.h index a5c9891..245231e 100644 --- a/srf/surface.h +++ b/srf/surface.h @@ -211,6 +211,7 @@ public: void TriangulateInto(SShell *shell, SMesh *sm); void MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv); void MakeClassifyingBsp(SShell *shell); + double ChordToleranceForEdge(Vector a, Vector b); void Reverse(void); void Clear(void); diff --git a/srf/triangulate.cpp b/srf/triangulate.cpp index 27a8817..823c0ee 100644 --- a/srf/triangulate.cpp +++ b/srf/triangulate.cpp @@ -1,6 +1,6 @@ #include "../solvespace.h" -void SPolygon::UvTriangulateInto(SMesh *m) { +void SPolygon::UvTriangulateInto(SMesh *m, SSurface *srf) { if(l.n <= 0) return; SDWORD in = GetMilliseconds(); @@ -80,7 +80,7 @@ void SPolygon::UvTriangulateInto(SMesh *m) { } // dbp("finished merging holes: %d ms", GetMilliseconds() - in); - merged.UvTriangulateInto(m); + merged.UvTriangulateInto(m, srf); // dbp("finished ear clippping: %d ms", GetMilliseconds() - in); merged.l.Clear(); el.Clear(); @@ -250,7 +250,7 @@ void SContour::ClipEarInto(SMesh *m, int bp) { l.RemoveTagged(); } -void SContour::UvTriangulateInto(SMesh *m) { +void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) { int i; // Clean the original contour by removing any zero-length edges. @@ -276,24 +276,57 @@ void SContour::UvTriangulateInto(SMesh *m) { } } - // And find a candidate ear; alternate the starting position so - // we generate strip-like triangulations instead of fan-like - int ear = -1; + int bestEar = -1; + double bestChordTol = VERY_POSITIVE; + // Alternate the starting position so we generate strip-like + // triangulations instead of fan-like toggle = !toggle; int offset = toggle ? -1 : 0; for(i = 0; i < l.n; i++) { - ear = WRAP(i+offset, l.n); + int ear = WRAP(i+offset, l.n); if(l.elem[ear].ear == SPoint::EAR) { - break; + if(!srf) { + bestEar = ear; + break; + } + // If we are triangulating a curved surface, then try to + // clip ears that have a small chord tolerance from the + // surface. + Vector prev = l.elem[WRAP((i+offset-1), l.n)].p, + next = l.elem[WRAP((i+offset+1), l.n)].p; + double tol = srf->ChordToleranceForEdge(prev, next); + if(tol < bestChordTol - LENGTH_EPS) { + bestEar = ear; + bestChordTol = tol; + } + if(bestChordTol < 0.1*(SS.chordTol / SS.GW.scale)) { + break; + } } } - if(ear < 0) { + if(bestEar < 0) { dbp("couldn't find an ear! fail"); return; } - ClipEarInto(m, ear); + ClipEarInto(m, bestEar); } ClipEarInto(m, 0); // add the last triangle } +double SSurface::ChordToleranceForEdge(Vector a, Vector b) { + Vector as = PointAt(a.x, a.y), bs = PointAt(b.x, b.y); + + double worst = VERY_NEGATIVE; + int i; + for(i = 1; i <= 3; i++) { + Vector p = a. Plus((b. Minus(a )).ScaledBy(i/4.0)), + ps = as.Plus((bs.Minus(as)).ScaledBy(i/4.0)); + + Vector pps = PointAt(p.x, p.y); + worst = max(worst, (pps.Minus(ps)).MagSquared()); + } + return sqrt(worst); +} + +