Fix Gizmo preview with hollowed mesh

This commit is contained in:
tamasmeszaros 2021-02-26 15:37:48 +01:00
parent dd202af8cd
commit 06bf02df69
5 changed files with 194 additions and 153 deletions

View File

@ -84,17 +84,17 @@ SLAPrint::Steps::Steps(SLAPrint *print)
void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o)
{
if (o == soSupport && !po.m_supportdata) return;
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 start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat();
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = scaled(doffs);
faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs);
size_t faded_lyrs_efc = std::max(size_t(1), faded_lyrs - 1);
auto efc = [start_efc, faded_lyrs_efc](size_t pos) {
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 ?
po.m_model_slices :
po.m_supportdata->support_slices;
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);
if (idx < slices.size())
slices[idx] = offset_ex(slices[idx], float(clpr_offs));
}
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);
if (idx < slices.size())
@ -124,7 +124,7 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
return;
}
BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!";
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);
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) {
BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes).";
return;
}
BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes.";
sla::DrainHoles drainholes = po.transformed_drainhole_points();
std::uniform_real_distribution<float> dist(0., float(EPSILON));
auto holes_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal({});
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);
MeshBoolean::cgal::plus(*holes_mesh_cgal, *cgal_m);
}
if (MeshBoolean::cgal::does_self_intersect(*holes_mesh_cgal))
throw Slic3r::SlicingError(L("Too many overlapping holes."));
auto hollowed_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal(hollowed_mesh);
try {
MeshBoolean::cgal::minus(*hollowed_mesh_cgal, *holes_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
// same imaginary grid (the height vector argument to TriangleMeshSlicer).
void SLAPrint::Steps::slice_model(SLAPrintObject &po)
{
{
const TriangleMesh &mesh = po.get_mesh_to_slice();
// We need to prepare the slice index...
double lhd = m_print->m_objects.front()->m_config.layer_height.getFloat();
float lh = float(lhd);
coord_t lhs = scaled(lhd);
@ -229,40 +230,40 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
auto minZf = float(minZ);
coord_t minZs = scaled(minZ);
coord_t maxZs = scaled(maxZ);
po.m_slice_index.clear();
size_t cap = size_t(1 + (maxZs - minZs - ilhs) / lhs);
po.m_slice_index.reserve(cap);
po.m_slice_index.emplace_back(minZs + ilhs, minZf + ilh / 2.f, ilh);
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);
// Just get the first record that is from the model:
auto slindex_it =
po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z)));
if(slindex_it == po.m_slice_index.end())
//TRN To be shown at the status bar on SLA slicing error.
throw Slic3r::RuntimeError(
L("Slicing had to be stopped due to an internal error: "
"Inconsistent slice index."));
po.m_model_height_levels.clear();
po.m_model_height_levels.reserve(po.m_slice_index.size());
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
po.m_model_height_levels.emplace_back(it->slice_level());
TriangleMeshSlicer slicer(&mesh);
po.m_model_slices.clear();
float closing_r = float(po.config().slice_closing_radius.value);
auto thr = [this]() { m_print->throw_if_canceled(); };
auto &slice_grid = po.m_model_height_levels;
slicer.slice(slice_grid, SlicingMode::Regular, closing_r, &po.m_model_slices, thr);
sla::Interior *interior = po.m_hollowing_data ?
po.m_hollowing_data->interior.get() :
nullptr;
@ -282,17 +283,17 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
diff_ex(po.m_model_slices[i], slice);
});
}
auto mit = slindex_it;
for (size_t id = 0;
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
id++) {
mit->set_model_slice_idx(po, id); ++mit;
}
// We apply the printer correction offset here.
apply_printer_corrections(po, soModel);
if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool())
{
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(!po.m_config.supports_enable.getBool()) return;
const TriangleMesh &mesh = po.get_mesh_to_slice();
if (!po.m_supportdata)
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
const ModelObject& mo = *po.m_model_object;
BOOST_LOG_TRIVIAL(debug) << "Support point count "
<< mo.sla_support_points.size();
// Unless the user modified the points or we already did the calculation,
// we will do the autoplacement. Otherwise we will just blindly copy the
// frontend data into the backend cache.
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
// calculate heights of slices (slices are calculated already)
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
// so they actually lie on the mesh.
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
throw_if_canceled();
sla::SupportPointGenerator::Config config;
const SLAPrintObjectConfig& cfg = po.config();
// the density config value is in percents:
config.density_relative = float(cfg.support_points_density_relative / 100.f);
config.minimal_distance = float(cfg.support_points_minimal_distance);
config.head_diameter = float(cfg.support_head_front_diameter);
// scaling for the sub operations
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
double init = current_status();
auto statuscb = [this, d, init](unsigned st)
{
double current = init + st * d;
if(std::round(current_status()) < std::round(current))
report_status(current, OBJ_STEP_LABELS(slaposSupportPoints));
};
// Construction of this object does the calculation.
throw_if_canceled();
sla::SupportPointGenerator auto_supports(
@ -359,10 +360,10 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
const std::vector<sla::SupportPoint>& points = auto_supports.output();
throw_if_canceled();
po.m_supportdata->pts = points;
BOOST_LOG_TRIVIAL(debug) << "Automatic support points: "
<< po.m_supportdata->pts.size();
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
// the update status to GLGizmoSlaSupports
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)
{
if(!po.m_supportdata) return;
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
if (pcfg.embed_object)
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,
float(po.m_supportdata->emesh.ground_level() + EPSILON));
}
po.m_supportdata->cfg = make_support_cfg(po.m_config);
// po.m_supportdata->emesh.load_holes(po.transformed_drainhole_points());
// scaling for the sub operations
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0;
double init = current_status();
sla::JobController ctl;
ctl.statuscb = [this, d, init](unsigned st, const std::string &logmsg) {
double current = init + st * d;
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.cancelfn = [this]() { throw_if_canceled(); };
po.m_supportdata->create_support_tree(ctl);
if (!po.m_config.supports_enable.getBool()) return;
throw_if_canceled();
// Create the unified mesh
auto rc = SlicingStatus::RELOAD_SCENE;
// This is to prevent "Done." being displayed during merged_mesh()
report_status(-1, L("Visualizing supports"));
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
<< po.m_supportdata->pts.size();
// Check the mesh for later troubleshooting.
if(po.support_mesh().empty())
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
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
// and before the supports had been sliced. (or the slicing has to be
// repeated)
if(po.m_config.pad_enable.getBool()) {
// Get the distilled pad configuration from the config
sla::PadConfig pcfg = make_pad_cfg(po.m_config);
ExPolygons bp; // This will store the base plate of the pad.
double pad_h = pcfg.full_height();
const TriangleMesh &trmesh = po.transformed_mesh();
if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) {
// No support (thus no elevation) or zero elevation mode
// 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()),
[this](){ throw_if_canceled(); });
}
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
auto &pad_mesh = po.m_supportdata->support_tree_ptr->retrieve_mesh(sla::MeshType::Pad);
if (!validate_pad(pad_mesh, pcfg))
throw Slic3r::SlicingError(
L("No pad can be generated for this model with the "
"current configuration"));
} else if(po.m_supportdata && po.m_supportdata->support_tree_ptr) {
po.m_supportdata->support_tree_ptr->remove_pad();
}
throw_if_canceled();
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)
void SLAPrint::Steps::slice_supports(SLAPrintObject &po) {
auto& sd = po.m_supportdata;
if(sd) sd->support_slices.clear();
// Don't bother if no supports and no pad is present.
if (!po.m_config.supports_enable.getBool() && !po.m_config.pad_enable.getBool())
return;
if(sd && sd->support_tree_ptr) {
auto heights = reserve_vector<float>(po.m_slice_index.size());
for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level());
sd->support_slices = sd->support_tree_ptr->slice(
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);
apply_printer_corrections(po, soSupport);
// 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)
{
ClipperLib::Clipper clipper;
bool closed = true;
for(auto& path : subjects) {
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
}
auto mode = ClipperLib::pftPositive;
return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode);
}
static ClipperPolygons polydiff(const ClipperPolygons &subjects, const ClipperPolygons& clips)
{
ClipperLib::Clipper clipper;
bool closed = true;
for(auto& path : subjects) {
clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed);
}
for(auto& path : clips) {
clipper.AddPath(path.Contour, ClipperLib::ptClip, closed);
clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed);
}
auto mode = ClipperLib::pftPositive;
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)
{
namespace sl = libnest2d::sl;
if (!record.print_obj()) return {};
ClipperPolygons polygons;
auto &input_polygons = record.get_slice(o);
auto &instances = record.print_obj()->instances();
bool is_lefthanded = record.print_obj()->is_left_handed();
polygons.reserve(input_polygons.size() * instances.size());
for (const ExPolygon& polygon : input_polygons) {
if(polygon.contour.empty()) continue;
for (size_t i = 0; i < instances.size(); ++i)
{
ClipperPolygon poly;
// We need to reverse if is_lefthanded is true but
bool needreverse = is_lefthanded;
// should be a move
poly.Contour.reserve(polygon.contour.size() + 1);
auto& cntr = polygon.contour.points;
if(needreverse)
for(auto it = cntr.rbegin(); it != cntr.rend(); ++it)
@ -573,12 +574,12 @@ static ClipperPolygons get_all_polygons(const SliceRecord& record, SliceOrigin o
else
for(auto& p : cntr)
poly.Contour.emplace_back(p.x(), p.y());
for(auto& h : polygon.holes) {
poly.Holes.emplace_back();
auto& hole = poly.Holes.back();
hole.reserve(h.points.size() + 1);
if(needreverse)
for(auto it = h.points.rbegin(); it != h.points.rend(); ++it)
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)
hole.emplace_back(p.x(), p.y());
}
if(is_lefthanded) {
for(auto& p : poly.Contour) 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::translate(poly, ClipperPoint{instances[i].shift.x(),
instances[i].shift.y()});
polygons.emplace_back(std::move(poly));
}
}
return polygons;
}
void SLAPrint::Steps::initialize_printer_input()
{
auto &printer_input = m_print->m_printer_input;
// clear the rasterizer input
printer_input.clear();
size_t mx = 0;
for(SLAPrintObject * o : m_print->m_objects) {
if(auto m = o->get_slice_index().size() > mx) mx = m;
}
printer_input.reserve(mx);
auto eps = coord_t(SCALED_EPSILON);
for(SLAPrintObject * o : m_print->m_objects) {
coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs;
for(const SliceRecord& slicerecord : o->get_slice_index()) {
if (!slicerecord.is_valid())
throw Slic3r::SlicingError(
@ -630,7 +631,7 @@ void SLAPrint::Steps::initialize_printer_input()
"objects printable."));
coord_t lvlid = slicerecord.print_level() - gndlvl;
// Neat trick to round the layer levels to the grid.
lvlid = eps * (lvlid / eps);
@ -640,8 +641,8 @@ void SLAPrint::Steps::initialize_printer_input()
if(it == printer_input.end() || it->level() != lvlid)
it = printer_input.insert(it, PrintLayer(lvlid));
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
// calculating print statistics from the merge result.
void SLAPrint::Steps::merge_slices_and_eval_stats() {
initialize_printer_input();
auto &print_statistics = m_print->m_print_statistics;
auto &printer_config = m_print->m_printer_config;
auto &material_config = m_print->m_material_config;
auto &printer_input = m_print->m_printer_input;
print_statistics.clear();
// libnest calculates positive area for clockwise polygons, Slic3r is in counter-clockwise
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 fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.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 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 auto width = scaled<double>(printer_config.display_width.getFloat());
const auto height = scaled<double>(printer_config.display_height.getFloat());
const double display_area = width*height;
double supports_volume(0.0);
double models_volume(0.0);
double estim_time(0.0);
std::vector<double> layers_times;
layers_times.reserve(printer_input.size());
size_t slow_layers = 0;
size_t fast_layers = 0;
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
double fade_layer_time = init_exp_time;
sla::ccr::SpinningMutex mutex;
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
// Going to parallel:
auto printlayerfn = [this,
// functions and read only vars
areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time,
// write vars
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
&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
auto& slicerecord_references = layer.slices();
if(slicerecord_references.empty()) return;
// Layer height should match for all object slices for a given level.
const auto l_height = double(slicerecord_references.front().get().layer_height());
// Calculation of the consumed material
ClipperPolygons model_polygons;
ClipperPolygons supports_polygons;
size_t c = std::accumulate(layer.slices().begin(),
layer.slices().end(),
size_t(0),
[](size_t a, const SliceRecord &sr) {
return a + sr.get_slice(soModel).size();
});
model_polygons.reserve(c);
c = std::accumulate(layer.slices().begin(),
layer.slices().end(),
size_t(0),
[](size_t a, const SliceRecord &sr) {
return a + sr.get_slice(soModel).size();
});
supports_polygons.reserve(c);
for(const SliceRecord& record : layer.slices()) {
ClipperPolygons modelslices = get_all_polygons(record, soModel);
for(ClipperPolygon& p_tmp : modelslices) model_polygons.emplace_back(std::move(p_tmp));
ClipperPolygons supportslices = get_all_polygons(record, soSupport);
for(ClipperPolygon& p_tmp : supportslices) supports_polygons.emplace_back(std::move(p_tmp));
}
model_polygons = polyunion(model_polygons);
double layer_model_area = 0;
for (const ClipperPolygon& polygon : model_polygons)
layer_model_area += areafn(polygon);
if (layer_model_area < 0 || layer_model_area > 0) {
Lock lck(mutex); models_volume += layer_model_area * l_height;
}
if(!supports_polygons.empty()) {
if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons);
else supports_polygons = polydiff(supports_polygons, model_polygons);
// allegedly, union of subject is done withing the diff according to the pftPositive polyFillType
}
double layer_support_area = 0;
for (const ClipperPolygon& polygon : supports_polygons)
layer_support_area += areafn(polygon);
if (layer_support_area < 0 || layer_support_area > 0) {
Lock lck(mutex); supports_volume += layer_support_area * l_height;
}
// Here we can save the expensively calculated polygons for printing
ClipperPolygons trslices;
trslices.reserve(model_polygons.size() + supports_polygons.size());
for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly));
for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly));
layer.transformed_slices(polyunion(trslices));
// 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 double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
{ Lock lck(mutex);
if (is_fast_layer)
fast_layers++;
else
slow_layers++;
// Calculation of the printing time
double layer_times = 0.0;
@ -803,15 +804,15 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
estim_time += layer_times;
}
};
// sequential version for debugging:
// for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i);
sla::ccr::for_each(size_t(0), printer_input.size(), printlayerfn);
auto SCALING2 = SCALING_FACTOR * SCALING_FACTOR;
print_statistics.support_used_material = supports_volume * SCALING2;
print_statistics.objects_used_material = models_volume * SCALING2;
// Estimated printing time
// A layers count o the highest object
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.layers_times = layers_times;
}
print_statistics.fast_layers_count = fast_layers;
print_statistics.slow_layers_count = slow_layers;
report_status(-2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
}
@ -831,23 +832,23 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
void SLAPrint::Steps::rasterize()
{
if(canceled() || !m_print->m_printer) return;
// coefficient to map the rasterization state (0-99) to the allocated
// portion (slot) of the process state
double sd = (100 - max_objstatus) / 100.0;
// slot is the portion of 100% that is realted to rasterization
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
// pst: previous state
double pst = current_status();
double increment = (slot * sd) / m_print->m_printer_input.size();
double dstatus = current_status();
sla::ccr::SpinningMutex slck;
using Lock = std::lock_guard<sla::ccr::SpinningMutex>;
// procedure to process one height level. This will run in parallel
auto lvlfn =
[this, &slck, increment, &dstatus, &pst]
@ -855,10 +856,10 @@ void SLAPrint::Steps::rasterize()
{
PrintLayer& printlayer = m_print->m_printer_input[idx];
if(canceled()) return;
for (const ClipperLib::Polygon& poly : printlayer.transformed_slices())
raster.draw(poly);
// Status indication guarded with the spinlock
{
Lock lck(slck);
@ -870,10 +871,10 @@ void SLAPrint::Steps::rasterize()
}
}
};
// last minute escape
if(canceled()) return;
// Print all the layers in parallel
m_print->m_printer->draw_layers(m_print->m_printer_input.size(), lvlfn);
}

