Add triangulation of surfaces with compound curvature; I just build
a grid of quads, with adaptive spacing. The quads that lie entirely within the trim polygon are triangulated and knocked out from the polygon, and then the polygon is triangulated. That works okay, though rather slow. But there are issues with surfaces of revolution that touch the axis, since they end up with a singularity. That will require some thought. [git-p4: depot-paths = "//depot/solvespace/": change = 1951]
This commit is contained in:
parent
3581d9b9ec
commit
d6d198ee40
|
@ -170,7 +170,10 @@ int SEdgeList::AnyEdgeCrossings(Vector a, Vector b, Vector *ppi) {
|
|||
dist_a = (se->a).DistanceToLine(a, d),
|
||||
dist_b = (se->b).DistanceToLine(a, d);
|
||||
|
||||
if(fabs(dist_a - dist_b) < LENGTH_EPS) {
|
||||
// Can't just test if dist_a equals dist_b; they could be on opposite
|
||||
// sides, since it's unsigned.
|
||||
double m = sqrt(d.Magnitude()*dse.Magnitude());
|
||||
if(sqrt(fabs(d.Dot(dse))) > (m - LENGTH_EPS)) {
|
||||
// The edges are parallel.
|
||||
if(fabs(dist_a) > LENGTH_EPS) {
|
||||
// and not coincident, so can't be interesecting
|
||||
|
|
|
@ -91,6 +91,7 @@ public:
|
|||
Vector AnyPoint(void);
|
||||
void OffsetInto(SPolygon *dest, double r);
|
||||
void UvTriangulateInto(SMesh *m, SSurface *srf);
|
||||
void UvGridTriangulateInto(SMesh *m, SSurface *srf);
|
||||
};
|
||||
|
||||
class STriangle {
|
||||
|
|
|
@ -40,9 +40,9 @@ void SolveSpace::Init(char *cmdLine) {
|
|||
lightDir[1].y = CnfThawFloat( 0.0f, "LightDir_1_Up" );
|
||||
lightDir[1].z = CnfThawFloat( 0.0f, "LightDir_1_Forward" );
|
||||
// Chord tolerance
|
||||
chordTol = CnfThawFloat(2.0f, "ChordTolerance");
|
||||
chordTol = CnfThawFloat(3.0f, "ChordTolerance");
|
||||
// Max pwl segments to generate
|
||||
maxSegments = CnfThawDWORD(40, "MaxSegments");
|
||||
maxSegments = CnfThawDWORD(10, "MaxSegments");
|
||||
// View units
|
||||
viewUnits = (Unit)CnfThawDWORD((DWORD)UNIT_MM, "ViewUnits");
|
||||
// Camera tangent (determines perspective)
|
||||
|
|
|
@ -299,9 +299,21 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
|
|||
ZERO(&poly);
|
||||
if(el.AssemblePolygon(&poly, NULL, true)) {
|
||||
int i, start = sm->l.n;
|
||||
// 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);
|
||||
if(degm == 1 && degn == 1) {
|
||||
// A plane; triangulate any old way
|
||||
poly.UvTriangulateInto(sm, NULL);
|
||||
} else if(degm == 1 || degn == 1) {
|
||||
// A surface with curvature along one direction only; so
|
||||
// choose the triangulation with chords that lie as much
|
||||
// as possible within the surface. And since the trim curves
|
||||
// have been pwl'd to within the desired chord tol, that will
|
||||
// produce a surface good to within roughly that tol.
|
||||
poly.UvTriangulateInto(sm, this);
|
||||
} else {
|
||||
// A surface with compound curvature. So we must overlay a
|
||||
// two-dimensional grid, and triangulate around that.
|
||||
poly.UvGridTriangulateInto(sm, this);
|
||||
}
|
||||
|
||||
STriMeta meta = { face, color };
|
||||
for(i = start; i < sm->l.n; i++) {
|
||||
|
|
|
@ -255,6 +255,9 @@ public:
|
|||
void MakeSectionEdgesInto(SShell *shell, SEdgeList *sel, SBezierList *sbl);
|
||||
void MakeClassifyingBsp(SShell *shell);
|
||||
double ChordToleranceForEdge(Vector a, Vector b);
|
||||
void MakeTriangulationGridInto(List<double> *l, double vs, double vf,
|
||||
bool swapped);
|
||||
Vector PointAtMaybeSwapped(double u, double v, bool swapped);
|
||||
|
||||
void Reverse(void);
|
||||
void Clear(void);
|
||||
|
|
|
@ -120,6 +120,29 @@ bool SContour::BridgeToContour(SContour *sc,
|
|||
int thisp, scp;
|
||||
|
||||
Vector a, b, *f;
|
||||
|
||||
// First check if the contours share a point; in that case we should
|
||||
// merge them there, without a bridge.
|
||||
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)) {
|
||||
if(f->Equals(a)) break;
|
||||
}
|
||||
if(f) continue;
|
||||
|
||||
for(j = 0; j < (sc->l.n - 1); j++) {
|
||||
scp = WRAP(j+sco, (sc->l.n - 1));
|
||||
b = sc->l.elem[scp].p;
|
||||
|
||||
if(a.Equals(b)) {
|
||||
goto haveEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If that fails, look for a bridge that does not intersect any edges.
|
||||
for(i = 0; i < l.n; i++) {
|
||||
thisp = WRAP(i+thiso, l.n);
|
||||
a = l.elem[thisp].p;
|
||||
|
@ -145,6 +168,7 @@ bool SContour::BridgeToContour(SContour *sc,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tried all the possibilities, didn't find an edge
|
||||
return false;
|
||||
|
||||
|
@ -329,4 +353,136 @@ double SSurface::ChordToleranceForEdge(Vector a, Vector b) {
|
|||
return sqrt(worst);
|
||||
}
|
||||
|
||||
Vector SSurface::PointAtMaybeSwapped(double u, double v, bool swapped) {
|
||||
if(swapped) {
|
||||
return PointAt(v, u);
|
||||
} else {
|
||||
return PointAt(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
void SSurface::MakeTriangulationGridInto(List<double> *l, double vs, double vf,
|
||||
bool swapped)
|
||||
{
|
||||
double worst = 0;
|
||||
|
||||
// Try piecewise linearizing four curves, at u = 0, 1/3, 2/3, 1; choose
|
||||
// the worst chord tolerance of any of those.
|
||||
int i;
|
||||
for(i = 0; i <= 3; i++) {
|
||||
double u = i/3.0;
|
||||
|
||||
// This chord test should be identical to the one in SBezier::MakePwl
|
||||
// to make the piecewise linear edges line up with the grid more or
|
||||
// less.
|
||||
Vector ps = PointAtMaybeSwapped(u, vs, swapped),
|
||||
pf = PointAtMaybeSwapped(u, vf, swapped);
|
||||
|
||||
double vm1 = (2*vs + vf) / 3,
|
||||
vm2 = (vs + 2*vf) / 3;
|
||||
|
||||
Vector pm1 = PointAtMaybeSwapped(u, vm1, swapped),
|
||||
pm2 = PointAtMaybeSwapped(u, vm2, swapped);
|
||||
|
||||
worst = max(worst, pm1.DistanceToLine(ps, pf.Minus(ps)));
|
||||
worst = max(worst, pm2.DistanceToLine(ps, pf.Minus(ps)));
|
||||
}
|
||||
|
||||
double step = 1.0/SS.maxSegments;
|
||||
if((vf - vs) < step || worst < SS.ChordTolMm()) {
|
||||
l->Add(&vf);
|
||||
} else {
|
||||
MakeTriangulationGridInto(l, vs, (vs+vf)/2, swapped);
|
||||
MakeTriangulationGridInto(l, (vs+vf)/2, vf, swapped);
|
||||
}
|
||||
}
|
||||
|
||||
void SPolygon::UvGridTriangulateInto(SMesh *mesh, SSurface *srf) {
|
||||
SEdgeList orig;
|
||||
ZERO(&orig);
|
||||
MakeEdgesInto(&orig);
|
||||
|
||||
SEdgeList holes;
|
||||
ZERO(&holes);
|
||||
|
||||
normal = Vector::From(0, 0, 1);
|
||||
FixContourDirections();
|
||||
|
||||
// Build a rectangular grid, with horizontal and vertical lines in the
|
||||
// uv plane. The spacing of these lines is adaptive, so calculate that.
|
||||
List<double> li, lj;
|
||||
ZERO(&li);
|
||||
ZERO(&lj);
|
||||
double v = 0;
|
||||
li.Add(&v);
|
||||
srf->MakeTriangulationGridInto(&li, 0, 1, true);
|
||||
lj.Add(&v);
|
||||
srf->MakeTriangulationGridInto(&lj, 0, 1, false);
|
||||
|
||||
// Now iterate over each quad in the grid. If it's outside the polygon,
|
||||
// or if it intersects the polygon, then we discard it. Otherwise we
|
||||
// generate two triangles in the mesh, and cut it out of our polygon.
|
||||
int i, j;
|
||||
for(i = 0; i < (li.n - 1); i++) {
|
||||
for(j = 0; j < (lj.n - 1); j++) {
|
||||
double us = li.elem[i], uf = li.elem[i+1],
|
||||
vs = lj.elem[j], vf = lj.elem[j+1];
|
||||
|
||||
Vector a = Vector::From(us, vs, 0),
|
||||
b = Vector::From(us, vf, 0),
|
||||
c = Vector::From(uf, vf, 0),
|
||||
d = Vector::From(uf, vs, 0);
|
||||
|
||||
if(orig.AnyEdgeCrossings(a, b, NULL) ||
|
||||
orig.AnyEdgeCrossings(b, c, NULL) ||
|
||||
orig.AnyEdgeCrossings(c, d, NULL) ||
|
||||
orig.AnyEdgeCrossings(d, a, NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// There's no intersections, so it doesn't matter which point
|
||||
// we decide to test.
|
||||
if(!this->ContainsPoint(a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the quad to our mesh
|
||||
STriangle tr;
|
||||
ZERO(&tr);
|
||||
tr.a = a;
|
||||
tr.b = b;
|
||||
tr.c = c;
|
||||
mesh->AddTriangle(&tr);
|
||||
tr.a = a;
|
||||
tr.b = c;
|
||||
tr.c = d;
|
||||
mesh->AddTriangle(&tr);
|
||||
|
||||
holes.AddEdge(a, b);
|
||||
holes.AddEdge(b, c);
|
||||
holes.AddEdge(c, d);
|
||||
holes.AddEdge(d, a);
|
||||
}
|
||||
}
|
||||
|
||||
holes.CullExtraneousEdges();
|
||||
SPolygon hp;
|
||||
ZERO(&hp);
|
||||
holes.AssemblePolygon(&hp, NULL, true);
|
||||
|
||||
SContour *sc;
|
||||
for(sc = hp.l.First(); sc; sc = hp.l.NextAfter(sc)) {
|
||||
l.Add(sc);
|
||||
}
|
||||
|
||||
orig.Clear();
|
||||
holes.Clear();
|
||||
li.Clear();
|
||||
lj.Clear();
|
||||
hp.l.Clear();
|
||||
|
||||
UvTriangulateInto(mesh, srf);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
marching algorithm for surface intersection
|
||||
surfaces of revolution (lathed)
|
||||
boundary avoidance when casting ray for point-in-shell
|
||||
tangent intersections
|
||||
short pwl edge avoidance
|
||||
|
|
Loading…
Reference in New Issue
Block a user