Fix Gizmo preview with hollowed mesh
This commit is contained in:
parent
dd202af8cd
commit
06bf02df69
5 changed files with 194 additions and 153 deletions
src
libslic3r
slic3r/GUI
|
@ -84,17 +84,17 @@ SLAPrint::Steps::Steps(SLAPrint *print)
|
||||||
void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o)
|
void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o)
|
||||||
{
|
{
|
||||||
if (o == soSupport && !po.m_supportdata) return;
|
if (o == soSupport && !po.m_supportdata) return;
|
||||||
|
|
||||||
auto faded_lyrs = size_t(po.m_config.faded_layers.getInt());
|
auto faded_lyrs = size_t(po.m_config.faded_layers.getInt());
|
||||||
double min_w = m_print->m_printer_config.elefant_foot_min_width.getFloat() / 2.;
|
double min_w = m_print->m_printer_config.elefant_foot_min_width.getFloat() / 2.;
|
||||||
double start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat();
|
double start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat();
|
||||||
|
|
||||||
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
|
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
|
||||||
coord_t clpr_offs = scaled(doffs);
|
coord_t clpr_offs = scaled(doffs);
|
||||||
|
|
||||||
faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs);
|
faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs);
|
||||||
size_t faded_lyrs_efc = std::max(size_t(1), faded_lyrs - 1);
|
size_t faded_lyrs_efc = std::max(size_t(1), faded_lyrs - 1);
|
||||||
|
|
||||||
auto efc = [start_efc, faded_lyrs_efc](size_t pos) {
|
auto efc = [start_efc, faded_lyrs_efc](size_t pos) {
|
||||||
return (faded_lyrs_efc - pos) * start_efc / faded_lyrs_efc;
|
return (faded_lyrs_efc - pos) * start_efc / faded_lyrs_efc;
|
||||||
};
|
};
|
||||||
|
@ -102,13 +102,13 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin
|
||||||
std::vector<ExPolygons> &slices = o == soModel ?
|
std::vector<ExPolygons> &slices = o == soModel ?
|
||||||
po.m_model_slices :
|
po.m_model_slices :
|
||||||
po.m_supportdata->support_slices;
|
po.m_supportdata->support_slices;
|
||||||
|
|
||||||
if (clpr_offs != 0) for (size_t i = 0; i < po.m_slice_index.size(); ++i) {
|
if (clpr_offs != 0) for (size_t i = 0; i < po.m_slice_index.size(); ++i) {
|
||||||
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
||||||
if (idx < slices.size())
|
if (idx < slices.size())
|
||||||
slices[idx] = offset_ex(slices[idx], float(clpr_offs));
|
slices[idx] = offset_ex(slices[idx], float(clpr_offs));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start_efc > 0.) for (size_t i = 0; i < faded_lyrs; ++i) {
|
if (start_efc > 0.) for (size_t i = 0; i < faded_lyrs; ++i) {
|
||||||
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
||||||
if (idx < slices.size())
|
if (idx < slices.size())
|
||||||
|
@ -124,7 +124,7 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
|
||||||
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
|
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!";
|
BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!";
|
||||||
|
|
||||||
double thickness = po.m_config.hollowing_min_thickness.getFloat();
|
double thickness = po.m_config.hollowing_min_thickness.getFloat();
|
||||||
|
@ -169,16 +169,17 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
||||||
sla::hollow_mesh(hollowed_mesh, *po.m_hollowing_data->interior);
|
sla::hollow_mesh(hollowed_mesh, *po.m_hollowing_data->interior);
|
||||||
|
|
||||||
TriangleMesh &mesh_view = po.m_hollowing_data->hollow_mesh_with_holes_trimmed;
|
TriangleMesh &mesh_view = po.m_hollowing_data->hollow_mesh_with_holes_trimmed;
|
||||||
sla::remove_inside_triangles(mesh_view, *po.m_hollowing_data->interior);
|
mesh_view = po.transformed_mesh();
|
||||||
|
sla::hollow_mesh(mesh_view, *po.m_hollowing_data->interior, sla::hfRemoveInsideTriangles);
|
||||||
|
|
||||||
if (! needs_drilling) {
|
if (! needs_drilling) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes).";
|
BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes).";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes.";
|
BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes.";
|
||||||
sla::DrainHoles drainholes = po.transformed_drainhole_points();
|
sla::DrainHoles drainholes = po.transformed_drainhole_points();
|
||||||
|
|
||||||
std::uniform_real_distribution<float> dist(0., float(EPSILON));
|
std::uniform_real_distribution<float> dist(0., float(EPSILON));
|
||||||
auto holes_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal({});
|
auto holes_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal({});
|
||||||
for (sla::DrainHole holept : drainholes) {
|
for (sla::DrainHole holept : drainholes) {
|
||||||
|
@ -190,12 +191,12 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
||||||
auto cgal_m = MeshBoolean::cgal::triangle_mesh_to_cgal(m);
|
auto cgal_m = MeshBoolean::cgal::triangle_mesh_to_cgal(m);
|
||||||
MeshBoolean::cgal::plus(*holes_mesh_cgal, *cgal_m);
|
MeshBoolean::cgal::plus(*holes_mesh_cgal, *cgal_m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MeshBoolean::cgal::does_self_intersect(*holes_mesh_cgal))
|
if (MeshBoolean::cgal::does_self_intersect(*holes_mesh_cgal))
|
||||||
throw Slic3r::SlicingError(L("Too many overlapping holes."));
|
throw Slic3r::SlicingError(L("Too many overlapping holes."));
|
||||||
|
|
||||||
auto hollowed_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal(hollowed_mesh);
|
auto hollowed_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal(hollowed_mesh);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MeshBoolean::cgal::minus(*hollowed_mesh_cgal, *holes_mesh_cgal);
|
MeshBoolean::cgal::minus(*hollowed_mesh_cgal, *holes_mesh_cgal);
|
||||||
hollowed_mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*hollowed_mesh_cgal);
|
hollowed_mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*hollowed_mesh_cgal);
|
||||||
|
@ -215,11 +216,11 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
||||||
// of it. In any case, the model and the supports have to be sliced in the
|
// of it. In any case, the model and the supports have to be sliced in the
|
||||||
// same imaginary grid (the height vector argument to TriangleMeshSlicer).
|
// same imaginary grid (the height vector argument to TriangleMeshSlicer).
|
||||||
void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
||||||
{
|
{
|
||||||
const TriangleMesh &mesh = po.get_mesh_to_slice();
|
const TriangleMesh &mesh = po.get_mesh_to_slice();
|
||||||
|
|
||||||
// We need to prepare the slice index...
|
// We need to prepare the slice index...
|
||||||
|
|
||||||
double lhd = m_print->m_objects.front()->m_config.layer_height.getFloat();
|
double lhd = m_print->m_objects.front()->m_config.layer_height.getFloat();
|
||||||
float lh = float(lhd);
|
float lh = float(lhd);
|
||||||
coord_t lhs = scaled(lhd);
|
coord_t lhs = scaled(lhd);
|
||||||
|
@ -229,40 +230,40 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
||||||
auto minZf = float(minZ);
|
auto minZf = float(minZ);
|
||||||
coord_t minZs = scaled(minZ);
|
coord_t minZs = scaled(minZ);
|
||||||
coord_t maxZs = scaled(maxZ);
|
coord_t maxZs = scaled(maxZ);
|
||||||
|
|
||||||
po.m_slice_index.clear();
|
po.m_slice_index.clear();
|
||||||
|
|
||||||
size_t cap = size_t(1 + (maxZs - minZs - ilhs) / lhs);
|
size_t cap = size_t(1 + (maxZs - minZs - ilhs) / lhs);
|
||||||
po.m_slice_index.reserve(cap);
|
po.m_slice_index.reserve(cap);
|
||||||
|
|
||||||
po.m_slice_index.emplace_back(minZs + ilhs, minZf + ilh / 2.f, ilh);
|
po.m_slice_index.emplace_back(minZs + ilhs, minZf + ilh / 2.f, ilh);
|
||||||
|
|
||||||
for(coord_t h = minZs + ilhs + lhs; h <= maxZs; h += lhs)
|
for(coord_t h = minZs + ilhs + lhs; h <= maxZs; h += lhs)
|
||||||
po.m_slice_index.emplace_back(h, unscaled<float>(h) - lh / 2.f, lh);
|
po.m_slice_index.emplace_back(h, unscaled<float>(h) - lh / 2.f, lh);
|
||||||
|
|
||||||
// Just get the first record that is from the model:
|
// Just get the first record that is from the model:
|
||||||
auto slindex_it =
|
auto slindex_it =
|
||||||
po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z)));
|
po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z)));
|
||||||
|
|
||||||
if(slindex_it == po.m_slice_index.end())
|
if(slindex_it == po.m_slice_index.end())
|
||||||
//TRN To be shown at the status bar on SLA slicing error.
|
//TRN To be shown at the status bar on SLA slicing error.
|
||||||
throw Slic3r::RuntimeError(
|
throw Slic3r::RuntimeError(
|
||||||
L("Slicing had to be stopped due to an internal error: "
|
L("Slicing had to be stopped due to an internal error: "
|
||||||
"Inconsistent slice index."));
|
"Inconsistent slice index."));
|
||||||
|
|
||||||
po.m_model_height_levels.clear();
|
po.m_model_height_levels.clear();
|
||||||
po.m_model_height_levels.reserve(po.m_slice_index.size());
|
po.m_model_height_levels.reserve(po.m_slice_index.size());
|
||||||
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
|
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
|
||||||
po.m_model_height_levels.emplace_back(it->slice_level());
|
po.m_model_height_levels.emplace_back(it->slice_level());
|
||||||
|
|
||||||
TriangleMeshSlicer slicer(&mesh);
|
TriangleMeshSlicer slicer(&mesh);
|
||||||
|
|
||||||
po.m_model_slices.clear();
|
po.m_model_slices.clear();
|
||||||
float closing_r = float(po.config().slice_closing_radius.value);
|
float closing_r = float(po.config().slice_closing_radius.value);
|
||||||
auto thr = [this]() { m_print->throw_if_canceled(); };
|
auto thr = [this]() { m_print->throw_if_canceled(); };
|
||||||
auto &slice_grid = po.m_model_height_levels;
|
auto &slice_grid = po.m_model_height_levels;
|
||||||
slicer.slice(slice_grid, SlicingMode::Regular, closing_r, &po.m_model_slices, thr);
|
slicer.slice(slice_grid, SlicingMode::Regular, closing_r, &po.m_model_slices, thr);
|
||||||
|
|
||||||
sla::Interior *interior = po.m_hollowing_data ?
|
sla::Interior *interior = po.m_hollowing_data ?
|
||||||
po.m_hollowing_data->interior.get() :
|
po.m_hollowing_data->interior.get() :
|
||||||
nullptr;
|
nullptr;
|
||||||
|
@ -282,17 +283,17 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
||||||
diff_ex(po.m_model_slices[i], slice);
|
diff_ex(po.m_model_slices[i], slice);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mit = slindex_it;
|
auto mit = slindex_it;
|
||||||
for (size_t id = 0;
|
for (size_t id = 0;
|
||||||
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
|
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
|
||||||
id++) {
|
id++) {
|
||||||
mit->set_model_slice_idx(po, id); ++mit;
|
mit->set_model_slice_idx(po, id); ++mit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We apply the printer correction offset here.
|
// We apply the printer correction offset here.
|
||||||
apply_printer_corrections(po, soModel);
|
apply_printer_corrections(po, soModel);
|
||||||
|
|
||||||
if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool())
|
if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool())
|
||||||
{
|
{
|
||||||
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
|
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
|
||||||
|
@ -305,22 +306,22 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||||
{
|
{
|
||||||
// If supports are disabled, we can skip the model scan.
|
// If supports are disabled, we can skip the model scan.
|
||||||
if(!po.m_config.supports_enable.getBool()) return;
|
if(!po.m_config.supports_enable.getBool()) return;
|
||||||
|
|
||||||
const TriangleMesh &mesh = po.get_mesh_to_slice();
|
const TriangleMesh &mesh = po.get_mesh_to_slice();
|
||||||
|
|
||||||
if (!po.m_supportdata)
|
if (!po.m_supportdata)
|
||||||
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
|
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
|
||||||
|
|
||||||
const ModelObject& mo = *po.m_model_object;
|
const ModelObject& mo = *po.m_model_object;
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
||||||
<< mo.sla_support_points.size();
|
<< mo.sla_support_points.size();
|
||||||
|
|
||||||
// Unless the user modified the points or we already did the calculation,
|
// Unless the user modified the points or we already did the calculation,
|
||||||
// we will do the autoplacement. Otherwise we will just blindly copy the
|
// we will do the autoplacement. Otherwise we will just blindly copy the
|
||||||
// frontend data into the backend cache.
|
// frontend data into the backend cache.
|
||||||
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
||||||
|
|
||||||
// calculate heights of slices (slices are calculated already)
|
// calculate heights of slices (slices are calculated already)
|
||||||
const std::vector<float>& heights = po.m_model_height_levels;
|
const std::vector<float>& heights = po.m_model_height_levels;
|
||||||
|
|
||||||
|
@ -328,27 +329,27 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||||
// calculated on slices, the algorithm then raycasts the points
|
// calculated on slices, the algorithm then raycasts the points
|
||||||
// so they actually lie on the mesh.
|
// so they actually lie on the mesh.
|
||||||
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
|
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
|
||||||
|
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
sla::SupportPointGenerator::Config config;
|
sla::SupportPointGenerator::Config config;
|
||||||
const SLAPrintObjectConfig& cfg = po.config();
|
const SLAPrintObjectConfig& cfg = po.config();
|
||||||
|
|
||||||
// the density config value is in percents:
|
// the density config value is in percents:
|
||||||
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
||||||
config.minimal_distance = float(cfg.support_points_minimal_distance);
|
config.minimal_distance = float(cfg.support_points_minimal_distance);
|
||||||
config.head_diameter = float(cfg.support_head_front_diameter);
|
config.head_diameter = float(cfg.support_head_front_diameter);
|
||||||
|
|
||||||
// scaling for the sub operations
|
// scaling for the sub operations
|
||||||
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
|
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
|
||||||
double init = current_status();
|
double init = current_status();
|
||||||
|
|
||||||
auto statuscb = [this, d, init](unsigned st)
|
auto statuscb = [this, d, init](unsigned st)
|
||||||
{
|
{
|
||||||
double current = init + st * d;
|
double current = init + st * d;
|
||||||
if(std::round(current_status()) < std::round(current))
|
if(std::round(current_status()) < std::round(current))
|
||||||
report_status(current, OBJ_STEP_LABELS(slaposSupportPoints));
|
report_status(current, OBJ_STEP_LABELS(slaposSupportPoints));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construction of this object does the calculation.
|
// Construction of this object does the calculation.
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
sla::SupportPointGenerator auto_supports(
|
sla::SupportPointGenerator auto_supports(
|
||||||
|
@ -359,10 +360,10 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||||
const std::vector<sla::SupportPoint>& points = auto_supports.output();
|
const std::vector<sla::SupportPoint>& points = auto_supports.output();
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
po.m_supportdata->pts = points;
|
po.m_supportdata->pts = points;
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Automatic support points: "
|
BOOST_LOG_TRIVIAL(debug) << "Automatic support points: "
|
||||||
<< po.m_supportdata->pts.size();
|
<< po.m_supportdata->pts.size();
|
||||||
|
|
||||||
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
|
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
|
||||||
// the update status to GLGizmoSlaSupports
|
// the update status to GLGizmoSlaSupports
|
||||||
report_status(-1, L("Generating support points"),
|
report_status(-1, L("Generating support points"),
|
||||||
|
@ -377,9 +378,9 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||||
void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
||||||
{
|
{
|
||||||
if(!po.m_supportdata) return;
|
if(!po.m_supportdata) return;
|
||||||
|
|
||||||
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
|
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
|
||||||
|
|
||||||
if (pcfg.embed_object)
|
if (pcfg.embed_object)
|
||||||
po.m_supportdata->emesh.ground_level_offset(pcfg.wall_thickness_mm);
|
po.m_supportdata->emesh.ground_level_offset(pcfg.wall_thickness_mm);
|
||||||
|
|
||||||
|
@ -389,15 +390,15 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
||||||
remove_bottom_points(po.m_supportdata->pts,
|
remove_bottom_points(po.m_supportdata->pts,
|
||||||
float(po.m_supportdata->emesh.ground_level() + EPSILON));
|
float(po.m_supportdata->emesh.ground_level() + EPSILON));
|
||||||
}
|
}
|
||||||
|
|
||||||
po.m_supportdata->cfg = make_support_cfg(po.m_config);
|
po.m_supportdata->cfg = make_support_cfg(po.m_config);
|
||||||
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
|
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
|
||||||
|
|
||||||
// scaling for the sub operations
|
// scaling for the sub operations
|
||||||
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0;
|
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0;
|
||||||
double init = current_status();
|
double init = current_status();
|
||||||
sla::JobController ctl;
|
sla::JobController ctl;
|
||||||
|
|
||||||
ctl.statuscb = [this, d, init](unsigned st, const std::string &logmsg) {
|
ctl.statuscb = [this, d, init](unsigned st, const std::string &logmsg) {
|
||||||
double current = init + st * d;
|
double current = init + st * d;
|
||||||
if (std::round(current_status()) < std::round(current))
|
if (std::round(current_status()) < std::round(current))
|
||||||
|
@ -406,26 +407,26 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
||||||
};
|
};
|
||||||
ctl.stopcondition = [this]() { return canceled(); };
|
ctl.stopcondition = [this]() { return canceled(); };
|
||||||
ctl.cancelfn = [this]() { throw_if_canceled(); };
|
ctl.cancelfn = [this]() { throw_if_canceled(); };
|
||||||
|
|
||||||
po.m_supportdata->create_support_tree(ctl);
|
po.m_supportdata->create_support_tree(ctl);
|
||||||
|
|
||||||
if (!po.m_config.supports_enable.getBool()) return;
|
if (!po.m_config.supports_enable.getBool()) return;
|
||||||
|
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
|
|
||||||
// Create the unified mesh
|
// Create the unified mesh
|
||||||
auto rc = SlicingStatus::RELOAD_SCENE;
|
auto rc = SlicingStatus::RELOAD_SCENE;
|
||||||
|
|
||||||
// This is to prevent "Done." being displayed during merged_mesh()
|
// This is to prevent "Done." being displayed during merged_mesh()
|
||||||
report_status(-1, L("Visualizing supports"));
|
report_status(-1, L("Visualizing supports"));
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
|
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
|
||||||
<< po.m_supportdata->pts.size();
|
<< po.m_supportdata->pts.size();
|
||||||
|
|
||||||
// Check the mesh for later troubleshooting.
|
// Check the mesh for later troubleshooting.
|
||||||
if(po.support_mesh().empty())
|
if(po.support_mesh().empty())
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
|
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
|
||||||
|
|
||||||
report_status(-1, L("Visualizing supports"), rc);
|
report_status(-1, L("Visualizing supports"), rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,15 +434,15 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||||
// this step can only go after the support tree has been created
|
// this step can only go after the support tree has been created
|
||||||
// and before the supports had been sliced. (or the slicing has to be
|
// and before the supports had been sliced. (or the slicing has to be
|
||||||
// repeated)
|
// repeated)
|
||||||
|
|
||||||
if(po.m_config.pad_enable.getBool()) {
|
if(po.m_config.pad_enable.getBool()) {
|
||||||
// Get the distilled pad configuration from the config
|
// Get the distilled pad configuration from the config
|
||||||
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
|
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
|
||||||
|
|
||||||
ExPolygons bp; // This will store the base plate of the pad.
|
ExPolygons bp; // This will store the base plate of the pad.
|
||||||
double pad_h = pcfg.full_height();
|
double pad_h = pcfg.full_height();
|
||||||
const TriangleMesh &trmesh = po.transformed_mesh();
|
const TriangleMesh &trmesh = po.transformed_mesh();
|
||||||
|
|
||||||
if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) {
|
if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) {
|
||||||
// No support (thus no elevation) or zero elevation mode
|
// No support (thus no elevation) or zero elevation mode
|
||||||
// we sometimes call it "builtin pad" is enabled so we will
|
// we sometimes call it "builtin pad" is enabled so we will
|
||||||
|
@ -451,19 +452,19 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||||
float(po.m_config.layer_height.getFloat()),
|
float(po.m_config.layer_height.getFloat()),
|
||||||
[this](){ throw_if_canceled(); });
|
[this](){ throw_if_canceled(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
|
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
|
||||||
auto &pad_mesh = po.m_supportdata->support_tree_ptr->retrieve_mesh(sla::MeshType::Pad);
|
auto &pad_mesh = po.m_supportdata->support_tree_ptr->retrieve_mesh(sla::MeshType::Pad);
|
||||||
|
|
||||||
if (!validate_pad(pad_mesh, pcfg))
|
if (!validate_pad(pad_mesh, pcfg))
|
||||||
throw Slic3r::SlicingError(
|
throw Slic3r::SlicingError(
|
||||||
L("No pad can be generated for this model with the "
|
L("No pad can be generated for this model with the "
|
||||||
"current configuration"));
|
"current configuration"));
|
||||||
|
|
||||||
} else if(po.m_supportdata && po.m_supportdata->support_tree_ptr) {
|
} else if(po.m_supportdata && po.m_supportdata->support_tree_ptr) {
|
||||||
po.m_supportdata->support_tree_ptr->remove_pad();
|
po.m_supportdata->support_tree_ptr->remove_pad();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
report_status(-1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE);
|
report_status(-1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE);
|
||||||
}
|
}
|
||||||
|
@ -473,25 +474,25 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||||
// be part of the slices)
|
// be part of the slices)
|
||||||
void SLAPrint::Steps::slice_supports(SLAPrintObject &po) {
|
void SLAPrint::Steps::slice_supports(SLAPrintObject &po) {
|
||||||
auto& sd = po.m_supportdata;
|
auto& sd = po.m_supportdata;
|
||||||
|
|
||||||
if(sd) sd->support_slices.clear();
|
if(sd) sd->support_slices.clear();
|
||||||
|
|
||||||
// Don't bother if no supports and no pad is present.
|
// Don't bother if no supports and no pad is present.
|
||||||
if (!po.m_config.supports_enable.getBool() && !po.m_config.pad_enable.getBool())
|
if (!po.m_config.supports_enable.getBool() && !po.m_config.pad_enable.getBool())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(sd && sd->support_tree_ptr) {
|
if(sd && sd->support_tree_ptr) {
|
||||||
auto heights = reserve_vector<float>(po.m_slice_index.size());
|
auto heights = reserve_vector<float>(po.m_slice_index.size());
|
||||||
|
|
||||||
for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level());
|
for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level());
|
||||||
|
|
||||||
sd->support_slices = sd->support_tree_ptr->slice(
|
sd->support_slices = sd->support_tree_ptr->slice(
|
||||||
heights, float(po.config().slice_closing_radius.value));
|
heights, float(po.config().slice_closing_radius.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i)
|
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i)
|
||||||
po.m_slice_index[i].set_support_slice_idx(po, i);
|
po.m_slice_index[i].set_support_slice_idx(po, i);
|
||||||
|
|
||||||
apply_printer_corrections(po, soSupport);
|
apply_printer_corrections(po, soSupport);
|
||||||
|
|
||||||
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update
|
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update
|
||||||
|
@ -506,37 +507,37 @@ using ClipperPolygons = std::vector<ClipperPolygon>;
|
||||||
static ClipperPolygons polyunion(const ClipperPolygons &subjects)
|
static ClipperPolygons polyunion(const ClipperPolygons &subjects)
|
||||||
{
|
{
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
|
|
||||||
bool closed = true;
|
bool closed = true;
|
||||||
|
|
||||||
for(auto& path : subjects) {
|
for(auto& path : subjects) {
|
||||||
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
||||||
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mode = ClipperLib::pftPositive;
|
auto mode = ClipperLib::pftPositive;
|
||||||
|
|
||||||
return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode);
|
return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClipperPolygons polydiff(const ClipperPolygons &subjects, const ClipperPolygons& clips)
|
static ClipperPolygons polydiff(const ClipperPolygons &subjects, const ClipperPolygons& clips)
|
||||||
{
|
{
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
|
|
||||||
bool closed = true;
|
bool closed = true;
|
||||||
|
|
||||||
for(auto& path : subjects) {
|
for(auto& path : subjects) {
|
||||||
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
|
||||||
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& path : clips) {
|
for(auto& path : clips) {
|
||||||
clipper.AddPath(path.Contour, ClipperLib::ptClip, closed);
|
clipper.AddPath(path.Contour, ClipperLib::ptClip, closed);
|
||||||
clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed);
|
clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mode = ClipperLib::pftPositive;
|
auto mode = ClipperLib::pftPositive;
|
||||||
|
|
||||||
return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode);
|
return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,28 +545,28 @@ static ClipperPolygons polydiff(const ClipperPolygons &subjects, const ClipperPo
|
||||||
static ClipperPolygons get_all_polygons(const SliceRecord& record, SliceOrigin o)
|
static ClipperPolygons get_all_polygons(const SliceRecord& record, SliceOrigin o)
|
||||||
{
|
{
|
||||||
namespace sl = libnest2d::sl;
|
namespace sl = libnest2d::sl;
|
||||||
|
|
||||||
if (!record.print_obj()) return {};
|
if (!record.print_obj()) return {};
|
||||||
|
|
||||||
ClipperPolygons polygons;
|
ClipperPolygons polygons;
|
||||||
auto &input_polygons = record.get_slice(o);
|
auto &input_polygons = record.get_slice(o);
|
||||||
auto &instances = record.print_obj()->instances();
|
auto &instances = record.print_obj()->instances();
|
||||||
bool is_lefthanded = record.print_obj()->is_left_handed();
|
bool is_lefthanded = record.print_obj()->is_left_handed();
|
||||||
polygons.reserve(input_polygons.size() * instances.size());
|
polygons.reserve(input_polygons.size() * instances.size());
|
||||||
|
|
||||||
for (const ExPolygon& polygon : input_polygons) {
|
for (const ExPolygon& polygon : input_polygons) {
|
||||||
if(polygon.contour.empty()) continue;
|
if(polygon.contour.empty()) continue;
|
||||||
|
|
||||||
for (size_t i = 0; i < instances.size(); ++i)
|
for (size_t i = 0; i < instances.size(); ++i)
|
||||||
{
|
{
|
||||||
ClipperPolygon poly;
|
ClipperPolygon poly;
|
||||||
|
|
||||||
// We need to reverse if is_lefthanded is true but
|
// We need to reverse if is_lefthanded is true but
|
||||||
bool needreverse = is_lefthanded;
|
bool needreverse = is_lefthanded;
|
||||||
|
|
||||||
// should be a move
|
// should be a move
|
||||||
poly.Contour.reserve(polygon.contour.size() + 1);
|
poly.Contour.reserve(polygon.contour.size() + 1);
|
||||||
|
|
||||||
auto& cntr = polygon.contour.points;
|
auto& cntr = polygon.contour.points;
|
||||||
if(needreverse)
|
if(needreverse)
|
||||||
for(auto it = cntr.rbegin(); it != cntr.rend(); ++it)
|
for(auto it = cntr.rbegin(); it != cntr.rend(); ++it)
|
||||||
|
@ -573,12 +574,12 @@ static ClipperPolygons get_all_polygons(const SliceRecord& record, SliceOrigin o
|
||||||
else
|
else
|
||||||
for(auto& p : cntr)
|
for(auto& p : cntr)
|
||||||
poly.Contour.emplace_back(p.x(), p.y());
|
poly.Contour.emplace_back(p.x(), p.y());
|
||||||
|
|
||||||
for(auto& h : polygon.holes) {
|
for(auto& h : polygon.holes) {
|
||||||
poly.Holes.emplace_back();
|
poly.Holes.emplace_back();
|
||||||
auto& hole = poly.Holes.back();
|
auto& hole = poly.Holes.back();
|
||||||
hole.reserve(h.points.size() + 1);
|
hole.reserve(h.points.size() + 1);
|
||||||
|
|
||||||
if(needreverse)
|
if(needreverse)
|
||||||
for(auto it = h.points.rbegin(); it != h.points.rend(); ++it)
|
for(auto it = h.points.rbegin(); it != h.points.rend(); ++it)
|
||||||
hole.emplace_back(it->x(), it->y());
|
hole.emplace_back(it->x(), it->y());
|
||||||
|
@ -586,42 +587,42 @@ static ClipperPolygons get_all_polygons(const SliceRecord& record, SliceOrigin o
|
||||||
for(auto& p : h.points)
|
for(auto& p : h.points)
|
||||||
hole.emplace_back(p.x(), p.y());
|
hole.emplace_back(p.x(), p.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_lefthanded) {
|
if(is_lefthanded) {
|
||||||
for(auto& p : poly.Contour) p.X = -p.X;
|
for(auto& p : poly.Contour) p.X = -p.X;
|
||||||
for(auto& h : poly.Holes) for(auto& p : h) p.X = -p.X;
|
for(auto& h : poly.Holes) for(auto& p : h) p.X = -p.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
sl::rotate(poly, double(instances[i].rotation));
|
sl::rotate(poly, double(instances[i].rotation));
|
||||||
sl::translate(poly, ClipperPoint{instances[i].shift.x(),
|
sl::translate(poly, ClipperPoint{instances[i].shift.x(),
|
||||||
instances[i].shift.y()});
|
instances[i].shift.y()});
|
||||||
|
|
||||||
polygons.emplace_back(std::move(poly));
|
polygons.emplace_back(std::move(poly));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return polygons;
|
return polygons;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SLAPrint::Steps::initialize_printer_input()
|
void SLAPrint::Steps::initialize_printer_input()
|
||||||
{
|
{
|
||||||
auto &printer_input = m_print->m_printer_input;
|
auto &printer_input = m_print->m_printer_input;
|
||||||
|
|
||||||
// clear the rasterizer input
|
// clear the rasterizer input
|
||||||
printer_input.clear();
|
printer_input.clear();
|
||||||
|
|
||||||
size_t mx = 0;
|
size_t mx = 0;
|
||||||
for(SLAPrintObject * o : m_print->m_objects) {
|
for(SLAPrintObject * o : m_print->m_objects) {
|
||||||
if(auto m = o->get_slice_index().size() > mx) mx = m;
|
if(auto m = o->get_slice_index().size() > mx) mx = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
printer_input.reserve(mx);
|
printer_input.reserve(mx);
|
||||||
|
|
||||||
auto eps = coord_t(SCALED_EPSILON);
|
auto eps = coord_t(SCALED_EPSILON);
|
||||||
|
|
||||||
for(SLAPrintObject * o : m_print->m_objects) {
|
for(SLAPrintObject * o : m_print->m_objects) {
|
||||||
coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs;
|
coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs;
|
||||||
|
|
||||||
for(const SliceRecord& slicerecord : o->get_slice_index()) {
|
for(const SliceRecord& slicerecord : o->get_slice_index()) {
|
||||||
if (!slicerecord.is_valid())
|
if (!slicerecord.is_valid())
|
||||||
throw Slic3r::SlicingError(
|
throw Slic3r::SlicingError(
|
||||||
|
@ -630,7 +631,7 @@ void SLAPrint::Steps::initialize_printer_input()
|
||||||
"objects printable."));
|
"objects printable."));
|
||||||
|
|
||||||
coord_t lvlid = slicerecord.print_level() - gndlvl;
|
coord_t lvlid = slicerecord.print_level() - gndlvl;
|
||||||
|
|
||||||
// Neat trick to round the layer levels to the grid.
|
// Neat trick to round the layer levels to the grid.
|
||||||
lvlid = eps * (lvlid / eps);
|
lvlid = eps * (lvlid / eps);
|
||||||
|
|
||||||
|
@ -640,8 +641,8 @@ void SLAPrint::Steps::initialize_printer_input()
|
||||||
|
|
||||||
if(it == printer_input.end() || it->level() != lvlid)
|
if(it == printer_input.end() || it->level() != lvlid)
|
||||||
it = printer_input.insert(it, PrintLayer(lvlid));
|
it = printer_input.insert(it, PrintLayer(lvlid));
|
||||||
|
|
||||||
|
|
||||||
it->add(slicerecord);
|
it->add(slicerecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -650,53 +651,53 @@ void SLAPrint::Steps::initialize_printer_input()
|
||||||
// Merging the slices from all the print objects into one slice grid and
|
// Merging the slices from all the print objects into one slice grid and
|
||||||
// calculating print statistics from the merge result.
|
// calculating print statistics from the merge result.
|
||||||
void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
|
|
||||||
initialize_printer_input();
|
initialize_printer_input();
|
||||||
|
|
||||||
auto &print_statistics = m_print->m_print_statistics;
|
auto &print_statistics = m_print->m_print_statistics;
|
||||||
auto &printer_config = m_print->m_printer_config;
|
auto &printer_config = m_print->m_printer_config;
|
||||||
auto &material_config = m_print->m_material_config;
|
auto &material_config = m_print->m_material_config;
|
||||||
auto &printer_input = m_print->m_printer_input;
|
auto &printer_input = m_print->m_printer_input;
|
||||||
|
|
||||||
print_statistics.clear();
|
print_statistics.clear();
|
||||||
|
|
||||||
// libnest calculates positive area for clockwise polygons, Slic3r is in counter-clockwise
|
// libnest calculates positive area for clockwise polygons, Slic3r is in counter-clockwise
|
||||||
auto areafn = [](const ClipperPolygon& poly) { return - libnest2d::sl::area(poly); };
|
auto areafn = [](const ClipperPolygon& poly) { return - libnest2d::sl::area(poly); };
|
||||||
|
|
||||||
const double area_fill = printer_config.area_fill.getFloat()*0.01;// 0.5 (50%);
|
const double area_fill = printer_config.area_fill.getFloat()*0.01;// 0.5 (50%);
|
||||||
const double fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.0;
|
const double fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.0;
|
||||||
const double slow_tilt = printer_config.slow_tilt_time.getFloat();// 8.0;
|
const double slow_tilt = printer_config.slow_tilt_time.getFloat();// 8.0;
|
||||||
|
|
||||||
const double init_exp_time = material_config.initial_exposure_time.getFloat();
|
const double init_exp_time = material_config.initial_exposure_time.getFloat();
|
||||||
const double exp_time = material_config.exposure_time.getFloat();
|
const double exp_time = material_config.exposure_time.getFloat();
|
||||||
|
|
||||||
const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.getInt();// 10 // [3;20]
|
const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.getInt();// 10 // [3;20]
|
||||||
|
|
||||||
const auto width = scaled<double>(printer_config.display_width.getFloat());
|
const auto width = scaled<double>(printer_config.display_width.getFloat());
|
||||||
const auto height = scaled<double>(printer_config.display_height.getFloat());
|
const auto height = scaled<double>(printer_config.display_height.getFloat());
|
||||||
const double display_area = width*height;
|
const double display_area = width*height;
|
||||||
|
|
||||||
double supports_volume(0.0);
|
double supports_volume(0.0);
|
||||||
double models_volume(0.0);
|
double models_volume(0.0);
|
||||||
|
|
||||||
double estim_time(0.0);
|
double estim_time(0.0);
|
||||||
std::vector<double> layers_times;
|
std::vector<double> layers_times;
|
||||||
layers_times.reserve(printer_input.size());
|
layers_times.reserve(printer_input.size());
|
||||||
|
|
||||||
size_t slow_layers = 0;
|
size_t slow_layers = 0;
|
||||||
size_t fast_layers = 0;
|
size_t fast_layers = 0;
|
||||||
|
|
||||||
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
|
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
|
||||||
double fade_layer_time = init_exp_time;
|
double fade_layer_time = init_exp_time;
|
||||||
|
|
||||||
sla::ccr::SpinningMutex mutex;
|
sla::ccr::SpinningMutex mutex;
|
||||||
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
|
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
|
||||||
|
|
||||||
// Going to parallel:
|
// Going to parallel:
|
||||||
auto printlayerfn = [this,
|
auto printlayerfn = [this,
|
||||||
// functions and read only vars
|
// functions and read only vars
|
||||||
areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time,
|
areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time,
|
||||||
|
|
||||||
// write vars
|
// write vars
|
||||||
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
|
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
|
||||||
&fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt)
|
&fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt)
|
||||||
|
@ -705,87 +706,87 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
|
|
||||||
// vector of slice record references
|
// vector of slice record references
|
||||||
auto& slicerecord_references = layer.slices();
|
auto& slicerecord_references = layer.slices();
|
||||||
|
|
||||||
if(slicerecord_references.empty()) return;
|
if(slicerecord_references.empty()) return;
|
||||||
|
|
||||||
// Layer height should match for all object slices for a given level.
|
// Layer height should match for all object slices for a given level.
|
||||||
const auto l_height = double(slicerecord_references.front().get().layer_height());
|
const auto l_height = double(slicerecord_references.front().get().layer_height());
|
||||||
|
|
||||||
// Calculation of the consumed material
|
// Calculation of the consumed material
|
||||||
|
|
||||||
ClipperPolygons model_polygons;
|
ClipperPolygons model_polygons;
|
||||||
ClipperPolygons supports_polygons;
|
ClipperPolygons supports_polygons;
|
||||||
|
|
||||||
size_t c = std::accumulate(layer.slices().begin(),
|
size_t c = std::accumulate(layer.slices().begin(),
|
||||||
layer.slices().end(),
|
layer.slices().end(),
|
||||||
size_t(0),
|
size_t(0),
|
||||||
[](size_t a, const SliceRecord &sr) {
|
[](size_t a, const SliceRecord &sr) {
|
||||||
return a + sr.get_slice(soModel).size();
|
return a + sr.get_slice(soModel).size();
|
||||||
});
|
});
|
||||||
|
|
||||||
model_polygons.reserve(c);
|
model_polygons.reserve(c);
|
||||||
|
|
||||||
c = std::accumulate(layer.slices().begin(),
|
c = std::accumulate(layer.slices().begin(),
|
||||||
layer.slices().end(),
|
layer.slices().end(),
|
||||||
size_t(0),
|
size_t(0),
|
||||||
[](size_t a, const SliceRecord &sr) {
|
[](size_t a, const SliceRecord &sr) {
|
||||||
return a + sr.get_slice(soModel).size();
|
return a + sr.get_slice(soModel).size();
|
||||||
});
|
});
|
||||||
|
|
||||||
supports_polygons.reserve(c);
|
supports_polygons.reserve(c);
|
||||||
|
|
||||||
for(const SliceRecord& record : layer.slices()) {
|
for(const SliceRecord& record : layer.slices()) {
|
||||||
|
|
||||||
ClipperPolygons modelslices = get_all_polygons(record, soModel);
|
ClipperPolygons modelslices = get_all_polygons(record, soModel);
|
||||||
for(ClipperPolygon& p_tmp : modelslices) model_polygons.emplace_back(std::move(p_tmp));
|
for(ClipperPolygon& p_tmp : modelslices) model_polygons.emplace_back(std::move(p_tmp));
|
||||||
|
|
||||||
ClipperPolygons supportslices = get_all_polygons(record, soSupport);
|
ClipperPolygons supportslices = get_all_polygons(record, soSupport);
|
||||||
for(ClipperPolygon& p_tmp : supportslices) supports_polygons.emplace_back(std::move(p_tmp));
|
for(ClipperPolygon& p_tmp : supportslices) supports_polygons.emplace_back(std::move(p_tmp));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model_polygons = polyunion(model_polygons);
|
model_polygons = polyunion(model_polygons);
|
||||||
double layer_model_area = 0;
|
double layer_model_area = 0;
|
||||||
for (const ClipperPolygon& polygon : model_polygons)
|
for (const ClipperPolygon& polygon : model_polygons)
|
||||||
layer_model_area += areafn(polygon);
|
layer_model_area += areafn(polygon);
|
||||||
|
|
||||||
if (layer_model_area < 0 || layer_model_area > 0) {
|
if (layer_model_area < 0 || layer_model_area > 0) {
|
||||||
Lock lck(mutex); models_volume += layer_model_area * l_height;
|
Lock lck(mutex); models_volume += layer_model_area * l_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!supports_polygons.empty()) {
|
if(!supports_polygons.empty()) {
|
||||||
if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons);
|
if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons);
|
||||||
else supports_polygons = polydiff(supports_polygons, model_polygons);
|
else supports_polygons = polydiff(supports_polygons, model_polygons);
|
||||||
// allegedly, union of subject is done withing the diff according to the pftPositive polyFillType
|
// allegedly, union of subject is done withing the diff according to the pftPositive polyFillType
|
||||||
}
|
}
|
||||||
|
|
||||||
double layer_support_area = 0;
|
double layer_support_area = 0;
|
||||||
for (const ClipperPolygon& polygon : supports_polygons)
|
for (const ClipperPolygon& polygon : supports_polygons)
|
||||||
layer_support_area += areafn(polygon);
|
layer_support_area += areafn(polygon);
|
||||||
|
|
||||||
if (layer_support_area < 0 || layer_support_area > 0) {
|
if (layer_support_area < 0 || layer_support_area > 0) {
|
||||||
Lock lck(mutex); supports_volume += layer_support_area * l_height;
|
Lock lck(mutex); supports_volume += layer_support_area * l_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we can save the expensively calculated polygons for printing
|
// Here we can save the expensively calculated polygons for printing
|
||||||
ClipperPolygons trslices;
|
ClipperPolygons trslices;
|
||||||
trslices.reserve(model_polygons.size() + supports_polygons.size());
|
trslices.reserve(model_polygons.size() + supports_polygons.size());
|
||||||
for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly));
|
for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly));
|
||||||
for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly));
|
for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly));
|
||||||
|
|
||||||
layer.transformed_slices(polyunion(trslices));
|
layer.transformed_slices(polyunion(trslices));
|
||||||
|
|
||||||
// Calculation of the slow and fast layers to the future controlling those values on FW
|
// Calculation of the slow and fast layers to the future controlling those values on FW
|
||||||
|
|
||||||
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
|
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
|
||||||
const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
|
const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
|
||||||
|
|
||||||
{ Lock lck(mutex);
|
{ Lock lck(mutex);
|
||||||
if (is_fast_layer)
|
if (is_fast_layer)
|
||||||
fast_layers++;
|
fast_layers++;
|
||||||
else
|
else
|
||||||
slow_layers++;
|
slow_layers++;
|
||||||
|
|
||||||
// Calculation of the printing time
|
// Calculation of the printing time
|
||||||
|
|
||||||
double layer_times = 0.0;
|
double layer_times = 0.0;
|
||||||
|
@ -803,15 +804,15 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
estim_time += layer_times;
|
estim_time += layer_times;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// sequential version for debugging:
|
// sequential version for debugging:
|
||||||
// for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i);
|
// for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i);
|
||||||
sla::ccr::for_each(size_t(0), printer_input.size(), printlayerfn);
|
sla::ccr::for_each(size_t(0), printer_input.size(), printlayerfn);
|
||||||
|
|
||||||
auto SCALING2 = SCALING_FACTOR * SCALING_FACTOR;
|
auto SCALING2 = SCALING_FACTOR * SCALING_FACTOR;
|
||||||
print_statistics.support_used_material = supports_volume * SCALING2;
|
print_statistics.support_used_material = supports_volume * SCALING2;
|
||||||
print_statistics.objects_used_material = models_volume * SCALING2;
|
print_statistics.objects_used_material = models_volume * SCALING2;
|
||||||
|
|
||||||
// Estimated printing time
|
// Estimated printing time
|
||||||
// A layers count o the highest object
|
// A layers count o the highest object
|
||||||
if (printer_input.size() == 0)
|
if (printer_input.size() == 0)
|
||||||
|
@ -820,10 +821,10 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
print_statistics.estimated_print_time = estim_time;
|
print_statistics.estimated_print_time = estim_time;
|
||||||
print_statistics.layers_times = layers_times;
|
print_statistics.layers_times = layers_times;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_statistics.fast_layers_count = fast_layers;
|
print_statistics.fast_layers_count = fast_layers;
|
||||||
print_statistics.slow_layers_count = slow_layers;
|
print_statistics.slow_layers_count = slow_layers;
|
||||||
|
|
||||||
report_status(-2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
report_status(-2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,23 +832,23 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
|
||||||
void SLAPrint::Steps::rasterize()
|
void SLAPrint::Steps::rasterize()
|
||||||
{
|
{
|
||||||
if(canceled() || !m_print->m_printer) return;
|
if(canceled() || !m_print->m_printer) return;
|
||||||
|
|
||||||
// coefficient to map the rasterization state (0-99) to the allocated
|
// coefficient to map the rasterization state (0-99) to the allocated
|
||||||
// portion (slot) of the process state
|
// portion (slot) of the process state
|
||||||
double sd = (100 - max_objstatus) / 100.0;
|
double sd = (100 - max_objstatus) / 100.0;
|
||||||
|
|
||||||
// slot is the portion of 100% that is realted to rasterization
|
// slot is the portion of 100% that is realted to rasterization
|
||||||
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
|
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
|
||||||
|
|
||||||
// pst: previous state
|
// pst: previous state
|
||||||
double pst = current_status();
|
double pst = current_status();
|
||||||
|
|
||||||
double increment = (slot * sd) / m_print->m_printer_input.size();
|
double increment = (slot * sd) / m_print->m_printer_input.size();
|
||||||
double dstatus = current_status();
|
double dstatus = current_status();
|
||||||
|
|
||||||
sla::ccr::SpinningMutex slck;
|
sla::ccr::SpinningMutex slck;
|
||||||
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
|
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
|
||||||
|
|
||||||
// procedure to process one height level. This will run in parallel
|
// procedure to process one height level. This will run in parallel
|
||||||
auto lvlfn =
|
auto lvlfn =
|
||||||
[this, &slck, increment, &dstatus, &pst]
|
[this, &slck, increment, &dstatus, &pst]
|
||||||
|
@ -855,10 +856,10 @@ void SLAPrint::Steps::rasterize()
|
||||||
{
|
{
|
||||||
PrintLayer& printlayer = m_print->m_printer_input[idx];
|
PrintLayer& printlayer = m_print->m_printer_input[idx];
|
||||||
if(canceled()) return;
|
if(canceled()) return;
|
||||||
|
|
||||||
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
|
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
|
||||||
raster.draw(poly);
|
raster.draw(poly);
|
||||||
|
|
||||||
// Status indication guarded with the spinlock
|
// Status indication guarded with the spinlock
|
||||||
{
|
{
|
||||||
Lock lck(slck);
|
Lock lck(slck);
|
||||||
|
@ -870,10 +871,10 @@ void SLAPrint::Steps::rasterize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// last minute escape
|
// last minute escape
|
||||||
if(canceled()) return;
|
if(canceled()) return;
|
||||||
|
|
||||||
// Print all the layers in parallel
|
// Print all the layers in parallel
|
||||||
m_print->m_printer->draw_layers(m_print->m_printer_input.size(), lvlfn);
|
m_print->m_printer->draw_layers(m_print->m_printer_input.size(), lvlfn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,12 +200,20 @@ void HollowedMesh::on_update()
|
||||||
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) {
|
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) {
|
||||||
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
|
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
|
||||||
if (timestamp > m_old_hollowing_timestamp) {
|
if (timestamp > m_old_hollowing_timestamp) {
|
||||||
const TriangleMesh& backend_mesh = print_object->get_mesh_to_print();
|
const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice();
|
||||||
if (! backend_mesh.empty()) {
|
if (! backend_mesh.empty()) {
|
||||||
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
|
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
|
||||||
Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse();
|
Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse();
|
||||||
m_hollowed_mesh_transformed->transform(trafo_inv);
|
m_hollowed_mesh_transformed->transform(trafo_inv);
|
||||||
m_old_hollowing_timestamp = timestamp;
|
m_old_hollowing_timestamp = timestamp;
|
||||||
|
|
||||||
|
const TriangleMesh &interior = print_object->hollowed_interior_mesh();
|
||||||
|
if (!interior.empty()) {
|
||||||
|
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(interior);
|
||||||
|
m_hollowed_interior_transformed->repaired = false;
|
||||||
|
m_hollowed_interior_transformed->repair(true);
|
||||||
|
m_hollowed_interior_transformed->transform(trafo_inv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_hollowed_mesh_transformed.reset(nullptr);
|
m_hollowed_mesh_transformed.reset(nullptr);
|
||||||
|
@ -230,6 +238,10 @@ const TriangleMesh* HollowedMesh::get_hollowed_mesh() const
|
||||||
return m_hollowed_mesh_transformed.get();
|
return m_hollowed_mesh_transformed.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TriangleMesh* HollowedMesh::get_hollowed_interior() const
|
||||||
|
{
|
||||||
|
return m_hollowed_interior_transformed.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -306,6 +318,10 @@ void ObjectClipper::on_update()
|
||||||
m_clippers.back()->set_mesh(*mesh);
|
m_clippers.back()->set_mesh(*mesh);
|
||||||
}
|
}
|
||||||
m_old_meshes = meshes;
|
m_old_meshes = meshes;
|
||||||
|
|
||||||
|
if (has_hollowed)
|
||||||
|
m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior());
|
||||||
|
|
||||||
m_active_inst_bb_radius =
|
m_active_inst_bb_radius =
|
||||||
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
|
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
|
||||||
//if (has_hollowed && m_clp_ratio != 0.)
|
//if (has_hollowed && m_clp_ratio != 0.)
|
||||||
|
|
|
@ -199,6 +199,7 @@ public:
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
const TriangleMesh* get_hollowed_mesh() const;
|
const TriangleMesh* get_hollowed_mesh() const;
|
||||||
|
const TriangleMesh* get_hollowed_interior() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void on_update() override;
|
void on_update() override;
|
||||||
|
@ -206,6 +207,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
|
std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
|
||||||
|
std::unique_ptr<TriangleMesh> m_hollowed_interior_transformed;
|
||||||
size_t m_old_hollowing_timestamp = 0;
|
size_t m_old_hollowing_timestamp = 0;
|
||||||
int m_print_object_idx = -1;
|
int m_print_object_idx = -1;
|
||||||
int m_print_objects_count = 0;
|
int m_print_objects_count = 0;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "libslic3r/Tesselate.hpp"
|
#include "libslic3r/Tesselate.hpp"
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
#include "slic3r/GUI/Camera.hpp"
|
#include "slic3r/GUI/Camera.hpp"
|
||||||
|
|
||||||
|
@ -31,6 +32,15 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
|
||||||
|
{
|
||||||
|
if (m_negative_mesh != &mesh) {
|
||||||
|
m_negative_mesh = &mesh;
|
||||||
|
m_triangles_valid = false;
|
||||||
|
m_triangles2d.resize(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
|
void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
|
||||||
|
@ -74,6 +84,15 @@ void MeshClipper::recalculate_triangles()
|
||||||
std::vector<ExPolygons> list_of_expolys;
|
std::vector<ExPolygons> list_of_expolys;
|
||||||
m_tms->set_up_direction(up.cast<float>());
|
m_tms->set_up_direction(up.cast<float>());
|
||||||
m_tms->slice(std::vector<float>{height_mesh}, SlicingMode::Regular, 0.f, &list_of_expolys, [](){});
|
m_tms->slice(std::vector<float>{height_mesh}, SlicingMode::Regular, 0.f, &list_of_expolys, [](){});
|
||||||
|
|
||||||
|
if (m_negative_mesh && !m_negative_mesh->empty()) {
|
||||||
|
TriangleMeshSlicer negative_tms{m_negative_mesh};
|
||||||
|
negative_tms.set_up_direction(up.cast<float>());
|
||||||
|
|
||||||
|
std::vector<ExPolygons> neg_polys;
|
||||||
|
negative_tms.slice(std::vector<float>{height_mesh}, SlicingMode::Regular, 0.f, &neg_polys, [](){});
|
||||||
|
list_of_expolys.front() = diff_ex(list_of_expolys.front(), neg_polys.front());
|
||||||
|
}
|
||||||
m_triangles2d = triangulate_expolygons_2f(list_of_expolys[0], m_trafo.get_matrix().matrix().determinant() < 0.);
|
m_triangles2d = triangulate_expolygons_2f(list_of_expolys[0], m_trafo.get_matrix().matrix().determinant() < 0.);
|
||||||
|
|
||||||
// Rotate the cut into world coords:
|
// Rotate the cut into world coords:
|
||||||
|
|
|
@ -78,6 +78,8 @@ public:
|
||||||
// must make sure that it stays valid.
|
// must make sure that it stays valid.
|
||||||
void set_mesh(const TriangleMesh& mesh);
|
void set_mesh(const TriangleMesh& mesh);
|
||||||
|
|
||||||
|
void set_negative_mesh(const TriangleMesh &mesh);
|
||||||
|
|
||||||
// Inform the MeshClipper about the transformation that transforms the mesh
|
// Inform the MeshClipper about the transformation that transforms the mesh
|
||||||
// into world coordinates.
|
// into world coordinates.
|
||||||
void set_transformation(const Geometry::Transformation& trafo);
|
void set_transformation(const Geometry::Transformation& trafo);
|
||||||
|
@ -91,6 +93,7 @@ private:
|
||||||
|
|
||||||
Geometry::Transformation m_trafo;
|
Geometry::Transformation m_trafo;
|
||||||
const TriangleMesh* m_mesh = nullptr;
|
const TriangleMesh* m_mesh = nullptr;
|
||||||
|
const TriangleMesh* m_negative_mesh = nullptr;
|
||||||
ClippingPlane m_plane;
|
ClippingPlane m_plane;
|
||||||
std::vector<Vec2f> m_triangles2d;
|
std::vector<Vec2f> m_triangles2d;
|
||||||
GLIndexedVertexArray m_vertex_array;
|
GLIndexedVertexArray m_vertex_array;
|
||||||
|
|
Loading…
Add table
Reference in a new issue