Background processing in C++, WIP.
This commit is contained in:
parent
8639df1cfd
commit
33e1108f65
@ -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("");
|
||||
|
@ -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()), © - 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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 ®ion = **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, ®ion, 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 ®ion_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;
|
||||
|
@ -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) {
|
||||
|
@ -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]);
|
||||
}
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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%{
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user