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; // 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 infill_flow = layerm.flow(frInfill);
Flow solid_infill_flow = layerm.flow(frSolidInfill); Flow solid_infill_flow = layerm.flow(frSolidInfill);
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill); 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)) { if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
group_attrib[i].is_solid = true; 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].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. // 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) { for (const Surface &surface : surfaces) {
if (surface.surface_type == stInternalVoid) if (surface.surface_type == stInternalVoid)
continue; continue;
InfillPattern fill_pattern = layerm.region()->config.fill_pattern.value; InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value;
double density = fill_density; double density = fill_density;
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill : FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill :
(surface.is_solid() ? frSolidInfill : frInfill); (surface.is_solid() ? frSolidInfill : frInfill);
@ -161,7 +161,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.is_solid()) { if (surface.is_solid()) {
density = 100.; density = 100.;
fill_pattern = (surface.is_external() && ! is_bridge) ? fill_pattern = (surface.is_external() && ! is_bridge) ?
layerm.region()->config.external_fill_pattern.value : layerm.region()->config().external_fill_pattern.value :
ipRectilinear; ipRectilinear;
} else if (density <= 0) } else if (density <= 0)
continue; continue;
@ -190,7 +190,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
// layer height // layer height
Flow internal_flow = layerm.region()->flow( Flow internal_flow = layerm.region()->flow(
frInfill, 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 bridge
false, // no first layer false, // no first layer
-1, // auto width -1, // auto width
@ -205,7 +205,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
double link_max_length = 0.; double link_max_length = 0.;
if (! is_bridge) { if (! is_bridge) {
#if 0 #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); // printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
#else #else
if (density > 80.) // 80% if (density > 80.) // 80%
@ -215,7 +215,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->layer_id = layerm.layer()->id(); f->layer_id = layerm.layer()->id();
f->z = layerm.layer()->print_z; 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. // Maximum length of the perimeter segment linking two infill lines.
f->link_max_length = scale_(link_max_length); f->link_max_length = scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths. // 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( return Flow::new_from_config_width(
frSupportMaterial, 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. // 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, (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. // 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)), 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), (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
false); false);
} }
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height) 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( return Flow::new_from_config_width(
frSupportMaterial, 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. // 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, (width.value > 0) ? width : object->config().extrusion_width,
float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), 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)), (layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)),
false); false);
} }
@ -135,10 +135,10 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
return Flow::new_from_config_width( return Flow::new_from_config_width(
frSupportMaterialInterface, 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. // 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, (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. // 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)), 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), (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
false); 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> GCode::collect_layers_to_print(const PrintObject &object)
{ {
std::vector<GCode::LayerToPrint> layers_to_print; 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. // Pair the object layers with the support layers by z.
size_t idx_object_layer = 0; size_t idx_object_layer = 0;
size_t idx_support_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; LayerToPrint layer_to_print;
layer_to_print.object_layer = (idx_object_layer < object.layers.size()) ? object.layers[idx_object_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; 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 && layer_to_print.support_layer) {
if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z - EPSILON) { if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z - EPSILON) {
layer_to_print.support_layer = nullptr; 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 object_idx;
size_t layer_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; std::vector<OrderingItem> ordering;
for (size_t i = 0; i < print.objects.size(); ++ i) { for (size_t i = 0; i < print.objects().size(); ++ i) {
per_object[i] = collect_layers_to_print(*print.objects[i]); per_object[i] = collect_layers_to_print(*print.objects()[i]);
OrderingItem ordering_item; OrderingItem ordering_item;
ordering_item.object_idx = i; ordering_item.object_idx = i;
ordering.reserve(ordering.size() + per_object[i].size()); 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; std::pair<coordf_t, std::vector<LayerToPrint>> merged;
// Assign an average print_z to the set of layers with nearly equal print_z. // 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.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) { for (; i < j; ++ i) {
const OrderingItem &oi = ordering[i]; const OrderingItem &oi = ordering[i];
assert(merged.second[oi.object_idx].layer() == nullptr); 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"); throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
try { try {
this->m_placeholder_parser_failed_templates.clear(); m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, preview_data); this->_do_export(*print, file, preview_data);
fflush(file); fflush(file);
if (ferror(file)) { if (ferror(file)) {
@ -382,10 +382,10 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw; throw;
} }
fclose(file); 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. // 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"; 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 += std::string("\t") + name + "\n";
msg += "\nPlease inspect the file "; msg += "\nPlease inspect the file ";
msg += path_tmp + " for error messages enclosed between\n"; 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 // resets time estimator
m_time_estimator.reset(); m_time_estimator.reset();
m_time_estimator.set_dialect(print.config.gcode_flavor); m_time_estimator.set_dialect(print.config().gcode_flavor);
// resets analyzer // resets analyzer
m_analyzer.reset(); 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? // How many times will be change_layer() called?
// change_layer() in turn increments the progress bar status. // change_layer() in turn increments the progress bar status.
m_layer_count = 0; m_layer_count = 0;
if (print.config.complete_objects.value) { if (print.config().complete_objects.value) {
// Add each of the object's layers separately. // Add each of the object's layers separately.
for (auto object : print.objects) { for (auto object : print.objects()) {
std::vector<coordf_t> zs; std::vector<coordf_t> zs;
zs.reserve(object->layers.size() + object->support_layers.size()); zs.reserve(object->layers().size() + object->support_layers().size());
for (auto layer : object->layers) for (auto layer : object->layers())
zs.push_back(layer->print_z); zs.push_back(layer->print_z);
for (auto layer : object->support_layers) for (auto layer : object->support_layers())
zs.push_back(layer->print_z); zs.push_back(layer->print_z);
std::sort(zs.begin(), zs.end()); std::sort(zs.begin(), zs.end());
m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); 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 { } else {
// Print all objects with the same print_z together. // Print all objects with the same print_z together.
std::vector<coordf_t> zs; std::vector<coordf_t> zs;
for (auto object : print.objects) { for (auto object : print.objects()) {
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
for (auto layer : object->layers) for (auto layer : object->layers())
zs.push_back(layer->print_z); zs.push_back(layer->print_z);
for (auto layer : object->support_layers) for (auto layer : object->support_layers())
zs.push_back(layer->print_z); zs.push_back(layer->print_z);
} }
std::sort(zs.begin(), zs.end()); 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(); print.throw_if_canceled();
m_enable_cooling_markers = true; m_enable_cooling_markers = true;
this->apply_print_config(print.config); this->apply_print_config(print.config());
this->set_extruders(print.extruders()); this->set_extruders(print.extruders());
// Initialize autospeed. // Initialize autospeed.
{ {
// get the minimum cross-section used in the print // get the minimum cross-section used in the print
std::vector<double> mm3_per_mm; std::vector<double> mm3_per_mm;
for (auto object : print.objects) { for (auto object : print.objects()) {
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
auto region = print.regions[region_id]; auto region = print.regions()[region_id];
for (auto layer : object->layers) { for (auto layer : object->layers()) {
auto layerm = layer->regions[region_id]; auto layerm = layer->regions()[region_id];
if (region->config.get_abs_value("perimeter_speed" ) == 0 || if (region->config().get_abs_value("perimeter_speed" ) == 0 ||
region->config.get_abs_value("small_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("external_perimeter_speed" ) == 0 ||
region->config.get_abs_value("bridge_speed" ) == 0) region->config().get_abs_value("bridge_speed" ) == 0)
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm()); mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
if (region->config.get_abs_value("infill_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("solid_infill_speed" ) == 0 ||
region->config.get_abs_value("top_solid_infill_speed" ) == 0 || region->config().get_abs_value("top_solid_infill_speed" ) == 0 ||
region->config.get_abs_value("bridge_speed" ) == 0) region->config().get_abs_value("bridge_speed" ) == 0)
mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm()); mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
} }
} }
if (object->config.get_abs_value("support_material_speed" ) == 0 || if (object->config().get_abs_value("support_material_speed" ) == 0 ||
object->config.get_abs_value("support_material_interface_speed" ) == 0) object->config().get_abs_value("support_material_interface_speed" ) == 0)
for (auto layer : object->support_layers) for (auto layer : object->support_layers())
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm()); mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
} }
print.throw_if_canceled(); 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 // volumetric speed as the volumetric speed produced by printing the
// smallest cross-section at the maximum speed: any larger cross-section // smallest cross-section at the maximum speed: any larger cross-section
// will need slower feedrates. // 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 // limit such volumetric speed with max_volumetric_speed if set
if (print.config.max_volumetric_speed.value > 0) if (print.config().max_volumetric_speed.value > 0)
m_volumetric_speed = std::min(m_volumetric_speed, print.config.max_volumetric_speed.value); m_volumetric_speed = std::min(m_volumetric_speed, print.config().max_volumetric_speed.value);
} }
} }
print.throw_if_canceled(); print.throw_if_canceled();
m_cooling_buffer = make_unique<CoolingBuffer>(*this); m_cooling_buffer = make_unique<CoolingBuffer>(*this);
if (print.config.spiral_vase.value) if (print.config().spiral_vase.value)
m_spiral_vase = make_unique<SpiralVase>(print.config); m_spiral_vase = make_unique<SpiralVase>(print.config());
if (print.config.max_volumetric_extrusion_rate_slope_positive.value > 0 || if (print.config().max_volumetric_extrusion_rate_slope_positive.value > 0 ||
print.config.max_volumetric_extrusion_rate_slope_negative.value > 0) print.config().max_volumetric_extrusion_rate_slope_negative.value > 0)
m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config); m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config());
m_enable_extrusion_role_markers = (bool)m_pressure_equalizer; m_enable_extrusion_role_markers = (bool)m_pressure_equalizer;
// Write information on the generator. // 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) // Write notes (content of the Print Settings tab -> Notes)
{ {
std::list<std::string> lines; 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) { for (auto line : lines) {
// Remove the trailing '\r' from the '\r\n' sequence. // Remove the trailing '\r' from the '\r\n' sequence.
if (! line.empty() && line.back() == '\r') 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(); print.throw_if_canceled();
// Write some terse information on the slicing parameters. // Write some terse information on the slicing parameters.
const PrintObject *first_object = print.objects.front(); const PrintObject *first_object = print.objects().front();
const double layer_height = first_object->config.layer_height.value; 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); 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) { for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
auto region = print.regions[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, "; 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, "; 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); _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); _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()) if (print.has_support_material())
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width); _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, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width);
_write_format(file, "\n"); _write_format(file, "\n");
} }
print.throw_if_canceled(); print.throw_if_canceled();
// Prepare the helper object for replacing placeholders in custom G-code and output filename. // 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(); m_placeholder_parser.update_timestamp();
// Get optimal tool ordering to minimize tool switches of a multi-exruder print. // 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; unsigned int final_extruder_id = (unsigned int)-1;
size_t initial_print_object_id = 0; size_t initial_print_object_id = 0;
bool has_wipe_tower = false; 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. // 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) { for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) {
tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id); tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id);
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
break; break;
} }
} else { } else {
// Find tool ordering for all the objects at once, and the initial extruder ID. // 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. // 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) : ToolOrdering(print, initial_extruder_id) :
print.m_tool_ordering; print.wipe_tower_data().tool_ordering;
initial_extruder_id = tool_ordering.first_extruder(); initial_extruder_id = tool_ordering.first_extruder();
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); 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); m_cooling_buffer->set_current_extruder(initial_extruder_id);
// Disable fan. // 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)); _write(file, m_writer.set_fan(0, true));
// Let the start-up script prime the 1st printing tool. // 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); 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. // 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); 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. // 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); 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 // Write the custom start G-code
_writeln(file, start_gcode); _writeln(file, start_gcode);
// Process filament-specific gcode in extruder order. // 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) { if (has_wipe_tower) {
// Wipe tower will control the extruder switching, it will call the start_filament_gcode. // Wipe tower will control the extruder switching, it will call the start_filament_gcode.
} else { } else {
// Only initialize the initial extruder. // 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 { } else {
for (const std::string &start_gcode : print.config.start_filament_gcode.values) 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()))); _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); this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
print.throw_if_canceled(); print.throw_if_canceled();
@ -634,12 +634,12 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write(file, this->preamble()); _write(file, this->preamble());
// Initialize a motion planner for object-to-object travel moves. // 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. // Collect outer contours of all objects over all layers.
// Discard objects only containing thin walls (offset would fail on an empty polygon). // Discard objects only containing thin walls (offset would fail on an empty polygon).
Polygons islands; Polygons islands;
for (const PrintObject *object : print.objects) for (const PrintObject *object : print.objects())
for (const Layer *layer : object->layers) for (const Layer *layer : object->layers())
for (const ExPolygon &expoly : layer->slices.expolygons) for (const ExPolygon &expoly : layer->slices.expolygons)
for (const Point &copy : object->_shifted_copies) { for (const Point &copy : object->_shifted_copies) {
islands.emplace_back(expoly.contour); 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 // 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; 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) for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
append(skirt_points, path.polyline.points); append(skirt_points, path.polyline.points);
if (! skirt_points.empty()) { if (! skirt_points.empty()) {
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
Polygons skirts; Polygons skirts;
for (unsigned int extruder_id : print.extruders()) { 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); Polygon s(outer_skirt);
s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y)); s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y));
skirts.emplace_back(std::move(s)); 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)); _write(file, this->set_extruder(initial_extruder_id));
// Do all objects for each layer. // 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 // Print objects from the smallest to the tallest to avoid collisions
// when moving onto next object starting point. // 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; }); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });
size_t finished_objects = 0; size_t finished_objects = 0;
for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { 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 // another one, set first layer temperatures. This happens before the Z move
// is triggered, so machine has more time to reach such temperatures. // is triggered, so machine has more time to reach such temperatures.
m_placeholder_parser.set("current_object_idx", int(finished_objects)); 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. // 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_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); 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. // Order objects using a nearest neighbor search.
std::vector<size_t> object_indices; std::vector<size_t> object_indices;
Points object_reference_points; Points object_reference_points;
for (PrintObject *object : print.objects) for (PrintObject *object : print.objects())
object_reference_points.push_back(object->_shifted_copies.front()); object_reference_points.push_back(object->_shifted_copies.front());
Slic3r::Geometry::chained_path(object_reference_points, object_indices); Slic3r::Geometry::chained_path(object_reference_points, object_indices);
// Sort layers by Z. // 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); std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> layers_to_print = collect_layers_to_print(print);
// Prusa Multi-Material wipe tower. // Prusa Multi-Material wipe tower.
if (has_wipe_tower && ! layers_to_print.empty()) { 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_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)); _write(file, m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions. // Verify, whether the print overaps the priming extrusions.
BoundingBoxf bbox_print(get_print_extrusions_extents(print)); 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; 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_print_object_extrusions_extents(*print_object, twolayers_printz));
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); 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. // 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. // 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 { } else {
for (const std::string &end_gcode : print.config.end_filament_gcode.values) 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_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.update_progress(m_layer_count, m_layer_count, true)); // 100%
_write(file, m_writer.postamble()); _write(file, m_writer.postamble());
print.throw_if_canceled(); print.throw_if_canceled();
@ -829,31 +829,27 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_time_estimator.calculate_time(); m_time_estimator.calculate_time();
// Get filament stats. // Get filament stats.
print.filament_stats.clear(); print.m_print_statistics.clear();
print.total_used_filament = 0.; print.m_print_statistics.estimated_print_time = m_time_estimator.get_time_hms();
print.total_extruded_volume = 0.;
print.total_weight = 0.;
print.total_cost = 0.;
print.estimated_print_time = m_time_estimator.get_time_hms();
for (const Extruder &extruder : m_writer.extruders()) { for (const Extruder &extruder : m_writer.extruders()) {
double used_filament = extruder.used_filament(); double used_filament = extruder.used_filament();
double extruded_volume = extruder.extruded_volume(); double extruded_volume = extruder.extruded_volume();
double filament_weight = extruded_volume * extruder.filament_density() * 0.001; double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
double filament_cost = filament_weight * extruder.filament_cost() * 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); _write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001);
if (filament_weight > 0.) { 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); _write_format(file, "; filament used = %.1lf\n", filament_weight);
if (filament_cost > 0.) { 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); _write_format(file, "; filament cost = %.1lf\n", filament_cost);
} }
} }
print.total_used_filament = print.total_used_filament + used_filament; print.m_print_statistics.total_used_filament = print.m_print_statistics.total_used_filament + used_filament;
print.total_extruded_volume = print.total_extruded_volume + extruded_volume; 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()); _write_format(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms().c_str());
// Append full config. // 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); return m_placeholder_parser.process(templ, current_extruder_id, config_override);
} catch (std::runtime_error &err) { } catch (std::runtime_error &err) {
// Collect the names of failed template substitutions for error reporting. // 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. // Insert the macro error message into the G-code.
return return
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" + 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) 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. // 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? // Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1; int temp_by_gcode = -1;
bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode); 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; int temp_by_gcode = -1;
if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) { 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. // 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) if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
temp = temp_by_gcode; temp = temp_by_gcode;
m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id); m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id);
} else { } else {
// Custom G-code does not set the extruder temperature. Do it now. // 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. // 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) if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id)); _write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id));
} else { } else {
// Set temperatures of all the printing extruders. // Set temperatures of all the printing extruders.
for (unsigned int tool_id : print.extruders()) { for (unsigned int tool_id : print.extruders()) {
int temp = print.config.first_layer_temperature.get_at(tool_id); int temp = print.config().first_layer_temperature.get_at(tool_id);
if (print.config.ooze_prevention.value) if (print.config().ooze_prevention.value)
temp += print.config.standby_temperature_delta.value; temp += print.config().standby_temperature_delta.value;
if (temp > 0) if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, tool_id)); _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(); unsigned int first_extruder_id = layer_tools.extruders.front();
// Initialize config with the 1st object to be printed at this layer. // 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. // 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. // 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) { 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) { if (enable) {
for (const LayerRegion *layer_region : layer.regions) for (const LayerRegion *layer_region : layer.regions())
if (layer_region->region()->config.bottom_solid_layers.value > layer.id() || if (layer_region->region()->config().bottom_solid_layers.value > layer.id() ||
layer_region->perimeters.items_count() > 1 || layer_region->perimeters.items_count() > 1 ||
layer_region->fills.items_count() > 0) { layer_region->fills.items_count() > 0) {
enable = false; enable = false;
@ -1084,22 +1080,22 @@ void GCode::process_layer(
std::string gcode; std::string gcode;
// Set new layer - this will change Z and force a retraction if retract_layer_change is enabled. // 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; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("before_layer_gcode", 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"; + "\n";
} }
gcode += this->change_layer(print_z); // this will increase m_layer_index gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer; m_layer = &layer;
if (! print.config.layer_gcode.value.empty()) { if (! print.config().layer_gcode.value.empty()) {
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("layer_gcode", 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"; + "\n";
} }
@ -1107,14 +1103,14 @@ void GCode::process_layer(
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
// first_layer_temperature vs. temperature settings. // first_layer_temperature vs. temperature settings.
for (const Extruder &extruder : m_writer.extruders()) { 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. // In single extruder multi material mode, set the temperature for the current extruder only.
continue; continue;
int temperature = print.config.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())) 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_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. // Mark the temperature transition from 1st to 2nd layer to be finished.
m_second_layer_things_done = true; 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 // 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. // not at the print_z of the interlaced support material layers.
bool extrude_skirt = bool extrude_skirt =
! print.skirt.entities.empty() && ! print.skirt().entities.empty() &&
// Not enough skirt layers printed yet. // 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 // This print_z has not been extruded yet
(m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON && (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. // 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; extruder_ids.front() = first_extruder_id;
break; break;
} }
size_t n_loops = print.skirt.entities.size(); size_t n_loops = print.skirt().entities.size();
if (n_loops <= extruder_ids.size()) { if (n_loops <= extruder_ids.size()) {
for (size_t i = 0; i < n_loops; ++i) 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); 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 } else
// Extrude all skirts with the current extruder. // 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. // 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_support = role == erMixed || role == erSupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface; bool has_interface = role == erMixed || role == erSupportMaterialInterface;
// Extruder ID of the support base. -1 if "don't care". // 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? // 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". // 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? // 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) { if (support_dontcare || interface_dontcare) {
// Some support will be printed with "don't care" material, preferably non-soluble. // Some support will be printed with "don't care" material, preferably non-soluble.
// Is the current extruder assigned a soluble filament? // Is the current extruder assigned a soluble filament?
unsigned int dontcare_extruder = first_extruder_id; 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. // The last extruder printed on the previous layer extrudes soluble filament.
// Try to find a non-soluble extruder on the same layer. // Try to find a non-soluble extruder on the same layer.
for (unsigned int extruder_id : layer_tools.extruders) 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; dontcare_extruder = extruder_id;
break; break;
} }
@ -1242,11 +1238,11 @@ void GCode::process_layer(
layer.slices.expolygons[i].contour.contains(point); layer.slices.expolygons[i].contour.contains(point);
}; };
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
const LayerRegion *layerm = layer.regions[region_id]; const LayerRegion *layerm = layer.regions()[region_id];
if (layerm == nullptr) if (layerm == nullptr)
continue; continue;
const PrintRegion &region = *print.regions[region_id]; const PrintRegion &region = *print.regions()[region_id];
// process perimeters // process perimeters
for (const ExtrusionEntity *ee : layerm->perimeters.entities) { 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. // Init by_extruder item only if we actually use the extruder.
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder( std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
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(), &layer_to_print - layers.data(),
layers.size(), n_slices+1); layers.size(), n_slices+1);
for (size_t i = 0; i <= n_slices; ++ i) 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 // perimeter_coll->first_point fits inside ith slice
point_inside_surface(i, perimeter_coll->first_point())) { point_inside_surface(i, perimeter_coll->first_point())) {
if (islands[i].by_region.empty()) 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); islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities);
break; break;
} }
@ -1285,7 +1281,7 @@ void GCode::process_layer(
// This shouldn't happen but first_point() would fail. // This shouldn't happen but first_point() would fail.
continue; continue;
// init by_extruder item only if we actually use the extruder // 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. // Init by_extruder item only if we actually use the extruder.
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder( std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
by_extruder, by_extruder,
@ -1298,7 +1294,7 @@ void GCode::process_layer(
// fill->first_point fits inside ith slice // fill->first_point fits inside ith slice
point_inside_surface(i, fill->first_point())) { point_inside_surface(i, fill->first_point())) {
if (islands[i].by_region.empty()) 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); islands[i].by_region[region_id].infills.append(fill->entities);
break; break;
} }
@ -1324,7 +1320,7 @@ void GCode::process_layer(
Flow skirt_flow = print.skirt_flow(); Flow skirt_flow = print.skirt_flow();
for (size_t i = loops.first; i < loops.second; ++ i) { for (size_t i = loops.first; i < loops.second; ++ i) {
// Adjust flow according to this layer's layer height. // 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); Flow layer_skirt_flow(skirt_flow);
layer_skirt_flow.height = (float)skirt_height; layer_skirt_flow.height = (float)skirt_height;
double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
@ -1345,7 +1341,7 @@ void GCode::process_layer(
if (! m_brim_done) { if (! m_brim_done) {
this->set_origin(0., 0.); this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp = true; 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); gcode += this->extrude_loop(*dynamic_cast<const ExtrusionLoop*>(ee), "brim", m_config.support_material_speed.value);
m_brim_done = true; m_brim_done = true;
m_avoid_crossing_perimeters.use_external_mp = false; 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. // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
continue; continue;
m_config.apply(print_object->config, true); m_config.apply(print_object->config(), true);
m_layer = layers[layer_id].layer(); m_layer = layers[layer_id].layer();
if (m_config.avoid_crossing_perimeters) if (m_config.avoid_crossing_perimeters)
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true)); 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(); m_layer = layers[layer_id].layer();
} }
for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { 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_infill(print, island.by_region);
gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]);
} else { } 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) 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) { for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) {
const StaticPrintConfig *cfg = configs[i]; const StaticPrintConfig *cfg = configs[i];
for (const std::string &key : cfg->keys()) 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; std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) { 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) for (ExtrusionEntity *ee : region.perimeters.entities)
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid); 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; std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) { 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); ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false);
for (ExtrusionEntity *fill : chained.entities) { for (ExtrusionEntity *fill : chained.entities) {
auto *eec = dynamic_cast<ExtrusionEntityCollection*>(fill); 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 get_print_extrusions_extents(const Print &print)
{ {
BoundingBoxf bbox(extrusionentity_extents(print.brim)); BoundingBoxf bbox(extrusionentity_extents(print.brim()));
bbox.merge(extrusionentity_extents(print.skirt)); bbox.merge(extrusionentity_extents(print.skirt()));
return bbox; return bbox;
} }
BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z) BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z)
{ {
BoundingBoxf bbox; BoundingBoxf bbox;
for (const Layer *layer : print_object.layers) { for (const Layer *layer : print_object.layers()) {
if (layer->print_z > max_print_z) if (layer->print_z > max_print_z)
break; break;
BoundingBoxf bbox_this; BoundingBoxf bbox_this;
for (const LayerRegion *layerm : layer->regions) { for (const LayerRegion *layerm : layer->regions()) {
bbox_this.merge(extrusionentity_extents(layerm->perimeters)); bbox_this.merge(extrusionentity_extents(layerm->perimeters));
for (const ExtrusionEntity *ee : layerm->fills.entities) for (const ExtrusionEntity *ee : layerm->fills.entities)
// fill represents infill extrusions of a single island. // 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 get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z)
{ {
BoundingBoxf bbox; 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) if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z)
break; break;
for (const WipeTower::ToolChangeResult &tcr : tool_changes) { 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 get_wipe_tower_priming_extrusions_extents(const Print &print)
{ {
BoundingBoxf bbox; BoundingBoxf bbox;
if (print.m_wipe_tower_priming) { if (print.wipe_tower_data().priming != nullptr) {
const WipeTower::ToolChangeResult &tcr = *print.m_wipe_tower_priming.get(); const WipeTower::ToolChangeResult &tcr = *print.wipe_tower_data().priming;
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) { for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
const WipeTower::Extrusion &e = tcr.extrusions[i]; const WipeTower::Extrusion &e = tcr.extrusions[i];
if (e.width > 0) { if (e.width > 0) {

View file

@ -16,19 +16,19 @@
namespace Slic3r { namespace Slic3r {
// For the use case when each object is printed separately // 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) ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
{ {
if (object.layers.empty()) if (object.layers().empty())
return; return;
// Initialize the print layers for just a single object. // Initialize the print layers for just a single object.
{ {
std::vector<coordf_t> zs; std::vector<coordf_t> zs;
zs.reserve(zs.size() + object.layers.size() + object.support_layers.size()); zs.reserve(zs.size() + object.layers().size() + object.support_layers().size());
for (auto layer : object.layers) for (auto layer : object.layers())
zs.emplace_back(layer->print_z); zs.emplace_back(layer->print_z);
for (auto layer : object.support_layers) for (auto layer : object.support_layers())
zs.emplace_back(layer->print_z); zs.emplace_back(layer->print_z);
this->initialize_layers(zs); this->initialize_layers(zs);
} }
@ -39,39 +39,39 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// Reorder the extruders to minimize tool switches. // Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder); 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); this->collect_extruder_statistics(prime_multi_material);
} }
// For the use case when all objects are printed at once. // 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) ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
{ {
// Initialize the print layers for all objects and all layers. // Initialize the print layers for all objects and all layers.
coordf_t object_bottom_z = 0.; coordf_t object_bottom_z = 0.;
{ {
std::vector<coordf_t> zs; std::vector<coordf_t> zs;
for (auto object : print.objects) { for (auto object : print.objects()) {
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
for (auto layer : object->layers) for (auto layer : object->layers())
zs.emplace_back(layer->print_z); zs.emplace_back(layer->print_z);
for (auto layer : object->support_layers) for (auto layer : object->support_layers())
zs.emplace_back(layer->print_z); zs.emplace_back(layer->print_z);
if (! object->layers.empty()) if (! object->layers().empty())
object_bottom_z = object->layers.front()->print_z - object->layers.front()->height; object_bottom_z = object->layers().front()->print_z - object->layers().front()->height;
} }
this->initialize_layers(zs); this->initialize_layers(zs);
} }
// Collect extruders reuqired to print the layers. // Collect extruders reuqired to print the layers.
for (auto object : print.objects) for (auto object : print.objects())
this->collect_extruders(*object); this->collect_extruders(*object);
// Reorder the extruders to minimize tool switches. // Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder); 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); 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) void ToolOrdering::collect_extruders(const PrintObject &object)
{ {
// Collect the support extruders. // 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); LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
ExtrusionRole role = support_layer->support_fills.role(); ExtrusionRole role = support_layer->support_fills.role();
bool has_support = role == erMixed || role == erSupportMaterial; bool has_support = role == erMixed || role == erSupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface; bool has_interface = role == erMixed || role == erSupportMaterialInterface;
unsigned int extruder_support = object.config.support_material_extruder.value; unsigned int extruder_support = object.config().support_material_extruder.value;
unsigned int extruder_interface = object.config.support_material_interface_extruder.value; unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
if (has_support) if (has_support)
layer_tools.extruders.push_back(extruder_support); layer_tools.extruders.push_back(extruder_support);
if (has_interface) if (has_interface)
@ -126,16 +126,16 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
layer_tools.has_support = true; layer_tools.has_support = true;
} }
// Collect the object extruders. // Collect the object extruders.
for (auto layer : object.layers) { for (auto layer : object.layers()) {
LayerTools &layer_tools = this->tools_for_layer(layer->print_z); LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
// What extruders are required to print this object layer? // What extruders are required to print this object layer?
for (size_t region_id = 0; region_id < object.print()->regions.size(); ++ region_id) { 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; const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr;
if (layerm == nullptr) if (layerm == nullptr)
continue; continue;
const PrintRegion &region = *object.print()->regions[region_id]; const PrintRegion &region = *object.print()->regions()[region_id];
if (! layerm->perimeters.entities.empty()) { 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; layer_tools.has_object = true;
} }
bool has_infill = false; bool has_infill = false;
@ -150,9 +150,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
has_infill = true; has_infill = true;
} }
if (has_solid_infill) 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) 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) if (has_solid_infill || has_infill)
layer_tools.has_object = true; 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->set_layer(first_layer_height, first_layer_height, tools.size(), true, false);
this->m_num_layer_changes = 0; m_num_layer_changes = 0;
this->m_current_tool = tools.front(); m_current_tool = tools.front();
// The Prusa i3 MK2 has a working space of [0, -2.2] to [250, 210]. // 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, // 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) { if (last_wipe_inside_wipe_tower) {
// Shrink the last wipe area to the area of the other purge areas, // 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. // 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)); 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.lu.y -= m_initial_extra_wipe;
cleaning_box.ru.y -= this->m_initial_extra_wipe; cleaning_box.ru.y -= m_initial_extra_wipe;
} }
toolchange_Wipe(writer, cleaning_box, false); toolchange_Wipe(writer, cleaning_box, false);
} else { } else {
@ -471,8 +471,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
m_idx_tool_change_in_layer = (unsigned int)(-1); m_idx_tool_change_in_layer = (unsigned int)(-1);
ToolChangeResult result; ToolChangeResult result;
result.print_z = this->m_z_pos; result.print_z = m_z_pos;
result.layer_height = this->m_layer_height; result.layer_height = m_layer_height;
result.gcode = writer.gcode(); result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time(); result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions(); result.extrusions = writer.extrusions();
@ -612,8 +612,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
} }
ToolChangeResult result; ToolChangeResult result;
result.print_z = this->m_z_pos; result.print_z = m_z_pos;
result.layer_height = this->m_layer_height; result.layer_height = m_layer_height;
result.gcode = writer.gcode(); result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time(); result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions(); result.extrusions = writer.extrusions();
@ -718,8 +718,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b
} }
ToolChangeResult result; ToolChangeResult result;
result.print_z = this->m_z_pos; result.print_z = m_z_pos;
result.layer_height = this->m_layer_height; result.layer_height = m_layer_height;
result.gcode = writer.gcode(); result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time(); result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions(); result.extrusions = writer.extrusions();
@ -1040,8 +1040,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer(Purpose purpose)
} }
ToolChangeResult result; ToolChangeResult result;
result.print_z = this->m_z_pos; result.print_z = m_z_pos;
result.layer_height = this->m_layer_height; result.layer_height = m_layer_height;
result.gcode = writer.gcode(); result.gcode = writer.gcode();
result.elapsed_time = writer.elapsed_time(); result.elapsed_time = writer.elapsed_time();
result.extrusions = writer.extrusions(); result.extrusions = writer.extrusions();

View file

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

View file

@ -15,16 +15,13 @@ class Layer;
class PrintRegion; class PrintRegion;
class PrintObject; class PrintObject;
// TODO: make stuff private
class LayerRegion class LayerRegion
{ {
friend class Layer;
public: public:
Layer* layer() { return this->_layer; } Layer* layer() { return m_layer; }
const Layer* layer() const { return this->_layer; } const Layer* layer() const { return m_layer; }
PrintRegion* region() { return this->_region; } PrintRegion* region() { return m_region; }
const PrintRegion* region() const { return this->_region; } const PrintRegion* region() const { return m_region; }
// collection of surfaces generated by slicing the original geometry // collection of surfaces generated by slicing the original geometry
// divided by type top/bottom/internal // divided by type top/bottom/internal
@ -77,29 +74,30 @@ public:
// Is there any valid extrusion assigned to this LayerRegion? // Is there any valid extrusion assigned to this LayerRegion?
bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); } bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); }
private: protected:
Layer *_layer; friend class Layer;
PrintRegion *_region;
LayerRegion(Layer *layer, PrintRegion *region) : _layer(layer), _region(region) {} LayerRegion(Layer *layer, PrintRegion *region) : m_layer(layer), m_region(region) {}
~LayerRegion() {} ~LayerRegion() {}
private:
Layer *m_layer;
PrintRegion *m_region;
}; };
typedef std::vector<LayerRegion*> LayerRegionPtrs; typedef std::vector<LayerRegion*> LayerRegionPtrs;
class Layer { class Layer
friend class PrintObject; {
public: public:
size_t id() const { return this->_id; } size_t id() const { return m_id; }
void set_id(size_t id) { this->_id = id; } void set_id(size_t id) { m_id = id; }
PrintObject* object() { return this->_object; } PrintObject* object() { return m_object; }
const PrintObject* object() const { return this->_object; } const PrintObject* object() const { return m_object; }
Layer *upper_layer; Layer *upper_layer;
Layer *lower_layer; Layer *lower_layer;
LayerRegionPtrs regions;
bool slicing_errors; bool slicing_errors;
coordf_t slice_z; // Z used for slicing in unscaled coordinates coordf_t slice_z; // Z used for slicing in unscaled coordinates
coordf_t print_z; // Z used for printing 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. // order will be recovered by the G-code generator.
ExPolygonCollection slices; ExPolygonCollection slices;
size_t region_count() const { return this->regions.size(); } size_t region_count() const { return m_regions.size(); }
const LayerRegion* get_region(int idx) const { return this->regions.at(idx); } const LayerRegion* get_region(int idx) const { return m_regions.at(idx); }
LayerRegion* get_region(int idx) { return this->regions.at(idx); } LayerRegion* get_region(int idx) { return m_regions[idx]; }
LayerRegion* add_region(PrintRegion* print_region); LayerRegion* add_region(PrintRegion* print_region);
const LayerRegionPtrs& regions() const { return m_regions; }
void make_slices(); void make_slices();
void merge_slices(); void merge_slices();
template <class T> bool any_internal_region_slice_contains(const T &item) const { 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; return false;
} }
template <class T> bool any_bottom_region_slice_contains(const T &item) const { 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; return false;
} }
void make_perimeters(); void make_perimeters();
@ -136,22 +135,26 @@ public:
void export_region_fill_surfaces_to_svg_debug(const char *name) const; void export_region_fill_surfaces_to_svg_debug(const char *name) const;
// Is there any valid extrusion assigned to this LayerRegion? // 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: protected:
size_t _id; // sequential number of layer, 0-based friend class PrintObject;
PrintObject *_object;
Layer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : 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), upper_layer(nullptr), lower_layer(nullptr), slicing_errors(false),
slice_z(slice_z), print_z(print_z), height(height), slice_z(slice_z), print_z(print_z), height(height),
_id(id), _object(object) {} m_id(id), m_object(object) {}
virtual ~Layer(); virtual ~Layer();
private:
// sequential number of layer, 0-based
size_t m_id;
PrintObject *m_object;
LayerRegionPtrs m_regions;
}; };
class SupportLayer : public Layer { class SupportLayer : public Layer
friend class PrintObject; {
public: public:
// Polygons covered by the supports: base, interface and contact areas. // Polygons covered by the supports: base, interface and contact areas.
ExPolygonCollection support_islands; ExPolygonCollection support_islands;
@ -161,7 +164,9 @@ public:
// Is there any valid extrusion assigned to this LayerRegion? // Is there any valid extrusion assigned to this LayerRegion?
virtual bool has_extrusions() const { return ! support_fills.empty(); } 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 // 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. // 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) : 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 Flow
LayerRegion::flow(FlowRole role, bool bridge, double width) const LayerRegion::flow(FlowRole role, bool bridge, double width) const
{ {
return this->_region->flow( return m_region->flow(
role, role,
this->_layer->height, m_layer->height,
bridge, bridge,
this->_layer->id() == 0, m_layer->id() == 0,
width, width,
*this->_layer->object() *m_layer->object()
); );
} }
@ -61,9 +61,9 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
&slices, &slices,
this->layer()->height, this->layer()->height,
this->flow(frPerimeter), this->flow(frPerimeter),
&this->region()->config, &this->region()->config(),
&this->layer()->object()->config, &this->layer()->object()->config(),
&this->layer()->object()->print()->config, &this->layer()->object()->print()->config(),
// output: // output:
&this->perimeters, &this->perimeters,
@ -116,7 +116,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
{ {
// bottom_polygons are used to trim inflated top surfaces. // bottom_polygons are used to trim inflated top surfaces.
fill_boundaries.reserve(number_polygons(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) { for (const Surface &surface : this->fill_surfaces.surfaces) {
if (surface.surface_type == stTop) { if (surface.surface_type == stTop) {
// Collect the top surfaces, inflate them and trim them by the bottom surfaces. // 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 #ifdef SLIC3R_DEBUG
printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id());
#endif #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; 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()); polygons_append(this->bridged, bd.coverage());
this->unsupported_bridge_edges.append(bd.unsupported_edges()); this->unsupported_bridge_edges.append(bd.unsupported_edges());
} }
@ -351,13 +351,13 @@ void LayerRegion::prepare_fill_surfaces()
the only meaningful information returned by psPerimeters. */ the only meaningful information returned by psPerimeters. */
// if no solid layers are requested, turn top/bottom surfaces to internal // 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) for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
if (surface->surface_type == stTop) 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; 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) { 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) if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
surface->surface_type = stInternal; 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 // 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! // 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) { 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) if (surface->surface_type == stInternal && surface->area() <= min_area)
surface->surface_type = stInternalSolid; surface->surface_type = stInternalSolid;

View file

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

View file

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

View file

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

View file

@ -14,7 +14,6 @@ class PlaceholderParser
public: public:
PlaceholderParser(); PlaceholderParser();
void update_timestamp();
void apply_config(const DynamicPrintConfig &config); void apply_config(const DynamicPrintConfig &config);
void apply_env_variables(); void apply_env_variables();
@ -37,6 +36,11 @@ public:
// Throws std::runtime_error on syntax or runtime error. // 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); 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: private:
DynamicConfig m_config; DynamicConfig m_config;
}; };

View file

@ -20,24 +20,27 @@ template class PrintState<PrintObjectStep, posCount>;
void Print::clear_objects() 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); this->delete_object(i);
for (PrintRegion *region : this->regions) for (PrintRegion *region : m_regions)
delete region; delete region;
this->regions.clear(); m_regions.clear();
} }
void Print::delete_object(size_t idx) void Print::delete_object(size_t idx)
{ {
tbb::mutex::scoped_lock lock(m_mutex);
// destroy object and remove it from our container // destroy object and remove it from our container
delete this->objects[idx]; delete m_objects[idx];
this->objects.erase(this->objects.begin() + idx); m_objects.erase(m_objects.begin() + idx);
this->invalidate_all_steps(); this->invalidate_all_steps();
// TODO: purge unused regions // TODO: purge unused regions
} }
void Print::reload_object(size_t /* idx */) 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 /* 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 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() 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 // collect all current model objects
ModelObjectPtrs model_objects; ModelObjectPtrs model_objects;
model_objects.reserve(this->objects.size()); model_objects.reserve(m_objects.size());
for (PrintObject *object : this->objects) for (PrintObject *object : m_objects)
model_objects.push_back(object->model_object()); model_objects.push_back(object->model_object());
// remove our print objects // remove our print objects
this->clear_objects(); this->clear_objects();
@ -63,15 +66,21 @@ void Print::reload_object(size_t /* idx */)
bool Print::reload_model_instances() bool Print::reload_model_instances()
{ {
bool invalidated = false; bool invalidated = false;
for (PrintObject *object : this->objects) for (PrintObject *object : m_objects)
invalidated |= object->reload_model_instances(); invalidated |= object->reload_model_instances();
return invalidated; return invalidated;
} }
PrintRegion* Print::add_region() PrintRegion* Print::add_region()
{ {
regions.push_back(new PrintRegion(this)); m_regions.emplace_back(new PrintRegion(this));
return regions.back(); 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(). // 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); invalidated |= this->invalidate_step(step);
sort_remove_duplicates(osteps); sort_remove_duplicates(osteps);
for (PrintObjectStep ostep : osteps) for (PrintObjectStep ostep : osteps)
for (PrintObject *object : this->objects) for (PrintObject *object : m_objects)
invalidated |= object->invalidate_step(ostep); invalidated |= object->invalidate_step(ostep);
return invalidated; return invalidated;
} }
bool Print::invalidate_step(PrintStep step) 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. // Propagate to dependent steps.
//FIXME Why should skirt invalidate brim? Shouldn't it be vice versa? //FIXME Why should skirt invalidate brim? Shouldn't it be vice versa?
if (step == psSkirt) if (step == psSkirt)
invalidated |= m_state.invalidate(psBrim); invalidated |= m_state.invalidate(psBrim, m_mutex, m_cancel_callback);
return invalidated; return invalidated;
} }
@ -243,9 +252,9 @@ bool Print::invalidate_step(PrintStep step)
// and there's at least one object // and there's at least one object
bool Print::is_step_done(PrintObjectStep step) const bool Print::is_step_done(PrintObjectStep step) const
{ {
if (this->objects.empty()) if (m_objects.empty())
return false; return false;
for (const PrintObject *object : this->objects) for (const PrintObject *object : m_objects)
if (!object->m_state.is_done(step)) if (!object->m_state.is_done(step))
return false; return false;
return true; return true;
@ -256,15 +265,15 @@ std::vector<unsigned int> Print::object_extruders() const
{ {
std::vector<unsigned int> extruders; 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 // these checks reflect the same logic used in the GUI for enabling/disabling
// extruder selection fields // extruder selection fields
if (region->config.perimeters.value > 0 || this->config.brim_width.value > 0) if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0)
extruders.push_back(region->config.perimeter_extruder - 1); extruders.push_back(region->config().perimeter_extruder - 1);
if (region->config.fill_density.value > 0) if (region->config().fill_density.value > 0)
extruders.push_back(region->config.infill_extruder - 1); extruders.push_back(region->config().infill_extruder - 1);
if (region->config.top_solid_layers.value > 0 || region->config.bottom_solid_layers.value > 0) if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0)
extruders.push_back(region->config.solid_infill_extruder - 1); extruders.push_back(region->config().solid_infill_extruder - 1);
} }
sort_remove_duplicates(extruders); sort_remove_duplicates(extruders);
@ -277,16 +286,16 @@ std::vector<unsigned int> Print::support_material_extruders() const
std::vector<unsigned int> extruders; std::vector<unsigned int> extruders;
bool support_uses_current_extruder = false; bool support_uses_current_extruder = false;
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
if (object->has_support_material()) { if (object->has_support_material()) {
if (object->config.support_material_extruder == 0) if (object->config().support_material_extruder == 0)
support_uses_current_extruder = true; support_uses_current_extruder = true;
else else
extruders.push_back(object->config.support_material_extruder - 1); extruders.push_back(object->config().support_material_extruder - 1);
if (object->config.support_material_interface_extruder == 0) if (object->config().support_material_interface_extruder == 0)
support_uses_current_extruder = true; support_uses_current_extruder = true;
else 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) void Print::_simplify_slices(double distance)
{ {
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
for (Layer *layer : object->layers) { for (Layer *layer : object->m_layers) {
layer->slices.simplify(distance); layer->slices.simplify(distance);
for (LayerRegion *layerm : layer->regions) for (LayerRegion *layerm : layer->regions())
layerm->slices.simplify(distance); layerm->slices.simplify(distance);
} }
} }
@ -322,7 +331,7 @@ double Print::max_allowed_layer_height() const
{ {
double nozzle_diameter_max = 0.; double nozzle_diameter_max = 0.;
for (unsigned int extruder_id : this->extruders()) 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; 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. // Initialize a new print object and store it at the given position.
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box()); PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
if (idx != -1) { if (idx != -1) {
delete this->objects[idx]; delete m_objects[idx];
this->objects[idx] = object; m_objects[idx] = object;
} else } else
this->objects.emplace_back(object); m_objects.emplace_back(object);
// Invalidate all print steps. // Invalidate all print steps.
this->invalidate_all_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]); PrintRegionConfig config = this->_region_config_from_model_volume(*model_object->volumes[volume_id]);
// Find an existing print region with the same config. // Find an existing print region with the same config.
size_t region_id = size_t(-1); size_t region_id = size_t(-1);
for (size_t i = 0; i < this->regions.size(); ++ i) for (size_t i = 0; i < m_regions.size(); ++ i)
if (config.equals(this->regions[i]->config)) { if (config.equals(m_regions[i]->config())) {
region_id = i; region_id = i;
break; break;
} }
// If no region exists with the same config, create a new one. // If no region exists with the same config, create a new one.
if (region_id == size_t(-1)) { if (region_id == size_t(-1)) {
region_id = this->regions.size(); region_id = this->regions().size();
this->add_region()->config.apply(config); this->add_region(config);
} }
// Assign volume to a region. // Assign volume to a region.
object->add_region_volume(region_id, volume_id); object->add_region_volume(region_id, volume_id);
} }
// Apply config to print object. // Apply config to print object.
object->config.apply(this->default_object_config); object->config_apply(this->default_object_config());
normalize_and_apply_config(object->config, model_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 // update placeholders
{ {
// get the first input file name // get the first input file name
std::string input_file; std::string input_file;
std::vector<std::string> v_scale; std::vector<std::string> v_scale;
for (const PrintObject *object : this->objects) { for (const PrintObject *object : m_objects) {
const ModelObject &mobj = *object->model_object(); const ModelObject &mobj = *object->model_object();
v_scale.push_back(boost::lexical_cast<std::string>(mobj.instances[0]->scaling_factor*100) + "%"); v_scale.push_back(boost::lexical_cast<std::string>(mobj.instances[0]->scaling_factor*100) + "%");
if (input_file.empty()) if (input_file.empty())
input_file = mobj.input_file; input_file = mobj.input_file;
} }
PlaceholderParser &pp = this->placeholder_parser; PlaceholderParser &pp = m_placeholder_parser;
pp.set("scale", v_scale); pp.set("scale", v_scale);
if (! input_file.empty()) { if (! input_file.empty()) {
// get basename with and without suffix // get basename with and without suffix
@ -393,19 +407,19 @@ bool Print::apply_config(DynamicPrintConfig config)
config.normalize(); config.normalize();
// apply variables to placeholder parser // apply variables to placeholder parser
this->placeholder_parser.apply_config(config); m_placeholder_parser.apply_config(config);
// handle changes to print config // handle changes to print config
t_config_option_keys print_diff = this->config.diff(config); t_config_option_keys print_diff = m_config.diff(config);
this->config.apply_only(config, print_diff, true); m_config.apply_only(config, print_diff, true);
bool invalidated = this->invalidate_state_by_config_options(print_diff); bool invalidated = this->invalidate_state_by_config_options(print_diff);
// handle changes to object config defaults // handle changes to object config defaults
this->default_object_config.apply(config, true); m_default_object_config.apply(config, true);
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
// we don't assume that config contains a full ObjectConfig, // we don't assume that config contains a full ObjectConfig,
// so we base it on the current print-wise default // 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 // we override the new config with object-specific options
normalize_and_apply_config(new_config, object->model_object()->config); 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. // 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; invalidated = true;
} }
// check whether the new config is different from the current one // check whether the new config is different from the current one
t_config_option_keys diff = object->config.diff(new_config); t_config_option_keys diff = object->config().diff(new_config);
object->config.apply_only(new_config, diff, true); object->config_apply_only(new_config, diff, true);
invalidated |= object->invalidate_state_by_config_options(diff); invalidated |= object->invalidate_state_by_config_options(diff);
} }
// handle changes to regions config defaults // 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. // All regions now have distinct settings.
// Check whether applying the new region config defaults we'd get different regions. // 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, // Collect the already visited region configs into other_region_configs,
// so one may check for duplicates. // so one may check for duplicates.
std::vector<PrintRegionConfig> other_region_configs; std::vector<PrintRegionConfig> other_region_configs;
for (size_t region_id = 0; region_id < this->regions.size(); ++ region_id) { for (size_t region_id = 0; region_id < m_regions.size(); ++ region_id) {
PrintRegion &region = *this->regions[region_id]; PrintRegion &region = *m_regions[region_id];
PrintRegionConfig this_region_config; PrintRegionConfig this_region_config;
bool this_region_config_set = false; bool this_region_config_set = false;
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
if (region_id < object->region_volumes.size()) { if (region_id < object->region_volumes.size()) {
for (int volume_id : object->region_volumes[region_id]) { for (int volume_id : object->region_volumes[region_id]) {
const ModelVolume &volume = *object->model_object()->volumes[volume_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) { 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()) { if (! diff.empty()) {
region.config.apply_only(this_region_config, diff); region.config_apply_only(this_region_config, diff, false);
for (PrintObject *object : this->objects) for (PrintObject *object : m_objects)
if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty()) if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty())
invalidated |= object->invalidate_state_by_config_options(diff); 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. // The current subdivision of regions does not make sense anymore.
// We need to remove all objects and re-add them. // We need to remove all objects and re-add them.
ModelObjectPtrs model_objects; ModelObjectPtrs model_objects;
model_objects.reserve(this->objects.size()); model_objects.reserve(m_objects.size());
for (PrintObject *object : this->objects) for (PrintObject *object : m_objects)
model_objects.push_back(object->model_object()); model_objects.push_back(object->model_object());
this->clear_objects(); this->clear_objects();
for (ModelObject *mo : model_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. // 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) if (! object->layer_height_profile_valid)
object->update_layer_height_profile(); object->update_layer_height_profile();
@ -503,32 +517,32 @@ exit_for_rearrange_regions:
bool Print::has_infinite_skirt() const bool Print::has_infinite_skirt() const
{ {
return (this->config.skirt_height == -1 && this->config.skirts > 0) return (m_config.skirt_height == -1 && m_config.skirts > 0)
|| (this->config.ooze_prevention && this->extruders().size() > 1); || (m_config.ooze_prevention && this->extruders().size() > 1);
} }
bool Print::has_skirt() const 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(); || this->has_infinite_skirt();
} }
std::string Print::validate() const std::string Print::validate() const
{ {
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values)); 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), config.max_print_height)); 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. // 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; 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))) if (! print_volume.contains(po->model_object()->tight_bounding_box(false)))
return "Some objects are outside of the print volume."; return "Some objects are outside of the print volume.";
} }
if (this->config.complete_objects) { if (m_config.complete_objects) {
// Check horizontal clearance. // Check horizontal clearance.
{ {
Polygons convex_hulls_other; 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. // Get convex hull of all meshes assigned to this print object.
Polygon convex_hull; 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. // Apply the same transformations we apply to the actual meshes when slicing them.
object->model_object()->instances.front()->transform_polygon(&convex_hull); object->model_object()->instances.front()->transform_polygon(&convex_hull);
// Grow convex hull with the clearance margin. // 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. // Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const Point &copy : object->_shifted_copies) { for (const Point &copy : object->_shifted_copies) {
Polygon p = convex_hull; Polygon p = convex_hull;
@ -556,47 +570,47 @@ std::string Print::validate() const
// Check vertical clearance. // Check vertical clearance.
{ {
std::vector<coord_t> object_height; 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); object_height.insert(object_height.end(), object->copies().size(), object->size.z);
std::sort(object_height.begin(), object_height.end()); std::sort(object_height.begin(), object_height.end());
// Ignore the tallest *copy* (this is why we repeat height for all of them): // 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. // it will be printed as last one so its height doesn't matter.
object_height.pop_back(); 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."; 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; size_t total_copies_count = 0;
for (const PrintObject *object : this->objects) for (const PrintObject *object : m_objects)
total_copies_count += object->copies().size(); total_copies_count += object->copies().size();
// #4043 // #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."; 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."; 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 #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) if (std::abs(dmr - 0.4) > EPSILON)
return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter."; return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter.";
#endif #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."; 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)."; 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(); SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters();
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
SlicingParameters slicing_params = object->slicing_parameters(); SlicingParameters slicing_params = object->slicing_parameters();
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || 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) 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"; 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()) 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"; 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"; 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)) if (! equal_layering(slicing_params, slicing_params0))
return "The Wipe Tower is only supported for multiple objects if they are sliced equally."; 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; object->layer_height_profile_valid = was_layer_height_profile_valid;
for (size_t i = 5; i < object->layer_height_profile.size(); i += 2) 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 && 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."; 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; std::vector<double> nozzle_diameters;
for (unsigned int extruder_id : extruders) 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()); double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) && if ((object->config().support_material_extruder == -1 || object->config().support_material_interface_extruder == -1) &&
(object->config.raft_layers > 0 || object->config.support_material.value)) { (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 // 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 // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
// are of the same diameter. // are of the same diameter.
@ -634,16 +648,16 @@ std::string Print::validate() const
} }
// validate first_layer_height // 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; 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 // if we have raft layers, only support material extruder is used on first layer
size_t first_layer_extruder = object->config.raft_layers == 1 size_t first_layer_extruder = object->config().raft_layers == 1
? object->config.support_material_interface_extruder-1 ? object->config().support_material_interface_extruder-1
: object->config.support_material_extruder-1; : object->config().support_material_extruder-1;
first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ? first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ?
min_nozzle_diameter : min_nozzle_diameter :
this->config.nozzle_diameter.get_at(first_layer_extruder); m_config.nozzle_diameter.get_at(first_layer_extruder);
} else { } else {
// if we don't have raft layers, any nozzle diameter is potentially used in first layer // if we don't have raft layers, any nozzle diameter is potentially used in first layer
first_layer_min_nozzle_diameter = min_nozzle_diameter; 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"; return "First layer height can't be greater than nozzle diameter";
// validate layer_height // 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"; 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 Print::bounding_box() const
{ {
BoundingBox bb; BoundingBox bb;
for (const PrintObject *object : this->objects) for (const PrintObject *object : m_objects)
for (Point copy : object->_shifted_copies) { for (Point copy : object->_shifted_copies) {
bb.merge(copy); bb.merge(copy);
copy.translate(object->size); copy.translate(object->size);
@ -683,7 +697,7 @@ BoundingBox Print::total_bounding_box() const
BoundingBox bb = this->bounding_box(); BoundingBox bb = this->bounding_box();
// we need to offset the objects bounding box by at least half the perimeters extrusion width // 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; double extra = perimeter_flow.width/2;
// consider support material // consider support material
@ -692,18 +706,18 @@ BoundingBox Print::total_bounding_box() const
} }
// consider brim and skirt // consider brim and skirt
if (this->config.brim_width.value > 0) { if (m_config.brim_width.value > 0) {
Flow brim_flow = this->brim_flow(); 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()) { 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; if (skirts == 0 && this->has_infinite_skirt()) skirts = 1;
Flow skirt_flow = this->skirt_flow(); Flow skirt_flow = this->skirt_flow();
extra = std::max( extra = std::max(
extra, extra,
this->config.brim_width.value m_config.brim_width.value
+ this->config.skirt_distance.value + m_config.skirt_distance.value
+ skirts * skirt_flow.spacing() + skirts * skirt_flow.spacing()
+ skirt_flow.width/2 + skirt_flow.width/2
); );
@ -717,17 +731,17 @@ BoundingBox Print::total_bounding_box() const
double Print::skirt_first_layer_height() const double Print::skirt_first_layer_height() const
{ {
if (this->objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects"); if (m_objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects");
return this->objects.front()->config.get_abs_value("first_layer_height"); return m_objects.front()->config().get_abs_value("first_layer_height");
} }
Flow Print::brim_flow() const 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) if (width.value == 0)
width = this->regions.front()->config.perimeter_extrusion_width; width = m_regions.front()->config().perimeter_extrusion_width;
if (width.value == 0) 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. /* We currently use a random region's perimeter extruder.
While this works for most cases, we should probably consider all of the perimeter 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( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
width, 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(), this->skirt_first_layer_height(),
0 0
); );
@ -745,11 +759,11 @@ Flow Print::brim_flow() const
Flow Print::skirt_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) if (width.value == 0)
width = this->regions.front()->config.perimeter_extrusion_width; width = m_regions.front()->config().perimeter_extrusion_width;
if (width.value == 0) 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. /* 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 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( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
width, 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(), this->skirt_first_layer_height(),
0 0
); );
@ -767,7 +781,7 @@ Flow Print::skirt_flow() const
PrintRegionConfig Print::_region_config_from_model_volume(const ModelVolume &volume) 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.get_object()->config);
normalize_and_apply_config(config, volume.config); normalize_and_apply_config(config, volume.config);
if (! volume.material_id().empty()) 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 bool Print::has_support_material() const
{ {
for (const PrintObject *object : this->objects) for (const PrintObject *object : m_objects)
if (object->has_support_material()) if (object->has_support_material())
return true; return true;
return false; return false;
@ -791,7 +805,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
if (model_object->volumes.size() < 2) if (model_object->volumes.size() < 2)
return; 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) { for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) {
ModelVolume *volume = model_object->volumes[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. //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() void Print::process()
{ {
BOOST_LOG_TRIVIAL(info) << "Staring the slicing process."; BOOST_LOG_TRIVIAL(info) << "Staring the slicing process.";
for (PrintObject *obj : this->objects) for (PrintObject *obj : m_objects)
obj->make_perimeters(); obj->make_perimeters();
this->throw_if_canceled(); this->throw_if_canceled();
this->set_status(70, "Infilling layers"); this->set_status(70, "Infilling layers");
for (PrintObject *obj : this->objects) for (PrintObject *obj : m_objects)
obj->infill(); obj->infill();
this->throw_if_canceled(); this->throw_if_canceled();
for (PrintObject *obj : this->objects) for (PrintObject *obj : m_objects)
obj->generate_support_material(); obj->generate_support_material();
this->throw_if_canceled(); this->throw_if_canceled();
if (! m_state.is_done(psSkirt)) { if (! m_state.is_done(psSkirt)) {
this->set_started(psSkirt); this->set_started(psSkirt);
this->skirt.clear(); m_skirt.clear();
if (this->has_skirt()) { if (this->has_skirt()) {
this->set_status(88, "Generating skirt"); this->set_status(88, "Generating skirt");
this->_make_skirt(); this->_make_skirt();
} }
m_state.set_done(psSkirt); this->set_done(psSkirt);
} }
this->throw_if_canceled(); this->throw_if_canceled();
if (! m_state.is_done(psBrim)) { if (! m_state.is_done(psBrim)) {
this->set_started(psBrim); this->set_started(psBrim);
this->brim.clear(); m_brim.clear();
if (this->config.brim_width > 0) { if (m_config.brim_width > 0) {
this->set_status(88, "Generating brim"); this->set_status(88, "Generating brim");
this->_make_brim(); this->_make_brim();
} }
m_state.set_done(psBrim); this->set_done(psBrim);
} }
this->throw_if_canceled(); this->throw_if_canceled();
if (! m_state.is_done(psWipeTower)) { if (! m_state.is_done(psWipeTower)) {
this->set_started(psWipeTower); this->set_started(psWipeTower);
this->_clear_wipe_tower(); m_wipe_tower_data.clear();
if (this->has_wipe_tower()) { if (this->has_wipe_tower()) {
//this->set_status(95, "Generating wipe tower"); //this->set_status(95, "Generating wipe tower");
this->_make_wipe_tower(); this->_make_wipe_tower();
} }
m_state.set_done(psWipeTower); this->set_done(psWipeTower);
} }
BOOST_LOG_TRIVIAL(info) << "Slicing process finished."; 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). // prepended to the first 'n' layers (with 'n' = skirt_height).
// $skirt_height_z in this case is the highest possible skirt height for safety. // $skirt_height_z in this case is the highest possible skirt height for safety.
coordf_t skirt_height_z = 0.; 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() ? size_t skirt_layers = this->has_infinite_skirt() ?
object->layer_count() : object->layer_count() :
std::min(size_t(this->config.skirt_height.value), object->layer_count()); std::min(size_t(m_config.skirt_height.value), object->layer_count());
skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z); 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. // Collect points from all layers contained in skirt height.
Points points; Points points;
for (const PrintObject *object : this->objects) { for (const PrintObject *object : m_objects) {
this->throw_if_canceled(); this->throw_if_canceled();
Points object_points; Points object_points;
// Get object layers up to skirt_height_z. // 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) if (layer->print_z > skirt_height_z)
break; break;
for (const ExPolygon &expoly : layer->slices.expolygons) for (const ExPolygon &expoly : layer->slices.expolygons)
@ -904,7 +918,7 @@ void Print::_make_skirt()
append(object_points, expoly.contour.points); append(object_points, expoly.contour.points);
} }
// Get support layers up to skirt_height_z. // 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) if (layer->print_z > skirt_height_z)
break; break;
for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities) 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()); extruders_e_per_mm.reserve(set_extruders.size());
for (auto &extruder_id : set_extruders) { for (auto &extruder_id : set_extruders) {
extruders.push_back(extruder_id); 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. // 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) if (this->has_infinite_skirt() && n_skirts == 0)
n_skirts = 1; n_skirts = 1;
// Initial offset of the brim inner edge from the object (possible with a support & raft). // 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. // 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. // 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. // 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.); 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 first_layer_height // this will be overridden at G-code export time
))); )));
eloop.paths.back().polyline = loop.split_at_first_point(); eloop.paths.back().polyline = loop.split_at_first_point();
this->skirt.append(eloop); m_skirt.append(eloop);
if (this->config.min_skirt_length.value > 0) { if (m_config.min_skirt_length.value > 0) {
// The skirt length is limited. Sum the total amount of filament length extruded, in mm. // 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]; 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. // Not extruded enough yet with the current extruder. Add another loop.
if (i == 1) if (i == 1)
++ i; ++ i;
} else { } 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, // Enough extruded with the current extruder. Extrude with the next one,
// until the prescribed number of skirt loops is extruded. // until the prescribed number of skirt loops is extruded.
if (extruder_idx + 1 < extruders.size()) 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. // Brims were generated inside out, reverse to print the outmost contour first.
this->skirt.reverse(); m_skirt.reverse();
} }
void Print::_make_brim() void Print::_make_brim()
@ -1006,13 +1020,13 @@ void Print::_make_brim()
// Brim is only printed on first layer and uses perimeter extruder. // Brim is only printed on first layer and uses perimeter extruder.
Flow flow = this->brim_flow(); Flow flow = this->brim_flow();
Polygons islands; Polygons islands;
for (PrintObject *object : this->objects) { for (PrintObject *object : m_objects) {
this->throw_if_canceled(); this->throw_if_canceled();
Polygons object_islands; 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); object_islands.push_back(expoly.contour);
if (! object->support_layers.empty()) if (! object->support_layers().empty())
object->support_layers.front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON)); 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()); islands.reserve(islands.size() + object_islands.size() * object->_shifted_copies.size());
for (const Point &pt : object->_shifted_copies) for (const Point &pt : object->_shifted_copies)
for (Polygon &poly : object_islands) { for (Polygon &poly : object_islands) {
@ -1021,7 +1035,7 @@ void Print::_make_brim()
} }
} }
Polygons loops; 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) { for (size_t i = 0; i < num_loops; ++ i) {
this->throw_if_canceled(); this->throw_if_canceled();
islands = offset(islands, float(flow.scaled_spacing()), jtSquare); islands = offset(islands, float(flow.scaled_spacing()), jtSquare);
@ -1037,32 +1051,24 @@ void Print::_make_brim()
loops = union_pt_chained(loops, false); loops = union_pt_chained(loops, false);
std::reverse(loops.begin(), loops.end()); 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. // Wipe tower support.
bool Print::has_wipe_tower() const bool Print::has_wipe_tower() const
{ {
return return
this->config.single_extruder_multi_material.value && m_config.single_extruder_multi_material.value &&
! this->config.spiral_vase.value && ! m_config.spiral_vase.value &&
this->config.wipe_tower.value && m_config.wipe_tower.value &&
this->config.nozzle_diameter.values.size() > 1; m_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);
} }
void Print::_make_wipe_tower() void Print::_make_wipe_tower()
{ {
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. // 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); m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
if (! m_tool_ordering.has_wipe_tower()) if (! m_wipe_tower_data.tool_ordering.has_wipe_tower())
// Don't generate any wipe tower. // Don't generate any wipe tower.
return; return;
@ -1072,33 +1078,31 @@ void Print::_make_wipe_tower()
// see https://github.com/prusa3d/Slic3r/issues/607 // see https://github.com/prusa3d/Slic3r/issues/607
{ {
size_t idx_begin = size_t(-1); 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. // 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) { 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) { if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) {
idx_begin = i; idx_begin = i;
break; break;
} }
} }
if (idx_begin != size_t(-1)) { if (idx_begin != size_t(-1)) {
// Find the position in this->objects.first()->support_layers to insert these new support layers. // Find the position in m_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; double wipe_tower_new_layer_print_z_first = m_wipe_tower_data.tool_ordering.layer_tools()[idx_begin].print_z;
SupportLayerPtrs::iterator it_layer = this->objects.front()->support_layers.begin(); SupportLayerPtrs::const_iterator it_layer = m_objects.front()->support_layers().begin();
SupportLayerPtrs::iterator it_end = this->objects.front()->support_layers.end(); 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); 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. // 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) { 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)) if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support))
break; break;
lt.has_support = true; lt.has_support = true;
// Insert the new support layer. // 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. //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(), it_layer = m_objects.front()->insert_support_layer(it_layer, size_t(-1), height, lt.print_z, lt.print_z - 0.5 * height);
height, lt.print_z, lt.print_z - 0.5 * height);
it_layer = this->objects.front()->support_layers.insert(it_layer, new_layer);
++ it_layer; ++ it_layer;
} }
} }
@ -1107,9 +1111,9 @@ void Print::_make_wipe_tower()
// Initialize the wipe tower. // Initialize the wipe tower.
WipeTowerPrusaMM wipe_tower( WipeTowerPrusaMM wipe_tower(
float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value), float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value),
float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value), float(m_config.wipe_tower_width.value), float(m_config.wipe_tower_per_color_wipe.value),
m_tool_ordering.first_extruder()); m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract(); //wipe_tower.set_retract();
//wipe_tower.set_zhop(); //wipe_tower.set_zhop();
@ -1118,29 +1122,29 @@ void Print::_make_wipe_tower()
for (size_t i = 0; i < 4; ++ i) for (size_t i = 0; i < 4; ++ i)
wipe_tower.set_extruder( wipe_tower.set_extruder(
i, i,
WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()), WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
this->config.temperature.get_at(i), m_config.temperature.get_at(i),
this->config.first_layer_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. // 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. // 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>( m_wipe_tower_data.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)); 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. // 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. // Set current_extruder_id to the last extruder primed.
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back(); unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back();
for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) { for (const ToolOrdering::LayerTools &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) {
this->throw_if_canceled(); this->throw_if_canceled();
if (! layer_tools.has_wipe_tower) if (! layer_tools.has_wipe_tower)
// This is a support only layer, or the wipe tower does not reach to this height. // This is a support only layer, or the wipe tower does not reach to this height.
continue; continue;
bool first_layer = &layer_tools == &m_tool_ordering.front(); bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
bool last_layer = &layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0; bool last_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0;
wipe_tower.set_layer( wipe_tower.set_layer(
float(layer_tools.print_z), float(layer_tools.print_z),
float(layer_tools.wipe_tower_layer_height), float(layer_tools.wipe_tower_layer_height),
@ -1151,7 +1155,7 @@ void Print::_make_wipe_tower()
for (unsigned int extruder_id : layer_tools.extruders) for (unsigned int extruder_id : layer_tools.extruders)
// Call the wipe_tower.tool_change() at the first layer for the initial extruder // Call the wipe_tower.tool_change() at the first layer for the initial extruder
// to extrude the wipe tower brim, // 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. // or when an extruder shall be switched.
extruder_id != current_extruder_id) { extruder_id != current_extruder_id) {
tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE)); 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(); 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) if (last_layer)
break; break;
} }
// Unload the current filament over the purge tower. // Unload the current filament over the purge tower.
coordf_t layer_height = this->objects.front()->config.layer_height.value; coordf_t layer_height = m_objects.front()->config().layer_height.value;
if (m_tool_ordering.back().wipe_tower_partitions > 0) { if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) {
// The wipe tower goes up to the last layer of the print. // The wipe tower goes up to the last layer of the print.
if (wipe_tower.layer_finished()) { 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. // 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. // 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 { } else {
// There is yet enough space at this layer of the wipe tower for the final purge. // There is yet enough space at this layer of the wipe tower for the final purge.
} }
} else { } else {
// The wipe tower does not reach the last print layer, perform the pruge at the last print layer. // 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); assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0);
wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true); 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)); 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 { 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) { } catch (std::runtime_error &err) {
throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what()); 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 we were supplied no path, generate an automatic one based on our first object's input file
if (path.empty()) { if (path.empty()) {
// get the first input file name // get the first input file name
std::string input_file; std::string input_file;
for (const PrintObject *object : this->objects) { for (const PrintObject *object : m_objects) {
input_file = object->model_object()->input_file; input_file = object->model_object()->input_file;
if (! input_file.empty()) if (! input_file.empty())
break; break;

View file

@ -51,7 +51,7 @@ template <class StepType, size_t COUNT>
class PrintState class PrintState
{ {
public: 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 { enum State {
INVALID, INVALID,
@ -59,24 +59,58 @@ public:
DONE, DONE,
}; };
// With full memory barrier.
bool is_done(StepType step) const { return m_state[step] == DONE; } bool is_done(StepType step) const { return m_state[step] == DONE; }
// set_started() will lock the provided mutex before setting the state.
// 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 // This is necessary to block until the Print::apply_config() updates its state, which may
// influence the processing step being entered. // influence the processing step being entered.
void set_started(StepType step, tbb::mutex &mtx) { mtx.lock(); m_state[step] = STARTED; mtx.unlock(); } void set_started(StepType step, tbb::mutex &mtx) {
void set_done(StepType step) { m_state[step] = DONE; } mtx.lock();
bool invalidate(StepType step) { m_state[step].store(STARTED, std::memory_order_relaxed);
bool invalidated = m_state[step] != INVALID; mtx.unlock();
m_state[step] = INVALID; }
// 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; 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; bool invalidated = false;
for (size_t i = 0; i < COUNT; ++ i) 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; invalidated = true;
m_state[i] = INVALID; }
break; m_state[i].store(INVALID, std::memory_order_relaxed);
} }
return invalidated; return invalidated;
} }
@ -91,17 +125,24 @@ class PrintRegion
{ {
friend class Print; friend class Print;
// Methods NOT modifying the PrintRegion's state:
public: public:
PrintRegionConfig config; const Print* print() const { return m_print; }
const PrintRegionConfig& config() const { return m_config; }
Print* print() { return this->_print; }
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const; 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; coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
private: // Methods modifying the PrintRegion's state:
Print* _print; 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() {} ~PrintRegion() {}
}; };
@ -117,7 +158,6 @@ class PrintObject
public: public:
// vector of (vectors of volume ids), indexed by region_id // vector of (vectors of volume ids), indexed by region_id
std::vector<std::vector<int>> region_volumes; std::vector<std::vector<int>> region_volumes;
PrintObjectConfig config;
t_layer_height_ranges layer_height_ranges; t_layer_height_ranges layer_height_ranges;
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // 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 // Slic3r::Point objects in scaled G-code coordinates in our coordinates
Points _shifted_copies; Points _shifted_copies;
LayerPtrs layers; Print* print() { return m_print; }
SupportLayerPtrs support_layers; 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 Points& copies() const { return m_copies; }
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; }
bool add_copy(const Pointf &point); bool add_copy(const Pointf &point);
bool delete_last_copy(); bool delete_last_copy();
bool delete_all_copies() { return this->set_copies(Points()); } 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 // this value is not supposed to be compared with Layer::id
// since they have different semantics. // since they have different semantics.
size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); } 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(); void clear_layers();
Layer* get_layer(int idx) { return this->layers.at(idx); } Layer* get_layer(int idx) { return m_layers[idx]; }
const Layer* get_layer(int idx) const { return this->layers.at(idx); } const Layer* get_layer(int idx) const { return m_layers[idx]; }
// print_z: top of the layer; slice_z: center of the layer. // 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); 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(); 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); 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); void delete_support_layer(int idx);
// methods for handling state // methods for handling state
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
bool invalidate_step(PrintObjectStep step); 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); } bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); }
// To be used over the layer_height_profile of both the PrintObject and ModelObject // To be used over the layer_height_profile of both the PrintObject and ModelObject
@ -229,9 +272,14 @@ private:
void combine_infill(); void combine_infill();
void _generate_support_material(); void _generate_support_material();
Print* _print; Print *m_print;
ModelObject* _model_object; ModelObject *m_model_object;
Points _copies; // Slic3r::Point objects in scaled G-code coordinates 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; PrintState<PrintObjectStep, posCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread: // Mutex used for synchronization of the worker thread with the UI thread:
@ -245,9 +293,49 @@ private:
~PrintObject() {} ~PrintObject() {}
void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); } 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); 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<PrintObject*> PrintObjectPtrs;
typedef std::vector<PrintRegion*> PrintRegionPtrs; typedef std::vector<PrintRegion*> PrintRegionPtrs;
@ -255,44 +343,27 @@ typedef std::vector<PrintRegion*> PrintRegionPtrs;
class Print class Print
{ {
public: public:
PrintConfig config; Print() { restart(); }
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() { clear_objects(); } ~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(); 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 delete_object(size_t idx);
void reload_object(size_t idx); void reload_object(size_t idx);
bool reload_model_instances(); bool reload_model_instances();
void add_model_object(ModelObject* model_object, int idx = -1);
// methods for handling regions bool apply_config(DynamicPrintConfig config);
PrintRegion* get_region(size_t idx) { return regions.at(idx); } void process();
const PrintRegion* get_region(size_t idx) const { return regions.at(idx); } void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
PrintRegion* add_region();
// methods for handling state // 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(PrintStep step) const { return m_state.is_done(step); }
bool is_step_done(PrintObjectStep step) const; 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_infinite_skirt() const;
bool has_skirt() const; bool has_skirt() const;
// Returns an empty string if valid, otherwise returns an error message. // 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> object_extruders() const;
std::vector<unsigned int> support_material_extruders() const; std::vector<unsigned int> support_material_extruders() const;
std::vector<unsigned int> extruders() const; std::vector<unsigned int> extruders() const;
void _simplify_slices(double distance);
double max_allowed_layer_height() const; double max_allowed_layer_height() const;
bool has_support_material() 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 auto_assign_extruders(ModelObject* model_object) const;
void process(); const PrintConfig& config() const { return m_config; }
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data); 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. // Wipe tower support.
bool has_wipe_tower() const; bool has_wipe_tower() const;
// Tool ordering of a non-sequential print has to be known to calculate the wipe tower. const WipeTowerData& wipe_tower_data() const { return m_wipe_tower_data; }
// 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;
std::string output_filename(); std::string output_filename() const;
std::string output_filepath(const std::string &path); std::string output_filepath(const std::string &path) const;
typedef std::function<void(int, const std::string&)> status_callback_type; typedef std::function<void(int, const std::string&)> status_callback_type;
// Default status console print out in the form of percent => message. // 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); if (m_status_callback) m_status_callback(percent, message);
else printf("%d => %s\n", percent, message.c_str()); 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. // Cancel the running computation. Stop execution of all the background threads.
void cancel() { m_canceled = true; } void cancel() { m_canceled = true; }
// Cancel the running computation. Stop execution of all the background threads. // Cancel the running computation. Stop execution of all the background threads.
void restart() { m_canceled = false; } void restart() { m_canceled = false; }
// Has the calculation been canceled?
bool canceled() { return m_canceled; } // Accessed by SupportMaterial
void throw_if_canceled() { if (m_canceled) throw CanceledException(); } const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
protected: protected:
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); } 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: private:
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); 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_skirt();
void _make_brim(); void _make_brim();
void _clear_wipe_tower();
void _make_wipe_tower(); void _make_wipe_tower();
void _simplify_slices(double distance);
PrintState<PrintStep, psCount> m_state; PrintState<PrintStep, psCount> m_state;
// Mutex used for synchronization of the worker thread with the UI thread: // 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. // Callback to be evoked regularly to update state of the UI thread.
status_callback_type m_status_callback; 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. // To allow GCode to set the Print's GCodeExport step status.
friend class GCode; 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_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)->m_objects, object)
#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) #define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->m_layers, layer)
#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->layers, layer) #define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->m_regions, layerm)
#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->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 { } else {
// otherwise, get extrusion width from configuration // otherwise, get extrusion width from configuration
// (might be an absolute value, or a percent value, or zero for auto) // (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) { if (first_layer && m_print->config().first_layer_extrusion_width.value > 0) {
config_width = this->_print->config.first_layer_extrusion_width; config_width = m_print->config().first_layer_extrusion_width;
} else if (role == frExternalPerimeter) { } else if (role == frExternalPerimeter) {
config_width = this->config.external_perimeter_extrusion_width; config_width = m_config.external_perimeter_extrusion_width;
} else if (role == frPerimeter) { } else if (role == frPerimeter) {
config_width = this->config.perimeter_extrusion_width; config_width = m_config.perimeter_extrusion_width;
} else if (role == frInfill) { } else if (role == frInfill) {
config_width = this->config.infill_extrusion_width; config_width = m_config.infill_extrusion_width;
} else if (role == frSolidInfill) { } else if (role == frSolidInfill) {
config_width = this->config.solid_infill_extrusion_width; config_width = m_config.solid_infill_extrusion_width;
} else if (role == frTopSolidInfill) { } else if (role == frTopSolidInfill) {
config_width = this->config.top_infill_extrusion_width; config_width = m_config.top_infill_extrusion_width;
} else { } else {
CONFESS("Unknown role"); CONFESS("Unknown role");
} }
} }
if (config_width.value == 0) { 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 // get the configured nozzle_diameter for the extruder associated
// to the flow role requested // to the flow role requested
size_t extruder = 0; // 1-based size_t extruder = 0; // 1-based
if (role == frPerimeter || role == frExternalPerimeter) { if (role == frPerimeter || role == frExternalPerimeter) {
extruder = this->config.perimeter_extruder; extruder = m_config.perimeter_extruder;
} else if (role == frInfill) { } else if (role == frInfill) {
extruder = this->config.infill_extruder; extruder = m_config.infill_extruder;
} else if (role == frSolidInfill || role == frTopSolidInfill) { } else if (role == frSolidInfill || role == frTopSolidInfill) {
extruder = this->config.solid_infill_extruder; extruder = m_config.solid_infill_extruder;
} else { } else {
CONFESS("Unknown role $role"); 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 coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const
{ {
return (print_config.nozzle_diameter.get_at(this->config.perimeter_extruder.value - 1) + return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) +
print_config.nozzle_diameter.get_at(this->config.infill_extruder.value - 1) + print_config.nozzle_diameter.get_at(m_config.infill_extruder.value - 1) +
print_config.nozzle_diameter.get_at(this->config.solid_infill_extruder.value - 1)) / 3.; 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) : PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) :
m_object (object), m_object (object),
m_print_config (&object->print()->config), m_print_config (&object->print()->config()),
m_object_config (&object->config), m_object_config (&object->config()),
m_slicing_params (slicing_params), m_slicing_params (slicing_params),
m_first_layer_flow (support_material_1st_layer_flow(object, float(slicing_params.first_print_layer_height))), 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))), 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.; coordf_t external_perimeter_width = 0.;
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
if (! object->region_volumes[region_id].empty()) { 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); coordf_t width = config.external_perimeter_extrusion_width.get_abs_value(slicing_params.layer_height);
if (width <= 0.) if (width <= 0.)
width = m_print_config->nozzle_diameter.get_at(config.perimeter_extruder-1); 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.; coordf_t max_object_layer_height = 0.;
for (size_t i = 0; i < object.layer_count(); ++ i) 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. // 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*>) // 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); layer_support_areas);
#ifdef SLIC3R_DEBUG #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( 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)); union_ex(layer_support_areas[layer_id], false));
#endif /* SLIC3R_DEBUG */ #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. // Sort the layers lexicographically by a raising print_z and a decreasing height.
std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare()); std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare());
int layer_id = 0; int layer_id = 0;
assert(object.support_layers.empty()); assert(object.support_layers().empty());
for (int i = 0; i < int(layers_sorted.size());) { 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. // 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. // 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. // 1) Count the new polygons first.
size_t n_polygons_new = 0; size_t n_polygons_new = 0;
for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { for (const LayerRegion* pregion : layer.regions()) {
const LayerRegion &region = *(*it_region); const LayerRegion &region = *pregion;
const SurfaceCollection &slices = region.slices; const SurfaceCollection &slices = region.slices;
for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) {
const Surface &surface = *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. // 2) Collect the new polygons.
Polygons out; Polygons out;
out.reserve(n_polygons_new); out.reserve(n_polygons_new);
for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { for (const LayerRegion *pregion : layer.regions()) {
const LayerRegion &region = *(*it_region); const LayerRegion &region = *pregion;
const SurfaceCollection &slices = region.slices; const SurfaceCollection &slices = region.slices;
for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) {
const Surface &surface = *it; const Surface &surface = *it;
@ -658,9 +658,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
std::vector<Polygons> buildplate_covered; std::vector<Polygons> buildplate_covered;
if (buildplate_only) { if (buildplate_only) {
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() - collecting regions covering the print bed."; BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() - collecting regions covering the print bed.";
buildplate_covered.assign(object.layers.size(), Polygons()); buildplate_covered.assign(object.layers().size(), Polygons());
for (size_t layer_id = 1; layer_id < object.layers.size(); ++ layer_id) { for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) {
const Layer &lower_layer = *object.layers[layer_id-1]; const Layer &lower_layer = *object.layers()[layer_id-1];
// Merge the new slices with the preceding slices. // Merge the new slices with the preceding slices.
// Apply the safety offset to the newly added polygons, so they will connect // Apply the safety offset to the newly added polygons, so they will connect
// with the polygons collected before, // 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) { [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) 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. // 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. // 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)); contact_polygons = offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN));
} else { } else {
// Generate overhang / contact_polygons for non-raft layers. // Generate overhang / contact_polygons for non-raft layers.
const Layer &lower_layer = *object.layers[layer_id-1]; const Layer &lower_layer = *object.layers()[layer_id-1];
for (LayerRegion *layerm : layer.regions) { for (LayerRegion *layerm : layer.regions()) {
// Extrusion width accounts for the roundings of the extrudates. // Extrusion width accounts for the roundings of the extrudates.
// It is the maximum widh of the extrudate. // It is the maximum widh of the extrudate.
float fw = float(layerm->flow(frExternalPerimeter).scaled_width()); float fw = float(layerm->flow(frExternalPerimeter).scaled_width());
float lower_layer_offset = 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. // Enforce a full possible support, ignore the overhang angle.
0.f : 0.f :
(threshold_rad > 0. ? (threshold_rad > 0. ?
@ -762,14 +762,14 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
} }
#endif /* SLIC3R_DEBUG */ #endif /* SLIC3R_DEBUG */
if (this->m_object_config->dont_support_bridges) { if (m_object_config->dont_support_bridges) {
// compute the area of bridging perimeters // compute the area of bridging perimeters
// Note: this is duplicate code from GCode.pm, we need to refactor // Note: this is duplicate code from GCode.pm, we need to refactor
if (true) { if (true) {
Polygons bridged_perimeters; Polygons bridged_perimeters;
{ {
Flow bridge_flow = layerm->flow(frPerimeter, true); 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); Polygons lower_grown_slices = offset(lower_layer_polygons, 0.5f*float(scale_(nozzle_diameter)), SUPPORT_SURFACES_OFFSET_PARAMETERS);
// Collect perimeters of this layer. // Collect perimeters of this layer.
@ -894,8 +894,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
} else { } else {
// Interface layer will be synchronized with the object. // Interface layer will be synchronized with the object.
assert(layer_id > 0); assert(layer_id > 0);
new_layer.height = object.layers[layer_id - 1]->height; 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.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers()[layer_id - 2]->print_z;
} }
} else { } else {
// Contact layer will be printed with a normal flow, but // 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. // In the future we may switch to a normal extrusion flow for the supported bridges.
// Get the average nozzle diameter used on this layer. // Get the average nozzle diameter used on this layer.
coordf_t nozzle_dmr = 0.; 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 += 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.print_z = layer.print_z - nozzle_dmr - m_object_config->support_material_contact_distance;
new_layer.bottom_z = new_layer.print_z; new_layer.bottom_z = new_layer.print_z;
new_layer.height = 0.; new_layer.height = 0.;
@ -1048,10 +1048,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// top shapes so this can be done here // top shapes so this can be done here
layer_new.height = m_slicing_params.soluble_interface ? layer_new.height = m_slicing_params.soluble_interface ?
// Align the interface layer with the object's layer height. // 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. // Place a bridge flow interface layer over the top surface.
m_support_material_interface_flow.nozzle_diameter; 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.print_z + layer_new.height + m_object_config->support_material_contact_distance.value;
layer_new.bottom_z = layer.print_z; layer_new.bottom_z = layer.print_z;
layer_new.idx_object_layer_below = layer_id; 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, // 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. // 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)); 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) { ++ 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. // 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; 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.) { if (diff > 0.) {
// The top contact layer is below this layer. Make the bridging layer thinner to align with the existing top layer. // 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(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.print_z = top_contacts[top_idx]->print_z;
layer_new.height -= diff; layer_new.height -= diff;
} else { } 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. // Trim the already created base layers above the current layer intersecting with the new bottom contacts layer.
touching = offset(touching, float(SCALED_EPSILON)); 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) { 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) if (layer_above.print_z > layer_new.print_z + EPSILON)
break; break;
if (! layer_support_areas[layer_id_above].empty()) { 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. // Verify that the extremes are separated by m_support_layer_height_min.
for (size_t i = 1; i < extremes.size(); ++ i) { for (size_t i = 1; i < extremes.size(); ++ i) {
assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() == 0. || 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. || assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > 0. ||
extremes[i]->layer_type == extremes[i-1]->layer_type || extremes[i]->layer_type == extremes[i-1]->layer_type ||
(extremes[i]->layer_type == sltBottomContact && extremes[i - 1]->layer_type == sltTopContact)); (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(). // 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->layer_type == sltTopContact);
assert(extr2->bottom_z == m_slicing_params.first_print_layer_height); 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) { if (intermediate_layers.empty() || intermediate_layers.back()->print_z < m_slicing_params.first_print_layer_height) {
MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate); MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.bottom_z = 0.; layer_new.bottom_z = 0.;
@ -1384,7 +1384,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
if (synchronize) { if (synchronize) {
// Emit support layers synchronized with the object layers. // Emit support layers synchronized with the object layers.
// Find the first object layer, which has its print_z in this support Z range. // 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; ++ idx_layer_object;
if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) { if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) {
// Insert one base support layer below the object. // Insert one base support layer below the object.
@ -1395,11 +1395,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
intermediate_layers.push_back(&layer_new); intermediate_layers.push_back(&layer_new);
} }
// Emit all intermediate support layers synchronized with object layers up to extr2z. // 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); MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.print_z = object.layers[idx_layer_object]->print_z; layer_new.print_z = object.layers()[idx_layer_object]->print_z;
layer_new.height = object.layers[idx_layer_object]->height; 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.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); assert(intermediate_layers.empty() || intermediate_layers.back()->print_z < layer_new.print_z + EPSILON);
intermediate_layers.push_back(&layer_new); intermediate_layers.push_back(&layer_new);
} }
@ -1409,10 +1409,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
assert(n_layers_extra > 0); assert(n_layers_extra > 0);
coordf_t step = dist / coordf_t(n_layers_extra); coordf_t step = dist / coordf_t(n_layers_extra);
if (extr1 != nullptr && extr1->layer_type == sltTopContact && 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 // 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. // 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. // Generate the first intermediate layer.
MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate); MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate);
layer_new.bottom_z = extr1->bottom_z; layer_new.bottom_z = extr1->bottom_z;
@ -1509,7 +1509,7 @@ void PrintObjectSupportMaterial::generate_base_layers(
Polygons polygons_new; Polygons polygons_new;
// Use the precomputed layer_support_areas. // 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; })); [&layer_intermediate](const Layer *layer){ return layer->print_z <= layer_intermediate.print_z + EPSILON; }));
polygons_new = layer_support_areas[idx_object_layer_above]; 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. // 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; coordf_t z_threshold = support_layer.print_z - support_layer.height - gap_extra_below + EPSILON;
idx_object_layer_overlapping = idx_higher_or_equal( 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; }); [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
// Collect all the object layers intersecting with this layer. // Collect all the object layers intersecting with this layer.
Polygons polygons_trimming; Polygons polygons_trimming;
size_t i = idx_object_layer_overlapping; size_t i = idx_object_layer_overlapping;
for (; i < object.layers.size(); ++ i) { for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers[i]; const Layer &object_layer = *object.layers()[i];
if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON) if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON)
break; break;
polygons_append(polygons_trimming, (Polygons)object_layer.slices); 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. // Collect all bottom surfaces, which will be extruded with a bridging flow.
for (; i < object.layers.size(); ++ i) { for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers[i]; const Layer &object_layer = *object.layers()[i];
bool some_region_overlaps = false; bool some_region_overlaps = false;
for (LayerRegion* region : object_layer.regions) { for (LayerRegion* region : object_layer.regions()) {
coordf_t nozzle_dmr = region->region()->nozzle_dmr_avg(*this->m_print_config); 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) if (object_layer.print_z - nozzle_dmr > support_layer.print_z + gap_extra_above - EPSILON)
break; break;
some_region_overlaps = true; some_region_overlaps = true;
@ -1764,7 +1764,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
// Expand the bases of the support columns in the 1st layer. // Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff( columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer), 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) if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons); columns_base->polygons = diff(columns_base->polygons, interface_polygons);
} }
@ -1909,8 +1909,8 @@ struct MyLayerExtruded
else else
*m_polygons_to_extrude = std::move(polygons); *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; } Polygons& polygons_to_extrude() { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; }
const Polygons& polygons_to_extrude() const { return (this->m_polygons_to_extrude == nullptr) ? layer->polygons : *this->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 { bool could_merge(const MyLayerExtruded &other) const {
return ! this->empty() && ! other.empty() && return ! this->empty() && ! other.empty() &&
@ -1923,21 +1923,21 @@ struct MyLayerExtruded
assert(this->could_merge(other)); assert(this->could_merge(other));
// 1) Merge the rest polygons to extrude, if there are any. // 1) Merge the rest polygons to extrude, if there are any.
if (other.m_polygons_to_extrude != nullptr) { 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). // 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()); 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)); Slic3r::polygons_append(*m_polygons_to_extrude, std::move(*other.m_polygons_to_extrude));
*this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true); *m_polygons_to_extrude = union_(*m_polygons_to_extrude, true);
delete other.m_polygons_to_extrude; delete other.m_polygons_to_extrude;
other.m_polygons_to_extrude = nullptr; 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); 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). // 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()); assert(other.extrusions.empty());
Slic3r::polygons_append(*this->m_polygons_to_extrude, other.layer->polygons); Slic3r::polygons_append(*m_polygons_to_extrude, other.layer->polygons);
*this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true); *m_polygons_to_extrude = union_(*m_polygons_to_extrude, true);
} }
// 2) Merge the extrusions. // 2) Merge the extrusions.
this->extrusions.insert(this->extrusions.end(), other.extrusions.begin(), other.extrusions.end()); 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) for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
{ {
assert(support_layer_id < raft_layers.size()); 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()); assert(support_layer.support_fills.entities.empty());
MyLayer &raft_layer = *raft_layers[support_layer_id]; MyLayer &raft_layer = *raft_layers[support_layer_id];
@ -2631,9 +2631,9 @@ void PrintObjectSupportMaterial::generate_toolpaths(
MyLayerExtruded interface_layer; MyLayerExtruded interface_layer;
std::vector<LayerCacheItem> overlaps; 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, [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] infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath]
(const tbb::blocked_range<size_t>& range) { (const tbb::blocked_range<size_t>& range) {
@ -2648,7 +2648,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler_support->set_bounding_box(bbox_object); filler_support->set_bounding_box(bbox_object);
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) 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]; LayerCache &layer_cache = layer_caches[support_layer_id];
// Find polygons with the same print_z. // Find polygons with the same print_z.
@ -2844,11 +2844,11 @@ void PrintObjectSupportMaterial::generate_toolpaths(
}); });
// Now modulate the support layer height in parallel. // 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] [this, &object, &layer_caches]
(const tbb::blocked_range<size_t>& range) { (const tbb::blocked_range<size_t>& range) {
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { 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]; LayerCache &layer_cache = layer_caches[support_layer_id];
for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) { 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); 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. // 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)); 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; return;
const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish
// number of skirt layers // number of skirt layers
size_t total_layer_count = 0; 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()); total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
size_t skirt_height = print->has_infinite_skirt() ? size_t skirt_height = print->has_infinite_skirt() ?
total_layer_count : total_layer_count :
std::min<size_t>(print->config.skirt_height.value, 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) if (skirt_height == 0 && print->config().brim_width.value > 0)
skirt_height = 1; skirt_height = 1;
// get first skirt_height layers (maybe this should be moved to a PrintObject method?) // 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; std::vector<float> print_zs;
print_zs.reserve(skirt_height * 2); print_zs.reserve(skirt_height * 2);
for (size_t i = 0; i < std::min(skirt_height, object0->layers.size()); ++ i) for (size_t i = 0; i < std::min(skirt_height, object0->layers().size()); ++ i)
print_zs.push_back(float(object0->layers[i]->print_z)); print_zs.push_back(float(object0->layers()[i]->print_z));
//FIXME why there are support layers? //FIXME why there are support layers?
for (size_t i = 0; i < std::min(skirt_height, object0->support_layers.size()); ++ i) 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)); print_zs.push_back(float(object0->support_layers()[i]->print_z));
sort_remove_duplicates(print_zs); sort_remove_duplicates(print_zs);
if (print_zs.size() > skirt_height) if (print_zs.size() > skirt_height)
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); 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.quad_indices.size());
volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size()); volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size());
if (i == 0) if (i == 0)
extrusionentity_to_verts(print->brim, 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); extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume);
} }
volume.bounding_box = volume.indexed_vertex_array.bounding_box(); volume.bounding_box = volume.indexed_vertex_array.bounding_box();
volume.indexed_vertex_array.finalize_geometry(use_VBOs); 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; ctxt.shifted_copies = &print_object->_shifted_copies;
// order layers by print_z // order layers by print_z
ctxt.layers.reserve(print_object->layers.size() + print_object->support_layers.size()); ctxt.layers.reserve(print_object->layers().size() + print_object->support_layers().size());
for (const Layer *layer : print_object->layers) for (const Layer *layer : print_object->layers())
ctxt.layers.push_back(layer); 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); 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; }); 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 Point &copy: *ctxt.shifted_copies) {
for (const LayerRegion *layerm : layer->regions) { for (const LayerRegion *layerm : layer->regions()) {
if (ctxt.has_perimeters) if (ctxt.has_perimeters)
extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, 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) { if (ctxt.has_infill) {
for (const ExtrusionEntity *ee : layerm->fills.entities) { for (const ExtrusionEntity *ee : layerm->fills.entities) {
// fill represents infill extrusions of a single island. // 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, extrusionentity_to_verts(*fill, float(layer->print_z), copy,
*vols[ctxt.volume_idx( *vols[ctxt.volume_idx(
is_solid_infill(fill->entities.front()->role()) ? is_solid_infill(fill->entities.front()->role()) ?
layerm->region()->config.solid_infill_extruder : layerm->region()->config().solid_infill_extruder :
layerm->region()->config.infill_extruder, layerm->region()->config().infill_extruder,
1)]); 1)]);
} }
} }
@ -1828,8 +1828,8 @@ void _3DScene::_load_print_object_toolpaths(
extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
*vols[ctxt.volume_idx( *vols[ctxt.volume_idx(
(extrusion_entity->role() == erSupportMaterial) ? (extrusion_entity->role() == erSupportMaterial) ?
support_layer->object()->config.support_material_extruder : support_layer->object()->config().support_material_extruder :
support_layer->object()->config.support_material_interface_extruder, support_layer->object()->config().support_material_interface_extruder,
2)]); 2)]);
} }
} }
@ -1877,7 +1877,7 @@ void _3DScene::_load_wipe_tower_toolpaths(
const std::vector<std::string> &tool_colors_str, const std::vector<std::string> &tool_colors_str,
bool use_VBOs) bool use_VBOs)
{ {
if (print->m_wipe_tower_tool_changes.empty()) if (print->wipe_tower_data().tool_changes.empty())
return; return;
std::vector<float> tool_colors = parse_colors(tool_colors_str); 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) { const std::vector<WipeTower::ToolChangeResult>& tool_change(size_t idx) {
return priming.empty() ? return priming.empty() ?
((idx == print->m_wipe_tower_tool_changes.size()) ? final : print->m_wipe_tower_tool_changes[idx]) : ((idx == print->wipe_tower_data().tool_changes.size()) ? final : print->wipe_tower_data().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 == 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> priming;
std::vector<WipeTower::ToolChangeResult> final; std::vector<WipeTower::ToolChangeResult> final;
@ -1911,15 +1911,15 @@ void _3DScene::_load_wipe_tower_toolpaths(
ctxt.print = print; ctxt.print = print;
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
if (print->m_wipe_tower_priming) if (print->wipe_tower_data().priming != nullptr)
ctxt.priming.emplace_back(*print->m_wipe_tower_priming.get()); ctxt.priming.emplace_back(*print->wipe_tower_data().priming);
if (print->m_wipe_tower_final_purge) if (print->wipe_tower_data().final_purge)
ctxt.final.emplace_back(*print->m_wipe_tower_final_purge.get()); ctxt.final.emplace_back(*print->wipe_tower_data().final_purge);
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
//FIXME Improve the heuristics for a grain size. //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)); size_t grain_size = std::max(n_items / 128, size_t(1));
tbb::spin_mutex new_volume_mutex; tbb::spin_mutex new_volume_mutex;
auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { 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(); 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); 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 // nothing to render, return
return; return;
// adds objects' volumes // adds objects' volumes
unsigned int object_id = 0; unsigned int object_id = 0;
for (PrintObject* obj : print.objects) for (PrintObject* obj : print.objects())
{ {
ModelObject* model_obj = obj->model_object(); 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 // adds wipe tower's volume
coordf_t max_z = print.objects[0]->model_object()->get_model()->bounding_box().max.z; coordf_t max_z = print.objects().front()->model_object()->get_model()->bounding_box().max.z;
const PrintConfig& config = print.config; const PrintConfig& config = print.config();
unsigned int extruders_count = config.nozzle_diameter.size(); unsigned int extruders_count = config.nozzle_diameter.size();
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) 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); 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 // owned by Print, no constructor/destructor
Ref<StaticPrintConfig> config() Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config(); %};
Ref<Print> print(); Ref<Print> print();
Clone<Flow> flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, PrintObject* object) 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 // owned by Print, no constructor/destructor
int region_count() int region_count()
%code%{ RETVAL = THIS->print()->regions.size(); %}; %code%{ RETVAL = THIS->print()->regions().size(); %};
Ref<Print> print(); Ref<Print> print();
Ref<ModelObject> model_object(); Ref<ModelObject> model_object();
Ref<StaticPrintConfig> config() Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config(); %};
Points copies(); Points copies();
t_layer_height_ranges layer_height_ranges() t_layer_height_ranges layer_height_ranges()
%code%{ RETVAL = THIS->layer_height_ranges; %}; %code%{ RETVAL = THIS->layer_height_ranges; %};
@ -95,32 +95,41 @@ _constant()
~Print(); ~Print();
Ref<StaticPrintConfig> config() Ref<StaticPrintConfig> config()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config(); %};
Ref<PlaceholderParser> placeholder_parser() Ref<PlaceholderParser> placeholder_parser()
%code%{ RETVAL = &THIS->placeholder_parser; %}; %code%{ RETVAL = &THIS->placeholder_parser(); %};
Ref<ExtrusionEntityCollection> skirt() Ref<ExtrusionEntityCollection> skirt()
%code%{ RETVAL = &THIS->skirt; %}; %code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->skirt()); %};
Ref<ExtrusionEntityCollection> brim() Ref<ExtrusionEntityCollection> brim()
%code%{ RETVAL = &THIS->brim; %}; %code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->brim()); %};
std::string estimated_print_time() 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() PrintObjectPtrs* objects()
%code%{ RETVAL = &THIS->objects; %}; %code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
void clear_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 delete_object(int idx);
void reload_object(int idx); void reload_object(int idx);
bool reload_model_instances(); bool reload_model_instances();
size_t object_count() size_t object_count()
%code%{ RETVAL = THIS->objects.size(); %}; %code%{ RETVAL = THIS->objects().size(); %};
PrintRegionPtrs* regions() PrintRegionPtrs* regions()
%code%{ RETVAL = &THIS->regions; %}; %code%{ RETVAL = const_cast<PrintRegionPtrs*>(&THIS->regions()); %};
Ref<PrintRegion> get_region(int idx); Ref<PrintRegion> get_region(int idx)
Ref<PrintRegion> add_region(); %code%{ RETVAL = THIS->regions()[idx]; %};
size_t region_count() size_t region_count()
%code%{ RETVAL = THIS->regions.size(); %}; %code%{ RETVAL = THIS->regions().size(); %};
bool step_done(PrintStep step) bool step_done(PrintStep step)
%code%{ RETVAL = THIS->is_step_done(step); %}; %code%{ RETVAL = THIS->is_step_done(step); %};
@ -130,7 +139,7 @@ _constant()
SV* filament_stats() SV* filament_stats()
%code%{ %code%{
HV* hv = newHV(); 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 // stringify extruder_id
std::ostringstream ss; std::ostringstream ss;
ss << it->first; 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
%}
}; };