Add polygon triangulation, by cheating. I'm using the gl tesselator

for that, and storing the triangles instead of rendering them
immediately. Not sure if that's smart; in theory could change from
implementation to implementation, but the results look much better
than I would get myself.

[git-p4: depot-paths = "//depot/solvespace/": change = 1733]
solver
Jonathan Westhues 2008-05-22 02:28:28 -08:00
parent e80328279e
commit 7c4d305895
9 changed files with 211 additions and 111 deletions

View File

@ -22,6 +22,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
$(OBJDIR)\file.obj \ $(OBJDIR)\file.obj \
$(OBJDIR)\system.obj \ $(OBJDIR)\system.obj \
$(OBJDIR)\polygon.obj \ $(OBJDIR)\polygon.obj \
$(OBJDIR)\mesh.obj \
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib

View File

@ -527,10 +527,7 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) { void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) {
LineDrawOrGetDistance(a, b); LineDrawOrGetDistance(a, b);
if(dogd.edges && !construction) { if(dogd.edges && !construction) {
SEdge edge; dogd.edges->AddEdge(a, b);
edge.tag = 0;
edge.a = a; edge.b = b;
dogd.edges->l.Add(&edge);
} }
} }

View File

@ -111,11 +111,24 @@ void glxColor4d(double r, double g, double b, double a)
if(!ColorLocked) glColor4d(r, g, b, a); if(!ColorLocked) glColor4d(r, g, b, a);
} }
static void __stdcall Vertex(Vector *p) { static void GLX_CALLBACK Vertex(Vector *p) {
glxVertex3v(*p); glxVertex3v(*p);
} }
static void __stdcall Combine(double coords[3], void *vertexData[4],
float weight[4], void **outData) void glxFillPolygon(SPolygon *p)
{
GLUtesselator *gt = gluNewTess();
gluTessCallback(gt, GLU_TESS_BEGIN, (glxCallbackFptr *)glBegin);
gluTessCallback(gt, GLU_TESS_END, (glxCallbackFptr *)glEnd);
gluTessCallback(gt, GLU_TESS_VERTEX, (glxCallbackFptr *)Vertex);
glxTesselatePolygon(gt, p);
gluDeleteTess(gt);
}
static void GLX_CALLBACK Combine(double coords[3], void *vertexData[4],
float weight[4], void **outData)
{ {
Vector *n = (Vector *)AllocTemporary(sizeof(Vector)); Vector *n = (Vector *)AllocTemporary(sizeof(Vector));
n->x = coords[0]; n->x = coords[0];
@ -124,16 +137,11 @@ static void __stdcall Combine(double coords[3], void *vertexData[4],
*outData = n; *outData = n;
} }
void glxFillPolygon(SPolygon *p) void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p)
{ {
int i, j; int i, j;
GLUtesselator *gt = gluNewTess(); gluTessCallback(gt, GLU_TESS_COMBINE, (glxCallbackFptr *)Combine);
typedef void __stdcall cf(void);
gluTessCallback(gt, GLU_TESS_BEGIN, (cf *)glBegin);
gluTessCallback(gt, GLU_TESS_END, (cf *)glEnd);
gluTessCallback(gt, GLU_TESS_VERTEX, (cf *)Vertex);
gluTessCallback(gt, GLU_TESS_COMBINE, (cf *)Combine);
gluTessProperty(gt, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessProperty(gt, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
Vector normal = p->normal; Vector normal = p->normal;
@ -155,7 +163,6 @@ void glxFillPolygon(SPolygon *p)
gluTessEndContour(gt); gluTessEndContour(gt);
} }
gluTessEndPolygon(gt); gluTessEndPolygon(gt);
gluDeleteTess(gt);
} }
void glxDebugPolygon(SPolygon *p) void glxDebugPolygon(SPolygon *p)
@ -196,7 +203,7 @@ void glxDebugEdgeList(SEdgeList *el)
if(se->tag) continue; if(se->tag) continue;
Vector a = se->a, b = se->b; Vector a = se->a, b = se->b;
glxLockColorTo(0, 1, 0); glxLockColorTo(0, 1, 1);
Vector d = (a.Minus(b)).WithMagnitude(-0); Vector d = (a.Minus(b)).WithMagnitude(-0);
glBegin(GL_LINES); glBegin(GL_LINES);
glxVertex3v(a.Plus(d)); glxVertex3v(a.Plus(d));
@ -210,6 +217,32 @@ void glxDebugEdgeList(SEdgeList *el)
} }
} }
void glxDebugMesh(SMesh *m)
{
int i;
glLineWidth(2);
glPointSize(7);
glDisable(GL_DEPTH_TEST);
glxUnlockColor();
for(i = 0; i < m->l.n; i++) {
STriangle *t = &(m->l.elem[i]);
if(t->tag) continue;
glxColor4d(0, 1, 0, 0.3);
glBegin(GL_LINE_LOOP);
glxVertex3v(t->a);
glxVertex3v(t->b);
glxVertex3v(t->c);
glEnd();
glxColor4d(0, 0, 1, 0.4);
glBegin(GL_POINTS);
glxVertex3v(t->a);
glxVertex3v(t->b);
glxVertex3v(t->c);
glEnd();
}
}
void glxMarkPolygonNormal(SPolygon *p) void glxMarkPolygonNormal(SPolygon *p)
{ {
Vector tail = Vector::MakeFrom(0, 0, 0); Vector tail = Vector::MakeFrom(0, 0, 0);

View File

@ -1181,10 +1181,11 @@ void GraphicsWindow::Paint(int w, int h) {
selection[i].Draw(); selection[i].Draw();
} }
if(SS.group.n >= 5) { if(SS.group.n >= 2) {
if(1) { SMesh m; ZERO(&m);
//XXX (SS.group.elem[1].poly).TriangulateInto(&m);
} glxDebugMesh(&m);
m.Clear();
} }
} }

