Back to opengl's tesselator for triangulation. I'll spend more time

writing mine later.

[git-p4: depot-paths = "//depot/solvespace/": change = 1810]
This commit is contained in:
Jonathan Westhues 2008-06-25 23:28:29 -08:00
parent 9b008ad1cd
commit a47a77c37c
4 changed files with 48 additions and 255 deletions

2
dsc.h
View File

@ -45,8 +45,6 @@ public:
static Vector From(hParam x, hParam y, hParam z); static Vector From(hParam x, hParam y, hParam z);
static Vector AtIntersectionOfPlanes(Vector n1, double d1, static Vector AtIntersectionOfPlanes(Vector n1, double d1,
Vector n2, double d2); Vector n2, double d2);
static bool LinesIntersect(Vector a0, Vector da, Vector b0, Vector db,
double *ta, double *tb);
bool Equals(Vector v); bool Equals(Vector v);
Vector Plus(Vector b); Vector Plus(Vector b);

View File

@ -314,246 +314,62 @@ bool SPolygon::AllPointsInPlane(Vector *notCoplanarAt) {
return true; return true;
} }
bool SPolygon::IntersectsPolygon(Vector ga, Vector gb) { static int TriMode, TriVertexCount;
int i, j; static Vector Tri1, TriNMinus1, TriNMinus2;
for(i = 0; i < l.n; i++) { static Vector TriNormal;
SContour *sc = &(l.elem[i]); static SMesh *TriMesh;
for(j = 0; j < sc->l.n; j++) { static STriMeta TriMeta;
Vector pa = sc->l.elem[j].p, static void GLX_CALLBACK TriBegin(int mode)
pb = sc->l.elem[WRAP(j+1, (sc->l.n - 1))].p;
// So do the lines from (ga to gb) and (pa to pb) intersect?
Vector dp = pb.Minus(pa), dg = gb.Minus(ga);
double tp, tg;
if(!Vector::LinesIntersect(pa, dp, ga, dg, &tp, &tg)) {
continue;
}
// So check if the line segments intersect
double lp = dp.Magnitude(), lg = dg.Magnitude();
tp *= lp;
tg *= lg;
if(tg > LENGTH_EPS && tg < (lg - LENGTH_EPS) &&
tp > LENGTH_EPS && tp < (lp - LENGTH_EPS))
{
return true;
}
}
}
return false;
}
bool SPolygon::VisibleVertices(SContour *outer, SContour *inner,
SEdgeList *extras, int *vo, int *vi)
{ {
int i, j, k; TriMode = mode;
TriVertexCount = 0;
double lmin = 1e12;
for(i = 0; i < outer->l.n; i++) {
Vector op = outer->l.elem[i].p;
for(j = 0; j < inner->l.n; j++) {
Vector ip = inner->l.elem[j].p;
if(IntersectsPolygon(op, ip)) goto dontuse;
for(k = 0; k < extras->l.n; k++) {
SEdge *se = &(extras->l.elem[k]);
if(ip.Equals(se->a) || ip.Equals(se->b) ||
op.Equals(se->a) || op.Equals(se->b))
{
goto dontuse;
}
Vector dt = ip.Minus(op), de = (se->b).Minus(se->a);
double te, tt;
if(!Vector::LinesIntersect(op, dt, se->a, de, &tt, &te))
continue;
double le = de.Magnitude(), lt = dt.Magnitude();
tt *= lt;
te *= le;
if(tt > LENGTH_EPS && tt < (lt - LENGTH_EPS) &&
te > LENGTH_EPS && te < (le - LENGTH_EPS))
{
goto dontuse;
}
}
if((op.Minus(ip)).Magnitude() < lmin) {
lmin = (op.Minus(ip)).Magnitude();
*vo = i;
*vi = j;
}
dontuse:;
}
}
if(lmin < 1e12) {
return true;
} else {
return false;
}
} }
static void GLX_CALLBACK TriEnd(void)
bool SContour::VertexIsEar(int v, Vector normal) { {
int va = WRAP(v-1, l.n), vb = WRAP(v , l.n), vc = WRAP(v+1, l.n);
Vector a = l.elem[va].p, b = l.elem[vb].p, c = l.elem[vc].p;
STriMeta meta;
ZERO(&meta);
STriangle tr = STriangle::From(meta, a, b, c);
if(normal.Dot(tr.Normal()) > 0) return false;
int i;
for(i = 0; i < l.n; i++) {
if(i == va) continue;
if(i == vb) continue;
if(i == vc) continue;
Vector p = l.elem[i].p;
if(p.Equals(tr.a)) continue;
if(p.Equals(tr.b)) continue;
if(p.Equals(tr.c)) continue;
if(tr.ContainsPoint(p)) return false;
}
return true;
} }
static void GLX_CALLBACK TriVertex(Vector *triN)
void SContour::TriangulateInto(SMesh *m, STriMeta meta, Vector normal) { {
int i; if(TriVertexCount == 0) {
Tri1 = *triN;
bool odd = false;
while(l.n >= 3) {
int start, end, incr;
if(odd) {
start = 0; end = l.n; incr = 1;
} else {
start = l.n - 1; end = -1; incr = -1;
}
for(i = start; i != end; i += incr) {
if(VertexIsEar(i, normal)) {
break;
}
}
if(i == end) {
dbp("couldn't find ear!");
return;
}
Vector a = l.elem[WRAP(i-1, l.n)].p,
b = l.elem[WRAP(i , l.n)].p,
c = l.elem[WRAP(i+1, l.n)].p;
m->AddTriangle(meta, c, b, a);
l.ClearTags();
l.elem[i].tag = 1;
l.RemoveTagged();
odd = !odd;
} }
if(TriMode == GL_TRIANGLES) {
if((TriVertexCount % 3) == 2) {
TriMesh->AddTriangle(
TriMeta, TriNormal, TriNMinus2, TriNMinus1, *triN);
}
} else if(TriMode == GL_TRIANGLE_FAN) {
if(TriVertexCount >= 2) {
TriMesh->AddTriangle(
TriMeta, TriNormal, Tri1, TriNMinus1, *triN);
}
} else if(TriMode == GL_TRIANGLE_STRIP) {
if(TriVertexCount >= 2) {
TriMesh->AddTriangle(
TriMeta, TriNormal, TriNMinus2, TriNMinus1, *triN);
}
} else oops();
l.Clear(); TriNMinus2 = TriNMinus1;
TriNMinus1 = *triN;
TriVertexCount++;
} }
void SPolygon::TriangulateInto(SMesh *m) { void SPolygon::TriangulateInto(SMesh *m) {
STriMeta meta; STriMeta meta;
ZERO(&meta); ZERO(&meta);
TriangulateInto(m, meta); TriangulateInto(m, meta);
} }
void SPolygon::TriangulateInto(SMesh *m, STriMeta meta) { void SPolygon::TriangulateInto(SMesh *m, STriMeta meta) {
FixContourDirections(); TriMesh = m;
TriNormal = normal;
TriMeta = meta;
int i, j, k; GLUtesselator *gt = gluNewTess();
bool *used = (bool *)AllocTemporary(l.n*sizeof(bool)); gluTessCallback(gt, GLU_TESS_BEGIN, (glxCallbackFptr *)TriBegin);
int *winding = (int *)AllocTemporary(l.n*sizeof(int)); gluTessCallback(gt, GLU_TESS_END, (glxCallbackFptr *)TriEnd);
bool **contained = (bool **)AllocTemporary(l.n*sizeof(bool *)); gluTessCallback(gt, GLU_TESS_VERTEX, (glxCallbackFptr *)TriVertex);
for(i = 0; i < l.n; i++) {
contained[i] = (bool *)AllocTemporary(l.n*sizeof(bool));
SContour *sci = &(l.elem[i]); glxTesselatePolygon(gt, this);
if(sci->l.n < 1) continue;
for(j = 0; j < l.n; j++) {
SContour *scj = &(l.elem[j]);
if(scj->l.n < 1) continue;
if(i == j) {
contained[i][j] = true;
continue;
}
if(scj->ContainsPointProjdToNormal(normal, sci->l.elem[0].p)) { gluDeleteTess(gt);
(winding[i])++;
contained[i][j] = true;
}
}
}
for(;;) {
for(i = 0; i < l.n; i++) {
if(winding[i] == 0) break;
}
if(i >= l.n) {
// No outer contours left, so we're done
break;
}
SContour *outer = &(l.elem[i]);
SContour merged;
ZERO(&merged);
SEdgeList extras;
ZERO(&extras);
for(j = 0; j < outer->l.n - 1; j++) {
merged.AddPoint(outer->l.elem[j].p);
}
// If this polygon has holes, then we must merge them in.
for(;;) {
for(j = 0; j < l.n; j++) {
if(used[j]) continue;
if(winding[j] != winding[i] + 1) continue;
if(!contained[j][i]) continue;
SContour *inner = &(l.elem[j]);
int vinner, vouter;
if(VisibleVertices(&merged, inner, &extras, &vouter, &vinner)) {
used[j] = true;
SEdge se =
{ 0, merged.l.elem[vouter].p, inner->l.elem[vinner].p };
extras.l.Add(&se);
SContour alt;
ZERO(&alt);
for(k = 0; k <= vouter; k++) {
alt.AddPoint(merged.l.elem[k].p);
}
for(k = 0; k <= inner->l.n - 1; k++) {
int v = WRAP(k + vinner, inner->l.n - 1);
alt.AddPoint(inner->l.elem[v].p);
}
for(k = vouter; k < merged.l.n; k++) {
alt.AddPoint(merged.l.elem[k].p);
}
merged.l.Clear();
merged = alt;
break;
}
}
if(j >= l.n) {
break;
}
}
merged.TriangulateInto(m, meta, normal);
merged.l.Clear();
extras.Clear();
for(j = 0; j < l.n; j++) {
if(contained[j][i]) winding[j] -= 2;
}
used[i] = true;
}
} }

