mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-28 19:21:20 -06:00
Merge remote-tracking branch 'remotes/origin/master' into lm_sla_supports_auto2
This commit is contained in:
commit
d31cb98fe9
59 changed files with 7616 additions and 364 deletions
|
|
@ -154,6 +154,8 @@ add_library(libslic3r STATIC
|
|||
SVG.cpp
|
||||
SVG.hpp
|
||||
Technologies.hpp
|
||||
Tesselate.cpp
|
||||
Tesselate.hpp
|
||||
TriangleMesh.cpp
|
||||
TriangleMesh.hpp
|
||||
utils.cpp
|
||||
|
|
@ -187,6 +189,7 @@ target_link_libraries(libslic3r
|
|||
${EXPAT_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
${PNG_LIBRARIES}
|
||||
glu-libtess
|
||||
polypartition
|
||||
poly2tri
|
||||
qhull
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
#include <float.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
|
||||
#include "SVG.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
|
@ -1120,6 +1121,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
{
|
||||
if (!keep_upper && !keep_lower) { return {}; }
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - start";
|
||||
|
||||
// Clone the object to duplicate instances, materials etc.
|
||||
ModelObject* upper = keep_upper ? ModelObject::new_clone(*this) : nullptr;
|
||||
ModelObject* lower = keep_lower ? ModelObject::new_clone(*this) : nullptr;
|
||||
|
|
@ -1254,6 +1257,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
res.push_back(lower);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2566,6 +2566,14 @@ void PrintConfigDef::init_sla_params()
|
|||
def->enum_labels.push_back(L("Dynamic"));
|
||||
def->default_value = new ConfigOptionEnum<SLAPillarConnectionMode>(slapcmDynamic);
|
||||
|
||||
def = this->add("support_buildplate_only", coBool);
|
||||
def->label = L("Support on build plate only");
|
||||
def->category = L("Supports");
|
||||
def->tooltip = L("Only create support if it lies on a build plate. Don't create support on a print.");
|
||||
def->cli = "support-buildplate-only!";
|
||||
def->mode = comSimple;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("support_pillar_widening_factor", coFloat);
|
||||
def->label = L("Pillar widening factor");
|
||||
def->category = L("Supports");
|
||||
|
|
|
|||
|
|
@ -976,6 +976,9 @@ public:
|
|||
// How the pillars are bridged together
|
||||
ConfigOptionEnum<SLAPillarConnectionMode> support_pillar_connection_mode;
|
||||
|
||||
// Generate only ground facing supports
|
||||
ConfigOptionBool support_buildplate_only;
|
||||
|
||||
// TODO: unimplemented at the moment. This coefficient will have an impact
|
||||
// when bridges and pillars are merged. The resulting pillar should be a bit
|
||||
// thicker than the ones merging into it. How much thicker? I don't know
|
||||
|
|
@ -1031,6 +1034,7 @@ protected:
|
|||
OPT_PTR(support_head_width);
|
||||
OPT_PTR(support_pillar_diameter);
|
||||
OPT_PTR(support_pillar_connection_mode);
|
||||
OPT_PTR(support_buildplate_only);
|
||||
OPT_PTR(support_pillar_widening_factor);
|
||||
OPT_PTR(support_base_diameter);
|
||||
OPT_PTR(support_base_height);
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ void Raster::save(std::ostream& stream, Compression comp)
|
|||
wr.write_row(ptr);
|
||||
}
|
||||
|
||||
wr.write_end_info();
|
||||
|
||||
break;
|
||||
}
|
||||
case Compression::RAW: {
|
||||
|
|
|
|||
|
|
@ -427,6 +427,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50,
|
|||
return r;
|
||||
});
|
||||
|
||||
// This is unavoidable...
|
||||
punion = unify(punion);
|
||||
|
||||
return punion;
|
||||
|
|
@ -448,10 +449,17 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
|||
slicer.slice(heights, &out, thrfn);
|
||||
|
||||
size_t count = 0; for(auto& o : out) count += o.size();
|
||||
|
||||
// Now we have to unify all slice layers which can be an expensive operation
|
||||
// so we will try to simplify the polygons
|
||||
ExPolygons tmp; tmp.reserve(count);
|
||||
for(auto& o : out) for(auto& e : o) tmp.emplace_back(std::move(e));
|
||||
for(ExPolygons& o : out) for(ExPolygon& e : o) {
|
||||
auto&& exss = e.simplify(0.1/SCALING_FACTOR);
|
||||
for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep));
|
||||
}
|
||||
|
||||
ExPolygons utmp = unify(tmp);
|
||||
|
||||
for(auto& o : utmp) {
|
||||
auto&& smp = o.simplify(0.1/SCALING_FACTOR);
|
||||
output.insert(output.end(), smp.begin(), smp.end());
|
||||
|
|
|
|||
|
|
@ -1907,6 +1907,17 @@ bool SLASupportTree::generate(const PointSet &points,
|
|||
}
|
||||
};
|
||||
|
||||
if(cfg.ground_facing_only) { // Delete the non-gnd steps if necessary
|
||||
program[ROUTING_NONGROUND] = []() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Skipping non-ground facing supports as "
|
||||
"requested.";
|
||||
};
|
||||
program[HEADLESS] = [](){
|
||||
BOOST_LOG_TRIVIAL(info) << "Skipping headless stick generation as "
|
||||
"requested";
|
||||
};
|
||||
}
|
||||
|
||||
Steps pc = BEGIN, pc_prev = BEGIN;
|
||||
|
||||
// Let's define a simple automaton that will run our program.
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ struct SupportConfig {
|
|||
// How to connect pillars
|
||||
PillarConnectionMode pillar_connection_mode = PillarConnectionMode::dynamic;
|
||||
|
||||
// Only generate pillars that can be routed to ground
|
||||
bool ground_facing_only = false;
|
||||
|
||||
// TODO: unimplemented at the moment. This coefficient will have an impact
|
||||
// when bridges and pillars are merged. The resulting pillar should be a bit
|
||||
// thicker than the ones merging into it. How much thicker? I don't know
|
||||
|
|
|
|||
|
|
@ -363,7 +363,11 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused;
|
||||
} else {
|
||||
auto print_object = new SLAPrintObject(this, &model_object);
|
||||
|
||||
// FIXME: this invalidates the transformed mesh in SLAPrintObject
|
||||
// which is expensive to calculate (especially the raw_mesh() call)
|
||||
print_object->set_trafo(sla_trafo(model_object));
|
||||
|
||||
print_object->set_instances(new_instances);
|
||||
print_object->config_apply(config, true);
|
||||
print_objects_new.emplace_back(print_object);
|
||||
|
|
@ -415,6 +419,7 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
|
|||
case slapcmDynamic:
|
||||
scfg.pillar_connection_mode = sla::PillarConnectionMode::dynamic; break;
|
||||
}
|
||||
scfg.ground_facing_only = c.support_buildplate_only.getBool();
|
||||
scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat();
|
||||
scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat();
|
||||
scfg.base_height_mm = c.support_base_height.getFloat();
|
||||
|
|
@ -620,8 +625,8 @@ void SLAPrint::process()
|
|||
// repeated)
|
||||
|
||||
if(!po.m_supportdata || !po.m_supportdata->support_tree_ptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Uninitialized support data at "
|
||||
<< "pad creation.";
|
||||
BOOST_LOG_TRIVIAL(error) << "Uninitialized support data at "
|
||||
<< "pad creation.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -643,9 +648,11 @@ void SLAPrint::process()
|
|||
// This call can get pretty time consuming
|
||||
auto thrfn = [this](){ throw_if_canceled(); };
|
||||
|
||||
if(elevation < pad_h)
|
||||
if(elevation < pad_h) {
|
||||
// we have to count with the model geometry for the base plate
|
||||
sla::base_plate(trmesh, bp, float(pad_h), float(lh),
|
||||
thrfn);
|
||||
}
|
||||
|
||||
pcfg.throw_on_cancel = thrfn;
|
||||
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
|
||||
|
|
@ -939,7 +946,7 @@ void SLAPrint::process()
|
|||
};
|
||||
|
||||
// this would disable the rasterization step
|
||||
// m_stepmask[slapsRasterize] = false;
|
||||
// m_stepmask[slapsRasterize] = false;
|
||||
|
||||
double pstd = (100 - max_objstatus) / 100.0;
|
||||
st = max_objstatus;
|
||||
|
|
@ -1063,6 +1070,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|
|||
|| opt_key == "support_head_width"
|
||||
|| opt_key == "support_pillar_diameter"
|
||||
|| opt_key == "support_pillar_connection_mode"
|
||||
|| opt_key == "support_buildplate_only"
|
||||
|| opt_key == "support_base_diameter"
|
||||
|| opt_key == "support_base_height"
|
||||
|| opt_key == "support_critical_angle"
|
||||
|
|
|
|||
204
src/libslic3r/Tesselate.cpp
Normal file
204
src/libslic3r/Tesselate.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
#include "Tesselate.hpp"
|
||||
|
||||
#include "ExPolygon.hpp"
|
||||
|
||||
#include <glu-libtess.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class GluTessWrapper {
|
||||
public:
|
||||
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);
|
||||
}
|
||||
|
||||
Pointf3s tesselate(const ExPolygon &expoly, double z_, bool flipped_)
|
||||
{
|
||||
m_z = z_;
|
||||
m_flipped = flipped_;
|
||||
m_output_triangles.clear();
|
||||
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);
|
||||
}
|
||||
gluTessBeginPolygon(m_tesselator, (void*)this);
|
||||
gluTessBeginContour(m_tesselator);
|
||||
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.);
|
||||
gluTessVertex(m_tesselator, &coords[coords.size() - 3], &coords[coords.size() - 3]);
|
||||
}
|
||||
gluTessEndContour(m_tesselator);
|
||||
for (const Polygon &poly : expoly.holes) {
|
||||
gluTessBeginContour(m_tesselator);
|
||||
for (const Point &pt : poly.points) {
|
||||
coords.emplace_back(unscale<double>(pt[0]));
|
||||
coords.emplace_back(unscale<double>(pt[1]));
|
||||
coords.emplace_back(0.);
|
||||
gluTessVertex(m_tesselator, &coords[coords.size() - 3], &coords[coords.size() - 3]);
|
||||
}
|
||||
gluTessEndContour(m_tesselator);
|
||||
}
|
||||
gluTessEndPolygon(m_tesselator);
|
||||
m_intersection_points.clear();
|
||||
return std::move(m_output_triangles);
|
||||
}
|
||||
|
||||
Pointf3s tesselate(const ExPolygons &expolygons, double z_, bool flipped_)
|
||||
{
|
||||
m_z = z_;
|
||||
m_flipped = flipped_;
|
||||
m_output_triangles.clear();
|
||||
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) {
|
||||
gluTessBeginPolygon(m_tesselator, (void*)this);
|
||||
gluTessBeginContour(m_tesselator);
|
||||
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.;
|
||||
gluTessVertex(m_tesselator, &coords[idx - 3], &coords[idx - 3]);
|
||||
}
|
||||
gluTessEndContour(m_tesselator);
|
||||
for (const Polygon &poly : expoly.holes) {
|
||||
gluTessBeginContour(m_tesselator);
|
||||
for (const Point &pt : poly.points) {
|
||||
coords[idx ++] = unscale<double>(pt[0]);
|
||||
coords[idx ++] = unscale<double>(pt[1]);
|
||||
coords[idx ++] = 0.;
|
||||
gluTessVertex(m_tesselator, &coords[idx - 3], &coords[idx - 3]);
|
||||
}
|
||||
gluTessEndContour(m_tesselator);
|
||||
}
|
||||
gluTessEndPolygon(m_tesselator);
|
||||
}
|
||||
m_intersection_points.clear();
|
||||
return std::move(m_output_triangles);
|
||||
}
|
||||
|
||||
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);
|
||||
m_primitive_type = which;
|
||||
m_num_points = 0;
|
||||
}
|
||||
|
||||
void tessEnd()
|
||||
{
|
||||
m_num_points = 0;
|
||||
}
|
||||
|
||||
void tessVertex(const GLvoid *data)
|
||||
{
|
||||
if (data == nullptr)
|
||||
return;
|
||||
const GLdouble *ptr = (const GLdouble*)data;
|
||||
++ 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);
|
||||
} else {
|
||||
bool flip = m_flipped;
|
||||
if (m_primitive_type == GL_TRIANGLE_STRIP && m_num_points == 4) {
|
||||
flip = !flip;
|
||||
m_num_points = 2;
|
||||
}
|
||||
m_output_triangles.emplace_back(m_pt0[0], m_pt0[1], m_z);
|
||||
if (flip) {
|
||||
m_output_triangles.emplace_back(ptr[0], ptr[1], m_z);
|
||||
m_output_triangles.emplace_back(m_pt1[0], m_pt1[1], m_z);
|
||||
} else {
|
||||
m_output_triangles.emplace_back(m_pt1[0], m_pt1[1], m_z);
|
||||
m_output_triangles.emplace_back(ptr[0], ptr[1], m_z);
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
assert(m_primitive_type == GL_TRIANGLES);
|
||||
assert(m_num_points == 3);
|
||||
m_num_points = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tessCombine(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData)
|
||||
{
|
||||
m_intersection_points.emplace_back(newVertex[0], newVertex[1], m_z);
|
||||
*outData = m_intersection_points.back().data();
|
||||
}
|
||||
|
||||
static void tessError(GLenum errorCode)
|
||||
{
|
||||
// const GLubyte *errorStr;
|
||||
// errorStr = gluErrorString(errorCode);
|
||||
// printf("Error: %s\n", (const char*)errorStr);
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
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
|
||||
18
src/libslic3r/Tesselate.hpp
Normal file
18
src/libslic3r/Tesselate.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef slic3r_Tesselate_hpp_
|
||||
#define slic3r_Tesselate_hpp_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygon;
|
||||
typedef std::vector<ExPolygon> ExPolygons;
|
||||
|
||||
extern Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z = 0, bool flip = false);
|
||||
extern Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z = 0, bool flip = false);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Tesselate_hpp_ */
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "TriangleMesh.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Tesselate.hpp"
|
||||
#include "qhull/src/libqhullcpp/Qhull.h"
|
||||
#include "qhull/src/libqhullcpp/QhullFacetList.h"
|
||||
#include "qhull/src/libqhullcpp/QhullVertexSet.h"
|
||||
|
|
@ -1686,6 +1687,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
{
|
||||
IntersectionLines upper_lines, lower_lines;
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object";
|
||||
float scaled_z = scale_(z);
|
||||
for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) {
|
||||
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
||||
|
|
@ -1775,57 +1777,35 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
}
|
||||
}
|
||||
|
||||
// triangulate holes of upper mesh
|
||||
if (upper != NULL) {
|
||||
// compute shape of section
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating upper part";
|
||||
ExPolygons section;
|
||||
this->make_expolygons_simple(upper_lines, §ion);
|
||||
|
||||
// triangulate section
|
||||
Polygons triangles;
|
||||
for (ExPolygons::const_iterator expolygon = section.begin(); expolygon != section.end(); ++expolygon)
|
||||
expolygon->triangulate_p2t(&triangles);
|
||||
|
||||
// convert triangles to facets and append them to mesh
|
||||
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||
Polygon p = *polygon;
|
||||
p.reverse();
|
||||
stl_facet facet;
|
||||
facet.normal = stl_normal(0, 0, -1.f);
|
||||
for (size_t i = 0; i <= 2; ++i) {
|
||||
facet.vertex[i](0) = unscale<float>(p.points[i](0));
|
||||
facet.vertex[i](1) = unscale<float>(p.points[i](1));
|
||||
facet.vertex[i](2) = z;
|
||||
}
|
||||
Pointf3s triangles = triangulate_expolygons_3df(section, z, true);
|
||||
stl_facet facet;
|
||||
facet.normal = stl_normal(0, 0, -1.f);
|
||||
for (size_t i = 0; i < triangles.size(); ) {
|
||||
for (size_t j = 0; j < 3; ++ j)
|
||||
facet.vertex[j] = triangles[i ++].cast<float>();
|
||||
stl_add_facet(&upper->stl, &facet);
|
||||
}
|
||||
}
|
||||
|
||||
// triangulate holes of lower mesh
|
||||
if (lower != NULL) {
|
||||
// compute shape of section
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating lower part";
|
||||
ExPolygons section;
|
||||
this->make_expolygons_simple(lower_lines, §ion);
|
||||
|
||||
// triangulate section
|
||||
Polygons triangles;
|
||||
for (ExPolygons::const_iterator expolygon = section.begin(); expolygon != section.end(); ++expolygon)
|
||||
expolygon->triangulate_p2t(&triangles);
|
||||
|
||||
// convert triangles to facets and append them to mesh
|
||||
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||
stl_facet facet;
|
||||
facet.normal = stl_normal(0, 0, 1.f);
|
||||
for (size_t i = 0; i <= 2; ++i) {
|
||||
facet.vertex[i](0) = unscale<float>(polygon->points[i](0));
|
||||
facet.vertex[i](1) = unscale<float>(polygon->points[i](1));
|
||||
facet.vertex[i](2) = z;
|
||||
}
|
||||
Pointf3s triangles = triangulate_expolygons_3df(section, z, false);
|
||||
stl_facet facet;
|
||||
facet.normal = stl_normal(0, 0, -1.f);
|
||||
for (size_t i = 0; i < triangles.size(); ) {
|
||||
for (size_t j = 0; j < 3; ++ j)
|
||||
facet.vertex[j] = triangles[i ++].cast<float>();
|
||||
stl_add_facet(&lower->stl, &facet);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the bounding box / sphere of the new meshes.
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - updating object sizes";
|
||||
stl_get_size(&upper->stl);
|
||||
stl_get_size(&lower->stl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ template <typename Number>
|
|||
static inline bool is_approx(Number value, Number test_value)
|
||||
{
|
||||
return std::fabs(double(value) - double(test_value)) < double(EPSILON);
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue