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:
parent
9b008ad1cd
commit
a47a77c37c
2
dsc.h
2
dsc.h
@ -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);
|
||||||
|
270
polygon.cpp
270
polygon.cpp
@ -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) {
|
||||||
l.Clear();
|
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();
|
||||||
|
|
||||||
|
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)) {
|
|
||||||
(winding[i])++;
|
|
||||||
contained[i][j] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;) {
|
gluDeleteTess(gt);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
polygon.h
16
polygon.h
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
15
util.cpp
15
util.cpp
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user