Background processing in C++, WIP.

This commit is contained in:
bubnikv 2018-03-28 17:05:31 +02:00
parent 8639df1cfd
commit 33e1108f65
17 changed files with 279 additions and 140 deletions

View File

@ -1162,7 +1162,7 @@ sub stop_background_process {
$self->statusbar->SetCancelCallback(undef);
$self->statusbar->StopBusy;
$self->statusbar->SetStatusText("");
# Stop the background task.
# Stop the background task, wait until the thread goes into the "Idle" state.
$self->{background_slicing_process}->stop;
# Update the UI with the slicing results.
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
@ -1275,7 +1275,11 @@ sub on_update_print_preview {
# This gets called also if we don't have threads.
sub on_process_completed {
my ($self, $result) = @_;
# Stop the background task, wait until the thread goes into the "Idle" state.
# At this point of time the thread should be either finished or canceled,
# so the following call just confirms, that the produced data were consumed.
$self->{background_slicing_process}->stop;
$self->statusbar->SetCancelCallback(undef);
$self->statusbar->StopBusy;
$self->statusbar->SetStatusText("");

View File

@ -365,13 +365,21 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
if (file == nullptr)
throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
this->m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, preview_data);
fflush(file);
if (ferror(file)) {
try {
this->m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, preview_data);
fflush(file);
if (ferror(file)) {
fclose(file);
boost::nowide::remove(path_tmp.c_str());
throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
}
} catch (std::exception &ex) {
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
// Close and remove the file.
fclose(file);
boost::nowide::remove(path_tmp.c_str());
throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
throw;
}
fclose(file);
if (! this->m_placeholder_parser_failed_templates.empty()) {
@ -403,6 +411,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
{
PROFILE_FUNC();
print.set_started(psGCodeExport);
// resets time estimator
m_time_estimator.reset();
m_time_estimator.set_dialect(print.config.gcode_flavor);
@ -444,6 +454,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
std::sort(zs.begin(), zs.end());
m_layer_count = (unsigned int)(std::unique(zs.begin(), zs.end()) - zs.begin());
}
print.throw_if_canceled();
m_enable_cooling_markers = true;
this->apply_print_config(print.config);
@ -475,6 +486,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
for (auto layer : object->support_layers)
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
}
print.throw_if_canceled();
// filter out 0-width segments
mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
if (! mm3_per_mm.empty()) {
@ -489,6 +501,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_volumetric_speed = std::min(m_volumetric_speed, print.config.max_volumetric_speed.value);
}
}
print.throw_if_canceled();
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
if (print.config.spiral_vase.value)
@ -513,6 +526,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
if (! lines.empty())
_write(file, "\n");
}
print.throw_if_canceled();
// Write some terse information on the slicing parameters.
const PrintObject *first_object = print.objects.front();
const double layer_height = first_object->config.layer_height.value;
@ -530,6 +545,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width);
_write_format(file, "\n");
}
print.throw_if_canceled();
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser;
@ -566,6 +582,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
final_extruder_id = tool_ordering.last_extruder();
assert(final_extruder_id != (unsigned int)-1);
}
print.throw_if_canceled();
m_cooling_buffer->set_current_extruder(initial_extruder_id);
@ -611,7 +628,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_writeln(file, this->placeholder_parser_process("start_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front())));
}
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
print.throw_if_canceled();
// Set other general things.
_write(file, this->preamble());
@ -629,6 +647,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
}
//FIXME Mege the islands in parallel.
m_avoid_crossing_perimeters.init_external_mp(union_ex(islands));
print.throw_if_canceled();
}
// Calculate wiping points if needed
@ -659,6 +678,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
);
#endif
}
print.throw_if_canceled();
}
// Set initial extruder only after custom start G-code.
@ -686,6 +706,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
final_extruder_id = tool_ordering.last_extruder();
assert(final_extruder_id != (unsigned int)-1);
}
print.throw_if_canceled();
this->set_origin(unscale(copy.x), unscale(copy.y));
if (finished_objects > 0) {
// Move to the origin position for the copy we're going to print.
@ -716,6 +737,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
std::vector<LayerToPrint> lrs;
lrs.emplace_back(std::move(ltp));
this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), &copy - object._shifted_copies.data());
print.throw_if_canceled();
}
if (m_pressure_equalizer)
_write(file, m_pressure_equalizer->process("", true));
@ -761,6 +783,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
_write(file, "M1 S10\n");
}
print.throw_if_canceled();
}
// Extrude the layers.
for (auto &layer : layers_to_print) {
@ -768,6 +791,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
if (m_wipe_tower && layer_tools.has_wipe_tower)
m_wipe_tower->next_layer();
this->process_layer(file, print, layer.second, layer_tools, size_t(-1));
print.throw_if_canceled();
}
if (m_pressure_equalizer)
_write(file, m_pressure_equalizer->process("", true));
@ -799,6 +823,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id()));
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
_write(file, m_writer.postamble());
print.throw_if_canceled();
// calculates estimated printing time
m_time_estimator.calculate_time();
@ -839,10 +864,13 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
if (!full_config.empty())
_write(file, full_config);
}
print.throw_if_canceled();
// starts analizer calculations
if (preview_data != nullptr)
m_analyzer.calc_gcode_preview_data(*preview_data);
print.set_done(psGCodeExport);
}
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)

