From 6ae07c3c9f1abd30e4e62df0495bf54d48777c42 Mon Sep 17 00:00:00 2001 From: kintel Date: Mon, 11 Jan 2010 22:15:24 +0000 Subject: [PATCH] Split out GLU tesselation into a separate file for easier experimentation git-svn-id: http://svn.clifford.at/openscad/trunk@265 b57f626f-c46c-0410-a088-ec61d464b74c --- dxftess-glu.cc | 375 +++++++++++++++++++++++++++++++++++++++++++++++++ dxftess.cc | 372 +----------------------------------------------- 2 files changed, 376 insertions(+), 371 deletions(-) create mode 100644 dxftess-glu.cc diff --git a/dxftess-glu.cc b/dxftess-glu.cc new file mode 100644 index 00000000..3256b4f5 --- /dev/null +++ b/dxftess-glu.cc @@ -0,0 +1,375 @@ +#ifdef WIN32 +# define STDCALL __stdcall +#else +# define STDCALL +#endif + +#undef DEBUG_TRIANGLE_SPLITTING + +struct tess_vdata { + GLdouble v[3]; +}; + +struct tess_triangle { + GLdouble *p[3]; + tess_triangle() { p[0] = NULL; p[1] = NULL; p[2] = NULL; } + tess_triangle(double *p1, double *p2, double *p3) { p[0] = p1; p[1] = p2; p[2] = p3; } +}; + +static GLenum tess_type; +static int tess_count; +static QVector tess_tri; +static GLdouble *tess_p1, *tess_p2; + +static void STDCALL tess_vertex(void *vertex_data) +{ + GLdouble *p = (double*)vertex_data; +#if 0 + printf(" %d: %f %f %f\n", tess_count, p[0], p[1], p[2]); +#endif + if (tess_type == GL_TRIANGLE_FAN) { + if (tess_count == 0) { + tess_p1 = p; + } + if (tess_count == 1) { + tess_p2 = p; + } + if (tess_count > 1) { + tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); + tess_p2 = p; + } + } + if (tess_type == GL_TRIANGLE_STRIP) { + if (tess_count == 0) { + tess_p1 = p; + } + if (tess_count == 1) { + tess_p2 = p; + } + if (tess_count > 1) { + if (tess_count % 2 == 1) { + tess_tri.append(tess_triangle(tess_p2, tess_p1, p)); + } else { + tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); + } + tess_p1 = tess_p2; + tess_p2 = p; + } + } + if (tess_type == GL_TRIANGLES) { + if (tess_count == 0) { + tess_p1 = p; + } + if (tess_count == 1) { + tess_p2 = p; + } + if (tess_count == 2) { + tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); + tess_count = -1; + } + } + tess_count++; +} + +static void STDCALL tess_begin(GLenum type) +{ +#if 0 + if (type == GL_TRIANGLE_FAN) { + printf("GL_TRIANGLE_FAN:\n"); + } + if (type == GL_TRIANGLE_STRIP) { + printf("GL_TRIANGLE_STRIP:\n"); + } + if (type == GL_TRIANGLES) { + printf("GL_TRIANGLES:\n"); + } +#endif + tess_count = 0; + tess_type = type; +} + +static void STDCALL tess_end(void) +{ + /* nothing to be done here */ +} + +static void STDCALL tess_error(GLenum errno) +{ + PRINTF("GLU tesselation error %d!", errno); +} + +static void STDCALL tess_begin_data() +{ + PRINTF("GLU tesselation BEGIN_DATA\n"); +} + +static void STDCALL tess_edge_flag(GLboolean flag) +{ +// PRINTF("GLU tesselation EDGE_FLAG\n"); +} + +static void STDCALL tess_edge_flag_data(GLboolean flag, void *polygon_data) +{ + PRINTF("GLU tesselation EDGE_FLAG_DATA\n"); +} +static void STDCALL tess_vertex_data(void *vertex_data, void *polygon_data) +{ + PRINTF("GLU tesselation VERTEX_DATA\n"); +} +static void STDCALL tess_end_data(void *polygon_data) +{ + PRINTF("GLU tesselation END_DATA\n"); +} +static void STDCALL tess_combine(GLdouble coords[3], void *vertex_data[4], + GLfloat weight[4], void **outData ) +{ + PRINTF("GLU tesselation COMBINE\n"); +} +static void STDCALL tess_combine_data(GLdouble coords[3], void *vertex_data[4], + GLfloat weight[4], void **outData, + void *polygon_data) +{ + PRINTF("GLU tesselation COMBINE_DATA\n"); +} +static void STDCALL tess_error_data(GLenum errno, void *polygon_data ) +{ + PRINTF("GLU tesselation ERROR_DATA\n"); +} + +static bool point_on_line(double *p1, double *p2, double *p3) +{ + if (fabs(p1[0] - p2[0]) < 0.00001 && fabs(p1[1] - p2[1]) < 0.00001) + return false; + + if (fabs(p3[0] - p2[0]) < 0.00001 && fabs(p3[1] - p2[1]) < 0.00001) + return false; + + double v1[2] = { p2[0] - p1[0], p2[1] - p1[1] }; + double v2[2] = { p3[0] - p1[0], p3[1] - p1[1] }; + + if (sqrt(v1[0]*v1[0] + v1[1]*v1[1]) > sqrt(v2[0]*v2[0] + v2[1]*v2[1])) + return false; + + if (fabs(v1[0]) > fabs(v1[1])) { + // y = x * dy/dx + if (v2[0] == 0 || ((v1[0] > 0) != (v2[0] > 0))) + return false; + double v1_dy_dx = v1[1] / v1[0]; + double v2_dy_dx = v2[1] / v2[0]; + if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) + return false; + } else { + // x = y * dx/dy + if (v2[1] == 0 || ((v1[1] > 0) != (v2[1] > 0))) + return false; + double v1_dy_dx = v1[0] / v1[1]; + double v2_dy_dx = v2[0] / v2[1]; + if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) + return false; + } + +#if 0 + printf("Point on line: %f/%f %f/%f %f/%f\n", p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]); +#endif + return true; +} + +/*! + up: true if the polygon is facing in the normal direction (i.e. normal = [0,0,1]) + rot: CLOCKWISE rotation around positive Z axis + */ + +void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_triangle_splitting, double h) +{ + GLUtesselator *tobj = gluNewTess(); + + gluTessCallback(tobj, GLU_TESS_VERTEX, (void(STDCALL *)())&tess_vertex); + gluTessCallback(tobj, GLU_TESS_BEGIN, (void(STDCALL *)())&tess_begin); + gluTessCallback(tobj, GLU_TESS_END, (void(STDCALL *)())&tess_end); + gluTessCallback(tobj, GLU_TESS_ERROR, (void(STDCALL *)())&tess_error); + + gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, (void(STDCALL *)())&tess_edge_flag); +// gluTessCallback(tobj, GLU_TESS_COMBINE, (void(STDCALL *)())&tess_combine); + +/* gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (void(STDCALL *)())&tess_begin_data); */ +/* gluTessCallback(tobj, GLU_TESS_EDGE_FLAG_DATA, (void(STDCALL *)())&tess_edge_flag_data); */ +/* gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (void(STDCALL *)())&tess_vertex_data); */ +/* gluTessCallback(tobj, GLU_TESS_END_DATA, (void(STDCALL *)())&tess_end_data); */ +/* gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (void(STDCALL *)())&tess_combine_data); */ +/* gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (void(STDCALL *)())&tess_error_data); */ + + + tess_tri.clear(); + QList vl; + + gluTessBeginPolygon(tobj, NULL); + + gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + if (up) { + gluTessNormal(tobj, 0, 0, -1); + } else { + gluTessNormal(tobj, 0, 0, +1); + } + + Grid3d< QPair > point_to_path; + + for (int i = 0; i < dxf->paths.count(); i++) { + if (!dxf->paths[i].is_closed) + continue; + gluTessBeginContour(tobj); + for (int j = 1; j < dxf->paths[i].points.count(); j++) { + point_to_path.data(dxf->paths[i].points[j]->x, + dxf->paths[i].points[j]->y, + h) = QPair(i, j); + vl.append(tess_vdata()); + vl.last().v[0] = dxf->paths[i].points[j]->x; + vl.last().v[1] = dxf->paths[i].points[j]->y; + vl.last().v[2] = h; + gluTessVertex(tobj, vl.last().v, vl.last().v); + } + gluTessEndContour(tobj); + } + + gluTessEndPolygon(tobj); + gluDeleteTess(tobj); + +#if 0 + for (int i = 0; i < tess_tri.count(); i++) { + printf("~~~\n"); + printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); + printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); + printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); + } +#endif + + // GLU tessing sometimes generates degenerated triangles. We must find and remove + // them so we can use the triangle array with CGAL.. + for (int i = 0; i < tess_tri.count(); i++) { + if (point_on_line(tess_tri[i].p[0], tess_tri[i].p[1], tess_tri[i].p[2]) || + point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) || + point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) { + // printf("DEBUG: Removed triangle\n"); + tess_tri.remove(i--); + } + } + + // GLU tessing creates T-junctions. This is ok for GL displaying but creates + // invalid polyhedrons for CGAL. So we split this tirangles up again in order + // to create polyhedrons that are also accepted by CGAL.. + // All triangle edges are sorted by their atan2 and only edges with a simmilar atan2 + // value are compared. This speeds up this code block dramatically (compared to the + // n^2 compares that are neccessary in the trivial implementation). +#if 1 + if (do_triangle_splitting) + { + bool added_triangles = true; + typedef QPair QPair_ii; + QHash tri_by_atan2; + for (int i = 0; i < tess_tri.count(); i++) + for (int j = 0; j < 3; j++) { + int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]), + fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001); + tri_by_atan2.insertMulti(ai, QPair(i, j)); + } + while (added_triangles) + { + added_triangles = false; +#ifdef DEBUG_TRIANGLE_SPLITTING + printf("*** Triangle splitting (%d) ***\n", tess_tri.count()+1); +#endif + for (int i = 0; i < tess_tri.count(); i++) + for (int k = 0; k < 3; k++) + { + QHash possible_neigh; + int ai = (int)floor(atan2(fabs(tess_tri[i].p[(k+1)%3][0] - tess_tri[i].p[k][0]), + fabs(tess_tri[i].p[(k+1)%3][1] - tess_tri[i].p[k][1])) / 0.001 - 0.5); + for (int j = 0; j < 2; j++) { + foreach (const QPair_ii &jl, tri_by_atan2.values(ai+j)) + if (i != jl.first) + possible_neigh[jl] = jl; + } +#ifdef DEBUG_TRIANGLE_SPLITTING + printf("%d/%d: %d\n", i, k, possible_neigh.count()); +#endif + foreach (const QPair_ii &jl, possible_neigh) { + int j = jl.first; + for (int l = jl.second; l != (jl.second + 2) % 3; l = (l + 1) % 3) + if (point_on_line(tess_tri[i].p[k], tess_tri[j].p[l], tess_tri[i].p[(k+1)%3])) { +#ifdef DEBUG_TRIANGLE_SPLITTING + printf("%% %f %f %f %f %f %f [%d %d]\n", + tess_tri[i].p[k][0], tess_tri[i].p[k][1], + tess_tri[j].p[l][0], tess_tri[j].p[l][1], + tess_tri[i].p[(k+1)%3][0], tess_tri[i].p[(k+1)%3][1], + i, j); +#endif + tess_tri.append(tess_triangle(tess_tri[j].p[l], + tess_tri[i].p[(k+1)%3], tess_tri[i].p[(k+2)%3])); + for (int m = 0; m < 2; m++) { + int ai = (int)round(atan2(fabs(tess_tri.last().p[(m+1)%3][0] - tess_tri.last().p[m][0]), + fabs(tess_tri.last().p[(m+1)%3][1] - tess_tri.last().p[m][1])) / 0.001 ); + tri_by_atan2.insertMulti(ai, QPair(tess_tri.count()-1, m)); + } + tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l]; + for (int m = 0; m < 2; m++) { + int ai = (int)round(atan2(fabs(tess_tri[i].p[(m+1)%3][0] - tess_tri[i].p[m][0]), + fabs(tess_tri[i].p[(m+1)%3][1] - tess_tri[i].p[m][1])) / 0.001 ); + tri_by_atan2.insertMulti(ai, QPair(i, m)); + } + added_triangles = true; + } + } + } + } + } +#endif + + for (int i = 0; i < tess_tri.count(); i++) + { +#if 0 + printf("---\n"); + printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); + printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); + printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); +#endif + double x, y; + ps->append_poly(); + + x = tess_tri[i].p[0][0] * cos(rot*M_PI/180) + tess_tri[i].p[0][1] * sin(rot*M_PI/180); + y = tess_tri[i].p[0][0] * -sin(rot*M_PI/180) + tess_tri[i].p[0][1] * cos(rot*M_PI/180); + ps->insert_vertex(x, y, tess_tri[i].p[0][2]); + + x = tess_tri[i].p[1][0] * cos(rot*M_PI/180) + tess_tri[i].p[1][1] * sin(rot*M_PI/180); + y = tess_tri[i].p[1][0] * -sin(rot*M_PI/180) + tess_tri[i].p[1][1] * cos(rot*M_PI/180); + ps->insert_vertex(x, y, tess_tri[i].p[1][2]); + + x = tess_tri[i].p[2][0] * cos(rot*M_PI/180) + tess_tri[i].p[2][1] * sin(rot*M_PI/180); + y = tess_tri[i].p[2][0] * -sin(rot*M_PI/180) + tess_tri[i].p[2][1] * cos(rot*M_PI/180); + ps->insert_vertex(x, y, tess_tri[i].p[2][2]); + + int i0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).first; + int j0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).second; + + int i1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).first; + int j1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).second; + + int i2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).first; + int j2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).second; + + if (i0 == i1 && j0 == 1 && j1 == 2) + dxf->paths[i0].is_inner = !up; + if (i0 == i1 && j0 == 2 && j1 == 1) + dxf->paths[i0].is_inner = up; + + if (i1 == i2 && j1 == 1 && j2 == 2) + dxf->paths[i1].is_inner = !up; + if (i1 == i2 && j1 == 2 && j2 == 1) + dxf->paths[i1].is_inner = up; + + if (i2 == i0 && j2 == 1 && j0 == 2) + dxf->paths[i2].is_inner = !up; + if (i2 == i0 && j2 == 2 && j0 == 1) + dxf->paths[i2].is_inner = up; + } + + tess_tri.clear(); +} diff --git a/dxftess.cc b/dxftess.cc index b66b1497..44336799 100644 --- a/dxftess.cc +++ b/dxftess.cc @@ -18,382 +18,12 @@ * */ -#ifdef WIN32 -# define STDCALL __stdcall -#else -# define STDCALL -#endif - #define INCLUDE_ABSTRACT_NODE_DETAILS #include "openscad.h" #include "printutils.h" -#undef DEBUG_TRIANGLE_SPLITTING - -struct tess_vdata { - GLdouble v[3]; -}; - -struct tess_triangle { - GLdouble *p[3]; - tess_triangle() { p[0] = NULL; p[1] = NULL; p[2] = NULL; } - tess_triangle(double *p1, double *p2, double *p3) { p[0] = p1; p[1] = p2; p[2] = p3; } -}; - -static GLenum tess_type; -static int tess_count; -static QVector tess_tri; -static GLdouble *tess_p1, *tess_p2; - -static void STDCALL tess_vertex(void *vertex_data) -{ - GLdouble *p = (double*)vertex_data; -#if 0 - printf(" %d: %f %f %f\n", tess_count, p[0], p[1], p[2]); -#endif - if (tess_type == GL_TRIANGLE_FAN) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count > 1) { - tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); - tess_p2 = p; - } - } - if (tess_type == GL_TRIANGLE_STRIP) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count > 1) { - if (tess_count % 2 == 1) { - tess_tri.append(tess_triangle(tess_p2, tess_p1, p)); - } else { - tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); - } - tess_p1 = tess_p2; - tess_p2 = p; - } - } - if (tess_type == GL_TRIANGLES) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count == 2) { - tess_tri.append(tess_triangle(tess_p1, tess_p2, p)); - tess_count = -1; - } - } - tess_count++; -} - -static void STDCALL tess_begin(GLenum type) -{ -#if 0 - if (type == GL_TRIANGLE_FAN) { - printf("GL_TRIANGLE_FAN:\n"); - } - if (type == GL_TRIANGLE_STRIP) { - printf("GL_TRIANGLE_STRIP:\n"); - } - if (type == GL_TRIANGLES) { - printf("GL_TRIANGLES:\n"); - } -#endif - tess_count = 0; - tess_type = type; -} - -static void STDCALL tess_end(void) -{ - /* nothing to be done here */ -} - -static void STDCALL tess_error(GLenum errno) -{ - PRINTF("GLU tesselation error %d!", errno); -} - -static void STDCALL tess_begin_data() -{ - PRINTF("GLU tesselation BEGIN_DATA\n"); -} - -static void STDCALL tess_edge_flag(GLboolean flag) -{ -// PRINTF("GLU tesselation EDGE_FLAG\n"); -} - -static void STDCALL tess_edge_flag_data(GLboolean flag, void *polygon_data) -{ - PRINTF("GLU tesselation EDGE_FLAG_DATA\n"); -} -static void STDCALL tess_vertex_data(void *vertex_data, void *polygon_data) -{ - PRINTF("GLU tesselation VERTEX_DATA\n"); -} -static void STDCALL tess_end_data(void *polygon_data) -{ - PRINTF("GLU tesselation END_DATA\n"); -} -static void STDCALL tess_combine(GLdouble coords[3], void *vertex_data[4], - GLfloat weight[4], void **outData ) -{ - PRINTF("GLU tesselation COMBINE\n"); -} -static void STDCALL tess_combine_data(GLdouble coords[3], void *vertex_data[4], - GLfloat weight[4], void **outData, - void *polygon_data) -{ - PRINTF("GLU tesselation COMBINE_DATA\n"); -} -static void STDCALL tess_error_data(GLenum errno, void *polygon_data ) -{ - PRINTF("GLU tesselation ERROR_DATA\n"); -} - -static bool point_on_line(double *p1, double *p2, double *p3) -{ - if (fabs(p1[0] - p2[0]) < 0.00001 && fabs(p1[1] - p2[1]) < 0.00001) - return false; - - if (fabs(p3[0] - p2[0]) < 0.00001 && fabs(p3[1] - p2[1]) < 0.00001) - return false; - - double v1[2] = { p2[0] - p1[0], p2[1] - p1[1] }; - double v2[2] = { p3[0] - p1[0], p3[1] - p1[1] }; - - if (sqrt(v1[0]*v1[0] + v1[1]*v1[1]) > sqrt(v2[0]*v2[0] + v2[1]*v2[1])) - return false; - - if (fabs(v1[0]) > fabs(v1[1])) { - // y = x * dy/dx - if (v2[0] == 0 || ((v1[0] > 0) != (v2[0] > 0))) - return false; - double v1_dy_dx = v1[1] / v1[0]; - double v2_dy_dx = v2[1] / v2[0]; - if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) - return false; - } else { - // x = y * dx/dy - if (v2[1] == 0 || ((v1[1] > 0) != (v2[1] > 0))) - return false; - double v1_dy_dx = v1[0] / v1[1]; - double v2_dy_dx = v2[0] / v2[1]; - if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) - return false; - } - -#if 0 - printf("Point on line: %f/%f %f/%f %f/%f\n", p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]); -#endif - return true; -} - -void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_triangle_splitting, double h) -{ - GLUtesselator *tobj = gluNewTess(); - - gluTessCallback(tobj, GLU_TESS_VERTEX, (void(STDCALL *)())&tess_vertex); - gluTessCallback(tobj, GLU_TESS_BEGIN, (void(STDCALL *)())&tess_begin); - gluTessCallback(tobj, GLU_TESS_END, (void(STDCALL *)())&tess_end); - gluTessCallback(tobj, GLU_TESS_ERROR, (void(STDCALL *)())&tess_error); - - gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, (void(STDCALL *)())&tess_edge_flag); - gluTessCallback(tobj, GLU_TESS_COMBINE, (void(STDCALL *)())&tess_combine); - -/* gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (void(STDCALL *)())&tess_begin_data); */ -/* gluTessCallback(tobj, GLU_TESS_EDGE_FLAG_DATA, (void(STDCALL *)())&tess_edge_flag_data); */ -/* gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (void(STDCALL *)())&tess_vertex_data); */ -/* gluTessCallback(tobj, GLU_TESS_END_DATA, (void(STDCALL *)())&tess_end_data); */ -/* gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (void(STDCALL *)())&tess_combine_data); */ -/* gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (void(STDCALL *)())&tess_error_data); */ - - - tess_tri.clear(); - QList vl; - - gluTessBeginPolygon(tobj, NULL); - - gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); - if (up) { - gluTessNormal(tobj, 0, 0, -1); - } else { - gluTessNormal(tobj, 0, 0, +1); - } - - Grid3d< QPair > point_to_path; - - for (int i = 0; i < dxf->paths.count(); i++) { - if (!dxf->paths[i].is_closed) - continue; - gluTessBeginContour(tobj); - for (int j = 1; j < dxf->paths[i].points.count(); j++) { - point_to_path.data(dxf->paths[i].points[j]->x, - dxf->paths[i].points[j]->y, - h) = QPair(i, j); - vl.append(tess_vdata()); - vl.last().v[0] = dxf->paths[i].points[j]->x; - vl.last().v[1] = dxf->paths[i].points[j]->y; - vl.last().v[2] = h; - gluTessVertex(tobj, vl.last().v, vl.last().v); - } - gluTessEndContour(tobj); - } - - gluTessEndPolygon(tobj); - gluDeleteTess(tobj); - -#if 0 - for (int i = 0; i < tess_tri.count(); i++) { - printf("~~~\n"); - printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); - printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); - printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); - } -#endif - - // GLU tessing sometimes generates degenerated triangles. We must find and remove - // them so we can use the triangle array with CGAL.. - for (int i = 0; i < tess_tri.count(); i++) { - if (point_on_line(tess_tri[i].p[0], tess_tri[i].p[1], tess_tri[i].p[2]) || - point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) || - point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) { - // printf("DEBUG: Removed triangle\n"); - tess_tri.remove(i--); - } - } - - // GLU tessing creates T-junctions. This is ok for GL displaying but creates - // invalid polyhedrons for CGAL. So we split this tirangles up again in order - // to create polyhedrons that are also accepted by CGAL.. - // All triangle edges are sorted by their atan2 and only edges with a simmilar atan2 - // value are compared. This speeds up this code block dramatically (compared to the - // n^2 compares that are neccessary in the trivial implementation). -#if 1 - if (do_triangle_splitting) - { - bool added_triangles = true; - typedef QPair QPair_ii; - QHash tri_by_atan2; - for (int i = 0; i < tess_tri.count(); i++) - for (int j = 0; j < 3; j++) { - int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]), - fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001); - tri_by_atan2.insertMulti(ai, QPair(i, j)); - } - while (added_triangles) - { - added_triangles = false; -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("*** Triangle splitting (%d) ***\n", tess_tri.count()+1); -#endif - for (int i = 0; i < tess_tri.count(); i++) - for (int k = 0; k < 3; k++) - { - QHash possible_neigh; - int ai = (int)floor(atan2(fabs(tess_tri[i].p[(k+1)%3][0] - tess_tri[i].p[k][0]), - fabs(tess_tri[i].p[(k+1)%3][1] - tess_tri[i].p[k][1])) / 0.001 - 0.5); - for (int j = 0; j < 2; j++) { - foreach (const QPair_ii &jl, tri_by_atan2.values(ai+j)) - if (i != jl.first) - possible_neigh[jl] = jl; - } -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("%d/%d: %d\n", i, k, possible_neigh.count()); -#endif - foreach (const QPair_ii &jl, possible_neigh) { - int j = jl.first; - for (int l = jl.second; l != (jl.second + 2) % 3; l = (l + 1) % 3) - if (point_on_line(tess_tri[i].p[k], tess_tri[j].p[l], tess_tri[i].p[(k+1)%3])) { -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("%% %f %f %f %f %f %f [%d %d]\n", - tess_tri[i].p[k][0], tess_tri[i].p[k][1], - tess_tri[j].p[l][0], tess_tri[j].p[l][1], - tess_tri[i].p[(k+1)%3][0], tess_tri[i].p[(k+1)%3][1], - i, j); -#endif - tess_tri.append(tess_triangle(tess_tri[j].p[l], - tess_tri[i].p[(k+1)%3], tess_tri[i].p[(k+2)%3])); - for (int m = 0; m < 2; m++) { - int ai = (int)round(atan2(fabs(tess_tri.last().p[(m+1)%3][0] - tess_tri.last().p[m][0]), - fabs(tess_tri.last().p[(m+1)%3][1] - tess_tri.last().p[m][1])) / 0.001 ); - tri_by_atan2.insertMulti(ai, QPair(tess_tri.count()-1, m)); - } - tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l]; - for (int m = 0; m < 2; m++) { - int ai = (int)round(atan2(fabs(tess_tri[i].p[(m+1)%3][0] - tess_tri[i].p[m][0]), - fabs(tess_tri[i].p[(m+1)%3][1] - tess_tri[i].p[m][1])) / 0.001 ); - tri_by_atan2.insertMulti(ai, QPair(i, m)); - } - added_triangles = true; - } - } - } - } - } -#endif - - for (int i = 0; i < tess_tri.count(); i++) - { -#if 0 - printf("---\n"); - printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); - printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); - printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); -#endif - double x, y; - ps->append_poly(); - - x = tess_tri[i].p[0][0] * cos(rot*M_PI/180) + tess_tri[i].p[0][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[0][0] * -sin(rot*M_PI/180) + tess_tri[i].p[0][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[0][2]); - - x = tess_tri[i].p[1][0] * cos(rot*M_PI/180) + tess_tri[i].p[1][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[1][0] * -sin(rot*M_PI/180) + tess_tri[i].p[1][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[1][2]); - - x = tess_tri[i].p[2][0] * cos(rot*M_PI/180) + tess_tri[i].p[2][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[2][0] * -sin(rot*M_PI/180) + tess_tri[i].p[2][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[2][2]); - - int i0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).first; - int j0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).second; - - int i1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).first; - int j1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).second; - - int i2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).first; - int j2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).second; - - if (i0 == i1 && j0 == 1 && j1 == 2) - dxf->paths[i0].is_inner = !up; - if (i0 == i1 && j0 == 2 && j1 == 1) - dxf->paths[i0].is_inner = up; - - if (i1 == i2 && j1 == 1 && j2 == 2) - dxf->paths[i1].is_inner = !up; - if (i1 == i2 && j1 == 2 && j2 == 1) - dxf->paths[i1].is_inner = up; - - if (i2 == i0 && j2 == 1 && j0 == 2) - dxf->paths[i2].is_inner = !up; - if (i2 == i0 && j2 == 2 && j0 == 1) - dxf->paths[i2].is_inner = up; - } - - tess_tri.clear(); -} - +#include "dxftess-glu.cc" void dxf_border_to_ps(PolySet *ps, DxfData *dxf) {