View File

@ -200,12 +200,20 @@ void HollowedMesh::on_update()
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) {
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).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()) {
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse();
m_hollowed_mesh_transformed->transform(trafo_inv);
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
m_hollowed_mesh_transformed.reset(nullptr);
@ -230,6 +238,10 @@ const TriangleMesh* HollowedMesh::get_hollowed_mesh() const
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_old_meshes = meshes;
if (has_hollowed)
m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior());
m_active_inst_bb_radius =
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
//if (has_hollowed && m_clp_ratio != 0.)

View File

@ -199,6 +199,7 @@ public:
#endif // NDEBUG
const TriangleMesh* get_hollowed_mesh() const;
const TriangleMesh* get_hollowed_interior() const;
protected:
void on_update() override;
@ -206,6 +207,7 @@ protected:
private:
std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
std::unique_ptr<TriangleMesh> m_hollowed_interior_transformed;
size_t m_old_hollowing_timestamp = 0;
int m_print_object_idx = -1;
int m_print_objects_count = 0;

View File

@ -2,6 +2,7 @@
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/ClipperUtils.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)
@ -74,6 +84,15 @@ void MeshClipper::recalculate_triangles()
std::vector<ExPolygons> list_of_expolys;
m_tms->set_up_direction(up.cast<float>());
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.);
// Rotate the cut into world coords:

View File

@ -78,6 +78,8 @@ public:
// must make sure that it stays valid.
void set_mesh(const TriangleMesh& mesh);
void set_negative_mesh(const TriangleMesh &mesh);
// Inform the MeshClipper about the transformation that transforms the mesh
// into world coordinates.
void set_transformation(const Geometry::Transformation& trafo);
@ -91,6 +93,7 @@ private:
Geometry::Transformation m_trafo;
const TriangleMesh* m_mesh = nullptr;
const TriangleMesh* m_negative_mesh = nullptr;
ClippingPlane m_plane;
std::vector<Vec2f> m_triangles2d;
GLIndexedVertexArray m_vertex_array;