View File

@ -136,7 +136,8 @@ public:
{}
~GCode() {}
// throws std::runtime_exception
// throws std::runtime_exception on error,
// throws CanceledException through print->throw_if_canceled().
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.

View File

@ -150,13 +150,12 @@ void Layer::make_fills()
#ifdef SLIC3R_DEBUG
printf("Making fills for layer " PRINTF_ZU "\n", this->id());
#endif
for (LayerRegionPtrs::iterator it_layerm = regions.begin(); it_layerm != regions.end(); ++ it_layerm) {
LayerRegion &layerm = *(*it_layerm);
layerm.fills.clear();
make_fill(layerm, layerm.fills);
for (LayerRegion *layerm : regions) {
layerm->fills.clear();
make_fill(*layerm, layerm->fills);
#ifndef NDEBUG
for (size_t i = 0; i < layerm.fills.entities.size(); ++ i)
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm.fills.entities[i]) != NULL);
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != NULL);
#endif
}
}

View File

@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
}
}
void
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
{
this->perimeters.clear();
this->thin_fills.clear();
@ -340,8 +339,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
}
void
LayerRegion::prepare_fill_surfaces()
void LayerRegion::prepare_fill_surfaces()
{
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
export_region_slices_to_svg_debug("2_prepare_fill_surfaces-initial");
@ -382,8 +380,7 @@ LayerRegion::prepare_fill_surfaces()
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
}
double
LayerRegion::infill_area_threshold() const
double LayerRegion::infill_area_threshold() const
{
double ss = this->flow(frSolidInfill).scaled_spacing();
return ss*ss;

View File

@ -83,7 +83,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
// Cache the plenty of parameters, which influence the G-code generator only,
// or they are only notes not influencing the generated G-code.
static std::unordered_set<std::string> steps_ignore = {
static std::unordered_set<std::string> steps_gcode = {
"avoid_crossing_perimeters",
"bed_shape",
"bed_temperature",
@ -159,13 +159,18 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"wipe"
};
static std::unordered_set<std::string> steps_ignore = {};
std::vector<PrintStep> steps;
std::vector<PrintObjectStep> osteps;
bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) {
if (steps_ignore.find(opt_key) != steps_ignore.end()) {
if (steps_gcode.find(opt_key) != steps_gcode.end()) {
// These options only affect G-code export or they are just notes without influence on the generated G-code,
// so there is nothing to invalidate.
steps.emplace_back(psGCodeExport);
} else if (steps_ignore.find(opt_key) != steps_ignore.end()) {
// These steps have no influence on the G-code whatsoever. Just ignore them.
} else if (
opt_key == "skirts"
|| opt_key == "skirt_height"
@ -226,22 +231,22 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
bool Print::invalidate_step(PrintStep step)
{
bool invalidated = this->state.invalidate(step);
bool invalidated = m_state.invalidate(step);
// Propagate to dependent steps.
//FIXME Why should skirt invalidate brim? Shouldn't it be vice versa?
if (step == psSkirt)
invalidated |= this->state.invalidate(psBrim);
invalidated |= m_state.invalidate(psBrim);
return invalidated;
}
// returns true if an object step is done on all objects
// and there's at least one object
bool Print::step_done(PrintObjectStep step) const
bool Print::is_step_done(PrintObjectStep step) const
{
if (this->objects.empty())
return false;
for (const PrintObject *object : this->objects)
if (!object->state.is_done(step))
if (!object->m_state.is_done(step))
return false;
return true;
}
@ -801,37 +806,42 @@ void Print::process()
BOOST_LOG_TRIVIAL(info) << "Staring the slicing process.";
for (PrintObject *obj : this->objects)
obj->make_perimeters();
this->throw_if_canceled();
this->set_status(70, "Infilling layers");
for (PrintObject *obj : this->objects)
obj->infill();
this->throw_if_canceled();
for (PrintObject *obj : this->objects)
obj->generate_support_material();
if (! this->state.is_done(psSkirt)) {
this->state.set_started(psSkirt);
this->throw_if_canceled();
if (! m_state.is_done(psSkirt)) {
this->set_started(psSkirt);
this->skirt.clear();
if (this->has_skirt()) {
this->set_status(88, "Generating skirt");
this->_make_skirt();
}
this->state.set_done(psSkirt);
m_state.set_done(psSkirt);
}
if (! this->state.is_done(psBrim)) {
this->state.set_started(psBrim);
this->throw_if_canceled();
if (! m_state.is_done(psBrim)) {
this->set_started(psBrim);
this->brim.clear();
if (this->config.brim_width > 0) {
this->set_status(88, "Generating brim");
this->_make_brim();
}
this->state.set_done(psBrim);
m_state.set_done(psBrim);
}
if (! this->state.is_done(psWipeTower)) {
this->state.set_started(psWipeTower);
this->throw_if_canceled();
if (! m_state.is_done(psWipeTower)) {
this->set_started(psWipeTower);
this->_clear_wipe_tower();
if (this->has_wipe_tower()) {
//this->set_status(95, "Generating wipe tower");
this->_make_wipe_tower();
}
this->state.set_done(psWipeTower);
m_state.set_done(psWipeTower);
}
BOOST_LOG_TRIVIAL(info) << "Slicing process finished.";
}
@ -883,6 +893,7 @@ void Print::_make_skirt()
// Collect points from all layers contained in skirt height.
Points points;
for (const PrintObject *object : this->objects) {
this->throw_if_canceled();
Points object_points;
// Get object layers up to skirt_height_z.
for (const Layer *layer : object->layers) {
@ -912,6 +923,7 @@ void Print::_make_skirt()
// At least three points required for a convex hull.
return;
this->throw_if_canceled();
Polygon convex_hull = Slic3r::Geometry::convex_hull(points);
// Skirt may be printed on several layers, having distinct layer heights,
@ -946,6 +958,7 @@ void Print::_make_skirt()
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
this->throw_if_canceled();
// Offset the skirt outside.
distance += coord_t(scale_(spacing));
// Generate the skirt centerline.
@ -994,6 +1007,7 @@ void Print::_make_brim()
Flow flow = this->brim_flow();
Polygons islands;
for (PrintObject *object : this->objects) {
this->throw_if_canceled();
Polygons object_islands;
for (ExPolygon &expoly : object->layers.front()->slices.expolygons)
object_islands.push_back(expoly.contour);
@ -1009,6 +1023,7 @@ void Print::_make_brim()
Polygons loops;
size_t num_loops = size_t(floor(this->config.brim_width.value / flow.width));
for (size_t i = 0; i < num_loops; ++ i) {
this->throw_if_canceled();
islands = offset(islands, float(flow.scaled_spacing()), jtSquare);
for (Polygon &poly : islands) {
// poly.simplify(SCALED_RESOLUTION);
@ -1088,6 +1103,7 @@ void Print::_make_wipe_tower()
}
}
}
this->throw_if_canceled();
// Initialize the wipe tower.
WipeTowerPrusaMM wipe_tower(
@ -1119,6 +1135,7 @@ void Print::_make_wipe_tower()
// Set current_extruder_id to the last extruder primed.
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) {
this->throw_if_canceled();
if (! layer_tools.has_wipe_tower)
// This is a support only layer, or the wipe tower does not reach to this height.
continue;

View File

@ -18,56 +18,71 @@
#include "GCode/WipeTower.hpp"
#include "tbb/atomic.h"
// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "tbb/mutex.h"
namespace Slic3r {
class Print;
class PrintObject;
class ModelObject;
class GCode;
class GCodePreviewData;
// Print step IDs for keeping track of the print state.
enum PrintStep {
psSkirt, psBrim, psWipeTower, psCount,
psSkirt, psBrim, psWipeTower, psGCodeExport, psCount,
};
enum PrintObjectStep {
posSlice, posPerimeters, posPrepareInfill,
posInfill, posSupportMaterial, posCount,
};
class CanceledException : public std::exception {
public:
const char* what() const throw() { return "Background processing has been canceled"; }
};
// To be instantiated over PrintStep or PrintObjectStep enums.
template <class StepType, size_t COUNT>
class PrintState
{
public:
PrintState() { memset(state, 0, sizeof(state)); }
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i] = INVALID; }
enum State {
INVALID,
STARTED,
DONE,
};
State state[COUNT];
bool is_started(StepType step) const { return this->state[step] == STARTED; }
bool is_done(StepType step) const { return this->state[step] == DONE; }
void set_started(StepType step) { this->state[step] = STARTED; }
void set_done(StepType step) { this->state[step] = DONE; }
bool is_done(StepType step) const { return m_state[step] == DONE; }
// set_started() will lock the provided mutex before setting the state.
// This is necessary to block until the Print::apply_config() updates its state, which may
// influence the processing step being entered.
void set_started(StepType step, tbb::mutex &mtx) { mtx.lock(); m_state[step] = STARTED; mtx.unlock(); }
void set_done(StepType step) { m_state[step] = DONE; }
bool invalidate(StepType step) {
bool invalidated = this->state[step] != INVALID;
this->state[step] = INVALID;
bool invalidated = m_state[step] != INVALID;
m_state[step] = INVALID;
return invalidated;
}
bool invalidate_all() {
bool invalidated = false;
for (size_t i = 0; i < COUNT; ++ i)
if (this->state[i] != INVALID) {
if (m_state[i] != INVALID) {
invalidated = true;
m_state[i] = INVALID;
break;
}
memset(state, 0, sizeof(state));
return invalidated;
}
private:
std::atomic<State> m_state[COUNT];
};
// A PrintRegion object represents a group of volumes to print
@ -131,7 +146,6 @@ public:
LayerPtrs layers;
SupportLayerPtrs support_layers;
PrintState<PrintObjectStep, posCount> state;
Print* print() { return this->_print; }
const Print* print() const { return this->_print; }
@ -174,7 +188,8 @@ public:
// methods for handling state
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
bool invalidate_step(PrintObjectStep step);
bool invalidate_all_steps() { return this->state.invalidate_all(); }
bool invalidate_all_steps() { return m_state.invalidate_all(); }
bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); }
// To be used over the layer_height_profile of both the PrintObject and ModelObject
// to initialize the height profile with the height ranges.
@ -218,11 +233,18 @@ private:
ModelObject* _model_object;
Points _copies; // Slic3r::Point objects in scaled G-code coordinates
PrintState<PrintObjectStep, posCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread:
// The mutex will be used to guard the worker thread against entering a stage
// while the data influencing the stage is modified.
tbb::mutex m_mutex;
// TODO: call model_object->get_bounding_box() instead of accepting
// parameter
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
~PrintObject() {}
void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); }
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
};
@ -242,7 +264,6 @@ public:
std::string estimated_print_time;
double total_used_filament, total_extruded_volume, total_cost, total_weight;
std::map<size_t, float> filament_stats;
PrintState<PrintStep, psCount> state;
// ordered collections of extrusion paths to build skirt loops and brim
ExtrusionEntityCollection skirt, brim;
@ -266,9 +287,10 @@ public:
// methods for handling state
bool invalidate_step(PrintStep step);
bool invalidate_all_steps() { return this->state.invalidate_all(); }
bool step_done(PrintObjectStep step) const;
bool invalidate_all_steps() { return m_state.invalidate_all(); }
bool is_step_done(PrintStep step) const { return m_state.is_done(step); }
bool is_step_done(PrintObjectStep step) const;
void add_model_object(ModelObject* model_object, int idx = -1);
bool apply_config(DynamicPrintConfig config);
bool has_infinite_skirt() const;
@ -308,7 +330,7 @@ public:
typedef std::function<void(int, const std::string&)> status_callback_type;
// Default status console print out in the form of percent => message.
void set_status_default() { m_status_callback = nullptr; }
// No status output or callback whatsoever.
// No status output or callback whatsoever, useful mostly for automatic tests.
void set_status_silent() { m_status_callback = [](int, const std::string&){}; }
// Register a custom status callback.
void set_status_callback(status_callback_type cb) { m_status_callback = cb; }
@ -323,7 +345,12 @@ public:
void restart() { m_canceled = false; }
// Has the calculation been canceled?
bool canceled() { return m_canceled; }
void throw_if_canceled() { if (m_canceled) throw CanceledException(); }
protected:
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); }
void set_done(PrintStep step) { m_state.set_done(step); }
private:
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume);
@ -333,9 +360,18 @@ private:
void _clear_wipe_tower();
void _make_wipe_tower();
PrintState<PrintStep, psCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread:
// The mutex will be used to guard the worker thread against entering a stage
// while the data influencing the stage is modified.
tbb::mutex m_mutex;
// Has the calculation been canceled?
tbb::atomic<bool> m_canceled;
status_callback_type m_status_callback;
tbb::atomic<bool> m_canceled;
// Callback to be evoked regularly to update state of the UI thread.
status_callback_type m_status_callback;
// To allow GCode to set the Print's GCodeExport step status.
friend class GCode;
};
#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator)