View File

@ -78,20 +78,12 @@ public:
Vector p; Vector p;
}; };
typedef struct {
DWORD face;
int color;
} STriMeta;
class SContour { class SContour {
public: public:
int tag;
SList<SPoint> l; SList<SPoint> l;
void AddPoint(Vector p); void AddPoint(Vector p);
void MakeEdgesInto(SEdgeList *el); void MakeEdgesInto(SEdgeList *el);
bool VertexIsEar(int v, Vector normal);
void TriangulateInto(SMesh *m, STriMeta meta, Vector normal);
void Reverse(void); void Reverse(void);
Vector ComputeNormal(void); Vector ComputeNormal(void);
bool IsClockwiseProjdToNormal(Vector n); bool IsClockwiseProjdToNormal(Vector n);
@ -99,6 +91,11 @@ public:
bool AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt); bool AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt);
}; };
typedef struct {
DWORD face;
int color;
} STriMeta;
class SPolygon { class SPolygon {
public: public:
SList<SContour> l; SList<SContour> l;
@ -115,9 +112,6 @@ public:
void Clear(void); void Clear(void);
bool AllPointsInPlane(Vector *notCoplanarAt); bool AllPointsInPlane(Vector *notCoplanarAt);
bool IsEmpty(void); bool IsEmpty(void);
bool IntersectsPolygon(Vector a, Vector b);
bool VisibleVertices(SContour *outer, SContour *inner,
SEdgeList *extras, int *vo, int *vi);
Vector AnyPoint(void); Vector AnyPoint(void);
}; };

View File

@ -500,21 +500,6 @@ Vector Vector::AtIntersectionOfPlanes(Vector n1, double d1,
return (n1.ScaledBy(c1)).Plus(n2.ScaledBy(c2)); return (n1.ScaledBy(c1)).Plus(n2.ScaledBy(c2));
} }
bool Vector::LinesIntersect(Vector a0, Vector da, Vector b0, Vector db,
double *ta, double *tb)
{
Vector dn = da.Cross(db); // normal to both
if(dn.Magnitude() < 1e-10) return false;
Vector dna = dn.Cross(da); // normal to dp
Vector dnb = dn.Cross(db); // normal to dg
*tb = ((a0.Minus(b0)).Dot(dna))/(db.Dot(dna));
*ta = -((a0.Minus(b0)).Dot(dnb))/(da.Dot(dnb));
return true;
}
Point2d Point2d::Plus(Point2d b) { Point2d Point2d::Plus(Point2d b) {
Point2d r; Point2d r;
r.x = x + b.x; r.x = x + b.x;