Improved constness of the Print / PrintObject / Layer ...

Split the wipe tower and time statistics data into separate objects.
Initial work in synchronizing the Model with the Print.
This commit is contained in:
bubnikv 2018-09-11 14:04:47 +02:00
parent 49697ed6aa
commit 41ce69f327
21 changed files with 1197 additions and 1101 deletions

View file

@ -34,7 +34,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
{
// Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
double fill_density = layerm.region()->config.fill_density;
double fill_density = layerm.region()->config().fill_density;
Flow infill_flow = layerm.flow(frInfill);
Flow solid_infill_flow = layerm.flow(frSolidInfill);
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
@ -69,7 +69,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
group_attrib[i].is_solid = true;
group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
group_attrib[i].pattern = surface.is_external() ? layerm.region()->config.external_fill_pattern.value : ipRectilinear;
group_attrib[i].pattern = surface.is_external() ? layerm.region()->config().external_fill_pattern.value : ipRectilinear;
}
}
// Loop through solid groups, find compatible groups and append them to this one.
@ -152,7 +152,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
for (const Surface &surface : surfaces) {
if (surface.surface_type == stInternalVoid)
continue;
InfillPattern fill_pattern = layerm.region()->config.fill_pattern.value;
InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value;
double density = fill_density;
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill :
(surface.is_solid() ? frSolidInfill : frInfill);
@ -161,7 +161,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.is_solid()) {
density = 100.;
fill_pattern = (surface.is_external() && ! is_bridge) ?
layerm.region()->config.external_fill_pattern.value :
layerm.region()->config().external_fill_pattern.value :
ipRectilinear;
} else if (density <= 0)
continue;
@ -190,7 +190,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
// layer height
Flow internal_flow = layerm.region()->flow(
frInfill,
layerm.layer()->object()->config.layer_height.value, // TODO: handle infill_every_layers?
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
false, // no bridge
false, // no first layer
-1, // auto width
@ -205,7 +205,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
double link_max_length = 0.;
if (! is_bridge) {
#if 0
link_max_length = layerm.region()->config.get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
#else
if (density > 80.) // 80%
@ -215,7 +215,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->layer_id = layerm.layer()->id();
f->z = layerm.layer()->print_z;
f->angle = float(Geometry::deg2rad(layerm.region()->config.fill_angle.value));
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// Maximum length of the perimeter segment linking two infill lines.
f->link_max_length = scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths.

View file

@ -111,22 +111,22 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
return Flow::new_from_config_width(
frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config.support_material_extrusion_width.value > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width,
// if object->config.support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.layer_height.value),
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
false);
}
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
{
const auto &width = (object->print()->config.first_layer_extrusion_width.value > 0) ? object->print()->config.first_layer_extrusion_width : object->config.support_material_extrusion_width;
const auto &width = (object->print()->config().first_layer_extrusion_width.value > 0) ? object->print()->config().first_layer_extrusion_width : object->config().support_material_extrusion_width;
return Flow::new_from_config_width(
frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(width.value > 0) ? width : object->config.extrusion_width,
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.first_layer_height.get_abs_value(object->config.layer_height.value)),
(width.value > 0) ? width : object->config().extrusion_width,
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)),
false);
}
@ -135,10 +135,10 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
return Flow::new_from_config_width(
frSupportMaterialInterface,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config.support_material_extrusion_width > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width,
// if object->config.support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config.layer_height.value),
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
false);
}

View file