View File

@ -31,8 +31,6 @@
#include <cassert>
#endif
#define PARALLEL_FOR_CANCEL do { if (this->print()->canceled()) return; } while (0)
namespace Slic3r {
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) :
@ -117,14 +115,16 @@ bool PrintObject::reload_model_instances()
// this should be idempotent
void PrintObject::slice()
{
if (this->state.is_done(posSlice))
if (m_state.is_done(posSlice))
return;
this->state.set_started(posSlice);
this->set_started(posSlice);
this->_print->set_status(10, "Processing triangulated mesh");
this->_slice();
this->_print->throw_if_canceled();
// Fix the model.
//FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
std::string warning = this->_fix_slicing_errors();
this->_print->throw_if_canceled();
if (! warning.empty())
BOOST_LOG_TRIVIAL(info) << warning;
// Simplify slices if required.
@ -132,7 +132,7 @@ void PrintObject::slice()
this->_simplify_slices(scale_(this->_print->config.resolution));
if (this->layers.empty())
throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");
this->state.set_done(posSlice);
m_state.set_done(posSlice);
}
// 1) Merges typed region slices into stInternal type.
@ -143,19 +143,21 @@ void PrintObject::make_perimeters()
// prerequisites
this->slice();
if (this->state.is_done(posPerimeters))
if (m_state.is_done(posPerimeters))
return;
this->state.set_started(posPerimeters);
this->set_started(posPerimeters);
this->_print->set_status(20, "Generating perimeters");
BOOST_LOG_TRIVIAL(info) << "Generating perimeters...";
// merge slices if they were split into types
if (this->typed_slices) {
FOREACH_LAYER(this, layer_it)
FOREACH_LAYER(this, layer_it) {
(*layer_it)->merge_slices();
this->_print->throw_if_canceled();
}
this->typed_slices = false;
this->state.invalidate(posPrepareInfill);
m_state.invalidate(posPrepareInfill);
}
// compare each layer to the one below, and mark those slices needing
@ -168,8 +170,7 @@ void PrintObject::make_perimeters()
FOREACH_REGION(this->_print, region_it) {
size_t region_id = region_it - this->_print->regions.begin();
const PrintRegion &region = **region_it;
if (!region.config.extra_perimeters
|| region.config.perimeters == 0
|| region.config.fill_density == 0
@ -181,7 +182,7 @@ void PrintObject::make_perimeters()
tbb::blocked_range<size_t>(0, this->layers.size() - 1),
[this, &region, region_id](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
LayerRegion &layerm = *this->layers[layer_idx]->regions[region_id];
const LayerRegion &upper_layerm = *this->layers[layer_idx+1]->regions[region_id];
const Polygons upper_layerm_polygons = upper_layerm.slices;
@ -230,6 +231,7 @@ void PrintObject::make_perimeters()
}
}
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end";
}
@ -238,11 +240,12 @@ void PrintObject::make_perimeters()
tbb::blocked_range<size_t>(0, this->layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
this->layers[layer_idx]->make_perimeters();
}
}
);
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
/*
@ -252,15 +255,15 @@ void PrintObject::make_perimeters()
###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
*/
this->state.set_done(posPerimeters);
m_state.set_done(posPerimeters);
}
void PrintObject::prepare_infill()
{
if (this->state.is_done(posPrepareInfill))
if (m_state.is_done(posPrepareInfill))
return;
this->state.set_started(posPrepareInfill);
this->set_started(posPrepareInfill);
this->_print->set_status(30, "Preparing infill");
// This will assign a type (top/bottom/internal) to $layerm->slices.
@ -268,14 +271,17 @@ void PrintObject::prepare_infill()
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
// by the cummulative area of the previous $layerm->fill_surfaces.
this->detect_surfaces_type();
this->_print->throw_if_canceled();
// Decide what surfaces are to be filled.
// Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured.
// Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID.
BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces...";
for (auto *layer : this->layers)
for (auto *region : layer->regions)
for (auto *region : layer->regions) {
region->prepare_fill_surfaces();
this->_print->throw_if_canceled();
}
// this will detect bridges and reverse bridges
// and rearrange top/bottom/internal surfaces
@ -287,9 +293,11 @@ void PrintObject::prepare_infill()
// 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
//FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
this->process_external_surfaces();
this->_print->throw_if_canceled();
// Add solid fills to ensure the shell vertical thickness.
this->discover_vertical_shells();
this->_print->throw_if_canceled();
// Debugging output.
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -309,6 +317,7 @@ void PrintObject::prepare_infill()
// to close these surfaces reliably.
//FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
this->discover_horizontal_shells();
this->_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
@ -327,6 +336,7 @@ void PrintObject::prepare_infill()
// Likely the sparse infill will not be anchored correctly, so it will not work as intended.
// Also one wishes the perimeters to be supported by a full infill.
this->clip_fill_surfaces();
this->_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
@ -341,9 +351,11 @@ void PrintObject::prepare_infill()
// the following step needs to be done before combination because it may need
// to remove only half of the combined infill
this->bridge_over_infill();
this->_print->throw_if_canceled();
// combine fill surfaces to honor the "infill every N layers" option
this->combine_infill();
this->_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
@ -359,7 +371,7 @@ void PrintObject::prepare_infill()
} // for each layer
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
this->state.set_done(posPrepareInfill);
m_state.set_done(posPrepareInfill);
}
void PrintObject::infill()
@ -367,36 +379,38 @@ void PrintObject::infill()
// prerequisites
this->prepare_infill();
if (! this->state.is_done(posInfill)) {
this->state.set_started(posInfill);
if (! m_state.is_done(posInfill)) {
this->set_started(posInfill);
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, this->layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
this->layers[layer_idx]->make_fills();
}
}
);
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end";
/* we could free memory now, but this would make this step not idempotent
### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
*/
this->state.set_done(posInfill);
m_state.set_done(posInfill);
}
}
void PrintObject::generate_support_material()
{
if (! this->state.is_done(posSupportMaterial)) {
this->state.set_started(posSupportMaterial);
if (! m_state.is_done(posSupportMaterial)) {
this->set_started(posSupportMaterial);
this->clear_support_layers();
if ((this->config.support_material || this->config.raft_layers > 0) && this->layers.size() > 1) {
this->_print->set_status(85, "Generating support material");
this->_generate_support_material();
this->_print->throw_if_canceled();
}
this->state.set_done(posSupportMaterial);
m_state.set_done(posSupportMaterial);
}
}
@ -545,7 +559,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
bool PrintObject::invalidate_step(PrintObjectStep step)
{
bool invalidated = this->state.invalidate(step);
bool invalidated = m_state.invalidate(step);
// propagate to dependent steps
if (step == posPerimeters) {
@ -624,7 +638,7 @@ void PrintObject::detect_surfaces_type()
(this->config.support_material.value && this->config.support_material_contact_distance.value == 0) ?
stBottom : stBottomBridge;
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
// BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << idx_region << " and layer " << layer->print_z;
Layer *layer = this->layers[idx_layer];
LayerRegion *layerm = layer->get_region(idx_region);
@ -749,6 +763,7 @@ void PrintObject::detect_surfaces_type()
}
}
); // for each layer of a region
this->_print->throw_if_canceled();
if (interface_shells) {
// Move surfaces_new to layerm->slices.surfaces
@ -762,7 +777,7 @@ void PrintObject::detect_surfaces_type()
tbb::blocked_range<size_t>(0, this->layers.size()),
[this, idx_region, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) {
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region);
layerm->slices_to_fill_surfaces_clipped();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -770,6 +785,7 @@ void PrintObject::detect_surfaces_type()
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} // for each layer of a region
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - end";
} // for each this->print->region_count
@ -789,12 +805,13 @@ void PrintObject::process_external_surfaces()
tbb::blocked_range<size_t>(0, this->layers.size()),
[this, region_id](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
// BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << this->layers[layer_idx]->print_z;
this->layers[layer_idx]->get_region(region_id)->process_external_surfaces((layer_idx == 0) ? NULL : this->layers[layer_idx - 1]);
}
}
);
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
}
}
@ -838,7 +855,7 @@ void PrintObject::discover_vertical_shells()
const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge };
const size_t num_regions = this->_print->regions.size();
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
const Layer &layer = *this->layers[idx_layer];
DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[idx_layer];
// Simulate single set of perimeters over all merged regions.
@ -893,6 +910,7 @@ void PrintObject::discover_vertical_shells()
cache.holes = union_(cache.holes, false);
}
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom";
}
@ -921,7 +939,7 @@ void PrintObject::discover_vertical_shells()
[this, idx_region, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge };
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
Layer &layer = *this->layers[idx_layer];
LayerRegion &layerm = *layer.regions[idx_region];
float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f;
@ -939,6 +957,7 @@ void PrintObject::discover_vertical_shells()
}
}
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end : cache top / bottom";
}
@ -950,7 +969,7 @@ void PrintObject::discover_vertical_shells()
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
PROFILE_BLOCK(discover_vertical_shells_region_layer);
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
static size_t debug_idx = 0;
++ debug_idx;
@ -1163,7 +1182,8 @@ void PrintObject::discover_vertical_shells()
layerm->fill_surfaces.append(new_internal_void, stInternalVoid);
layerm->fill_surfaces.append(new_internal_solid, stInternalSolid);
} // for each layer
});
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end";
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -1303,6 +1323,7 @@ void PrintObject::bridge_over_infill()
layerm->export_region_slices_to_svg_debug("7_bridge_over_infill");
layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
this->_print->throw_if_canceled();
}
}
}
@ -1411,9 +1432,11 @@ void PrintObject::_slice()
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
this->layers[layer_id]->regions[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end";
}
@ -1422,6 +1445,7 @@ void PrintObject::_slice()
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true);
this->_print->throw_if_canceled();
// loop through the other regions and 'steal' the slices belonging to this one
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " start";
for (size_t other_region_id = 0; other_region_id < this->print()->regions.size(); ++ other_region_id) {
@ -1443,6 +1467,7 @@ void PrintObject::_slice()
layerm->slices.append(std::move(my_parts), stInternal);
}
}
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " end";
}
}
@ -1459,6 +1484,7 @@ void PrintObject::_slice()
if (! this->layers.empty())
this->layers.back()->upper_layer = nullptr;
}
this->_print->throw_if_canceled();
end:
;
@ -1467,7 +1493,7 @@ end:
tbb::blocked_range<size_t>(0, this->layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
Layer *layer = this->layers[layer_id];
// Apply size compensation and perform clipping of multi-part objects.
float delta = float(scale_(this->config.xy_size_compensation.value));
@ -1503,6 +1529,7 @@ end:
layer->make_slices();
}
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
}
@ -1519,6 +1546,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::
ModelVolume *volume = this->model_object()->volumes[volume_id];
if (volume->modifier == modifier)
mesh.merge(volume->mesh);
this->_print->throw_if_canceled();
}
if (mesh.stl.stats.number_of_facets > 0) {
// transform mesh
@ -1528,8 +1556,12 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
mesh.translate(- float(unscale(this->_copies_shift.x)), - float(unscale(this->_copies_shift.y)), -float(this->model_object()->bounding_box().min.z));
// perform actual slicing
TriangleMeshSlicer mslicer(&mesh);
mslicer.slice(z, &layers);
TriangleMeshSlicer mslicer;
Print *print = this->print();
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
mslicer.init(&mesh, callback);
mslicer.slice(z, &layers, callback);
this->_print->throw_if_canceled();
}
}
}
@ -1551,7 +1583,7 @@ std::string PrintObject::_fix_slicing_errors()
tbb::blocked_range<size_t>(0, buggy_layers.size()),
[this, &buggy_layers](const tbb::blocked_range<size_t>& range) {
for (size_t buggy_layer_idx = range.begin(); buggy_layer_idx < range.end(); ++ buggy_layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
size_t idx_layer = buggy_layers[buggy_layer_idx];
Layer *layer = this->layers[idx_layer];
assert(layer->slicing_errors);
@ -1602,6 +1634,7 @@ std::string PrintObject::_fix_slicing_errors()
layer->make_slices();
}
});
this->_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end";
// remove empty layers from bottom
@ -1628,7 +1661,7 @@ void PrintObject::_simplify_slices(double distance)
tbb::blocked_range<size_t>(0, this->layers.size()),
[this, distance](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
PARALLEL_FOR_CANCEL;
this->_print->throw_if_canceled();
Layer *layer = this->layers[layer_idx];
for (size_t region_idx = 0; region_idx < layer->regions.size(); ++ region_idx)
layer->regions[region_idx]->slices.simplify(distance);
@ -1721,6 +1754,7 @@ void PrintObject::clip_fill_surfaces()
layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
#endif
}
this->_print->throw_if_canceled();
}
}
@ -1730,6 +1764,7 @@ void PrintObject::discover_horizontal_shells()
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
for (int i = 0; i < int(this->layers.size()); ++ i) {
this->_print->throw_if_canceled();
LayerRegion *layerm = this->layers[i]->regions[region_id];
PrintRegionConfig &region_config = layerm->region()->config;
if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
@ -1746,6 +1781,7 @@ void PrintObject::discover_horizontal_shells()
continue;
for (int idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
this->_print->throw_if_canceled();
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
// Find slices of current type for current layer.
// Use slices instead of fill_surfaces, because they also include the perimeter area,
@ -1932,6 +1968,7 @@ void PrintObject::combine_infill()
double current_height = 0.;
size_t num_layers = 0;
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) {
this->_print->throw_if_canceled();
const Layer *layer = this->layers[layer_idx];
if (layer->id() == 0)
// Skip first print layer (which may not be first layer in array because of raft).
@ -1954,6 +1991,7 @@ void PrintObject::combine_infill()
// loop through layers to which we have assigned layers to combine
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) {
this->_print->throw_if_canceled();
size_t num_layers = combine[layer_idx];
if (num_layers <= 1)
continue;

View File

@ -2,8 +2,7 @@
namespace Slic3r {
Flow
PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
{
ConfigOptionFloatOrPercent config_width;
if (width != -1) {

View File

@ -606,11 +606,11 @@ TriangleMesh::require_shared_vertices()
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
}
TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
mesh(_mesh)
void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type throw_on_cancel)
{
mesh = _mesh;
_mesh->require_shared_vertices();
throw_on_cancel();
facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
// Scale the copied vertices.
@ -650,6 +650,7 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
e2f.face_edge = - e2f.face_edge;
}
}
throw_on_cancel();
std::sort(edges_map.begin(), edges_map.end());
// Assign a unique common edge id to touching triangle edges.
@ -689,11 +690,12 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
edge_j.face = -1;
}
++ num_edges;
if ((i & 0x0ffff) == 0)
throw_on_cancel();
}
}
void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
@ -730,13 +732,17 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
boost::mutex lines_mutex;
tbb::parallel_for(
tbb::blocked_range<int>(0,this->mesh->stl.stats.number_of_facets),
[&lines, &lines_mutex, &z, this](const tbb::blocked_range<int>& range) {
for (int facet_idx = range.begin(); facet_idx < range.end(); ++ facet_idx)
[&lines, &lines_mutex, &z, throw_on_cancel, this](const tbb::blocked_range<int>& range) {
for (int facet_idx = range.begin(); facet_idx < range.end(); ++ facet_idx) {
if ((facet_idx & 0x0ffff) == 0)
throw_on_cancel();
this->_slice_do(facet_idx, &lines, &lines_mutex, z);
}
}
);
}
throw_on_cancel();
// v_scaled_shared could be freed here
// build loops
@ -744,9 +750,12 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
layers->resize(z.size());
tbb::parallel_for(
tbb::blocked_range<size_t>(0, z.size()),
[&lines, &layers, this](const tbb::blocked_range<size_t>& range) {
for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx)
[&lines, &layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx) {
if ((line_idx & 0x0ffff) == 0)
throw_on_cancel();
this->make_loops(lines[line_idx], &(*layers)[line_idx]);
}
}
);
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice finished";
@ -823,21 +832,21 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
}
}
void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{
std::vector<Polygons> layers_p;
this->slice(z, &layers_p);
this->slice(z, &layers_p, throw_on_cancel);
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - start";
layers->resize(z.size());
tbb::parallel_for(
tbb::blocked_range<size_t>(0, z.size()),
[&layers_p, layers, this](const tbb::blocked_range<size_t>& range) {
[&layers_p, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]);
#endif
throw_on_cancel();
this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]);
}
});