View File

@ -1,5 +1,16 @@
#include "solvespace.h" #include "solvespace.h"
void SEdgeList::Clear(void) {
l.Clear();
}
void SEdgeList::AddEdge(Vector a, Vector b) {
SEdge e; ZERO(&e);
e.a = a;
e.b = b;
l.Add(&e);
}
bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) { bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) {
dest->Clear(); dest->Clear();
@ -52,79 +63,6 @@ bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) {
} }
} }
void SPolygon::Clear(void) {
int i;
for(i = 0; i < l.n; i++) {
(l.elem[i]).l.Clear();
}
l.Clear();
}
void SPolygon::AddEmptyContour(void) {
SContour c;
memset(&c, 0, sizeof(c));
l.Add(&c);
}
void SPolygon::AddPoint(Vector p) {
if(l.n < 1) oops();
SPoint sp;
sp.tag = 0;
sp.p = p;
// Add to the last contour in the list
(l.elem[l.n-1]).l.Add(&sp);
}
void SPolygon::MakeEdgesInto(SEdgeList *el) {
int i;
for(i = 0; i < l.n; i++) {
(l.elem[i]).MakeEdgesInto(el);
}
}
Vector SPolygon::ComputeNormal(void) {
if(l.n < 1) return Vector::MakeFrom(0, 0, 0);
return (l.elem[0]).ComputeNormal();
}
bool SPolygon::ContainsPoint(Vector p) {
bool inside = false;
int i;
for(i = 0; i < l.n; i++) {
SContour *sc = &(l.elem[i]);
if(sc->ContainsPointProjdToNormal(normal, p)) {
inside = !inside;
}
}
return inside;
}
void SPolygon::FixContourDirections(void) {
// Outside curve looks counterclockwise, projected against our normal.
int i, j;
for(i = 0; i < l.n; i++) {
SContour *sc = &(l.elem[i]);
if(sc->l.n < 1) continue;
Vector pt = (sc->l.elem[0]).p;
bool outer = true;
for(j = 0; j < l.n; j++) {
if(i == j) continue;
SContour *sct = &(l.elem[j]);
if(sct->ContainsPointProjdToNormal(normal, pt)) {
outer = !outer;
}
}
bool clockwise = sc->IsClockwiseProjdToNormal(normal);
if(clockwise && outer || (!clockwise && !outer)) {
sc->Reverse();
}
}
}
void SContour::MakeEdgesInto(SEdgeList *el) { void SContour::MakeEdgesInto(SEdgeList *el) {
int i; int i;
for(i = 0; i < (l.n-1); i++) { for(i = 0; i < (l.n-1); i++) {
@ -208,3 +146,124 @@ void SContour::Reverse(void) {
} }
} }
void SPolygon::Clear(void) {
int i;
for(i = 0; i < l.n; i++) {
(l.elem[i]).l.Clear();
}
l.Clear();
}
void SPolygon::AddEmptyContour(void) {
SContour c;
memset(&c, 0, sizeof(c));
l.Add(&c);
}
void SPolygon::AddPoint(Vector p) {
if(l.n < 1) oops();
SPoint sp;
sp.tag = 0;
sp.p = p;
// Add to the last contour in the list
(l.elem[l.n-1]).l.Add(&sp);
}
void SPolygon::MakeEdgesInto(SEdgeList *el) {
int i;
for(i = 0; i < l.n; i++) {
(l.elem[i]).MakeEdgesInto(el);
}
}
Vector SPolygon::ComputeNormal(void) {
if(l.n < 1) return Vector::MakeFrom(0, 0, 0);
return (l.elem[0]).ComputeNormal();
}
bool SPolygon::ContainsPoint(Vector p) {
bool inside = false;
int i;
for(i = 0; i < l.n; i++) {
SContour *sc = &(l.elem[i]);
if(sc->ContainsPointProjdToNormal(normal, p)) {
inside = !inside;
}
}
return inside;
}
void SPolygon::FixContourDirections(void) {
// Outside curve looks counterclockwise, projected against our normal.
int i, j;
for(i = 0; i < l.n; i++) {
SContour *sc = &(l.elem[i]);
if(sc->l.n < 1) continue;
Vector pt = (sc->l.elem[0]).p;
bool outer = true;
for(j = 0; j < l.n; j++) {
if(i == j) continue;
SContour *sct = &(l.elem[j]);
if(sct->ContainsPointProjdToNormal(normal, pt)) {
outer = !outer;
}
}
bool clockwise = sc->IsClockwiseProjdToNormal(normal);
if(clockwise && outer || (!clockwise && !outer)) {
sc->Reverse();
}
}
}
static int TriMode, TriVertexCount;
static Vector Tri1, TriNMinus1, TriNMinus2;
static SMesh *TriMesh;
static void GLX_CALLBACK TriBegin(int mode)
{
TriMode = mode;
TriVertexCount = 0;
}
static void GLX_CALLBACK TriEnd(void)
{
}
static void GLX_CALLBACK TriVertex(Vector *triN)
{
if(TriVertexCount == 0) {
Tri1 = *triN;
}
if(TriMode == GL_TRIANGLES) {
if((TriVertexCount % 3) == 2) {
TriMesh->AddTriangle(TriNMinus2, TriNMinus1, *triN);
}
} else if(TriMode == GL_TRIANGLE_FAN) {
if(TriVertexCount >= 2) {
TriMesh->AddTriangle(Tri1, TriNMinus1, *triN);
}
} else if(TriMode == GL_TRIANGLE_STRIP) {
if(TriVertexCount >= 2) {
TriMesh->AddTriangle(TriNMinus2, TriNMinus1, *triN);
}
} else oops();
TriNMinus2 = TriNMinus1;
TriNMinus1 = *triN;
TriVertexCount++;
}
void SPolygon::TriangulateInto(SMesh *m) {
TriMesh = m;
GLUtesselator *gt = gluNewTess();
gluTessCallback(gt, GLU_TESS_BEGIN, (glxCallbackFptr *)TriBegin);
gluTessCallback(gt, GLU_TESS_END, (glxCallbackFptr *)TriEnd);
gluTessCallback(gt, GLU_TESS_VERTEX, (glxCallbackFptr *)TriVertex);
glxTesselatePolygon(gt, this);
gluDeleteTess(gt);
}

View File

@ -3,6 +3,7 @@
#define __POLYGON_H #define __POLYGON_H
class SPolygon; class SPolygon;
class SMesh;
template <class T> template <class T>
class SList { class SList {
@ -43,12 +44,9 @@ class SEdgeList {
public: public:
SList<SEdge> l; SList<SEdge> l;
void Clear(void);
void AddEdge(Vector a, Vector b);
bool AssemblePolygon(SPolygon *dest, SEdge *errorAt); bool AssemblePolygon(SPolygon *dest, SEdge *errorAt);
void CopyBreaking(SEdgeList *dest);
static const int UNION = 0, DIFF = 1, INTERSECT = 2;
bool BooleanOp(int op, bool inA, bool inB);
void CullForBoolean(int op, SPolygon *a, SPolygon *b);
void CullDuplicates(void);
}; };
class SPoint { class SPoint {
@ -66,8 +64,6 @@ public:
Vector ComputeNormal(void); Vector ComputeNormal(void);
bool IsClockwiseProjdToNormal(Vector n); bool IsClockwiseProjdToNormal(Vector n);
bool ContainsPointProjdToNormal(Vector n, Vector p); bool ContainsPointProjdToNormal(Vector n, Vector p);
void IntersectAgainstPlane(double *inter, int *inters,
Vector u, Vector v, double vp);
}; };
class SPolygon { class SPolygon {
@ -81,20 +77,24 @@ public:
bool ContainsPoint(Vector p); bool ContainsPoint(Vector p);
void MakeEdgesInto(SEdgeList *el); void MakeEdgesInto(SEdgeList *el);
void FixContourDirections(void); void FixContourDirections(void);
void TriangulateInto(SMesh *m);
void Clear(void); void Clear(void);
}; };
class STriangle { class STriangle {
public: public:
Vector a, b, c; int tag;
Vector a, b, c;
}; };
class SBsp2 { class SBsp2 {
public:
SEdge edge; SEdge edge;
};
class SBsp1d { SBsp2 *pos;
SEdge edge; SBsp2 *neg;
SBsp2 *more;
}; };
class SBsp3 { class SBsp3 {
@ -112,6 +112,9 @@ public:
class SMesh { class SMesh {
public: public:
SList<STriangle> l; SList<STriangle> l;
void Clear(void);
void AddTriangle(Vector a, Vector b, Vector c);
}; };
#endif #endif

View File

@ -418,7 +418,7 @@ void Group::MakePolygons(void) {
} }
// Get the source polygon to extrude, and break it down to edges // Get the source polygon to extrude, and break it down to edges
edges.l.Clear(); edges.Clear();
Group *src = SS.GetGroup(opA); Group *src = SS.GetGroup(opA);
(src->poly).MakeEdgesInto(&edges); (src->poly).MakeEdgesInto(&edges);
@ -440,7 +440,7 @@ void Group::MakePolygons(void) {
np.FixContourDirections(); np.FixContourDirections();
// Regenerate the edges, with the contour directions fixed up. // Regenerate the edges, with the contour directions fixed up.
edges.l.Clear(); edges.Clear();
np.MakeEdgesInto(&edges); np.MakeEdgesInto(&edges);
// The sides // The sides
@ -465,7 +465,7 @@ void Group::MakePolygons(void) {
if(!edges.AssemblePolygon(&np, NULL)) oops(); if(!edges.AssemblePolygon(&np, NULL)) oops();
np.normal = n.ScaledBy(-1); np.normal = n.ScaledBy(-1);
} }
edges.l.Clear(); edges.Clear();
} }
void Group::Draw(void) { void Group::Draw(void) {

View File

@ -14,6 +14,9 @@
#define SWAP(T, a, b) do { T temp = (a); (a) = (b); (b) = temp; } while(0) #define SWAP(T, a, b) do { T temp = (a); (a) = (b); (b) = temp; } while(0)
#define ZERO(v) memset((v), 0, sizeof(*(v))) #define ZERO(v) memset((v), 0, sizeof(*(v)))
#define CO(v) (v).x, (v).y, (v).z
#define LENGTH_EPS (0.0001)
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#') #define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
@ -70,9 +73,13 @@ void vl(void); // debug function to validate
// Utility functions that are provided in the platform-independent code. // Utility functions that are provided in the platform-independent code.
void glxVertex3v(Vector u); void glxVertex3v(Vector u);
#define GLX_CALLBACK __stdcall
typedef void GLX_CALLBACK glxCallbackFptr(void);
void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p);
void glxFillPolygon(SPolygon *p); void glxFillPolygon(SPolygon *p);
void glxDebugPolygon(SPolygon *p); void glxDebugPolygon(SPolygon *p);
void glxDebugEdgeList(SEdgeList *l); void glxDebugEdgeList(SEdgeList *l);
void glxDebugMesh(SMesh *m);
void glxMarkPolygonNormal(SPolygon *p); void glxMarkPolygonNormal(SPolygon *p);
void glxWriteText(char *str); void glxWriteText(char *str);
void glxWriteTextRefCenter(char *str); void glxWriteTextRefCenter(char *str);

View File

@ -178,10 +178,9 @@ Vector Vector::MakeFrom(double x, double y, double z) {
} }
bool Vector::Equals(Vector v) { bool Vector::Equals(Vector v) {
double tol = 0.00001; if(fabs(x - v.x) > LENGTH_EPS) return false;
if(fabs(x - v.x) > tol) return false; if(fabs(y - v.y) > LENGTH_EPS) return false;
if(fabs(y - v.y) > tol) return false; if(fabs(z - v.z) > LENGTH_EPS) return false;
if(fabs(z - v.z) > tol) return false;
return true; return true;
} }