PrusaSlicer-NonPlainar/src/libslic3r/Tesselate.cpp

205 lines
8.2 KiB
C++
Raw Normal View History

2019-02-05 19:24:25 +00:00
#include "Tesselate.hpp"
#include "ExPolygon.hpp"
#include <glu-libtess.h>
namespace Slic3r {
class GluTessWrapper {
public:
2019-02-05 19:49:09 +00:00
GluTessWrapper() : m_tesselator(gluNewTess()) {
// register callback functions
gluTessCallback(m_tesselator, GLU_TESS_BEGIN_DATA, (_GLUfuncptr)tessBeginCB);
gluTessCallback(m_tesselator, GLU_TESS_END_DATA, (_GLUfuncptr)tessEndCB);
gluTessCallback(m_tesselator, GLU_TESS_ERROR_DATA, (_GLUfuncptr)tessErrorCB);
gluTessCallback(m_tesselator, GLU_TESS_VERTEX_DATA, (_GLUfuncptr)tessVertexCB);
gluTessCallback(m_tesselator, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)tessCombineCB);
}
~GluTessWrapper() {
gluDeleteTess(m_tesselator);
}
2019-02-05 19:24:25 +00:00
Pointf3s tesselate(const ExPolygon &expoly, double z_, bool flipped_)
{
2019-02-05 19:49:09 +00:00
m_z = z_;
m_flipped = flipped_;
2019-02-05 19:54:01 +00:00
m_output_triangles.clear();
2019-02-05 19:24:25 +00:00
std::vector<GLdouble> coords;
{
size_t num_coords = expoly.contour.points.size();
for (const Polygon &poly : expoly.holes)
num_coords += poly.points.size();
coords.reserve(num_coords * 3);
}
2019-02-05 19:49:09 +00:00
gluTessBeginPolygon(m_tesselator, (void*)this);
gluTessBeginContour(m_tesselator);
2019-02-05 19:24:25 +00:00
for (const Point &pt : expoly.contour.points) {
coords.emplace_back(unscale<double>(pt[0]));
coords.emplace_back(unscale<double>(pt[1]));
coords.emplace_back(0.);
2019-02-05 19:49:09 +00:00
gluTessVertex(m_tesselator, &coords[coords.size() - 3], &coords[coords.size() - 3]);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndContour(m_tesselator);
2019-02-05 19:24:25 +00:00
for (const Polygon &poly : expoly.holes) {
2019-02-05 19:49:09 +00:00
gluTessBeginContour(m_tesselator);
2019-02-05 19:24:25 +00:00
for (const Point &pt : poly.points) {
coords.emplace_back(unscale<double>(pt[0]));
coords.emplace_back(unscale<double>(pt[1]));
coords.emplace_back(0.);
2019-02-05 19:49:09 +00:00
gluTessVertex(m_tesselator, &coords[coords.size() - 3], &coords[coords.size() - 3]);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndContour(m_tesselator);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndPolygon(m_tesselator);
m_intersection_points.clear();
return std::move(m_output_triangles);
2019-02-05 19:24:25 +00:00
}
Pointf3s tesselate(const ExPolygons &expolygons, double z_, bool flipped_)
{
2019-02-05 19:49:09 +00:00
m_z = z_;
m_flipped = flipped_;
2019-02-05 19:54:01 +00:00
m_output_triangles.clear();
2019-02-05 19:24:25 +00:00
std::vector<GLdouble> coords;
{
size_t num_coords = 0;
for (const ExPolygon &expoly : expolygons) {
size_t num_coords_this = expoly.contour.points.size();
for (const Polygon &poly : expoly.holes)
num_coords_this += poly.points.size();
num_coords = std::max(num_coords, num_coords_this);
}
coords.assign(num_coords * 3, 0);
}
for (const ExPolygon &expoly : expolygons) {
2019-02-05 19:49:09 +00:00
gluTessBeginPolygon(m_tesselator, (void*)this);
gluTessBeginContour(m_tesselator);
2019-02-05 19:24:25 +00:00
size_t idx = 0;
for (const Point &pt : expoly.contour.points) {
coords[idx ++] = unscale<double>(pt[0]);
coords[idx ++] = unscale<double>(pt[1]);
coords[idx ++] = 0.;
2019-02-05 19:49:09 +00:00
gluTessVertex(m_tesselator, &coords[idx - 3], &coords[idx - 3]);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndContour(m_tesselator);
2019-02-05 19:24:25 +00:00
for (const Polygon &poly : expoly.holes) {
2019-02-05 19:49:09 +00:00
gluTessBeginContour(m_tesselator);
2019-02-05 19:24:25 +00:00
for (const Point &pt : poly.points) {
coords[idx ++] = unscale<double>(pt[0]);
coords[idx ++] = unscale<double>(pt[1]);
coords[idx ++] = 0.;
2019-02-05 19:49:09 +00:00
gluTessVertex(m_tesselator, &coords[idx - 3], &coords[idx - 3]);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndContour(m_tesselator);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
gluTessEndPolygon(m_tesselator);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
m_intersection_points.clear();
return std::move(m_output_triangles);
2019-02-05 19:24:25 +00:00
}
private:
static void tessBeginCB(GLenum which, void *polygonData) { reinterpret_cast<GluTessWrapper*>(polygonData)->tessBegin(which); }
static void tessEndCB(void *polygonData) { reinterpret_cast<GluTessWrapper*>(polygonData)->tessEnd(); }
static void tessVertexCB(const GLvoid *data, void *polygonData) { reinterpret_cast<GluTessWrapper*>(polygonData)->tessVertex(data); }
static void tessCombineCB(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData, void *polygonData)
{ reinterpret_cast<GluTessWrapper*>(polygonData)->tessCombine(newVertex, neighborVertex, neighborWeight, outData); }
static void tessErrorCB(GLenum errorCode, void *polygonData) { reinterpret_cast<GluTessWrapper*>(polygonData)->tessError(errorCode); }
void tessBegin(GLenum which)
{
assert(which == GL_TRIANGLES || which == GL_TRIANGLE_FAN || which == GL_TRIANGLE_STRIP);
2019-02-05 19:49:09 +00:00
m_primitive_type = which;
m_num_points = 0;
2019-02-05 19:24:25 +00:00
}
void tessEnd()
{
2019-02-05 19:49:09 +00:00
m_num_points = 0;
2019-02-05 19:24:25 +00:00
}
void tessVertex(const GLvoid *data)
{
if (data == nullptr)
return;
const GLdouble *ptr = (const GLdouble*)data;
2019-02-05 19:49:09 +00:00
++ m_num_points;
if (m_num_points == 1) {
memcpy(m_pt0, ptr, sizeof(GLdouble) * 3);
} else if (m_num_points == 2) {
memcpy(m_pt1, ptr, sizeof(GLdouble) * 3);
2019-02-05 19:24:25 +00:00
} else {
2019-02-05 19:49:09 +00:00
bool flip = m_flipped;
if (m_primitive_type == GL_TRIANGLE_STRIP && m_num_points == 4) {
2019-02-05 19:24:25 +00:00
flip = !flip;
2019-02-05 19:49:09 +00:00
m_num_points = 2;
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
m_output_triangles.emplace_back(m_pt0[0], m_pt0[1], m_z);
2019-02-05 19:24:25 +00:00
if (flip) {
2019-02-05 19:49:09 +00:00
m_output_triangles.emplace_back(ptr[0], ptr[1], m_z);
m_output_triangles.emplace_back(m_pt1[0], m_pt1[1], m_z);
2019-02-05 19:24:25 +00:00
} else {
2019-02-05 19:49:09 +00:00
m_output_triangles.emplace_back(m_pt1[0], m_pt1[1], m_z);
m_output_triangles.emplace_back(ptr[0], ptr[1], m_z);
2019-02-05 19:24:25 +00:00
}
2019-02-05 19:49:09 +00:00
if (m_primitive_type == GL_TRIANGLE_STRIP) {
memcpy(m_pt0, m_pt1, sizeof(GLdouble) * 3);
memcpy(m_pt1, ptr, sizeof(GLdouble) * 3);
} else if (m_primitive_type == GL_TRIANGLE_FAN) {
memcpy(m_pt1, ptr, sizeof(GLdouble) * 3);
2019-02-05 19:24:25 +00:00
} else {
2019-02-05 19:49:09 +00:00
assert(m_primitive_type == GL_TRIANGLES);
assert(m_num_points == 3);
m_num_points = 0;
2019-02-05 19:24:25 +00:00
}
}
}
void tessCombine(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData)
{
2019-02-05 19:49:09 +00:00
m_intersection_points.emplace_back(newVertex[0], newVertex[1], m_z);
*outData = m_intersection_points.back().data();
2019-02-05 19:24:25 +00:00
}
static void tessError(GLenum errorCode)
{
// const GLubyte *errorStr;
// errorStr = gluErrorString(errorCode);
// printf("Error: %s\n", (const char*)errorStr);
}
2019-02-05 19:49:09 +00:00
// Instance owned over the life time of this wrapper.
GLUtesselator *m_tesselator;
// Currently processed primitive type.
GLenum m_primitive_type;
// Two last vertices received for m_primitive_type. Used for processing triangle strips, fans etc.
GLdouble m_pt0[3];
GLdouble m_pt1[3];
// Number of points processed over m_primitive_type.
int m_num_points;
// Triangles generated by the tesselator.
Pointf3s m_output_triangles;
// Intersection points generated by tessCombine callback. There should be none if the input contour is not self intersecting.
std::deque<Vec3d> m_intersection_points;
// Fixed third coordinate.
double m_z;
// Output triangles shall be flipped (normal points down).
bool m_flipped;
2019-02-05 19:24:25 +00:00
};
Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z, bool flip)
{
GluTessWrapper tess;
return tess.tesselate(poly, z, flip);
}
Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z, bool flip)
{
GluTessWrapper tess;
return tess.tesselate(polys, z, flip);
}
} // namespace Slic3r