View File

@ -3,6 +3,7 @@
#include "libslic3r.h"
#include <admesh/stl.h>
#include <functional>
#include <vector>
#include <boost/thread.hpp>
#include "BoundingBox.hpp"
@ -130,9 +131,13 @@ typedef std::vector<IntersectionLine*> IntersectionLinePtrs;
class TriangleMeshSlicer
{
public:
TriangleMeshSlicer(TriangleMesh* _mesh);
void slice(const std::vector<float> &z, std::vector<Polygons>* layers) const;
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const;
typedef std::function<void()> throw_on_cancel_callback_type;
TriangleMeshSlicer() : mesh(nullptr) {}
// Not quite nice, but the constructor and init() methods require non-const mesh pointer to be able to call mesh->require_shared_vertices()
TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, throw_on_cancel_callback_type()); }
void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
bool slice_facet(float slice_z, const stl_facet &facet, const int facet_idx,
const float min_z, const float max_z, IntersectionLine *line_out) const;
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;

View File

@ -647,14 +647,10 @@ std::vector<double> GLVolumeCollection::get_current_print_zs() const
for (GLVolume *vol : this->volumes)
{
for (coordf_t z : vol->print_zs)
{
double round_z = (double)round(z * 100000.0f) / 100000.0f;
if (std::find(print_zs.begin(), print_zs.end(), round_z) == print_zs.end())
print_zs.push_back(round_z);
}
print_zs.emplace_back((double)round(z * 100000.0f) / 100000.0f);
}
std::sort(print_zs.begin(), print_zs.end());
sort_remove_duplicates(print_zs);
return print_zs;
}
@ -1671,6 +1667,9 @@ void _3DScene::_load_print_toolpaths(
const std::vector<std::string> &tool_colors,
bool use_VBOs)
{
// The skirt and brim steps should be marked as done, so their paths are valid.
assert(print->is_step_done(psSkirt) && print->is_step_done(psBrim));
if (!print->has_skirt() && print->config.brim_width.value == 0)
return;
@ -1762,9 +1761,9 @@ void _3DScene::_load_print_object_toolpaths(
std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; });
// Maximum size of an allocation block: 32MB / sizeof(float)
ctxt.has_perimeters = print_object->state.is_done(posPerimeters);
ctxt.has_infill = print_object->state.is_done(posInfill);
ctxt.has_support = print_object->state.is_done(posSupportMaterial);
ctxt.has_perimeters = print_object->is_step_done(posPerimeters);
ctxt.has_infill = print_object->is_step_done(posInfill);
ctxt.has_support = print_object->is_step_done(posSupportMaterial);
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start";

