When clipping ears to triangulate a curved surface, clip the ear

that minimizes the chord tolerance.

[git-p4: depot-paths = "//depot/solvespace/": change = 1921]
This commit is contained in:
Jonathan Westhues 2009-02-27 06:05:08 -08:00
parent 2023667311
commit 77cace05ce
5 changed files with 50 additions and 13 deletions

View File

@ -61,7 +61,7 @@ public:
bool IsEar(int bp); bool IsEar(int bp);
bool BridgeToContour(SContour *sc, SEdgeList *el, List<Vector> *vl); bool BridgeToContour(SContour *sc, SEdgeList *el, List<Vector> *vl);
void ClipEarInto(SMesh *m, int bp); void ClipEarInto(SMesh *m, int bp);
void UvTriangulateInto(SMesh *m); void UvTriangulateInto(SMesh *m, SSurface *srf);
}; };
typedef struct { typedef struct {
@ -88,7 +88,7 @@ public:
bool IsEmpty(void); bool IsEmpty(void);
Vector AnyPoint(void); Vector AnyPoint(void);
void OffsetInto(SPolygon *dest, double r); void OffsetInto(SPolygon *dest, double r);
void UvTriangulateInto(SMesh *m); void UvTriangulateInto(SMesh *m, SSurface *srf);
}; };
class STriangle { class STriangle {

View File

@ -141,6 +141,7 @@ void vl(void); // debug function to validate heaps
//================ //================
class SSurface;
#include "dsc.h" #include "dsc.h"
#include "polygon.h" #include "polygon.h"
#include "srf/surface.h" #include "srf/surface.h"

View File

@ -731,7 +731,9 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
ZERO(&poly); ZERO(&poly);
if(el.AssemblePolygon(&poly, NULL, true)) { if(el.AssemblePolygon(&poly, NULL, true)) {
int i, start = sm->l.n; 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 }; STriMeta meta = { face, color };
for(i = start; i < sm->l.n; i++) { for(i = start; i < sm->l.n; i++) {

View File

@ -211,6 +211,7 @@ public:
void TriangulateInto(SShell *shell, SMesh *sm); void TriangulateInto(SShell *shell, SMesh *sm);
void MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv); void MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv);
void MakeClassifyingBsp(SShell *shell); void MakeClassifyingBsp(SShell *shell);
double ChordToleranceForEdge(Vector a, Vector b);
void Reverse(void); void Reverse(void);
void Clear(void); void Clear(void);

View File

@ -1,6 +1,6 @@
#include "../solvespace.h" #include "../solvespace.h"
void SPolygon::UvTriangulateInto(SMesh *m) { void SPolygon::UvTriangulateInto(SMesh *m, SSurface *srf) {
if(l.n <= 0) return; if(l.n <= 0) return;
SDWORD in = GetMilliseconds(); SDWORD in = GetMilliseconds();
@ -80,7 +80,7 @@ void SPolygon::UvTriangulateInto(SMesh *m) {
} }
// dbp("finished merging holes: %d ms", GetMilliseconds() - in); // dbp("finished merging holes: %d ms", GetMilliseconds() - in);
merged.UvTriangulateInto(m); merged.UvTriangulateInto(m, srf);
// dbp("finished ear clippping: %d ms", GetMilliseconds() - in); // dbp("finished ear clippping: %d ms", GetMilliseconds() - in);
merged.l.Clear(); merged.l.Clear();
el.Clear(); el.Clear();
@ -250,7 +250,7 @@ void SContour::ClipEarInto(SMesh *m, int bp) {
l.RemoveTagged(); l.RemoveTagged();
} }
void SContour::UvTriangulateInto(SMesh *m) { void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
int i; int i;
// Clean the original contour by removing any zero-length edges. // 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 int bestEar = -1;
// we generate strip-like triangulations instead of fan-like double bestChordTol = VERY_POSITIVE;
int ear = -1; // Alternate the starting position so we generate strip-like
// triangulations instead of fan-like
toggle = !toggle; toggle = !toggle;
int offset = toggle ? -1 : 0; int offset = toggle ? -1 : 0;
for(i = 0; i < l.n; i++) { 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) { if(l.elem[ear].ear == SPoint::EAR) {
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; break;
} }
} }
if(ear < 0) { }
if(bestEar < 0) {
dbp("couldn't find an ear! fail"); dbp("couldn't find an ear! fail");
return; return;
} }
ClipEarInto(m, ear); ClipEarInto(m, bestEar);
} }
ClipEarInto(m, 0); // add the last triangle 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);
}