@ -275,15 +275,15 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen)
std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObject &object)
{
std::vector<GCode::LayerToPrint> layers_to_print;
layers_to_print.reserve(object.layers.size() + object.support_layers.size());
layers_to_print.reserve(object.layers().size() + object.support_layers().size());
// Pair the object layers with the support layers by z.
size_t idx_object_layer = 0;
size_t idx_support_layer = 0;
while (idx_object_layer < object.layers.size() || idx_support_layer < object.support_layers.size()) {
while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) {
LayerToPrint layer_to_print;
layer_to_print.object_layer = (idx_object_layer < object.layers.size()) ? object.layers[idx_object_layer ++] : nullptr;
layer_to_print.support_layer = (idx_support_layer < object.support_layers.size()) ? object.support_layers[idx_support_layer ++] : nullptr;
layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer ++] : nullptr;
layer_to_print.support_layer = (idx_support_layer < object.support_layers().size()) ? object.support_layers()[idx_support_layer ++] : nullptr;
if (layer_to_print.object_layer && layer_to_print.support_layer) {
if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z - EPSILON) {
layer_to_print.support_layer = nullptr;
@ -309,10 +309,10 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
size_t object_idx;
size_t layer_idx;
};
std::vector<std::vector<LayerToPrint>> per_object(print.objects.size(), std::vector<LayerToPrint>());
std::vector<std::vector<LayerToPrint>> per_object(print.objects().size(), std::vector<LayerToPrint>());
std::vector<OrderingItem> ordering;
for (size_t i = 0; i < print.objects.size(); ++ i) {
per_object[i] = collect_layers_to_print(*print.objects[i]);
for (size_t i = 0; i < print.objects().size(); ++ i) {
per_object[i] = collect_layers_to_print(*print.objects()[i]);
OrderingItem ordering_item;
ordering_item.object_idx = i;
ordering.reserve(ordering.size() + per_object[i].size());
@ -337,7 +337,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
std::pair<coordf_t, std::vector<LayerToPrint>> merged;
// Assign an average print_z to the set of layers with nearly equal print_z.
merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z);
merged.second.assign(print.objects.size(), LayerToPrint());
merged.second.assign(print.objects().size(), LayerToPrint());
for (; i < j; ++ i) {
const OrderingItem &oi = ordering[i];
assert(merged.second[oi.object_idx].layer() == nullptr);
@ -366,7 +366,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
try {
this->m_placeholder_parser_failed_templates.clear();
m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, preview_data);
fflush(file);
if (ferror(file)) {
@ -382,10 +382,10 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw;
}
fclose(file);
if (! this->m_placeholder_parser_failed_templates.empty()) {
if (! m_placeholder_parser_failed_templates.empty()) {
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
for (const std::string &name : this->m_placeholder_parser_failed_templates)
for (const std::string &name : m_placeholder_parser_failed_templates)
msg += std::string("\t") + name + "\n";
msg += "\nPlease inspect the file ";
msg += path_tmp + " for error messages enclosed between\n";
@ -415,7 +415,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// resets time estimator
m_time_estimator.reset();
m_time_estimator.set_dialect(print.config.gcode_flavor);
m_time_estimator.set_dialect(print.config().gcode_flavor);
// resets analyzer
m_analyzer.reset();
@ -429,14 +429,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// How many times will be change_layer() called?
// change_layer() in turn increments the progress bar status.
m_layer_count = 0;
if (print.config.complete_objects.value) {
if (print.config().complete_objects.value) {
// Add each of the object's layers separately.
for (auto object : print.objects) {
for (auto object : print.objects()) {
std::vector<coordf_t> zs;
zs.reserve(object->layers.size() + object->support_layers.size());
for (auto layer : object->layers)
zs.reserve(object->layers().size() + object->support_layers().size());
for (auto layer : object->layers())
zs.push_back(layer->print_z);
for (auto layer : object->support_layers)
for (auto layer : object->support_layers())
zs.push_back(layer->print_z);
std::sort(zs.begin(), zs.end());
m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin()));
@ -444,11 +444,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
} else {
// Print all objects with the same print_z together.
std::vector<coordf_t> zs;
for (auto object : print.objects) {
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
for (auto layer : object->layers)
for (auto object : print.objects()) {
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
for (auto layer : object->layers())
zs.push_back(layer->print_z);
for (auto layer : object->support_layers)
for (auto layer : object->support_layers())
zs.push_back(layer->print_z);
}
std::sort(zs.begin(), zs.end());
@ -457,33 +457,33 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
print.throw_if_canceled();
m_enable_cooling_markers = true;
this->apply_print_config(print.config);
this->apply_print_config(print.config());
this->set_extruders(print.extruders());
// Initialize autospeed.
{
// get the minimum cross-section used in the print
std::vector<double> mm3_per_mm;
for (auto object : print.objects) {
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
auto region = print.regions[region_id];
for (auto layer : object->layers) {
auto layerm = layer->regions[region_id];
if (region->config.get_abs_value("perimeter_speed" ) == 0 ||
region->config.get_abs_value("small_perimeter_speed" ) == 0 ||
region->config.get_abs_value("external_perimeter_speed" ) == 0 ||
region->config.get_abs_value("bridge_speed" ) == 0)
for (auto object : print.objects()) {
for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
auto region = print.regions()[region_id];
for (auto layer : object->layers()) {
auto layerm = layer->regions()[region_id];
if (region->config().get_abs_value("perimeter_speed" ) == 0 ||
region->config().get_abs_value("small_perimeter_speed" ) == 0 ||
region->config().get_abs_value("external_perimeter_speed" ) == 0 ||
region->config().get_abs_value("bridge_speed" ) == 0)
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
if (region->config.get_abs_value("infill_speed" ) == 0 ||
region->config.get_abs_value("solid_infill_speed" ) == 0 ||
region->config.get_abs_value("top_solid_infill_speed" ) == 0 ||
region->config.get_abs_value("bridge_speed" ) == 0)
if (region->config().get_abs_value("infill_speed" ) == 0 ||
region->config().get_abs_value("solid_infill_speed" ) == 0 ||
region->config().get_abs_value("top_solid_infill_speed" ) == 0 ||
region->config().get_abs_value("bridge_speed" ) == 0)
mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
}
}
if (object->config.get_abs_value("support_material_speed" ) == 0 ||
object->config.get_abs_value("support_material_interface_speed" ) == 0)
for (auto layer : object->support_layers)
if (object->config().get_abs_value("support_material_speed" ) == 0 ||
object->config().get_abs_value("support_material_interface_speed" ) == 0)
for (auto layer : object->support_layers())
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
}
print.throw_if_canceled();
@ -495,20 +495,20 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// volumetric speed as the volumetric speed produced by printing the
// smallest cross-section at the maximum speed: any larger cross-section
// will need slower feedrates.
m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config.max_print_speed.value;
m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value;
// limit such volumetric speed with max_volumetric_speed if set
if (print.config.max_volumetric_speed.value > 0)
m_volumetric_speed = std::min(m_volumetric_speed, print.config.max_volumetric_speed.value);
if (print.config().max_volumetric_speed.value > 0)
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)
m_spiral_vase = make_unique<SpiralVase>(print.config);
if (print.config.max_volumetric_extrusion_rate_slope_positive.value > 0 ||
print.config.max_volumetric_extrusion_rate_slope_negative.value > 0)
m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config);
if (print.config().spiral_vase.value)
m_spiral_vase = make_unique<SpiralVase>(print.config());
if (print.config().max_volumetric_extrusion_rate_slope_positive.value > 0 ||
print.config().max_volumetric_extrusion_rate_slope_negative.value > 0)
m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config());
m_enable_extrusion_role_markers = (bool)m_pressure_equalizer;
// Write information on the generator.
@ -516,7 +516,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// Write notes (content of the Print Settings tab -> Notes)
{
std::list<std::string> lines;
boost::split(lines, print.config.notes.value, boost::is_any_of("\n"), boost::token_compress_off);
boost::split(lines, print.config().notes.value, boost::is_any_of("\n"), boost::token_compress_off);
for (auto line : lines) {
// Remove the trailing '\r' from the '\r\n' sequence.
if (! line.empty() && line.back() == '\r')
@ -529,11 +529,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
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;
const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height);
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
auto region = print.regions[region_id];
const PrintObject *first_object = print.objects().front();
const double layer_height = first_object->config().layer_height.value;
const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height);
for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
auto region = print.regions()[region_id];
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width);
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width);
_write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width);
@ -541,14 +541,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width);
if (print.has_support_material())
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width);
if (print.config.first_layer_extrusion_width.value > 0)
if (print.config().first_layer_extrusion_width.value > 0)
_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;
m_placeholder_parser = print.placeholder_parser();
m_placeholder_parser.update_timestamp();
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
@ -558,19 +558,19 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
unsigned int final_extruder_id = (unsigned int)-1;
size_t initial_print_object_id = 0;
bool has_wipe_tower = false;
if (print.config.complete_objects.value) {
if (print.config().complete_objects.value) {
// Find the 1st printing object, find its tool ordering and the initial extruder ID.
for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) {
tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id);
for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) {
tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id);
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
break;
}
} else {
// Find tool ordering for all the objects at once, and the initial extruder ID.
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
tool_ordering = print.m_tool_ordering.empty() ?
tool_ordering = print.wipe_tower_data().tool_ordering.empty() ?
ToolOrdering(print, initial_extruder_id) :
print.m_tool_ordering;
print.wipe_tower_data().tool_ordering;
initial_extruder_id = tool_ordering.first_extruder();
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
}
@ -587,7 +587,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_cooling_buffer->set_current_extruder(initial_extruder_id);
// Disable fan.
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id))
_write(file, m_writer.set_fan(0, true));
// Let the start-up script prime the 1st printing tool.
@ -598,7 +598,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_placeholder_parser.set("current_object_idx", 0);
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id);
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
@ -616,16 +616,16 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// Write the custom start G-code
_writeln(file, start_gcode);
// Process filament-specific gcode in extruder order.
if (print.config.single_extruder_multi_material) {
if (print.config().single_extruder_multi_material) {
if (has_wipe_tower) {
// Wipe tower will control the extruder switching, it will call the start_filament_gcode.
} else {
// Only initialize the initial extruder.
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config.start_filament_gcode.values[initial_extruder_id], initial_extruder_id));
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id));
}
} else {
for (const std::string &start_gcode : print.config.start_filament_gcode.values)
_writeln(file, this->placeholder_parser_process("start_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front())));
for (const std::string &start_gcode : print.config().start_filament_gcode.values)
_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();
@ -634,12 +634,12 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write(file, this->preamble());
// Initialize a motion planner for object-to-object travel moves.
if (print.config.avoid_crossing_perimeters.value) {
if (print.config().avoid_crossing_perimeters.value) {
// Collect outer contours of all objects over all layers.
// Discard objects only containing thin walls (offset would fail on an empty polygon).
Polygons islands;
for (const PrintObject *object : print.objects)
for (const Layer *layer : object->layers)
for (const PrintObject *object : print.objects())
for (const Layer *layer : object->layers())
for (const ExPolygon &expoly : layer->slices.expolygons)
for (const Point &copy : object->_shifted_copies) {
islands.emplace_back(expoly.contour);
@ -651,16 +651,16 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
}
// Calculate wiping points if needed
if (print.config.ooze_prevention.value && ! print.config.single_extruder_multi_material) {
if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
Points skirt_points;
for (const ExtrusionEntity *ee : print.skirt.entities)
for (const ExtrusionEntity *ee : print.skirt().entities)
for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
append(skirt_points, path.polyline.points);
if (! skirt_points.empty()) {
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
Polygons skirts;
for (unsigned int extruder_id : print.extruders()) {
const Pointf &extruder_offset = print.config.extruder_offset.get_at(extruder_id);
const Pointf &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
Polygon s(outer_skirt);
s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y));
skirts.emplace_back(std::move(s));
@ -685,10 +685,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write(file, this->set_extruder(initial_extruder_id));
// Do all objects for each layer.
if (print.config.complete_objects.value) {
if (print.config().complete_objects.value) {
// Print objects from the smallest to the tallest to avoid collisions
// when moving onto next object starting point.
std::vector<PrintObject*> objects(print.objects);
std::vector<PrintObject*> objects(print.objects());
std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });
size_t finished_objects = 0;
for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
@ -722,7 +722,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// another one, set first layer temperatures. This happens before the Z move
// is triggered, so machine has more time to reach such temperatures.
m_placeholder_parser.set("current_object_idx", int(finished_objects));
std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config.between_objects_gcode.value, initial_extruder_id);
std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id);
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
@ -751,7 +751,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// Order objects using a nearest neighbor search.
std::vector<size_t> object_indices;
Points object_reference_points;
for (PrintObject *object : print.objects)
for (PrintObject *object : print.objects())
object_reference_points.push_back(object->_shifted_copies.front());
Slic3r::Geometry::chained_path(object_reference_points, object_indices);
// Sort layers by Z.
@ -759,13 +759,13 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> layers_to_print = collect_layers_to_print(print);
// Prusa Multi-Material wipe tower.
if (has_wipe_tower && ! layers_to_print.empty()) {
m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get()));
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
_write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
_write(file, m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions.
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
for (const PrintObject *print_object : print.objects)
for (const PrintObject *print_object : print.objects())
bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz));
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
@ -813,14 +813,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
}
// Process filament-specific gcode in extruder order.
if (print.config.single_extruder_multi_material) {
if (print.config().single_extruder_multi_material) {
// Process the end_filament_gcode for the active filament only.
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id()));
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id()));
} else {
for (const std::string &end_gcode : print.config.end_filament_gcode.values)
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front())));
for (const std::string &end_gcode : print.config().end_filament_gcode.values)
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front())));
}
_writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id()));
_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();
@ -829,31 +829,27 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_time_estimator.calculate_time();
// Get filament stats.
print.filament_stats.clear();
print.total_used_filament = 0.;
print.total_extruded_volume = 0.;
print.total_weight = 0.;
print.total_cost = 0.;
print.estimated_print_time = m_time_estimator.get_time_hms();
print.m_print_statistics.clear();
print.m_print_statistics.estimated_print_time = m_time_estimator.get_time_hms();
for (const Extruder &extruder : m_writer.extruders()) {
double used_filament = extruder.used_filament();
double extruded_volume = extruder.extruded_volume();
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
print.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament));
print.m_print_statistics.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament));
_write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001);
if (filament_weight > 0.) {
print.total_weight = print.total_weight + filament_weight;
print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight;
_write_format(file, "; filament used = %.1lf\n", filament_weight);
if (filament_cost > 0.) {
print.total_cost = print.total_cost + filament_cost;
print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost;
_write_format(file, "; filament cost = %.1lf\n", filament_cost);
}
}
print.total_used_filament = print.total_used_filament + used_filament;
print.total_extruded_volume = print.total_extruded_volume + extruded_volume;
print.m_print_statistics.total_used_filament = print.m_print_statistics.total_used_filament + used_filament;
print.m_print_statistics.total_extruded_volume = print.m_print_statistics.total_extruded_volume + extruded_volume;
}
_write_format(file, "; total filament cost = %.1lf\n", print.total_cost);
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
_write_format(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms().c_str());
// Append full config.
@ -879,7 +875,7 @@ std::string GCode::placeholder_parser_process(const std::string &name, const std
return m_placeholder_parser.process(templ, current_extruder_id, config_override);
} catch (std::runtime_error &err) {
// Collect the names of failed template substitutions for error reporting.
this->m_placeholder_parser_failed_templates.insert(name);
m_placeholder_parser_failed_templates.insert(name);
// Insert the macro error message into the G-code.
return
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
@ -949,7 +945,7 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{
// Initial bed temperature based on the first extruder.
int temp = print.config.first_layer_bed_temperature.get_at(first_printing_extruder_id);
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
// Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1;
bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode);
@ -972,23 +968,23 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
int temp_by_gcode = -1;
if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) {
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
temp = temp_by_gcode;
m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id);
} else {
// Custom G-code does not set the extruder temperature. Do it now.
if (print.config.single_extruder_multi_material.value) {
if (print.config().single_extruder_multi_material.value) {
// Set temperature of the first printing extruder only.
int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id));
} else {
// Set temperatures of all the printing extruders.
for (unsigned int tool_id : print.extruders()) {
int temp = print.config.first_layer_temperature.get_at(tool_id);
if (print.config.ooze_prevention.value)
temp += print.config.standby_temperature_delta.value;
int temp = print.config().first_layer_temperature.get_at(tool_id);
if (print.config().ooze_prevention.value)
temp += print.config().standby_temperature_delta.value;
if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, tool_id));
}
@ -1061,15 +1057,15 @@ void GCode::process_layer(
unsigned int first_extruder_id = layer_tools.extruders.front();
// Initialize config with the 1st object to be printed at this layer.
m_config.apply(layer.object()->config, true);
m_config.apply(layer.object()->config(), true);
// Check whether it is possible to apply the spiral vase logic for this layer.
// Just a reminder: A spiral vase mode is allowed for a single object, single material print only.
if (m_spiral_vase && layers.size() == 1 && support_layer == nullptr) {
bool enable = (layer.id() > 0 || print.config.brim_width.value == 0.) && (layer.id() >= print.config.skirt_height.value && ! print.has_infinite_skirt());
bool enable = (layer.id() > 0 || print.config().brim_width.value == 0.) && (layer.id() >= print.config().skirt_height.value && ! print.has_infinite_skirt());
if (enable) {
for (const LayerRegion *layer_region : layer.regions)
if (layer_region->region()->config.bottom_solid_layers.value > layer.id() ||
for (const LayerRegion *layer_region : layer.regions())
if (layer_region->region()->config().bottom_solid_layers.value > layer.id() ||
layer_region->perimeters.items_count() > 1 ||
layer_region->fills.items_count() > 0) {
enable = false;
@ -1084,22 +1080,22 @@ void GCode::process_layer(
std::string gcode;
// Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
if (! print.config.before_layer_gcode.value.empty()) {
if (! print.config().before_layer_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("before_layer_gcode",
print.config.before_layer_gcode.value, m_writer.extruder()->id(), &config)
print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
+ "\n";
}
gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer;
if (! print.config.layer_gcode.value.empty()) {
if (! print.config().layer_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("layer_gcode",
print.config.layer_gcode.value, m_writer.extruder()->id(), &config)
print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
+ "\n";
}
@ -1107,14 +1103,14 @@ void GCode::process_layer(
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
// first_layer_temperature vs. temperature settings.
for (const Extruder &extruder : m_writer.extruders()) {
if (print.config.single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id())
if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id())
// In single extruder multi material mode, set the temperature for the current extruder only.
continue;
int temperature = print.config.temperature.get_at(extruder.id());
if (temperature > 0 && temperature != print.config.first_layer_temperature.get_at(extruder.id()))
int temperature = print.config().temperature.get_at(extruder.id());
if (temperature > 0 && temperature != print.config().first_layer_temperature.get_at(extruder.id()))
gcode += m_writer.set_temperature(temperature, false, extruder.id());
}
gcode += m_writer.set_bed_temperature(print.config.bed_temperature.get_at(first_extruder_id));
gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id));
// Mark the temperature transition from 1st to 2nd layer to be finished.
m_second_layer_things_done = true;
}
@ -1122,9 +1118,9 @@ void GCode::process_layer(
// Extrude skirt at the print_z of the raft layers and normal object layers
// not at the print_z of the interlaced support material layers.
bool extrude_skirt =
! print.skirt.entities.empty() &&
! print.skirt().entities.empty() &&
// Not enough skirt layers printed yet.
(m_skirt_done.size() < print.config.skirt_height.value || print.has_infinite_skirt()) &&
(m_skirt_done.size() < print.config().skirt_height.value || print.has_infinite_skirt()) &&
// This print_z has not been extruded yet
(m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON &&
// and this layer is the 1st layer, or it is an object layer, or it is a raft layer.
@ -1146,7 +1142,7 @@ void GCode::process_layer(
extruder_ids.front() = first_extruder_id;
break;
}
size_t n_loops = print.skirt.entities.size();
size_t n_loops = print.skirt().entities.size();
if (n_loops <= extruder_ids.size()) {
for (size_t i = 0; i < n_loops; ++i)
skirt_loops_per_extruder[extruder_ids[i]] = std::pair<size_t, size_t>(i, i + 1);
@ -1165,7 +1161,7 @@ void GCode::process_layer(
}
} else
// Extrude all skirts with the current extruder.
skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config.skirts.value);
skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config().skirts.value);
}
// Group extrusions by an extruder, then by an object, an island and a region.
@ -1180,22 +1176,22 @@ void GCode::process_layer(
bool has_support = role == erMixed || role == erSupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
// Extruder ID of the support base. -1 if "don't care".
unsigned int support_extruder = object.config.support_material_extruder.value - 1;
unsigned int support_extruder = object.config().support_material_extruder.value - 1;
// Shall the support be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
bool support_dontcare = object.config.support_material_extruder.value == 0;
bool support_dontcare = object.config().support_material_extruder.value == 0;
// Extruder ID of the support interface. -1 if "don't care".
unsigned int interface_extruder = object.config.support_material_interface_extruder.value - 1;
unsigned int interface_extruder = object.config().support_material_interface_extruder.value - 1;
// Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
bool interface_dontcare = object.config.support_material_interface_extruder.value == 0;
bool interface_dontcare = object.config().support_material_interface_extruder.value == 0;
if (support_dontcare || interface_dontcare) {
// Some support will be printed with "don't care" material, preferably non-soluble.
// Is the current extruder assigned a soluble filament?
unsigned int dontcare_extruder = first_extruder_id;
if (print.config.filament_soluble.get_at(dontcare_extruder)) {
if (print.config().filament_soluble.get_at(dontcare_extruder)) {
// The last extruder printed on the previous layer extrudes soluble filament.
// Try to find a non-soluble extruder on the same layer.
for (unsigned int extruder_id : layer_tools.extruders)
if (! print.config.filament_soluble.get_at(extruder_id)) {
if (! print.config().filament_soluble.get_at(extruder_id)) {
dontcare_extruder = extruder_id;
break;
}
@ -1242,11 +1238,11 @@ void GCode::process_layer(
layer.slices.expolygons[i].contour.contains(point);
};
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
const LayerRegion *layerm = layer.regions[region_id];
for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
const LayerRegion *layerm = layer.regions()[region_id];
if (layerm == nullptr)
continue;
const PrintRegion &region = *print.regions[region_id];
const PrintRegion &region = *print.regions()[region_id];
// process perimeters
for (const ExtrusionEntity *ee : layerm->perimeters.entities) {
@ -1258,7 +1254,7 @@ void GCode::process_layer(
// Init by_extruder item only if we actually use the extruder.
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
by_extruder,
std::max<int>(region.config.perimeter_extruder.value - 1, 0),
std::max<int>(region.config().perimeter_extruder.value - 1, 0),
&layer_to_print - layers.data(),
layers.size(), n_slices+1);
for (size_t i = 0; i <= n_slices; ++ i)
@ -1267,7 +1263,7 @@ void GCode::process_layer(
// perimeter_coll->first_point fits inside ith slice
point_inside_surface(i, perimeter_coll->first_point())) {
if (islands[i].by_region.empty())
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region());
islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities);
break;
}
@ -1285,7 +1281,7 @@ void GCode::process_layer(
// This shouldn't happen but first_point() would fail.
continue;
// init by_extruder item only if we actually use the extruder
int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1);
int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1);
// Init by_extruder item only if we actually use the extruder.
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
by_extruder,
@ -1298,7 +1294,7 @@ void GCode::process_layer(
// fill->first_point fits inside ith slice
point_inside_surface(i, fill->first_point())) {
if (islands[i].by_region.empty())
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region());
islands[i].by_region[region_id].infills.append(fill->entities);
break;
}
@ -1324,7 +1320,7 @@ void GCode::process_layer(
Flow skirt_flow = print.skirt_flow();
for (size_t i = loops.first; i < loops.second; ++ i) {
// Adjust flow according to this layer's layer height.
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt.entities[i]);
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
Flow layer_skirt_flow(skirt_flow);
layer_skirt_flow.height = (float)skirt_height;
double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
@ -1345,7 +1341,7 @@ void GCode::process_layer(
if (! m_brim_done) {
this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp = true;
for (const ExtrusionEntity *ee : print.brim.entities)
for (const ExtrusionEntity *ee : print.brim().entities)
gcode += this->extrude_loop(*dynamic_cast<const ExtrusionLoop*>(ee), "brim", m_config.support_material_speed.value);
m_brim_done = true;
m_avoid_crossing_perimeters.use_external_mp = false;
@ -1363,7 +1359,7 @@ void GCode::process_layer(
// This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
continue;
m_config.apply(print_object->config, true);
m_config.apply(print_object->config(), true);
m_layer = layers[layer_id].layer();
if (m_config.avoid_crossing_perimeters)
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true));
@ -1389,7 +1385,7 @@ void GCode::process_layer(
m_layer = layers[layer_id].layer();
}
for (const ObjectByExtruder::Island &island : object_by_extruder.islands) {
if (print.config.infill_first) {
if (print.config().infill_first) {
gcode += this->extrude_infill(print, island.by_region);
gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]);
} else {
@ -1430,7 +1426,7 @@ void GCode::apply_print_config(const PrintConfig &print_config)
void GCode::append_full_config(const Print& print, std::string& str)
{
const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
const StaticPrintConfig *configs[] = { &print.config(), &print.default_object_config(), &print.default_region_config() };
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) {
const StaticPrintConfig *cfg = configs[i];
for (const std::string &key : cfg->keys())
@ -2015,7 +2011,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
{
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions[&region - &by_region.front()]->config);
m_config.apply(print.regions()[&region - &by_region.front()]->config());
for (ExtrusionEntity *ee : region.perimeters.entities)
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
}
@ -2027,7 +2023,7 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
{
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions[&region - &by_region.front()]->config);
m_config.apply(print.regions()[&region - &by_region.front()]->config());
ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false);
for (ExtrusionEntity *fill : chained.entities) {
auto *eec = dynamic_cast<ExtrusionEntityCollection*>(fill);

View file

@ -99,19 +99,19 @@ static BoundingBoxf extrusionentity_extents(const ExtrusionEntity *extrusion_ent
BoundingBoxf get_print_extrusions_extents(const Print &print)
{
BoundingBoxf bbox(extrusionentity_extents(print.brim));
bbox.merge(extrusionentity_extents(print.skirt));
BoundingBoxf bbox(extrusionentity_extents(print.brim()));
bbox.merge(extrusionentity_extents(print.skirt()));
return bbox;
}
BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z)
{
BoundingBoxf bbox;
for (const Layer *layer : print_object.layers) {
for (const Layer *layer : print_object.layers()) {
if (layer->print_z > max_print_z)
break;
BoundingBoxf bbox_this;
for (const LayerRegion *layerm : layer->regions) {
for (const LayerRegion *layerm : layer->regions()) {
bbox_this.merge(extrusionentity_extents(layerm->perimeters));
for (const ExtrusionEntity *ee : layerm->fills.entities)
// fill represents infill extrusions of a single island.
@ -135,7 +135,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z)
{
BoundingBoxf bbox;
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) {
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.wipe_tower_data().tool_changes) {
if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z)
break;
for (const WipeTower::ToolChangeResult &tcr : tool_changes) {
@ -161,8 +161,8 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
{
BoundingBoxf bbox;
if (print.m_wipe_tower_priming) {
const WipeTower::ToolChangeResult &tcr = *print.m_wipe_tower_priming.get();
if (print.wipe_tower_data().priming != nullptr) {
const WipeTower::ToolChangeResult &tcr = *print.wipe_tower_data().priming;
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
const WipeTower::Extrusion &e = tcr.extrusions[i];
if (e.width > 0) {

View file

@ -16,19 +16,19 @@
namespace Slic3r {
// For the use case when each object is printed separately
// (print.config.complete_objects is true).
// (print.config().complete_objects is true).
ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
{
if (object.layers.empty())
if (object.layers().empty())
return;
// Initialize the print layers for just a single object.
{
std::vector<coordf_t> zs;
zs.reserve(zs.size() + object.layers.size() + object.support_layers.size());
for (auto layer : object.layers)
zs.reserve(zs.size() + object.layers().size() + object.support_layers().size());
for (auto layer : object.layers())
zs.emplace_back(layer->print_z);
for (auto layer : object.support_layers)
for (auto layer : object.support_layers())
zs.emplace_back(layer->print_z);
this->initialize_layers(zs);
}
@ -39,39 +39,39 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
this->fill_wipe_tower_partitions(object.print()->config, object.layers.front()->print_z - object.layers.front()->height);
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height);
this->collect_extruder_statistics(prime_multi_material);
}
// For the use case when all objects are printed at once.
// (print.config.complete_objects is false).
// (print.config().complete_objects is false).
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
{
// Initialize the print layers for all objects and all layers.
coordf_t object_bottom_z = 0.;
{
std::vector<coordf_t> zs;
for (auto object : print.objects) {
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
for (auto layer : object->layers)
for (auto object : print.objects()) {
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
for (auto layer : object->layers())
zs.emplace_back(layer->print_z);
for (auto layer : object->support_layers)
for (auto layer : object->support_layers())
zs.emplace_back(layer->print_z);
if (! object->layers.empty())
object_bottom_z = object->layers.front()->print_z - object->layers.front()->height;
if (! object->layers().empty())
object_bottom_z = object->layers().front()->print_z - object->layers().front()->height;
}
this->initialize_layers(zs);
}
// Collect extruders reuqired to print the layers.
for (auto object : print.objects)
for (auto object : print.objects())
this->collect_extruders(*object);
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
this->fill_wipe_tower_partitions(print.config, object_bottom_z);
this->fill_wipe_tower_partitions(print.config(), object_bottom_z);
this->collect_extruder_statistics(prime_multi_material);
}
@ -111,13 +111,13 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
void ToolOrdering::collect_extruders(const PrintObject &object)
{
// Collect the support extruders.
for (auto support_layer : object.support_layers) {
for (auto support_layer : object.support_layers()) {
LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
ExtrusionRole role = support_layer->support_fills.role();
bool has_support = role == erMixed || role == erSupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
unsigned int extruder_support = object.config.support_material_extruder.value;
unsigned int extruder_interface = object.config.support_material_interface_extruder.value;
unsigned int extruder_support = object.config().support_material_extruder.value;
unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
if (has_support)
layer_tools.extruders.push_back(extruder_support);
if (has_interface)
@ -126,16 +126,16 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
layer_tools.has_support = true;
}
// Collect the object extruders.
for (auto layer : object.layers) {
for (auto layer : object.layers()) {
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
// What extruders are required to print this object layer?
for (size_t region_id = 0; region_id < object.print()->regions.size(); ++ region_id) {
const LayerRegion *layerm = (region_id < layer->regions.size()) ? layer->regions[region_id] : nullptr;
for (size_t region_id = 0; region_id < object.print()->regions().size(); ++ region_id) {
const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr;
if (layerm == nullptr)
continue;
const PrintRegion &region = *object.print()->regions[region_id];
const PrintRegion &region = *object.print()->regions()[region_id];
if (! layerm->perimeters.entities.empty()) {
layer_tools.extruders.push_back(region.config.perimeter_extruder.value);
layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
layer_tools.has_object = true;
}
bool has_infill = false;
@ -150,9 +150,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
has_infill = true;
}
if (has_solid_infill)
layer_tools.extruders.push_back(region.config.solid_infill_extruder);
layer_tools.extruders.push_back(region.config().solid_infill_extruder);
if (has_infill)
layer_tools.extruders.push_back(region.config.infill_extruder);
layer_tools.extruders.push_back(region.config().infill_extruder);
if (has_solid_infill || has_infill)
layer_tools.has_object = true;
}

View file

@ -396,8 +396,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
}
this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false);
this->m_num_layer_changes = 0;
this->m_current_tool = tools.front();
m_num_layer_changes = 0;
m_current_tool = tools.front();
// The Prusa i3 MK2 has a working space of [0, -2.2] to [250, 210].
// Due to the XYZ calibration, this working space may shrink slightly from all directions,
@ -439,9 +439,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
if (last_wipe_inside_wipe_tower) {
// Shrink the last wipe area to the area of the other purge areas,
// remember the last initial wipe width to be purged into the 1st layer of the wipe tower.
this->m_initial_extra_wipe = std::max(0.f, wipe_area - (y_end + 0.5f * 0.85f * m_perimeter_width - cleaning_box.ld.y));
cleaning_box.lu.y -= this->m_initial_extra_wipe;
cleaning_box.ru.y -= this->m_initial_extra_wipe;
m_initial_extra_wipe = std::max(0.f, wipe_area - (y_end + 0.5f * 0.85f * m_perimeter_width - cleaning_box.ld.y));
cleaning_box.lu.y -= m_initial_extra_wipe;
cleaning_box.ru.y -= m_initial_extra_wipe;
}
toolchange_Wipe(writer, cleaning_box, false);
} else {
@ -471,8 +471,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
m_idx_tool_change_in_layer = (unsigned int)(-1);
ToolChangeResult result;
result.print_z = this->m_z_pos;
result.layer_height = this->m_layer_height;
result.print_z = m_z_pos;
result.layer_height = m_layer_height;
result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions();
@ -612,8 +612,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
}
ToolChangeResult result;
result.print_z = this->m_z_pos;
result.layer_height = this->m_layer_height;
result.print_z = m_z_pos;
result.layer_height = m_layer_height;
result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions();
@ -718,8 +718,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b
}
ToolChangeResult result;
result.print_z = this->m_z_pos;
result.layer_height = this->m_layer_height;
result.print_z = m_z_pos;
result.layer_height = m_layer_height;
result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions();
@ -1040,8 +1040,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer(Purpose purpose)
}
ToolChangeResult result;
result.print_z = this->m_z_pos;
result.layer_height = this->m_layer_height;
result.print_z = m_z_pos;
result.layer_height = m_layer_height;
result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions();

View file

@ -12,24 +12,24 @@ namespace Slic3r {
Layer::~Layer()
{
this->lower_layer = this->upper_layer = nullptr;
for (LayerRegion *region : this->regions)
for (LayerRegion *region : m_regions)
delete region;
this->regions.clear();
m_regions.clear();
}
LayerRegion* Layer::add_region(PrintRegion* print_region)
{
this->regions.emplace_back(new LayerRegion(this, print_region));
return this->regions.back();
m_regions.emplace_back(new LayerRegion(this, print_region));
return m_regions.back();
}
// merge all regions' slices to get islands
void Layer::make_slices()
{
ExPolygons slices;
if (this->regions.size() == 1) {
if (m_regions.size() == 1) {
// optimization: if we only have one region, take its slices
slices = this->regions.front()->slices;
slices = m_regions.front()->slices;
} else {
Polygons slices_p;
FOREACH_LAYERREGION(this, layerm) {
@ -58,10 +58,10 @@ void Layer::make_slices()
void Layer::merge_slices()
{
if (this->regions.size() == 1) {
if (m_regions.size() == 1) {
// Optimization, also more robust. Don't merge classified pieces of layerm->slices,
// but use the non-split islands of a layer. For a single region print, these shall be equal.
this->regions.front()->slices.set(this->slices.expolygons, stInternal);
m_regions.front()->slices.set(this->slices.expolygons, stInternal);
} else {
FOREACH_LAYERREGION(this, layerm) {
// without safety offset, artifacts are generated (GH #2494)
@ -81,18 +81,18 @@ void Layer::make_perimeters()
std::set<size_t> done;
FOREACH_LAYERREGION(this, layerm) {
size_t region_id = layerm - this->regions.begin();
size_t region_id = layerm - m_regions.begin();
if (done.find(region_id) != done.end()) continue;
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
done.insert(region_id);
const PrintRegionConfig &config = (*layerm)->region()->config;
const PrintRegionConfig &config = (*layerm)->region()->config();
// find compatible regions
LayerRegionPtrs layerms;
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != this->regions.end(); ++it) {
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
LayerRegion* other_layerm = *it;
const PrintRegionConfig &other_config = other_layerm->region()->config;
const PrintRegionConfig &other_config = other_layerm->region()->config();
if (config.perimeter_extruder == other_config.perimeter_extruder
&& config.perimeters == other_config.perimeters
@ -104,7 +104,7 @@ void Layer::make_perimeters()
&& config.thin_walls == other_config.thin_walls
&& config.external_perimeters_first == other_config.external_perimeters_first) {
layerms.push_back(other_layerm);
done.insert(it - this->regions.begin());
done.insert(it - m_regions.begin());
}
}
@ -150,7 +150,7 @@ void Layer::make_fills()
#ifdef SLIC3R_DEBUG
printf("Making fills for layer " PRINTF_ZU "\n", this->id());
#endif
for (LayerRegion *layerm : regions) {
for (LayerRegion *layerm : m_regions) {
layerm->fills.clear();
make_fill(*layerm, layerm->fills);
#ifndef NDEBUG
@ -163,18 +163,18 @@ void Layer::make_fills()
void Layer::export_region_slices_to_svg(const char *path) const
{
BoundingBox bbox;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min.x, bbox.max.y);
bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface)
svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency);
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
@ -189,18 +189,18 @@ void Layer::export_region_slices_to_svg_debug(const char *name) const
void Layer::export_region_fill_surfaces_to_svg(const char *path) const
{
BoundingBox bbox;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min.x, bbox.max.y);
bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface)
svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency);
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}

View file

@ -15,16 +15,13 @@ class Layer;
class PrintRegion;
class PrintObject;
// TODO: make stuff private
class LayerRegion
{
friend class Layer;
public:
Layer* layer() { return this->_layer; }
const Layer* layer() const { return this->_layer; }
PrintRegion* region() { return this->_region; }
const PrintRegion* region() const { return this->_region; }
Layer* layer() { return m_layer; }
const Layer* layer() const { return m_layer; }
PrintRegion* region() { return m_region; }
const PrintRegion* region() const { return m_region; }
// collection of surfaces generated by slicing the original geometry
// divided by type top/bottom/internal
@ -77,29 +74,30 @@ public:
// Is there any valid extrusion assigned to this LayerRegion?
bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); }
private:
Layer *_layer;
PrintRegion *_region;
protected:
friend class Layer;
LayerRegion(Layer *layer, PrintRegion *region) : _layer(layer), _region(region) {}
LayerRegion(Layer *layer, PrintRegion *region) : m_layer(layer), m_region(region) {}
~LayerRegion() {}
private:
Layer *m_layer;
PrintRegion *m_region;
};
typedef std::vector<LayerRegion*> LayerRegionPtrs;
class Layer {
friend class PrintObject;
class Layer
{
public:
size_t id() const { return this->_id; }
void set_id(size_t id) { this->_id = id; }
PrintObject* object() { return this->_object; }
const PrintObject* object() const { return this->_object; }
size_t id() const { return m_id; }
void set_id(size_t id) { m_id = id; }
PrintObject* object() { return m_object; }
const PrintObject* object() const { return m_object; }
Layer *upper_layer;
Layer *lower_layer;
LayerRegionPtrs regions;
bool slicing_errors;
coordf_t slice_z; // Z used for slicing in unscaled coordinates
coordf_t print_z; // Z used for printing in unscaled coordinates
@ -111,19 +109,20 @@ public:
// order will be recovered by the G-code generator.
ExPolygonCollection slices;
size_t region_count() const { return this->regions.size(); }
const LayerRegion* get_region(int idx) const { return this->regions.at(idx); }
LayerRegion* get_region(int idx) { return this->regions.at(idx); }
size_t region_count() const { return m_regions.size(); }
const LayerRegion* get_region(int idx) const { return m_regions.at(idx); }
LayerRegion* get_region(int idx) { return m_regions[idx]; }
LayerRegion* add_region(PrintRegion* print_region);
const LayerRegionPtrs& regions() const { return m_regions; }
void make_slices();
void merge_slices();
template <class T> bool any_internal_region_slice_contains(const T &item) const {
for (const LayerRegion *layerm : this->regions) if (layerm->slices.any_internal_contains(item)) return true;
for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_internal_contains(item)) return true;
return false;
}
template <class T> bool any_bottom_region_slice_contains(const T &item) const {
for (const LayerRegion *layerm : this->regions) if (layerm->slices.any_bottom_contains(item)) return true;
for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_bottom_contains(item)) return true;
return false;
}
void make_perimeters();
@ -136,22 +135,26 @@ public:
void export_region_fill_surfaces_to_svg_debug(const char *name) const;
// Is there any valid extrusion assigned to this LayerRegion?
virtual bool has_extrusions() const { for (auto layerm : this->regions) if (layerm->has_extrusions()) return true; return false; }
virtual bool has_extrusions() const { for (auto layerm : m_regions) if (layerm->has_extrusions()) return true; return false; }
protected:
size_t _id; // sequential number of layer, 0-based
PrintObject *_object;
friend class PrintObject;
Layer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) :
upper_layer(nullptr), lower_layer(nullptr), slicing_errors(false),
slice_z(slice_z), print_z(print_z), height(height),
_id(id), _object(object) {}
m_id(id), m_object(object) {}
virtual ~Layer();
private:
// sequential number of layer, 0-based
size_t m_id;
PrintObject *m_object;
LayerRegionPtrs m_regions;
};
class SupportLayer : public Layer {
friend class PrintObject;
class SupportLayer : public Layer
{
public:
// Polygons covered by the supports: base, interface and contact areas.
ExPolygonCollection support_islands;
@ -161,7 +164,9 @@ public:
// Is there any valid extrusion assigned to this LayerRegion?
virtual bool has_extrusions() const { return ! support_fills.empty(); }
//protected:
protected:
friend class PrintObject;
// The constructor has been made public to be able to insert additional support layers for the skirt or a wipe tower
// between the raft and the object first layer.
SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) :

View file

@ -18,13 +18,13 @@ namespace Slic3r {
Flow
LayerRegion::flow(FlowRole role, bool bridge, double width) const
{
return this->_region->flow(
return m_region->flow(
role,
this->_layer->height,
m_layer->height,
bridge,
this->_layer->id() == 0,
m_layer->id() == 0,
width,
*this->_layer->object()
*m_layer->object()
);
}
@ -61,9 +61,9 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
&slices,
this->layer()->height,
this->flow(frPerimeter),
&this->region()->config,
&this->layer()->object()->config,
&this->layer()->object()->print()->config,
&this->region()->config(),
&this->layer()->object()->config(),
&this->layer()->object()->print()->config(),
// output:
&this->perimeters,
@ -116,7 +116,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
{
// bottom_polygons are used to trim inflated top surfaces.
fill_boundaries.reserve(number_polygons(surfaces));
bool has_infill = this->region()->config.fill_density.value > 0.;
bool has_infill = this->region()->config().fill_density.value > 0.;
for (const Surface &surface : this->fill_surfaces.surfaces) {
if (surface.surface_type == stTop) {
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
@ -259,9 +259,9 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
#ifdef SLIC3R_DEBUG
printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id());
#endif
if (bd.detect_angle(Geometry::deg2rad(this->region()->config.bridge_angle.value))) {
if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) {
bridges[idx_last].bridge_angle = bd.angle;
if (this->layer()->object()->config.support_material) {
if (this->layer()->object()->config().support_material) {
polygons_append(this->bridged, bd.coverage());
this->unsupported_bridge_edges.append(bd.unsupported_edges());
}
@ -351,13 +351,13 @@ void LayerRegion::prepare_fill_surfaces()
the only meaningful information returned by psPerimeters. */
// if no solid layers are requested, turn top/bottom surfaces to internal
if (this->region()->config.top_solid_layers == 0) {
if (this->region()->config().top_solid_layers == 0) {
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
if (surface->surface_type == stTop)
surface->surface_type = (this->layer()->object()->config.infill_only_where_needed) ?
surface->surface_type = (this->layer()->object()->config().infill_only_where_needed) ?
stInternalVoid : stInternal;
}
if (this->region()->config.bottom_solid_layers == 0) {
if (this->region()->config().bottom_solid_layers == 0) {
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
surface->surface_type = stInternal;
@ -365,9 +365,9 @@ void LayerRegion::prepare_fill_surfaces()
}
// turn too small internal regions into solid regions according to the user setting
if (this->region()->config.fill_density.value > 0) {
if (this->region()->config().fill_density.value > 0) {
// scaling an area requires two calls!
double min_area = scale_(scale_(this->region()->config.solid_infill_below_area.value));
double min_area = scale_(scale_(this->region()->config().solid_infill_below_area.value));
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type == stInternal && surface->area() <= min_area)
surface->surface_type = stInternalSolid;

View file

@ -6,8 +6,7 @@
namespace Slic3r {
void
PerimeterGenerator::process()
void PerimeterGenerator::process()
{
// other perimeters
this->_mm3_per_mm = this->perimeter_flow.mm3_per_mm();

View file

@ -38,30 +38,30 @@ typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops;
class PerimeterGenerator {
public:
// Inputs:
const SurfaceCollection* slices;
const ExPolygonCollection* lower_slices;
const SurfaceCollection *slices;
const ExPolygonCollection *lower_slices;
double layer_height;
int layer_id;
Flow perimeter_flow;
Flow ext_perimeter_flow;
Flow overhang_flow;
Flow solid_infill_flow;
PrintRegionConfig* config;
PrintObjectConfig* object_config;
PrintConfig* print_config;
const PrintRegionConfig *config;
const PrintObjectConfig *object_config;
const PrintConfig *print_config;
// Outputs:
ExtrusionEntityCollection* loops;
ExtrusionEntityCollection* gap_fill;
SurfaceCollection* fill_surfaces;
ExtrusionEntityCollection *loops;
ExtrusionEntityCollection *gap_fill;
SurfaceCollection *fill_surfaces;
PerimeterGenerator(
// Input:
const SurfaceCollection* slices,
double layer_height,
Flow flow,
PrintRegionConfig* config,
PrintObjectConfig* object_config,
PrintConfig* print_config,
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
const PrintConfig* print_config,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection* loops,
@ -84,10 +84,8 @@ private:
double _mm3_per_mm_overhang;
Polygons _lower_slices_p;
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops,
ThickPolylines &thin_walls) const;
ExtrusionEntityCollection _variable_width
(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const;
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;
ExtrusionEntityCollection _variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const;
};
}

View file

@ -69,7 +69,7 @@ PlaceholderParser::PlaceholderParser()
this->update_timestamp();
}
void PlaceholderParser::update_timestamp()
void PlaceholderParser::update_timestamp(DynamicConfig &config)
{
time_t rawtime;
time(&rawtime);
@ -84,14 +84,14 @@ void PlaceholderParser::update_timestamp()
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_hour;
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_min;
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_sec;
this->set("timestamp", ss.str());
config.set_key_value("timestamp", new ConfigOptionString(ss.str()));
}
this->set("year", 1900 + timeinfo->tm_year);
this->set("month", 1 + timeinfo->tm_mon);
this->set("day", timeinfo->tm_mday);
this->set("hour", timeinfo->tm_hour);
this->set("minute", timeinfo->tm_min);
this->set("second", timeinfo->tm_sec);
config.set_key_value("year", new ConfigOptionInt(1900 + timeinfo->tm_year));
config.set_key_value("month", new ConfigOptionInt(1 + timeinfo->tm_mon));
config.set_key_value("day", new ConfigOptionInt(timeinfo->tm_mday));
config.set_key_value("hour", new ConfigOptionInt(timeinfo->tm_hour));
config.set_key_value("minute", new ConfigOptionInt(timeinfo->tm_min));
config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec));
}
// Scalar configuration values are stored into m_single,

View file

@ -14,7 +14,6 @@ class PlaceholderParser
public:
PlaceholderParser();
void update_timestamp();
void apply_config(const DynamicPrintConfig &config);
void apply_env_variables();
@ -37,6 +36,11 @@ public:
// Throws std::runtime_error on syntax or runtime error.
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);
// Update timestamp, year, month, day, hour, minute, second variables at the provided config.
static void update_timestamp(DynamicConfig &config);
// Update timestamp, year, month, day, hour, minute, second variables at m_config.
void update_timestamp() { update_timestamp(m_config); }
private:
DynamicConfig m_config;
};

View file

@ -20,24 +20,27 @@ template class PrintState<PrintObjectStep, posCount>;
void Print::clear_objects()
{
for (int i = int(this->objects.size())-1; i >= 0; --i)
tbb::mutex::scoped_lock lock(m_mutex);
for (int i = int(m_objects.size())-1; i >= 0; --i)
this->delete_object(i);
for (PrintRegion *region : this->regions)
for (PrintRegion *region : m_regions)
delete region;
this->regions.clear();
m_regions.clear();
}
void Print::delete_object(size_t idx)
{
tbb::mutex::scoped_lock lock(m_mutex);
// destroy object and remove it from our container
delete this->objects[idx];
this->objects.erase(this->objects.begin() + idx);
delete m_objects[idx];
m_objects.erase(m_objects.begin() + idx);
this->invalidate_all_steps();
// TODO: purge unused regions
}
void Print::reload_object(size_t /* idx */)
{
tbb::mutex::scoped_lock lock(m_mutex);
/* TODO: this method should check whether the per-object config and per-material configs
have changed in such a way that regions need to be rearranged or we can just apply
the diff and invalidate something. Same logic as apply_config()
@ -46,8 +49,8 @@ void Print::reload_object(size_t /* idx */)
// collect all current model objects
ModelObjectPtrs model_objects;
model_objects.reserve(this->objects.size());
for (PrintObject *object : this->objects)
model_objects.reserve(m_objects.size());
for (PrintObject *object : m_objects)
model_objects.push_back(object->model_object());
// remove our print objects
this->clear_objects();
@ -63,15 +66,21 @@ void Print::reload_object(size_t /* idx */)
bool Print::reload_model_instances()
{
bool invalidated = false;
for (PrintObject *object : this->objects)
for (PrintObject *object : m_objects)
invalidated |= object->reload_model_instances();
return invalidated;
}
PrintRegion* Print::add_region()
{
regions.push_back(new PrintRegion(this));
return regions.back();
m_regions.emplace_back(new PrintRegion(this));
return m_regions.back();
}
PrintRegion* Print::add_region(const PrintRegionConfig &config)
{
m_regions.emplace_back(new PrintRegion(this, config));
return m_regions.back();
}
// Called by Print::apply_config().
@ -224,18 +233,18 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
invalidated |= this->invalidate_step(step);
sort_remove_duplicates(osteps);
for (PrintObjectStep ostep : osteps)
for (PrintObject *object : this->objects)
for (PrintObject *object : m_objects)
invalidated |= object->invalidate_step(ostep);
return invalidated;
}
bool Print::invalidate_step(PrintStep step)
{
bool invalidated = m_state.invalidate(step);
bool invalidated = m_state.invalidate(step, m_mutex, m_cancel_callback);
// Propagate to dependent steps.
//FIXME Why should skirt invalidate brim? Shouldn't it be vice versa?
if (step == psSkirt)
invalidated |= m_state.invalidate(psBrim);
invalidated |= m_state.invalidate(psBrim, m_mutex, m_cancel_callback);
return invalidated;
}
@ -243,9 +252,9 @@ bool Print::invalidate_step(PrintStep step)
// and there's at least one object
bool Print::is_step_done(PrintObjectStep step) const
{
if (this->objects.empty())
if (m_objects.empty())
return false;
for (const PrintObject *object : this->objects)
for (const PrintObject *object : m_objects)
if (!object->m_state.is_done(step))
return false;
return true;
@ -256,15 +265,15 @@ std::vector<unsigned int> Print::object_extruders() const
{
std::vector<unsigned int> extruders;
for (PrintRegion* region : this->regions) {
for (PrintRegion* region : m_regions) {
// these checks reflect the same logic used in the GUI for enabling/disabling
// extruder selection fields
if (region->config.perimeters.value > 0 || this->config.brim_width.value > 0)
extruders.push_back(region->config.perimeter_extruder - 1);
if (region->config.fill_density.value > 0)
extruders.push_back(region->config.infill_extruder - 1);
if (region->config.top_solid_layers.value > 0 || region->config.bottom_solid_layers.value > 0)
extruders.push_back(region->config.solid_infill_extruder - 1);
if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0)
extruders.push_back(region->config().perimeter_extruder - 1);
if (region->config().fill_density.value > 0)
extruders.push_back(region->config().infill_extruder - 1);
if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0)
extruders.push_back(region->config().solid_infill_extruder - 1);
}
sort_remove_duplicates(extruders);
@ -277,16 +286,16 @@ std::vector<unsigned int> Print::support_material_extruders() const
std::vector<unsigned int> extruders;
bool support_uses_current_extruder = false;
for (PrintObject *object : this->objects) {
for (PrintObject *object : m_objects) {
if (object->has_support_material()) {
if (object->config.support_material_extruder == 0)
if (object->config().support_material_extruder == 0)
support_uses_current_extruder = true;
else
extruders.push_back(object->config.support_material_extruder - 1);
if (object->config.support_material_interface_extruder == 0)
extruders.push_back(object->config().support_material_extruder - 1);
if (object->config().support_material_interface_extruder == 0)
support_uses_current_extruder = true;
else
extruders.push_back(object->config.support_material_interface_extruder - 1);
extruders.push_back(object->config().support_material_interface_extruder - 1);
}
}
@ -309,10 +318,10 @@ std::vector<unsigned int> Print::extruders() const
void Print::_simplify_slices(double distance)
{
for (PrintObject *object : this->objects) {
for (Layer *layer : object->layers) {
for (PrintObject *object : m_objects) {
for (Layer *layer : object->m_layers) {
layer->slices.simplify(distance);
for (LayerRegion *layerm : layer->regions)
for (LayerRegion *layerm : layer->regions())
layerm->slices.simplify(distance);
}
}
@ -322,7 +331,7 @@ double Print::max_allowed_layer_height() const
{
double nozzle_diameter_max = 0.;
for (unsigned int extruder_id : this->extruders())
nozzle_diameter_max = std::max(nozzle_diameter_max, this->config.nozzle_diameter.get_at(extruder_id));
nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(extruder_id));
return nozzle_diameter_max;
}
@ -333,10 +342,10 @@ void Print::add_model_object(ModelObject* model_object, int idx)
// Initialize a new print object and store it at the given position.
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
if (idx != -1) {
delete this->objects[idx];
this->objects[idx] = object;
delete m_objects[idx];
m_objects[idx] = object;
} else
this->objects.emplace_back(object);
m_objects.emplace_back(object);
// Invalidate all print steps.
this->invalidate_all_steps();
@ -345,37 +354,42 @@ void Print::add_model_object(ModelObject* model_object, int idx)
PrintRegionConfig config = this->_region_config_from_model_volume(*model_object->volumes[volume_id]);
// Find an existing print region with the same config.
size_t region_id = size_t(-1);
for (size_t i = 0; i < this->regions.size(); ++ i)
if (config.equals(this->regions[i]->config)) {
for (size_t i = 0; i < m_regions.size(); ++ i)
if (config.equals(m_regions[i]->config())) {
region_id = i;
break;
}
// If no region exists with the same config, create a new one.
if (region_id == size_t(-1)) {
region_id = this->regions.size();
this->add_region()->config.apply(config);
region_id = this->regions().size();
this->add_region(config);
}
// Assign volume to a region.
object->add_region_volume(region_id, volume_id);
}
// Apply config to print object.
object->config.apply(this->default_object_config);
normalize_and_apply_config(object->config, model_object->config);
object->config_apply(this->default_object_config());
{
//normalize_and_apply_config(object->config(), model_object->config);
DynamicPrintConfig src_normalized(model_object->config);
src_normalized.normalize();
object->config_apply(src_normalized, true);
}
// update placeholders
{
// get the first input file name
std::string input_file;
std::vector<std::string> v_scale;
for (const PrintObject *object : this->objects) {
for (const PrintObject *object : m_objects) {
const ModelObject &mobj = *object->model_object();
v_scale.push_back(boost::lexical_cast<std::string>(mobj.instances[0]->scaling_factor*100) + "%");
if (input_file.empty())
input_file = mobj.input_file;
}
PlaceholderParser &pp = this->placeholder_parser;
PlaceholderParser &pp = m_placeholder_parser;
pp.set("scale", v_scale);
if (! input_file.empty()) {
// get basename with and without suffix
@ -393,19 +407,19 @@ bool Print::apply_config(DynamicPrintConfig config)
config.normalize();
// apply variables to placeholder parser
this->placeholder_parser.apply_config(config);
m_placeholder_parser.apply_config(config);
// handle changes to print config
t_config_option_keys print_diff = this->config.diff(config);
this->config.apply_only(config, print_diff, true);
t_config_option_keys print_diff = m_config.diff(config);
m_config.apply_only(config, print_diff, true);
bool invalidated = this->invalidate_state_by_config_options(print_diff);
// handle changes to object config defaults
this->default_object_config.apply(config, true);
for (PrintObject *object : this->objects) {
m_default_object_config.apply(config, true);
for (PrintObject *object : m_objects) {
// we don't assume that config contains a full ObjectConfig,
// so we base it on the current print-wise default
PrintObjectConfig new_config = this->default_object_config;
PrintObjectConfig new_config = this->default_object_config();
// we override the new config with object-specific options
normalize_and_apply_config(new_config, object->model_object()->config);
// Force a refresh of a variable layer height profile at the PrintObject if it is not valid.
@ -417,13 +431,13 @@ bool Print::apply_config(DynamicPrintConfig config)
invalidated = true;
}
// check whether the new config is different from the current one
t_config_option_keys diff = object->config.diff(new_config);
object->config.apply_only(new_config, diff, true);
t_config_option_keys diff = object->config().diff(new_config);
object->config_apply_only(new_config, diff, true);
invalidated |= object->invalidate_state_by_config_options(diff);
}
// handle changes to regions config defaults
this->default_region_config.apply(config, true);
m_default_region_config.apply(config, true);
// All regions now have distinct settings.
// Check whether applying the new region config defaults we'd get different regions.
@ -432,11 +446,11 @@ bool Print::apply_config(DynamicPrintConfig config)
// Collect the already visited region configs into other_region_configs,
// so one may check for duplicates.
std::vector<PrintRegionConfig> other_region_configs;
for (size_t region_id = 0; region_id < this->regions.size(); ++ region_id) {
PrintRegion &region = *this->regions[region_id];
for (size_t region_id = 0; region_id < m_regions.size(); ++ region_id) {
PrintRegion &region = *m_regions[region_id];
PrintRegionConfig this_region_config;
bool this_region_config_set = false;
for (PrintObject *object : this->objects) {
for (PrintObject *object : m_objects) {
if (region_id < object->region_volumes.size()) {
for (int volume_id : object->region_volumes[region_id]) {
const ModelVolume &volume = *object->model_object()->volumes[volume_id];
@ -466,10 +480,10 @@ bool Print::apply_config(DynamicPrintConfig config)
}
}
if (this_region_config_set) {
t_config_option_keys diff = region.config.diff(this_region_config);
t_config_option_keys diff = region.config().diff(this_region_config);
if (! diff.empty()) {
region.config.apply_only(this_region_config, diff);
for (PrintObject *object : this->objects)
region.config_apply_only(this_region_config, diff, false);
for (PrintObject *object : m_objects)
if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty())
invalidated |= object->invalidate_state_by_config_options(diff);
}
@ -484,8 +498,8 @@ exit_for_rearrange_regions:
// The current subdivision of regions does not make sense anymore.
// We need to remove all objects and re-add them.
ModelObjectPtrs model_objects;
model_objects.reserve(this->objects.size());
for (PrintObject *object : this->objects)
model_objects.reserve(m_objects.size());
for (PrintObject *object : m_objects)
model_objects.push_back(object->model_object());
this->clear_objects();
for (ModelObject *mo : model_objects)
@ -494,7 +508,7 @@ exit_for_rearrange_regions:
}
// Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
for (PrintObject *object : this->objects)
for (PrintObject *object : m_objects)
if (! object->layer_height_profile_valid)
object->update_layer_height_profile();
@ -503,32 +517,32 @@ exit_for_rearrange_regions:
bool Print::has_infinite_skirt() const
{
return (this->config.skirt_height == -1 && this->config.skirts > 0)
|| (this->config.ooze_prevention && this->extruders().size() > 1);
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|| (m_config.ooze_prevention && this->extruders().size() > 1);
}
bool Print::has_skirt() const
{
return (this->config.skirt_height > 0 && this->config.skirts > 0)
return (m_config.skirt_height > 0 && m_config.skirts > 0)
|| this->has_infinite_skirt();
}
std::string Print::validate() const
{
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values));
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height));
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(m_config.bed_shape.values));
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), m_config.max_print_height));
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
print_volume.min.z = -1e10;
for (PrintObject *po : this->objects) {
for (PrintObject *po : m_objects) {
if (! print_volume.contains(po->model_object()->tight_bounding_box(false)))
return "Some objects are outside of the print volume.";
}
if (this->config.complete_objects) {
if (m_config.complete_objects) {
// Check horizontal clearance.
{
Polygons convex_hulls_other;
for (PrintObject *object : this->objects) {
for (PrintObject *object : m_objects) {
// Get convex hull of all meshes assigned to this print object.
Polygon convex_hull;
{
@ -542,7 +556,7 @@ std::string Print::validate() const
// Apply the same transformations we apply to the actual meshes when slicing them.
object->model_object()->instances.front()->transform_polygon(&convex_hull);
// Grow convex hull with the clearance margin.
convex_hull = offset(convex_hull, scale_(this->config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1)).front();
convex_hull = offset(convex_hull, scale_(m_config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1)).front();
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const Point &copy : object->_shifted_copies) {
Polygon p = convex_hull;
@ -556,47 +570,47 @@ std::string Print::validate() const
// Check vertical clearance.
{
std::vector<coord_t> object_height;
for (const PrintObject *object : this->objects)
for (const PrintObject *object : m_objects)
object_height.insert(object_height.end(), object->copies().size(), object->size.z);
std::sort(object_height.begin(), object_height.end());
// Ignore the tallest *copy* (this is why we repeat height for all of them):
// it will be printed as last one so its height doesn't matter.
object_height.pop_back();
if (! object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
if (! object_height.empty() && object_height.back() > scale_(m_config.extruder_clearance_height.value))
return "Some objects are too tall and cannot be printed without extruder collisions.";
}
} // end if (this->config.complete_objects)
} // end if (m_config.complete_objects)
if (this->config.spiral_vase) {
if (m_config.spiral_vase) {
size_t total_copies_count = 0;
for (const PrintObject *object : this->objects)
for (const PrintObject *object : m_objects)
total_copies_count += object->copies().size();
// #4043
if (total_copies_count > 1 && ! this->config.complete_objects.value)
if (total_copies_count > 1 && ! m_config.complete_objects.value)
return "The Spiral Vase option can only be used when printing a single object.";
if (this->regions.size() > 1)
if (m_regions.size() > 1)
return "The Spiral Vase option can only be used when printing single material objects.";
}
if (this->has_wipe_tower() && ! this->objects.empty()) {
if (this->has_wipe_tower() && ! m_objects.empty()) {
#if 0
for (auto dmr : this->config.nozzle_diameter.values)
for (auto dmr : m_config.nozzle_diameter.values)
if (std::abs(dmr - 0.4) > EPSILON)
return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter.";
#endif
if (this->config.gcode_flavor != gcfRepRap && this->config.gcode_flavor != gcfMarlin)
if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfMarlin)
return "The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors.";
if (! this->config.use_relative_e_distances)
if (! m_config.use_relative_e_distances)
return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).";
SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters();
for (PrintObject *object : this->objects) {
SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters();
for (PrintObject *object : m_objects) {
SlicingParameters slicing_params = object->slicing_parameters();
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
return "The Wipe Tower is only supported for multiple objects if they have equal layer heigths";
if (slicing_params.raft_layers() != slicing_params0.raft_layers())
return "The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers";
if (object->config.support_material_contact_distance != this->objects.front()->config.support_material_contact_distance)
if (object->config().support_material_contact_distance != m_objects.front()->config().support_material_contact_distance)
return "The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance";
if (! equal_layering(slicing_params, slicing_params0))
return "The Wipe Tower is only supported for multiple objects if they are sliced equally.";
@ -605,7 +619,7 @@ std::string Print::validate() const
object->layer_height_profile_valid = was_layer_height_profile_valid;
for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON &&
std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON)
std::abs(object->layer_height_profile[i] - object->config().layer_height) > EPSILON)
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";
}
}
@ -618,12 +632,12 @@ std::string Print::validate() const
std::vector<double> nozzle_diameters;
for (unsigned int extruder_id : extruders)
nozzle_diameters.push_back(this->config.nozzle_diameter.get_at(extruder_id));
nozzle_diameters.push_back(m_config.nozzle_diameter.get_at(extruder_id));
double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
for (PrintObject *object : this->objects) {
if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) &&
(object->config.raft_layers > 0 || object->config.support_material.value)) {
for (PrintObject *object : m_objects) {
if ((object->config().support_material_extruder == -1 || object->config().support_material_interface_extruder == -1) &&
(object->config().raft_layers > 0 || object->config().support_material.value)) {
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
// are of the same diameter.
@ -634,16 +648,16 @@ std::string Print::validate() const
}
// validate first_layer_height
double first_layer_height = object->config.get_abs_value("first_layer_height");
double first_layer_height = object->config().get_abs_value("first_layer_height");
double first_layer_min_nozzle_diameter;
if (object->config.raft_layers > 0) {
if (object->config().raft_layers > 0) {
// if we have raft layers, only support material extruder is used on first layer
size_t first_layer_extruder = object->config.raft_layers == 1
? object->config.support_material_interface_extruder-1
: object->config.support_material_extruder-1;
size_t first_layer_extruder = object->config().raft_layers == 1
? object->config().support_material_interface_extruder-1
: object->config().support_material_extruder-1;
first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ?
min_nozzle_diameter :
this->config.nozzle_diameter.get_at(first_layer_extruder);
m_config.nozzle_diameter.get_at(first_layer_extruder);
} else {
// if we don't have raft layers, any nozzle diameter is potentially used in first layer
first_layer_min_nozzle_diameter = min_nozzle_diameter;
@ -652,7 +666,7 @@ std::string Print::validate() const
return "First layer height can't be greater than nozzle diameter";
// validate layer_height
if (object->config.layer_height.value > min_nozzle_diameter)
if (object->config().layer_height.value > min_nozzle_diameter)
return "Layer height can't be greater than nozzle diameter";
}
}
@ -665,7 +679,7 @@ std::string Print::validate() const
BoundingBox Print::bounding_box() const
{
BoundingBox bb;
for (const PrintObject *object : this->objects)
for (const PrintObject *object : m_objects)
for (Point copy : object->_shifted_copies) {
bb.merge(copy);
copy.translate(object->size);
@ -683,7 +697,7 @@ BoundingBox Print::total_bounding_box() const
BoundingBox bb = this->bounding_box();
// we need to offset the objects bounding box by at least half the perimeters extrusion width
Flow perimeter_flow = this->objects.front()->get_layer(0)->get_region(0)->flow(frPerimeter);
Flow perimeter_flow = m_objects.front()->get_layer(0)->get_region(0)->flow(frPerimeter);
double extra = perimeter_flow.width/2;
// consider support material
@ -692,18 +706,18 @@ BoundingBox Print::total_bounding_box() const
}
// consider brim and skirt
if (this->config.brim_width.value > 0) {
if (m_config.brim_width.value > 0) {
Flow brim_flow = this->brim_flow();
extra = std::max(extra, this->config.brim_width.value + brim_flow.width/2);
extra = std::max(extra, m_config.brim_width.value + brim_flow.width/2);
}
if (this->has_skirt()) {
int skirts = this->config.skirts.value;
int skirts = m_config.skirts.value;
if (skirts == 0 && this->has_infinite_skirt()) skirts = 1;
Flow skirt_flow = this->skirt_flow();
extra = std::max(
extra,
this->config.brim_width.value
+ this->config.skirt_distance.value
m_config.brim_width.value
+ m_config.skirt_distance.value
+ skirts * skirt_flow.spacing()
+ skirt_flow.width/2
);
@ -717,17 +731,17 @@ BoundingBox Print::total_bounding_box() const
double Print::skirt_first_layer_height() const
{
if (this->objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects");
return this->objects.front()->config.get_abs_value("first_layer_height");
if (m_objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects");
return m_objects.front()->config().get_abs_value("first_layer_height");
}
Flow Print::brim_flow() const
{
ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width;
ConfigOptionFloatOrPercent width = m_config.first_layer_extrusion_width;
if (width.value == 0)
width = this->regions.front()->config.perimeter_extrusion_width;
width = m_regions.front()->config().perimeter_extrusion_width;
if (width.value == 0)
width = this->objects.front()->config.extrusion_width;
width = m_objects.front()->config().extrusion_width;
/* We currently use a random region's perimeter extruder.
While this works for most cases, we should probably consider all of the perimeter
@ -737,7 +751,7 @@ Flow Print::brim_flow() const
return Flow::new_from_config_width(
frPerimeter,
width,
this->config.nozzle_diameter.get_at(this->regions.front()->config.perimeter_extruder-1),
m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
this->skirt_first_layer_height(),
0
);
@ -745,11 +759,11 @@ Flow Print::brim_flow() const
Flow Print::skirt_flow() const
{
ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width;
ConfigOptionFloatOrPercent width = m_config.first_layer_extrusion_width;
if (width.value == 0)
width = this->regions.front()->config.perimeter_extrusion_width;
width = m_regions.front()->config().perimeter_extrusion_width;
if (width.value == 0)
width = this->objects.front()->config.extrusion_width;
width = m_objects.front()->config().extrusion_width;
/* We currently use a random object's support material extruder.
While this works for most cases, we should probably consider all of the support material
@ -759,7 +773,7 @@ Flow Print::skirt_flow() const
return Flow::new_from_config_width(
frPerimeter,
width,
this->config.nozzle_diameter.get_at(this->objects.front()->config.support_material_extruder-1),
m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
this->skirt_first_layer_height(),
0
);
@ -767,7 +781,7 @@ Flow Print::skirt_flow() const
PrintRegionConfig Print::_region_config_from_model_volume(const ModelVolume &volume)
{
PrintRegionConfig config = this->default_region_config;
PrintRegionConfig config = this->default_region_config();
normalize_and_apply_config(config, volume.get_object()->config);
normalize_and_apply_config(config, volume.config);
if (! volume.material_id().empty())
@ -777,7 +791,7 @@ PrintRegionConfig Print::_region_config_from_model_volume(const ModelVolume &vol
bool Print::has_support_material() const
{
for (const PrintObject *object : this->objects)
for (const PrintObject *object : m_objects)
if (object->has_support_material())
return true;
return false;
@ -791,7 +805,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
if (model_object->volumes.size() < 2)
return;
// size_t extruders = this->config.nozzle_diameter.values.size();
// size_t extruders = m_config.nozzle_diameter.values.size();
for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) {
ModelVolume *volume = model_object->volumes[volume_id];
//FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned.
@ -804,44 +818,44 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
void Print::process()
{
BOOST_LOG_TRIVIAL(info) << "Staring the slicing process.";
for (PrintObject *obj : this->objects)
for (PrintObject *obj : m_objects)
obj->make_perimeters();
this->throw_if_canceled();
this->set_status(70, "Infilling layers");
for (PrintObject *obj : this->objects)
for (PrintObject *obj : m_objects)
obj->infill();
this->throw_if_canceled();
for (PrintObject *obj : this->objects)
for (PrintObject *obj : m_objects)
obj->generate_support_material();
this->throw_if_canceled();
if (! m_state.is_done(psSkirt)) {
this->set_started(psSkirt);
this->skirt.clear();
m_skirt.clear();
if (this->has_skirt()) {
this->set_status(88, "Generating skirt");
this->_make_skirt();
}
m_state.set_done(psSkirt);
this->set_done(psSkirt);
}
this->throw_if_canceled();
if (! m_state.is_done(psBrim)) {
this->set_started(psBrim);
this->brim.clear();
if (this->config.brim_width > 0) {
m_brim.clear();
if (m_config.brim_width > 0) {
this->set_status(88, "Generating brim");
this->_make_brim();
}
m_state.set_done(psBrim);
this->set_done(psBrim);
}
this->throw_if_canceled();
if (! m_state.is_done(psWipeTower)) {
this->set_started(psWipeTower);
this->_clear_wipe_tower();
m_wipe_tower_data.clear();
if (this->has_wipe_tower()) {
//this->set_status(95, "Generating wipe tower");
this->_make_wipe_tower();
}
m_state.set_done(psWipeTower);
this->set_done(psWipeTower);
}
BOOST_LOG_TRIVIAL(info) << "Slicing process finished.";
}
@ -883,20 +897,20 @@ void Print::_make_skirt()
// prepended to the first 'n' layers (with 'n' = skirt_height).
// $skirt_height_z in this case is the highest possible skirt height for safety.
coordf_t skirt_height_z = 0.;
for (const PrintObject *object : this->objects) {
for (const PrintObject *object : m_objects) {
size_t skirt_layers = this->has_infinite_skirt() ?
object->layer_count() :
std::min(size_t(this->config.skirt_height.value), object->layer_count());
skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z);
std::min(size_t(m_config.skirt_height.value), object->layer_count());
skirt_height_z = std::max(skirt_height_z, object->m_layers[skirt_layers-1]->print_z);
}
// Collect points from all layers contained in skirt height.
Points points;
for (const PrintObject *object : this->objects) {
for (const PrintObject *object : m_objects) {
this->throw_if_canceled();
Points object_points;
// Get object layers up to skirt_height_z.
for (const Layer *layer : object->layers) {
for (const Layer *layer : object->m_layers) {
if (layer->print_z > skirt_height_z)
break;
for (const ExPolygon &expoly : layer->slices.expolygons)
@ -904,7 +918,7 @@ void Print::_make_skirt()
append(object_points, expoly.contour.points);
}
// Get support layers up to skirt_height_z.
for (const SupportLayer *layer : object->support_layers) {
for (const SupportLayer *layer : object->support_layers()) {
if (layer->print_z > skirt_height_z)
break;
for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities)
@ -942,18 +956,18 @@ void Print::_make_skirt()
extruders_e_per_mm.reserve(set_extruders.size());
for (auto &extruder_id : set_extruders) {
extruders.push_back(extruder_id);
extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, &this->config).e_per_mm(mm3_per_mm));
extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, &m_config).e_per_mm(mm3_per_mm));
}
}
// Number of skirt loops per skirt layer.
int n_skirts = this->config.skirts.value;
int n_skirts = m_config.skirts.value;
if (this->has_infinite_skirt() && n_skirts == 0)
n_skirts = 1;
// Initial offset of the brim inner edge from the object (possible with a support & raft).
// The skirt will touch the brim if the brim is extruded.
coord_t distance = scale_(std::max(this->config.skirt_distance.value, this->config.brim_width.value));
coord_t distance = scale_(std::max(m_config.skirt_distance.value, m_config.brim_width.value));
// Draw outlines from outside to inside.
// 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.);
@ -978,16 +992,16 @@ void Print::_make_skirt()
first_layer_height // this will be overridden at G-code export time
)));
eloop.paths.back().polyline = loop.split_at_first_point();
this->skirt.append(eloop);
if (this->config.min_skirt_length.value > 0) {
m_skirt.append(eloop);
if (m_config.min_skirt_length.value > 0) {
// The skirt length is limited. Sum the total amount of filament length extruded, in mm.
extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx];
if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) {
if (extruded_length[extruder_idx] < m_config.min_skirt_length.value) {
// Not extruded enough yet with the current extruder. Add another loop.
if (i == 1)
++ i;
} else {
assert(extruded_length[extruder_idx] >= this->config.min_skirt_length.value);
assert(extruded_length[extruder_idx] >= m_config.min_skirt_length.value);
// Enough extruded with the current extruder. Extrude with the next one,
// until the prescribed number of skirt loops is extruded.
if (extruder_idx + 1 < extruders.size())
@ -998,7 +1012,7 @@ void Print::_make_skirt()
}
}
// Brims were generated inside out, reverse to print the outmost contour first.
this->skirt.reverse();
m_skirt.reverse();
}
void Print::_make_brim()
@ -1006,13 +1020,13 @@ void Print::_make_brim()
// Brim is only printed on first layer and uses perimeter extruder.
Flow flow = this->brim_flow();
Polygons islands;
for (PrintObject *object : this->objects) {
for (PrintObject *object : m_objects) {
this->throw_if_canceled();
Polygons object_islands;
for (ExPolygon &expoly : object->layers.front()->slices.expolygons)
for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons)
object_islands.push_back(expoly.contour);
if (! object->support_layers.empty())
object->support_layers.front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON));
if (! object->support_layers().empty())
object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON));
islands.reserve(islands.size() + object_islands.size() * object->_shifted_copies.size());
for (const Point &pt : object->_shifted_copies)
for (Polygon &poly : object_islands) {
@ -1021,7 +1035,7 @@ void Print::_make_brim()
}
}
Polygons loops;
size_t num_loops = size_t(floor(this->config.brim_width.value / flow.width));
size_t num_loops = size_t(floor(m_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);
@ -1037,32 +1051,24 @@ void Print::_make_brim()
loops = union_pt_chained(loops, false);
std::reverse(loops.begin(), loops.end());
extrusion_entities_append_loops(this->brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
extrusion_entities_append_loops(m_brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
}
// Wipe tower support.
bool Print::has_wipe_tower() const
{
return
this->config.single_extruder_multi_material.value &&
! this->config.spiral_vase.value &&
this->config.wipe_tower.value &&
this->config.nozzle_diameter.values.size() > 1;
}
void Print::_clear_wipe_tower()
{
m_tool_ordering.clear();
m_wipe_tower_priming.reset(nullptr);
m_wipe_tower_tool_changes.clear();
m_wipe_tower_final_purge.reset(nullptr);
m_config.single_extruder_multi_material.value &&
! m_config.spiral_vase.value &&
m_config.wipe_tower.value &&
m_config.nozzle_diameter.values.size() > 1;
}
void Print::_make_wipe_tower()
{
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
if (! m_tool_ordering.has_wipe_tower())
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
if (! m_wipe_tower_data.tool_ordering.has_wipe_tower())
// Don't generate any wipe tower.
return;
@ -1072,33 +1078,31 @@ void Print::_make_wipe_tower()
// see https://github.com/prusa3d/Slic3r/issues/607
{
size_t idx_begin = size_t(-1);
size_t idx_end = m_tool_ordering.layer_tools().size();
size_t idx_end = m_wipe_tower_data.tool_ordering.layer_tools().size();
// Find the first wipe tower layer, which does not have a counterpart in an object or a support layer.
for (size_t i = 0; i < idx_end; ++ i) {
const ToolOrdering::LayerTools &lt = m_tool_ordering.layer_tools()[i];
const ToolOrdering::LayerTools &lt = m_wipe_tower_data.tool_ordering.layer_tools()[i];
if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) {
idx_begin = i;
break;
}
}
if (idx_begin != size_t(-1)) {
// Find the position in this->objects.first()->support_layers to insert these new support layers.
double wipe_tower_new_layer_print_z_first = m_tool_ordering.layer_tools()[idx_begin].print_z;
SupportLayerPtrs::iterator it_layer = this->objects.front()->support_layers.begin();
SupportLayerPtrs::iterator it_end = this->objects.front()->support_layers.end();
// Find the position in m_objects.first()->support_layers to insert these new support layers.
double wipe_tower_new_layer_print_z_first = m_wipe_tower_data.tool_ordering.layer_tools()[idx_begin].print_z;
SupportLayerPtrs::const_iterator it_layer = m_objects.front()->support_layers().begin();
SupportLayerPtrs::const_iterator it_end = m_objects.front()->support_layers().end();
for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer);
// Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer.
for (size_t i = idx_begin; i < idx_end; ++ i) {
ToolOrdering::LayerTools &lt = const_cast<ToolOrdering::LayerTools&>(m_tool_ordering.layer_tools()[i]);
ToolOrdering::LayerTools &lt = const_cast<ToolOrdering::LayerTools&>(m_wipe_tower_data.tool_ordering.layer_tools()[i]);
if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support))
break;
lt.has_support = true;
// Insert the new support layer.
double height = lt.print_z - m_tool_ordering.layer_tools()[i-1].print_z;
double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z;
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
auto *new_layer = new SupportLayer(size_t(-1), this->objects.front(),
height, lt.print_z, lt.print_z - 0.5 * height);
it_layer = this->objects.front()->support_layers.insert(it_layer, new_layer);
it_layer = m_objects.front()->insert_support_layer(it_layer, size_t(-1), height, lt.print_z, lt.print_z - 0.5 * height);
++ it_layer;
}
}
@ -1107,9 +1111,9 @@ void Print::_make_wipe_tower()
// Initialize the wipe tower.
WipeTowerPrusaMM wipe_tower(
float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value),
float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value),
m_tool_ordering.first_extruder());
float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value),
float(m_config.wipe_tower_width.value), float(m_config.wipe_tower_per_color_wipe.value),
m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract();
//wipe_tower.set_zhop();
@ -1118,29 +1122,29 @@ void Print::_make_wipe_tower()
for (size_t i = 0; i < 4; ++ i)
wipe_tower.set_extruder(
i,
WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()),
this->config.temperature.get_at(i),
this->config.first_layer_temperature.get_at(i));
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
m_config.temperature.get_at(i),
m_config.first_layer_temperature.get_at(i));
// When printing the first layer's wipe tower, the first extruder is expected to be active and primed.
// Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer.
// Therefore the number of wipe sections at the wipe tower will be (m_wipe_tower_data.tool_ordering.front().extruders-1) at the 1st layer.
// The following variable is true if the last priming section cannot be squeezed inside the wipe tower.
bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions;
bool last_priming_wipe_full = m_wipe_tower_data.tool_ordering.front().extruders.size() > m_wipe_tower_data.tool_ordering.front().wipe_tower_partitions;
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE));
m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
wipe_tower.prime(this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE));
// Generate the wipe tower layers.
m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size());
m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size());
// 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()) {
unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back();
for (const ToolOrdering::LayerTools &layer_tools : m_wipe_tower_data.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;
bool first_layer = &layer_tools == &m_tool_ordering.front();
bool last_layer = &layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0;
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
bool last_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0;
wipe_tower.set_layer(
float(layer_tools.print_z),
float(layer_tools.wipe_tower_layer_height),
@ -1151,7 +1155,7 @@ void Print::_make_wipe_tower()
for (unsigned int extruder_id : layer_tools.extruders)
// Call the wipe_tower.tool_change() at the first layer for the initial extruder
// to extrude the wipe tower brim,
if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) ||
if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) ||
// or when an extruder shall be switched.
extruder_id != current_extruder_id) {
tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE));
@ -1175,48 +1179,49 @@ void Print::_make_wipe_tower()
tool_changes.pop_back();
}
}
m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes));
m_wipe_tower_data.tool_changes.emplace_back(std::move(tool_changes));
if (last_layer)
break;
}
// Unload the current filament over the purge tower.
coordf_t layer_height = this->objects.front()->config.layer_height.value;
if (m_tool_ordering.back().wipe_tower_partitions > 0) {
coordf_t layer_height = m_objects.front()->config().layer_height.value;
if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) {
// The wipe tower goes up to the last layer of the print.
if (wipe_tower.layer_finished()) {
// The wipe tower is printed to the top of the print and it has no space left for the final extruder purge.
// Lift Z to the next layer.
wipe_tower.set_layer(float(m_tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, true);
wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, true);
} else {
// There is yet enough space at this layer of the wipe tower for the final purge.
}
} else {
// The wipe tower does not reach the last print layer, perform the pruge at the last print layer.
assert(m_tool_ordering.back().wipe_tower_partitions == 0);
wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true);
assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0);
wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z), float(layer_height), 0, false, true);
}
m_wipe_tower_final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>(
m_wipe_tower_data.final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>(
wipe_tower.tool_change((unsigned int)-1, false, WipeTower::PURPOSE_EXTRUDE));
}
std::string Print::output_filename()
std::string Print::output_filename() const
{
this->placeholder_parser.update_timestamp();
DynamicConfig cfg_timestamp;
PlaceholderParser::update_timestamp(cfg_timestamp);
try {
return this->placeholder_parser.process(this->config.output_filename_format.value, 0);
return this->placeholder_parser().process(m_config.output_filename_format.value, 0, &cfg_timestamp);
} catch (std::runtime_error &err) {
throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what());
}
}
std::string Print::output_filepath(const std::string &path)
std::string Print::output_filepath(const std::string &path) const
{
// if we were supplied no path, generate an automatic one based on our first object's input file
if (path.empty()) {
// get the first input file name
std::string input_file;
for (const PrintObject *object : this->objects) {
for (const PrintObject *object : m_objects) {
input_file = object->model_object()->input_file;
if (! input_file.empty())
break;

View file

@ -51,7 +51,7 @@ template <class StepType, size_t COUNT>
class PrintState
{
public:
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i] = INVALID; }
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); }
enum State {
INVALID,
@ -59,24 +59,58 @@ public:
DONE,
};
// With full memory barrier.
bool is_done(StepType step) const { return m_state[step] == DONE; }
// set_started() will lock the provided mutex before setting the state.
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
// modified by the UI thread.
// 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 = m_state[step] != INVALID;
m_state[step] = INVALID;
void set_started(StepType step, tbb::mutex &mtx) {
mtx.lock();
m_state[step].store(STARTED, std::memory_order_relaxed);
mtx.unlock();
}
// Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being
// modified by the UI thread.
void set_done(StepType step, tbb::mutex &mtx) {
mtx.lock();
m_state[step].store(DONE, std::memory_order_relaxed);
mtx.unlock();
}
// Make the step invalid.
// The provided mutex should be locked at this point, guarding access to m_state.
// In case the step has already been entered or finished, cancel the background
// processing by calling the cancel callback.
template<typename CancelationCallback>
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback &cancel) {
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
if (invalidated) {
mtx.unlock();
cancel();
mtx.lock();
}
return invalidated;
}
bool invalidate_all() {
// Make all steps invalid.
// The provided mutex should be locked at this point, guarding access to m_state.
// In case any step has already been entered or finished, cancel the background
// processing by calling the cancel callback.
template<typename CancelationCallback>
bool invalidate_all(tbb::mutex &mtx, CancelationCallback &cancel) {
bool invalidated = false;
for (size_t i = 0; i < COUNT; ++ i)
if (m_state[i] != INVALID) {
if (m_state[i].load(std::memory_order_relaxed) != INVALID) {
if (! invalidated) {
mtx.unlock();
cancel();
mtx.lock();
invalidated = true;
m_state[i] = INVALID;
break;
}
m_state[i].store(INVALID, std::memory_order_relaxed);
}
return invalidated;
}
@ -91,17 +125,24 @@ class PrintRegion
{
friend class Print;
// Methods NOT modifying the PrintRegion's state:
public:
PrintRegionConfig config;
Print* print() { return this->_print; }
const Print* print() const { return m_print; }
const PrintRegionConfig& config() const { return m_config; }
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const;
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
private:
Print* _print;
// Methods modifying the PrintRegion's state:
public:
Print* print() { return m_print; }
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
PrintRegion(Print* print) : _print(print) {}
private:
Print *m_print;
PrintRegionConfig m_config;
PrintRegion(Print* print) : m_print(print) {}
PrintRegion(Print* print, const PrintRegionConfig &config) : m_print(print), m_config(config) {}
~PrintRegion() {}
};
@ -117,7 +158,6 @@ class PrintObject
public:
// vector of (vectors of volume ids), indexed by region_id
std::vector<std::vector<int>> region_volumes;
PrintObjectConfig config;
t_layer_height_ranges layer_height_ranges;
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
@ -144,15 +184,17 @@ public:
// Slic3r::Point objects in scaled G-code coordinates in our coordinates
Points _shifted_copies;
LayerPtrs layers;
SupportLayerPtrs support_layers;
Print* print() { return m_print; }
const Print* print() const { return m_print; }
ModelObject* model_object() { return m_model_object; }
const ModelObject* model_object() const { return m_model_object; }
const PrintObjectConfig& config() const { return m_config; }
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
const LayerPtrs& layers() const { return m_layers; }
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
Print* print() { return this->_print; }
const Print* print() const { return this->_print; }
ModelObject* model_object() { return this->_model_object; }
const ModelObject* model_object() const { return this->_model_object; }
const Points& copies() const { return this->_copies; }
const Points& copies() const { return m_copies; }
bool add_copy(const Pointf &point);
bool delete_last_copy();
bool delete_all_copies() { return this->set_copies(Points()); }
@ -171,24 +213,25 @@ public:
// this value is not supposed to be compared with Layer::id
// since they have different semantics.
size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); }
size_t layer_count() const { return this->layers.size(); }
size_t layer_count() const { return m_layers.size(); }
void clear_layers();
Layer* get_layer(int idx) { return this->layers.at(idx); }
const Layer* get_layer(int idx) const { return this->layers.at(idx); }
Layer* get_layer(int idx) { return m_layers[idx]; }
const Layer* get_layer(int idx) const { return m_layers[idx]; }
// print_z: top of the layer; slice_z: center of the layer.
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
size_t support_layer_count() const { return this->support_layers.size(); }
size_t support_layer_count() const { return m_support_layers.size(); }
void clear_support_layers();
SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); }
SupportLayer* get_support_layer(int idx) { return m_support_layers[idx]; }
SupportLayer* add_support_layer(int id, coordf_t height, coordf_t print_z);
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
void delete_support_layer(int idx);
// 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 m_state.invalidate_all(); }
bool invalidate_all_steps();
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
@ -229,9 +272,14 @@ private:
void combine_infill();
void _generate_support_material();
Print* _print;
ModelObject* _model_object;
Points _copies; // Slic3r::Point objects in scaled G-code coordinates
Print *m_print;
ModelObject *m_model_object;
PrintObjectConfig m_config;
// Slic3r::Point objects in scaled G-code coordinates
Points m_copies;
LayerPtrs m_layers;
SupportLayerPtrs m_support_layers;
PrintState<PrintObjectStep, posCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread:
@ -245,9 +293,49 @@ private:
~PrintObject() {}
void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); }
void set_done(PrintObjectStep step) { m_state.set_done(step, m_mutex); }
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
};
struct WipeTowerData
{
// Following section will be consumed by the GCodeGenerator.
// Tool ordering of a non-sequential print has to be known to calculate the wipe tower.
// Cache it here, so it does not need to be recalculated during the G-code generation.
ToolOrdering tool_ordering;
// Cache of tool changes per print layer.
std::unique_ptr<WipeTower::ToolChangeResult> priming;
std::vector<std::vector<WipeTower::ToolChangeResult>> tool_changes;
std::unique_ptr<WipeTower::ToolChangeResult> final_purge;
void clear() {
tool_ordering.clear();
priming.reset(nullptr);
tool_changes.clear();
final_purge.reset(nullptr);
}
};
struct PrintStatistics
{
PrintStatistics() { clear(); }
std::string estimated_print_time;
double total_used_filament;
double total_extruded_volume;
double total_cost;
double total_weight;
std::map<size_t, float> filament_stats;
void clear() {
estimated_print_time.clear();
total_used_filament = 0.;
total_extruded_volume = 0.;
total_weight = 0.;
total_cost = 0.;
filament_stats.clear();
}
};
typedef std::vector<PrintObject*> PrintObjectPtrs;
typedef std::vector<PrintRegion*> PrintRegionPtrs;
@ -255,44 +343,27 @@ typedef std::vector<PrintRegion*> PrintRegionPtrs;
class Print
{
public:
PrintConfig config;
PrintObjectConfig default_object_config;
PrintRegionConfig default_region_config;
PrintObjectPtrs objects;
PrintRegionPtrs regions;
PlaceholderParser placeholder_parser;
std::string estimated_print_time;
double total_used_filament, total_extruded_volume, total_cost, total_weight;
std::map<size_t, float> filament_stats;
// ordered collections of extrusion paths to build skirt loops and brim
ExtrusionEntityCollection skirt, brim;
Print() : total_used_filament(0), total_extruded_volume(0) { restart(); }
Print() { restart(); }
~Print() { clear_objects(); }
// methods for handling objects
// Methods, which change the state of Print / PrintObject / PrintRegion.
// The following methods are synchronized with process() and export_gcode(),
// so that process() and export_gcode() may be called from a background thread.
// In case the following methods need to modify data processed by process() or export_gcode(),
// a cancellation callback is executed to stop the background processing before the operation.
void clear_objects();
PrintObject* get_object(size_t idx) { return objects.at(idx); }
const PrintObject* get_object(size_t idx) const { return objects.at(idx); }
void delete_object(size_t idx);
void reload_object(size_t idx);
bool reload_model_instances();
// methods for handling regions
PrintRegion* get_region(size_t idx) { return regions.at(idx); }
const PrintRegion* get_region(size_t idx) const { return regions.at(idx); }
PrintRegion* add_region();
void add_model_object(ModelObject* model_object, int idx = -1);
bool apply_config(DynamicPrintConfig config);
void process();
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
// methods for handling state
bool invalidate_step(PrintStep step);
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;
bool has_skirt() const;
// Returns an empty string if valid, otherwise returns an error message.
@ -306,26 +377,29 @@ public:
std::vector<unsigned int> object_extruders() const;
std::vector<unsigned int> support_material_extruders() const;
std::vector<unsigned int> extruders() const;
void _simplify_slices(double distance);
double max_allowed_layer_height() const;
bool has_support_material() const;
// Make sure the background processing has no access to this model_object during this call!
void auto_assign_extruders(ModelObject* model_object) const;
void process();
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
const PrintConfig& config() const { return m_config; }
const PrintObjectConfig& default_object_config() const { return m_default_object_config; }
const PrintRegionConfig& default_region_config() const { return m_default_region_config; }
const PrintObjectPtrs& objects() const { return m_objects; }
const PrintRegionPtrs& regions() const { return m_regions; }
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
const ExtrusionEntityCollection& brim() const { return m_brim; }
const PrintStatistics& print_statistics() const { return m_print_statistics; }
// Wipe tower support.
bool has_wipe_tower() const;
// Tool ordering of a non-sequential print has to be known to calculate the wipe tower.
// Cache it here, so it does not need to be recalculated during the G-code generation.
ToolOrdering m_tool_ordering;
// Cache of tool changes per print layer.
std::unique_ptr<WipeTower::ToolChangeResult> m_wipe_tower_priming;
std::vector<std::vector<WipeTower::ToolChangeResult>> m_wipe_tower_tool_changes;
std::unique_ptr<WipeTower::ToolChangeResult> m_wipe_tower_final_purge;
const WipeTowerData& wipe_tower_data() const { return m_wipe_tower_data; }
std::string output_filename();
std::string output_filepath(const std::string &path);
std::string output_filename() const;
std::string output_filepath(const std::string &path) const;
typedef std::function<void(int, const std::string&)> status_callback_type;
// Default status console print out in the form of percent => message.
@ -339,26 +413,45 @@ public:
if (m_status_callback) m_status_callback(percent, message);
else printf("%d => %s\n", percent, message.c_str());
}
typedef std::function<void()> cancel_callback_type;
// Various methods will call this callback to stop the background processing (the Print::process() call)
// in case a successive change of the Print / PrintObject / PrintRegion instances changed
// the state of the finished or running calculations.
void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; }
// Has the calculation been canceled?
bool canceled() const { return m_canceled; }
// Cancel the running computation. Stop execution of all the background threads.
void cancel() { m_canceled = true; }
// Cancel the running computation. Stop execution of all the background threads.
void restart() { m_canceled = false; }
// Has the calculation been canceled?
bool canceled() { return m_canceled; }
void throw_if_canceled() { if (m_canceled) throw CanceledException(); }
// Accessed by SupportMaterial
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
protected:
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); }
void set_done(PrintStep step) { m_state.set_done(step); }
void set_done(PrintStep step) { m_state.set_done(step, m_mutex); }
bool invalidate_step(PrintStep step);
bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); }
// methods for handling regions
PrintRegion* get_region(size_t idx) { return m_regions[idx]; }
PrintRegion* add_region();
PrintRegion* add_region(const PrintRegionConfig &config);
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);
// If the background processing stop was requested, throw CanceledException.
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
void throw_if_canceled() { if (m_canceled) throw CanceledException(); }
void _make_skirt();
void _make_brim();
void _clear_wipe_tower();
void _make_wipe_tower();
void _simplify_slices(double distance);
PrintState<PrintStep, psCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread:
@ -370,15 +463,36 @@ private:
// Callback to be evoked regularly to update state of the UI thread.
status_callback_type m_status_callback;
// Callback to be evoked to stop the background processing before a state is updated.
cancel_callback_type m_cancel_callback = [](){};
PrintConfig m_config;
PrintObjectConfig m_default_object_config;
PrintRegionConfig m_default_region_config;
PrintObjectPtrs m_objects;
PrintRegionPtrs m_regions;
PlaceholderParser m_placeholder_parser;
// Ordered collections of extrusion paths to build skirt loops and brim.
ExtrusionEntityCollection m_skirt;
ExtrusionEntityCollection m_brim;
// Following section will be consumed by the GCodeGenerator.
WipeTowerData m_wipe_tower_data;
// Estimated print time, filament consumed.
PrintStatistics m_print_statistics;
// To allow GCode to set the Print's GCodeExport step status.
friend class GCode;
// Allow PrintObject to access m_mutex and m_cancel_callback.
friend class PrintObject;
};
#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator)
#define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region)
#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object)
#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->layers, layer)
#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->regions, layerm)
#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->m_objects, object)
#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->m_layers, layer)
#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->m_regions, layerm)
}

File diff suppressed because it is too large Load diff

View file

@ -12,48 +12,48 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
} else {
// otherwise, get extrusion width from configuration
// (might be an absolute value, or a percent value, or zero for auto)
if (first_layer && this->_print->config.first_layer_extrusion_width.value > 0) {
config_width = this->_print->config.first_layer_extrusion_width;
if (first_layer && m_print->config().first_layer_extrusion_width.value > 0) {
config_width = m_print->config().first_layer_extrusion_width;
} else if (role == frExternalPerimeter) {
config_width = this->config.external_perimeter_extrusion_width;
config_width = m_config.external_perimeter_extrusion_width;
} else if (role == frPerimeter) {
config_width = this->config.perimeter_extrusion_width;
config_width = m_config.perimeter_extrusion_width;
} else if (role == frInfill) {
config_width = this->config.infill_extrusion_width;
config_width = m_config.infill_extrusion_width;
} else if (role == frSolidInfill) {
config_width = this->config.solid_infill_extrusion_width;
config_width = m_config.solid_infill_extrusion_width;
} else if (role == frTopSolidInfill) {
config_width = this->config.top_infill_extrusion_width;
config_width = m_config.top_infill_extrusion_width;
} else {
CONFESS("Unknown role");
}
}
if (config_width.value == 0) {
config_width = object.config.extrusion_width;
config_width = object.config().extrusion_width;
}
// get the configured nozzle_diameter for the extruder associated
// to the flow role requested
size_t extruder = 0; // 1-based
if (role == frPerimeter || role == frExternalPerimeter) {
extruder = this->config.perimeter_extruder;
extruder = m_config.perimeter_extruder;
} else if (role == frInfill) {
extruder = this->config.infill_extruder;
extruder = m_config.infill_extruder;
} else if (role == frSolidInfill || role == frTopSolidInfill) {
extruder = this->config.solid_infill_extruder;
extruder = m_config.solid_infill_extruder;
} else {
CONFESS("Unknown role $role");
}
double nozzle_diameter = this->_print->config.nozzle_diameter.get_at(extruder-1);
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1);
return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)this->config.bridge_flow_ratio : 0.0);
return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0);
}
coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const
{
return (print_config.nozzle_diameter.get_at(this->config.perimeter_extruder.value - 1) +
print_config.nozzle_diameter.get_at(this->config.infill_extruder.value - 1) +
print_config.nozzle_diameter.get_at(this->config.solid_infill_extruder.value - 1)) / 3.;
return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) +
print_config.nozzle_diameter.get_at(m_config.infill_extruder.value - 1) +
print_config.nozzle_diameter.get_at(m_config.solid_infill_extruder.value - 1)) / 3.;
}
}

View file

@ -142,8 +142,8 @@ void export_print_z_polygons_and_extrusions_to_svg(
PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) :
m_object (object),
m_print_config (&object->print()->config),
m_object_config (&object->config),
m_print_config (&object->print()->config()),
m_object_config (&object->config()),
m_slicing_params (slicing_params),
m_first_layer_flow (support_material_1st_layer_flow(object, float(slicing_params.first_print_layer_height))),
m_support_material_flow (support_material_flow(object, float(slicing_params.layer_height))),
@ -164,7 +164,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
coordf_t external_perimeter_width = 0.;
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
if (! object->region_volumes[region_id].empty()) {
const PrintRegionConfig &config = object->print()->get_region(region_id)->config;
const PrintRegionConfig &config = object->print()->get_region(region_id)->config();
coordf_t width = config.external_perimeter_extrusion_width.get_abs_value(slicing_params.layer_height);
if (width <= 0.)
width = m_print_config->nozzle_diameter.get_at(config.perimeter_extruder-1);
@ -226,7 +226,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
coordf_t max_object_layer_height = 0.;
for (size_t i = 0; i < object.layer_count(); ++ i)
max_object_layer_height = std::max(max_object_layer_height, object.layers[i]->height);
max_object_layer_height = std::max(max_object_layer_height, object.layers()[i]->height);
// Layer instances will be allocated by std::deque and they will be kept until the end of this function call.
// The layers will be referenced by various LayersPtr (of type std::vector<Layer*>)
@ -266,9 +266,9 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
layer_support_areas);
#ifdef SLIC3R_DEBUG
for (size_t layer_id = 0; layer_id < object.layers.size(); ++ layer_id)
for (size_t layer_id = 0; layer_id < object.layers().size(); ++ layer_id)
Slic3r::SVG::export_expolygons(
debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers[layer_id]->print_z),
debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers()[layer_id]->print_z),
union_ex(layer_support_areas[layer_id], false));
#endif /* SLIC3R_DEBUG */
@ -354,7 +354,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
// Sort the layers lexicographically by a raising print_z and a decreasing height.
std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare());
int layer_id = 0;
assert(object.support_layers.empty());
assert(object.support_layers().empty());
for (int i = 0; i < int(layers_sorted.size());) {
// Find the last layer with roughly the same print_z, find the minimum layer height of all.
// Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
@ -420,8 +420,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t
{
// 1) Count the new polygons first.
size_t n_polygons_new = 0;
for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) {
const LayerRegion &region = *(*it_region);
for (const LayerRegion* pregion : layer.regions()) {
const LayerRegion &region = *pregion;
const SurfaceCollection &slices = region.slices;
for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) {
const Surface &surface = *it;
@ -433,8 +433,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t
// 2) Collect the new polygons.
Polygons out;
out.reserve(n_polygons_new);
for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) {
const LayerRegion &region = *(*it_region);
for (const LayerRegion *pregion : layer.regions()) {
const LayerRegion &region = *pregion;
const SurfaceCollection &slices = region.slices;
for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) {
const Surface &surface = *it;
@ -658,9 +658,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
std::vector<Polygons> buildplate_covered;
if (buildplate_only) {
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() - collecting regions covering the print bed.";
buildplate_covered.assign(object.layers.size(), Polygons());
for (size_t layer_id = 1; layer_id < object.layers.size(); ++ layer_id) {
const Layer &lower_layer = *object.layers[layer_id-1];
buildplate_covered.assign(object.layers().size(), Polygons());
for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) {
const Layer &lower_layer = *object.layers()[layer_id-1];
// Merge the new slices with the preceding slices.
// Apply the safety offset to the newly added polygons, so they will connect
// with the polygons collected before,
@ -686,7 +686,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
[this, &object, &buildplate_covered, threshold_rad, &layer_storage, &layer_storage_mutex, &contact_out](const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id)
{
const Layer &layer = *object.layers[layer_id];
const Layer &layer = *object.layers()[layer_id];
// Detect overhangs and contact areas needed to support them.
// Collect overhangs and contacts of all regions of this layer supported by the layer immediately below.
@ -703,13 +703,13 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
contact_polygons = offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN));
} else {
// Generate overhang / contact_polygons for non-raft layers.
const Layer &lower_layer = *object.layers[layer_id-1];
for (LayerRegion *layerm : layer.regions) {
const Layer &lower_layer = *object.layers()[layer_id-1];
for (LayerRegion *layerm : layer.regions()) {
// Extrusion width accounts for the roundings of the extrudates.
// It is the maximum widh of the extrudate.
float fw = float(layerm->flow(frExternalPerimeter).scaled_width());
float lower_layer_offset =
(layer_id < this->m_object_config->support_material_enforce_layers.value) ?
(layer_id < m_object_config->support_material_enforce_layers.value) ?
// Enforce a full possible support, ignore the overhang angle.
0.f :
(threshold_rad > 0. ?
@ -762,14 +762,14 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
}
#endif /* SLIC3R_DEBUG */
if (this->m_object_config->dont_support_bridges) {
if (m_object_config->dont_support_bridges) {
// compute the area of bridging perimeters
// Note: this is duplicate code from GCode.pm, we need to refactor
if (true) {
Polygons bridged_perimeters;
{
Flow bridge_flow = layerm->flow(frPerimeter, true);
coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(layerm->region()->config.perimeter_extruder-1);
coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder-1);
Polygons lower_grown_slices = offset(lower_layer_polygons, 0.5f*float(scale_(nozzle_diameter)), SUPPORT_SURFACES_OFFSET_PARAMETERS);
// Collect perimeters of this layer.
@ -894,8 +894,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
} else {
// Interface layer will be synchronized with the object.
assert(layer_id > 0);
new_layer.height = object.layers[layer_id - 1]->height;
new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers[layer_id - 2]->print_z;
new_layer.height = object.layers()[layer_id - 1]->height;
new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers()[layer_id - 2]->print_z;
}
} else {
// Contact layer will be printed with a normal flow, but
@ -904,9 +904,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
// In the future we may switch to a normal extrusion flow for the supported bridges.
// Get the average nozzle diameter used on this layer.
coordf_t nozzle_dmr = 0.;
for (const LayerRegion *region : layer.regions)
for (const LayerRegion *region : layer.regions())
nozzle_dmr += region->region()->nozzle_dmr_avg(*m_print_config);
nozzle_dmr /= coordf_t(layer.regions.size());
nozzle_dmr /= coordf_t(layer.regions().size());
new_layer.print_z = layer.print_z - nozzle_dmr - m_object_config->support_material_contact_distance;
new_layer.bottom_z = new_layer.print_z;
new_layer.height = 0.;
@ -1048,10 +1048,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// top shapes so this can be done here
layer_new.height = m_slicing_params.soluble_interface ?
// Align the interface layer with the object's layer height.
object.layers[layer_id + 1]->height :
object.layers()[layer_id + 1]->height :
// Place a bridge flow interface layer over the top surface.
m_support_material_interface_flow.nozzle_diameter;
layer_new.print_z = m_slicing_params.soluble_interface ? object.layers[layer_id + 1]->print_z :
layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z :
layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value;
layer_new.bottom_z = layer.print_z;
layer_new.idx_object_layer_below = layer_id;
@ -1062,16 +1062,16 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// Walk the top surfaces, snap the top of the new bottom surface to the closest top of the top surface,
// so there will be no support surfaces generated with thickness lower than m_support_layer_height_min.
for (size_t top_idx = size_t(std::max<int>(0, contact_idx));
top_idx < top_contacts.size() && top_contacts[top_idx]->print_z < layer_new.print_z + this->m_support_layer_height_min;
top_idx < top_contacts.size() && top_contacts[top_idx]->print_z < layer_new.print_z + m_support_layer_height_min;
++ top_idx) {
if (top_contacts[top_idx]->print_z > layer_new.print_z - this->m_support_layer_height_min) {
if (top_contacts[top_idx]->print_z > layer_new.print_z - m_support_layer_height_min) {
// A top layer has been found, which is close to the new bottom layer.
coordf_t diff = layer_new.print_z - top_contacts[top_idx]->print_z;
assert(std::abs(diff) <= this->m_support_layer_height_min);
assert(std::abs(diff) <= m_support_layer_height_min);
if (diff > 0.) {
// The top contact layer is below this layer. Make the bridging layer thinner to align with the existing top layer.
assert(diff < layer_new.height + EPSILON);
assert(layer_new.height - diff >= this->m_support_layer_height_min - EPSILON);
assert(layer_new.height - diff >= m_support_layer_height_min - EPSILON);
layer_new.print_z = top_contacts[top_idx]->print_z;
layer_new.height -= diff;
} else {
@ -1093,7 +1093,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// Trim the already created base layers above the current layer intersecting with the new bottom contacts layer.
touching = offset(touching, float(SCALED_EPSILON));
for (int layer_id_above = layer_id + 1; layer_id_above < int(object.total_layer_count()); ++ layer_id_above) {
const Layer &layer_above = *object.layers[layer_id_above];
const Layer &layer_above = *object.layers()[layer_id_above];
if (layer_above.print_z > layer_new.print_z + EPSILON)
break;
if (! layer_support_areas[layer_id_above].empty()) {
@ -1320,7 +1320,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
// Verify that the extremes are separated by m_support_layer_height_min.
for (size_t i = 1; i < extremes.size(); ++ i) {
assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() == 0. ||
extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > this->m_support_layer_height_min - EPSILON);
extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > m_support_layer_height_min - EPSILON);
assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > 0. ||
extremes[i]->layer_type == extremes[i-1]->layer_type ||
(extremes[i]->layer_type == sltBottomContact && extremes[i - 1]->layer_type == sltTopContact));
@ -1344,7 +1344,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
// This is a bottom of a synchronized (or soluble) top contact layer, its height has been decided in this->top_contact_layers().
assert(extr2->layer_type == sltTopContact);
assert(extr2->bottom_z == m_slicing_params.first_print_layer_height);
assert(extr2->print_z >= m_slicing_params.first_print_layer_height + this->m_support_layer_height_min - EPSILON);
assert(extr2->print_z >= m_slicing_params.first_print_layer_height + m_support_layer_height_min - EPSILON);
if (intermediate_layers.empty() || intermediate_layers.back()->print_z < m_slicing_params.first_print_layer_height) {
MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.bottom_z = 0.;
@ -1384,7 +1384,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
if (synchronize) {
// Emit support layers synchronized with the object layers.
// Find the first object layer, which has its print_z in this support Z range.
while (idx_layer_object < object.layers.size() && object.layers[idx_layer_object]->print_z < extr1z + EPSILON)
while (idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr1z + EPSILON)
++ idx_layer_object;
if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) {
// Insert one base support layer below the object.
@ -1395,11 +1395,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
intermediate_layers.push_back(&layer_new);
}
// Emit all intermediate support layers synchronized with object layers up to extr2z.
for (; idx_layer_object < object.layers.size() && object.layers[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) {
for (; idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) {
MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.print_z = object.layers[idx_layer_object]->print_z;
layer_new.height = object.layers[idx_layer_object]->height;
layer_new.bottom_z = (idx_layer_object > 0) ? object.layers[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height);
layer_new.print_z = object.layers()[idx_layer_object]->print_z;
layer_new.height = object.layers()[idx_layer_object]->height;
layer_new.bottom_z = (idx_layer_object > 0) ? object.layers()[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height);
assert(intermediate_layers.empty() || intermediate_layers.back()->print_z < layer_new.print_z + EPSILON);
intermediate_layers.push_back(&layer_new);
}
@ -1409,10 +1409,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
assert(n_layers_extra > 0);
coordf_t step = dist / coordf_t(n_layers_extra);
if (extr1 != nullptr && extr1->layer_type == sltTopContact &&
extr1->print_z + this->m_support_layer_height_min > extr1->bottom_z + step) {
extr1->print_z + m_support_layer_height_min > extr1->bottom_z + step) {
// The bottom extreme is a bottom of a top surface. Ensure that the gap
// between the 1st intermediate layer print_z and extr1->print_z is not too small.
assert(extr1->bottom_z + this->m_support_layer_height_min < extr1->print_z + EPSILON);
assert(extr1->bottom_z + m_support_layer_height_min < extr1->print_z + EPSILON);
// Generate the first intermediate layer.
MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.bottom_z = extr1->bottom_z;
@ -1509,7 +1509,7 @@ void PrintObjectSupportMaterial::generate_base_layers(
Polygons polygons_new;
// Use the precomputed layer_support_areas.
idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers, idx_object_layer_above,
idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers(), idx_object_layer_above,
[&layer_intermediate](const Layer *layer){ return layer->print_z <= layer_intermediate.print_z + EPSILON; }));
polygons_new = layer_support_areas[idx_object_layer_above];
@ -1644,24 +1644,24 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
// Find the overlapping object layers including the extra above / below gap.
coordf_t z_threshold = support_layer.print_z - support_layer.height - gap_extra_below + EPSILON;
idx_object_layer_overlapping = idx_higher_or_equal(
object.layers, idx_object_layer_overlapping,
object.layers(), idx_object_layer_overlapping,
[z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
// Collect all the object layers intersecting with this layer.
Polygons polygons_trimming;
size_t i = idx_object_layer_overlapping;
for (; i < object.layers.size(); ++ i) {
const Layer &object_layer = *object.layers[i];
for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers()[i];
if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON)
break;
polygons_append(polygons_trimming, (Polygons)object_layer.slices);
}
if (! this->m_slicing_params.soluble_interface) {
if (! m_slicing_params.soluble_interface) {
// Collect all bottom surfaces, which will be extruded with a bridging flow.
for (; i < object.layers.size(); ++ i) {
const Layer &object_layer = *object.layers[i];
for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers()[i];
bool some_region_overlaps = false;
for (LayerRegion* region : object_layer.regions) {
coordf_t nozzle_dmr = region->region()->nozzle_dmr_avg(*this->m_print_config);
for (LayerRegion* region : object_layer.regions()) {
coordf_t nozzle_dmr = region->region()->nozzle_dmr_avg(*m_print_config);
if (object_layer.print_z - nozzle_dmr > support_layer.print_z + gap_extra_above - EPSILON)
break;
some_region_overlaps = true;
@ -1764,7 +1764,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
// Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer),
offset(m_object->layers.front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
offset(m_object->layers().front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
}
@ -1909,8 +1909,8 @@ struct MyLayerExtruded
else
*m_polygons_to_extrude = std::move(polygons);
}
Polygons& polygons_to_extrude() { return (this->m_polygons_to_extrude == nullptr) ? layer->polygons : *this->m_polygons_to_extrude; }
const Polygons& polygons_to_extrude() const { return (this->m_polygons_to_extrude == nullptr) ? layer->polygons : *this->m_polygons_to_extrude; }
Polygons& polygons_to_extrude() { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
bool could_merge(const MyLayerExtruded &other) const {
return ! this->empty() && ! other.empty() &&
@ -1923,21 +1923,21 @@ struct MyLayerExtruded
assert(this->could_merge(other));
// 1) Merge the rest polygons to extrude, if there are any.
if (other.m_polygons_to_extrude != nullptr) {
if (this->m_polygons_to_extrude == nullptr) {
if (m_polygons_to_extrude == nullptr) {
// This layer has no extrusions generated yet, if it has no m_polygons_to_extrude (its area to extrude was not reduced yet).
assert(this->extrusions.empty());
this->m_polygons_to_extrude = new Polygons(this->layer->polygons);
m_polygons_to_extrude = new Polygons(this->layer->polygons);
}
Slic3r::polygons_append(*this->m_polygons_to_extrude, std::move(*other.m_polygons_to_extrude));
*this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true);
Slic3r::polygons_append(*m_polygons_to_extrude, std::move(*other.m_polygons_to_extrude));
*m_polygons_to_extrude = union_(*m_polygons_to_extrude, true);
delete other.m_polygons_to_extrude;
other.m_polygons_to_extrude = nullptr;
} else if (this->m_polygons_to_extrude != nullptr) {
} else if (m_polygons_to_extrude != nullptr) {
assert(other.m_polygons_to_extrude == nullptr);
// The other layer has no extrusions generated yet, if it has no m_polygons_to_extrude (its area to extrude was not reduced yet).
assert(other.extrusions.empty());
Slic3r::polygons_append(*this->m_polygons_to_extrude, other.layer->polygons);
*this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true);
Slic3r::polygons_append(*m_polygons_to_extrude, other.layer->polygons);
*m_polygons_to_extrude = union_(*m_polygons_to_extrude, true);
}
// 2) Merge the extrusions.
this->extrusions.insert(this->extrusions.end(), other.extrusions.begin(), other.extrusions.end());
@ -2535,7 +2535,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
{
assert(support_layer_id < raft_layers.size());
SupportLayer &support_layer = *object.support_layers[support_layer_id];
SupportLayer &support_layer = *object.support_layers()[support_layer_id];
assert(support_layer.support_fills.entities.empty());
MyLayer &raft_layer = *raft_layers[support_layer_id];
@ -2631,9 +2631,9 @@ void PrintObjectSupportMaterial::generate_toolpaths(
MyLayerExtruded interface_layer;
std::vector<LayerCacheItem> overlaps;
};
std::vector<LayerCache> layer_caches(object.support_layers.size(), LayerCache());
std::vector<LayerCache> layer_caches(object.support_layers().size(), LayerCache());
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers.size()),
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers().size()),
[this, &object, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &layer_caches, &loop_interface_processor,
infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath]
(const tbb::blocked_range<size_t>& range) {
@ -2648,7 +2648,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler_support->set_bounding_box(bbox_object);
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
{
SupportLayer &support_layer = *object.support_layers[support_layer_id];
SupportLayer &support_layer = *object.support_layers()[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id];
// Find polygons with the same print_z.
@ -2844,11 +2844,11 @@ void PrintObjectSupportMaterial::generate_toolpaths(
});
// Now modulate the support layer height in parallel.
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers.size()),
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers().size()),
[this, &object, &layer_caches]
(const tbb::blocked_range<size_t>& range) {
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) {
SupportLayer &support_layer = *object.support_layers[support_layer_id];
SupportLayer &support_layer = *object.support_layers()[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id];
for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) {
modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping);

View file

@ -1670,30 +1670,30 @@ void _3DScene::_load_print_toolpaths(
// 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)
if (!print->has_skirt() && print->config().brim_width.value == 0)
return;
const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish
// number of skirt layers
size_t total_layer_count = 0;
for (const PrintObject *print_object : print->objects)
for (const PrintObject *print_object : print->objects())
total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
size_t skirt_height = print->has_infinite_skirt() ?
total_layer_count :
std::min<size_t>(print->config.skirt_height.value, total_layer_count);
if (skirt_height == 0 && print->config.brim_width.value > 0)
std::min<size_t>(print->config().skirt_height.value, total_layer_count);
if (skirt_height == 0 && print->config().brim_width.value > 0)
skirt_height = 1;
// get first skirt_height layers (maybe this should be moved to a PrintObject method?)
const PrintObject *object0 = print->objects.front();
const PrintObject *object0 = print->objects().front();
std::vector<float> print_zs;
print_zs.reserve(skirt_height * 2);
for (size_t i = 0; i < std::min(skirt_height, object0->layers.size()); ++ i)
print_zs.push_back(float(object0->layers[i]->print_z));
for (size_t i = 0; i < std::min(skirt_height, object0->layers().size()); ++ i)
print_zs.push_back(float(object0->layers()[i]->print_z));
//FIXME why there are support layers?
for (size_t i = 0; i < std::min(skirt_height, object0->support_layers.size()); ++ i)
print_zs.push_back(float(object0->support_layers[i]->print_z));
for (size_t i = 0; i < std::min(skirt_height, object0->support_layers().size()); ++ i)
print_zs.push_back(float(object0->support_layers()[i]->print_z));
sort_remove_duplicates(print_zs);
if (print_zs.size() > skirt_height)
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
@ -1705,8 +1705,8 @@ void _3DScene::_load_print_toolpaths(
volume.offsets.push_back(volume.indexed_vertex_array.quad_indices.size());
volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size());
if (i == 0)
extrusionentity_to_verts(print->brim, print_zs[i], Point(0, 0), volume);
extrusionentity_to_verts(print->skirt, print_zs[i], Point(0, 0), volume);
extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), volume);
extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume);
}
volume.bounding_box = volume.indexed_vertex_array.bounding_box();
volume.indexed_vertex_array.finalize_geometry(use_VBOs);
@ -1753,10 +1753,10 @@ void _3DScene::_load_print_object_toolpaths(
ctxt.shifted_copies = &print_object->_shifted_copies;
// order layers by print_z
ctxt.layers.reserve(print_object->layers.size() + print_object->support_layers.size());
for (const Layer *layer : print_object->layers)
ctxt.layers.reserve(print_object->layers().size() + print_object->support_layers().size());
for (const Layer *layer : print_object->layers())
ctxt.layers.push_back(layer);
for (const Layer *layer : print_object->support_layers)
for (const Layer *layer : print_object->support_layers())
ctxt.layers.push_back(layer);
std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; });
@ -1803,10 +1803,10 @@ void _3DScene::_load_print_object_toolpaths(
}
}
for (const Point &copy: *ctxt.shifted_copies) {
for (const LayerRegion *layerm : layer->regions) {
for (const LayerRegion *layerm : layer->regions()) {
if (ctxt.has_perimeters)
extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
*vols[ctxt.volume_idx(layerm->region()->config.perimeter_extruder.value, 0)]);
*vols[ctxt.volume_idx(layerm->region()->config().perimeter_extruder.value, 0)]);
if (ctxt.has_infill) {
for (const ExtrusionEntity *ee : layerm->fills.entities) {
// fill represents infill extrusions of a single island.
@ -1815,8 +1815,8 @@ void _3DScene::_load_print_object_toolpaths(
extrusionentity_to_verts(*fill, float(layer->print_z), copy,
*vols[ctxt.volume_idx(
is_solid_infill(fill->entities.front()->role()) ?
layerm->region()->config.solid_infill_extruder :
layerm->region()->config.infill_extruder,
layerm->region()->config().solid_infill_extruder :
layerm->region()->config().infill_extruder,
1)]);
}
}
@ -1828,8 +1828,8 @@ void _3DScene::_load_print_object_toolpaths(
extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
*vols[ctxt.volume_idx(
(extrusion_entity->role() == erSupportMaterial) ?
support_layer->object()->config.support_material_extruder :
support_layer->object()->config.support_material_interface_extruder,
support_layer->object()->config().support_material_extruder :
support_layer->object()->config().support_material_interface_extruder,
2)]);
}
}
@ -1877,7 +1877,7 @@ void _3DScene::_load_wipe_tower_toolpaths(
const std::vector<std::string> &tool_colors_str,
bool use_VBOs)
{
if (print->m_wipe_tower_tool_changes.empty())
if (print->wipe_tower_data().tool_changes.empty())
return;
std::vector<float> tool_colors = parse_colors(tool_colors_str);
@ -1902,8 +1902,8 @@ void _3DScene::_load_wipe_tower_toolpaths(
const std::vector<WipeTower::ToolChangeResult>& tool_change(size_t idx) {
return priming.empty() ?
((idx == print->m_wipe_tower_tool_changes.size()) ? final : print->m_wipe_tower_tool_changes[idx]) :
((idx == 0) ? priming : (idx == print->m_wipe_tower_tool_changes.size() + 1) ? final : print->m_wipe_tower_tool_changes[idx - 1]);
((idx == print->wipe_tower_data().tool_changes.size()) ? final : print->wipe_tower_data().tool_changes[idx]) :
((idx == 0) ? priming : (idx == print->wipe_tower_data().tool_changes.size() + 1) ? final : print->wipe_tower_data().tool_changes[idx - 1]);
}
std::vector<WipeTower::ToolChangeResult> priming;
std::vector<WipeTower::ToolChangeResult> final;
@ -1911,15 +1911,15 @@ void _3DScene::_load_wipe_tower_toolpaths(
ctxt.print = print;
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
if (print->m_wipe_tower_priming)
ctxt.priming.emplace_back(*print->m_wipe_tower_priming.get());
if (print->m_wipe_tower_final_purge)
ctxt.final.emplace_back(*print->m_wipe_tower_final_purge.get());
if (print->wipe_tower_data().priming != nullptr)
ctxt.priming.emplace_back(*print->wipe_tower_data().priming);
if (print->wipe_tower_data().final_purge)
ctxt.final.emplace_back(*print->wipe_tower_data().final_purge);
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
//FIXME Improve the heuristics for a grain size.
size_t n_items = print->m_wipe_tower_tool_changes.size() + (ctxt.priming.empty() ? 0 : 1);
size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1);
size_t grain_size = std::max(n_items / 128, size_t(1));
tbb::spin_mutex new_volume_mutex;
auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* {
@ -2554,13 +2554,13 @@ void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, boo
size_t initial_volumes_count = volumes.volumes.size();
s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Shell, 0, (unsigned int)initial_volumes_count);
if (print.objects.empty())
if (print.objects().empty())
// nothing to render, return
return;
// adds objects' volumes
unsigned int object_id = 0;
for (PrintObject* obj : print.objects)
for (PrintObject* obj : print.objects())
{
ModelObject* model_obj = obj->model_object();
@ -2579,8 +2579,8 @@ void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, boo
}
// adds wipe tower's volume
coordf_t max_z = print.objects[0]->model_object()->get_model()->bounding_box().max.z;
const PrintConfig& config = print.config;
coordf_t max_z = print.objects().front()->model_object()->get_model()->bounding_box().max.z;
const PrintConfig& config = print.config();
unsigned int extruders_count = config.nozzle_diameter.size();
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects)
volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, config.wipe_tower_per_color_wipe * (extruders_count - 1), max_z, use_VBOs);

View file

@ -31,7 +31,7 @@ _constant()
// owned by Print, no constructor/destructor
Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %};
%code%{ RETVAL = &THIS->config(); %};
Ref<Print> print();
Clone<Flow> flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, PrintObject* object)
@ -42,12 +42,12 @@ _constant()
// owned by Print, no constructor/destructor
int region_count()
%code%{ RETVAL = THIS->print()->regions.size(); %};
%code%{ RETVAL = THIS->print()->regions().size(); %};
Ref<Print> print();
Ref<ModelObject> model_object();
Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %};
%code%{ RETVAL = &THIS->config(); %};
Points copies();
t_layer_height_ranges layer_height_ranges()
%code%{ RETVAL = THIS->layer_height_ranges; %};
@ -95,32 +95,41 @@ _constant()
~Print();
Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %};
%code%{ RETVAL = &THIS->config(); %};
Ref<PlaceholderParser> placeholder_parser()
%code%{ RETVAL = &THIS->placeholder_parser; %};
%code%{ RETVAL = &THIS->placeholder_parser(); %};
Ref<ExtrusionEntityCollection> skirt()
%code%{ RETVAL = &THIS->skirt; %};
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->skirt()); %};
Ref<ExtrusionEntityCollection> brim()
%code%{ RETVAL = &THIS->brim; %};
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->brim()); %};
std::string estimated_print_time()
%code%{ RETVAL = THIS->estimated_print_time; %};
%code%{ RETVAL = THIS->print_statistics().estimated_print_time; %};
double total_used_filament()
%code%{ RETVAL = THIS->print_statistics().total_used_filament; %};
double total_extruded_volume()
%code%{ RETVAL = THIS->print_statistics().total_extruded_volume; %};
double total_weight()
%code%{ RETVAL = THIS->print_statistics().total_weight; %};
double total_cost()
%code%{ RETVAL = THIS->print_statistics().total_cost; %};
PrintObjectPtrs* objects()
%code%{ RETVAL = &THIS->objects; %};
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
void clear_objects();
Ref<PrintObject> get_object(int idx);
Ref<PrintObject> get_object(int idx)
%code%{ RETVAL = THIS->objects()[idx]; %};
void delete_object(int idx);
void reload_object(int idx);
bool reload_model_instances();
size_t object_count()
%code%{ RETVAL = THIS->objects.size(); %};
%code%{ RETVAL = THIS->objects().size(); %};
PrintRegionPtrs* regions()
%code%{ RETVAL = &THIS->regions; %};
Ref<PrintRegion> get_region(int idx);
Ref<PrintRegion> add_region();
%code%{ RETVAL = const_cast<PrintRegionPtrs*>(&THIS->regions()); %};
Ref<PrintRegion> get_region(int idx)
%code%{ RETVAL = THIS->regions()[idx]; %};
size_t region_count()
%code%{ RETVAL = THIS->regions.size(); %};
%code%{ RETVAL = THIS->regions().size(); %};
bool step_done(PrintStep step)
%code%{ RETVAL = THIS->is_step_done(step); %};
@ -130,7 +139,7 @@ _constant()
SV* filament_stats()
%code%{
HV* hv = newHV();
for (std::map<size_t,float>::const_iterator it = THIS->filament_stats.begin(); it != THIS->filament_stats.end(); ++it) {
for (std::map<size_t,float>::const_iterator it = THIS->print_statistics().filament_stats.begin(); it != THIS->print_statistics().filament_stats.end(); ++it) {
// stringify extruder_id
std::ostringstream ss;
ss << it->first;
@ -194,47 +203,4 @@ _constant()
}
%};
%{
double
Print::total_used_filament(...)
CODE:
if (items > 1) {
THIS->total_used_filament = (double)SvNV(ST(1));
}
RETVAL = THIS->total_used_filament;
OUTPUT:
RETVAL
double
Print::total_extruded_volume(...)
CODE:
if (items > 1) {
THIS->total_extruded_volume = (double)SvNV(ST(1));
}
RETVAL = THIS->total_extruded_volume;
OUTPUT:
RETVAL
double
Print::total_weight(...)
CODE:
if (items > 1) {
THIS->total_weight = (double)SvNV(ST(1));
}
RETVAL = THIS->total_weight;
OUTPUT:
RETVAL
double
Print::total_cost(...)
CODE:
if (items > 1) {
THIS->total_cost = (double)SvNV(ST(1));
}
RETVAL = THIS->total_cost;
OUTPUT:
RETVAL
%}
};