View File

@ -24,7 +24,7 @@ void BackgroundSlicingProcess::thread_proc()
lck.unlock();
m_condition.notify_one();
for (;;) {
assert(m_state == STATE_IDLE);
assert(m_state == STATE_IDLE || m_state == STATE_CANCELED || m_state == STATE_FINISHED);
// Wait until a new task is ready to be executed, or this thread should be finished.
lck.lock();
m_condition.wait(lck, [this](){ return m_state == STATE_STARTED || m_state == STATE_EXIT; });
@ -38,10 +38,13 @@ void BackgroundSlicingProcess::thread_proc()
try {
assert(m_print != nullptr);
m_print->process();
if (m_print->canceled())
return;
wxQueueEvent(GUI::g_wxPlater, new wxCommandEvent(m_event_sliced_id));
m_print->export_gcode(m_output_path, m_gcode_preview_data);
if (! m_print->canceled()) {
wxQueueEvent(GUI::g_wxPlater, new wxCommandEvent(m_event_sliced_id));
m_print->export_gcode(m_output_path, m_gcode_preview_data);
}
} catch (CanceledException &ex) {
// Canceled, this is all right.
assert(m_print->canceled());
} catch (std::exception &ex) {
error = ex.what();
} catch (...) {
@ -53,6 +56,7 @@ void BackgroundSlicingProcess::thread_proc()
evt.SetString(error);
evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0));
wxQueueEvent(GUI::g_wxPlater, evt.Clone());
m_print->restart();
lck.unlock();
// Let the UI thread wake up if it is waiting for the background task to finish.
m_condition.notify_one();
@ -112,21 +116,23 @@ bool BackgroundSlicingProcess::stop()
if (m_state == STATE_STARTED || m_state == STATE_RUNNING) {
m_print->cancel();
// Wait until the background processing stops by being canceled.
lck.unlock();
m_condition.wait(lck, [this](){ return m_state == STATE_CANCELED; });
// In the "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE;
} else if (m_state == STATE_FINISHED || m_state == STATE_CANCELED) {
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE;
}
return true;
}
// Apply config over the print. Returns false, if the new config values caused any of the already
// processed steps to be invalidated, therefore the task will need to be restarted.
bool BackgroundSlicingProcess::apply_config(DynamicPrintConfig *config)
bool BackgroundSlicingProcess::apply_config(const DynamicPrintConfig &config)
{
/*
// apply new config
my $invalidated = $self->{print}->apply_config(wxTheApp->{preset_bundle}->full_config);
*/
return true;
this->stop();
bool invalidated = this->m_print->apply_config(config);
return invalidated;
}
}; // namespace Slic3r

View File

@ -39,7 +39,7 @@ public:
// Apply config over the print. Returns false, if the new config values caused any of the already
// processed steps to be invalidated, therefore the task will need to be restarted.
bool apply_config(DynamicPrintConfig *config);
bool apply_config(const DynamicPrintConfig &config);
enum State {
// m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet).

View File

@ -17,7 +17,8 @@
bool start();
bool stop();
bool apply_config(DynamicPrintConfig *config);
bool apply_config(DynamicPrintConfig *config)
%code%{ RETVAL = THIS->apply_config(*config); %};
bool running();
};

View File

@ -74,7 +74,7 @@ _constant()
Ref<SupportLayer> get_support_layer(int idx);
bool step_done(PrintObjectStep step)
%code%{ RETVAL = THIS->state.is_done(step); %};
%code%{ RETVAL = THIS->is_step_done(step); %};
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
%code%{
@ -123,9 +123,9 @@ _constant()
%code%{ RETVAL = THIS->regions.size(); %};
bool step_done(PrintStep step)
%code%{ RETVAL = THIS->state.is_done(step); %};
%code%{ RETVAL = THIS->is_step_done(step); %};
bool object_step_done(PrintObjectStep step)
%code%{ RETVAL = THIS->step_done(step); %};
%code%{ RETVAL = THIS->is_step_done(step); %};
SV* filament_stats()
%code%{

View File

@ -185,7 +185,7 @@ TriangleMesh::slice(z)
std::vector<ExPolygons> layers;
TriangleMeshSlicer mslicer(THIS);
mslicer.slice(z_f, &layers);
mslicer.slice(z_f, &layers, [](){});
AV* layers_av = newAV();
size_t len = layers.size();