diff options
Diffstat (limited to 'xs/src/libslic3r')
-rw-r--r-- | xs/src/libslic3r/Fill/Fill.cpp | 14 | ||||
-rw-r--r-- | xs/src/libslic3r/Flow.cpp | 24 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode.cpp | 272 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode/PrintExtents.cpp | 14 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode/ToolOrdering.cpp | 50 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 26 | ||||
-rw-r--r-- | xs/src/libslic3r/Layer.cpp | 52 | ||||
-rw-r--r-- | xs/src/libslic3r/Layer.hpp | 145 | ||||
-rw-r--r-- | xs/src/libslic3r/LayerRegion.cpp | 30 | ||||
-rw-r--r-- | xs/src/libslic3r/PerimeterGenerator.cpp | 3 | ||||
-rw-r--r-- | xs/src/libslic3r/PerimeterGenerator.hpp | 48 | ||||
-rw-r--r-- | xs/src/libslic3r/PlaceholderParser.cpp | 16 | ||||
-rw-r--r-- | xs/src/libslic3r/PlaceholderParser.hpp | 6 | ||||
-rw-r--r-- | xs/src/libslic3r/Print.cpp | 401 | ||||
-rw-r--r-- | xs/src/libslic3r/Print.hpp | 346 | ||||
-rw-r--r-- | xs/src/libslic3r/PrintObject.cpp | 541 | ||||
-rw-r--r-- | xs/src/libslic3r/PrintRegion.cpp | 32 | ||||
-rw-r--r-- | xs/src/libslic3r/SupportMaterial.cpp | 130 | ||||
-rw-r--r-- | xs/src/libslic3r/SupportMaterial.hpp | 2 |
19 files changed, 1141 insertions, 1011 deletions
diff --git a/xs/src/libslic3r/Fill/Fill.cpp b/xs/src/libslic3r/Fill/Fill.cpp index 5333fcfec..f1436c931 100644 --- a/xs/src/libslic3r/Fill/Fill.cpp +++ b/xs/src/libslic3r/Fill/Fill.cpp @@ -34,7 +34,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) { // Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id; - double fill_density = layerm.region()->config.fill_density; + double fill_density = layerm.region()->config().fill_density; Flow infill_flow = layerm.flow(frInfill); Flow solid_infill_flow = layerm.flow(frSolidInfill); Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill); @@ -69,7 +69,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) { group_attrib[i].is_solid = true; group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width; - group_attrib[i].pattern = surface.is_external() ? layerm.region()->config.external_fill_pattern.value : ipRectilinear; + group_attrib[i].pattern = surface.is_external() ? layerm.region()->config().external_fill_pattern.value : ipRectilinear; } } // Loop through solid groups, find compatible groups and append them to this one. @@ -152,7 +152,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) for (const Surface &surface : surfaces) { if (surface.surface_type == stInternalVoid) continue; - InfillPattern fill_pattern = layerm.region()->config.fill_pattern.value; + InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value; double density = fill_density; FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill); @@ -161,7 +161,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) if (surface.is_solid()) { density = 100.; fill_pattern = (surface.is_external() && ! is_bridge) ? - layerm.region()->config.external_fill_pattern.value : + layerm.region()->config().external_fill_pattern.value : ipRectilinear; } else if (density <= 0) continue; @@ -190,7 +190,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // layer height Flow internal_flow = layerm.region()->flow( frInfill, - layerm.layer()->object()->config.layer_height.value, // TODO: handle infill_every_layers? + layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers? false, // no bridge false, // no first layer -1, // auto width @@ -205,7 +205,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) double link_max_length = 0.; if (! is_bridge) { #if 0 - link_max_length = layerm.region()->config.get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing()); + link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing()); // printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length); #else if (density > 80.) // 80% @@ -215,7 +215,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) f->layer_id = layerm.layer()->id(); f->z = layerm.layer()->print_z; - f->angle = float(Geometry::deg2rad(layerm.region()->config.fill_angle.value)); + f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value)); // Maximum length of the perimeter segment linking two infill lines. f->link_max_length = scale_(link_max_length); // Used by the concentric infill pattern to clip the loops to create extrusion paths. diff --git a/xs/src/libslic3r/Flow.cpp b/xs/src/libslic3r/Flow.cpp index b60e26dcc..c33de8b6e 100644 --- a/xs/src/libslic3r/Flow.cpp +++ b/xs/src/libslic3r/Flow.cpp @@ -111,22 +111,22 @@ Flow support_material_flow(const PrintObject *object, float layer_height) return Flow::new_from_config_width( frSupportMaterial, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. - (object->config.support_material_extrusion_width.value > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width, - // if object->config.support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. - float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), - (layer_height > 0.f) ? layer_height : float(object->config.layer_height.value), + (object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, + // if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. + float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)), + (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value), false); } Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height) { - const auto &width = (object->print()->config.first_layer_extrusion_width.value > 0) ? object->print()->config.first_layer_extrusion_width : object->config.support_material_extrusion_width; + const auto &width = (object->print()->config().first_layer_extrusion_width.value > 0) ? object->print()->config().first_layer_extrusion_width : object->config().support_material_extrusion_width; return Flow::new_from_config_width( frSupportMaterial, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. - (width.value > 0) ? width : object->config.extrusion_width, - float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), - (layer_height > 0.f) ? layer_height : float(object->config.first_layer_height.get_abs_value(object->config.layer_height.value)), + (width.value > 0) ? width : object->config().extrusion_width, + float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)), + (layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)), false); } @@ -135,10 +135,10 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig return Flow::new_from_config_width( frSupportMaterialInterface, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. - (object->config.support_material_extrusion_width > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width, - // if object->config.support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. - float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1)), - (layer_height > 0.f) ? layer_height : float(object->config.layer_height.value), + (object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width, + // if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. + float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)), + (layer_height > 0.f) ? layer_height : float(object->config().layer_height.value), false); } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 9c6143fd6..e55404845 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -275,15 +275,15 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen) std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObject &object) { std::vector<GCode::LayerToPrint> layers_to_print; - layers_to_print.reserve(object.layers.size() + object.support_layers.size()); + layers_to_print.reserve(object.layers().size() + object.support_layers().size()); // Pair the object layers with the support layers by z. size_t idx_object_layer = 0; size_t idx_support_layer = 0; - while (idx_object_layer < object.layers.size() || idx_support_layer < object.support_layers.size()) { + while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) { LayerToPrint layer_to_print; - layer_to_print.object_layer = (idx_object_layer < object.layers.size()) ? object.layers[idx_object_layer ++] : nullptr; - layer_to_print.support_layer = (idx_support_layer < object.support_layers.size()) ? object.support_layers[idx_support_layer ++] : nullptr; + layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer ++] : nullptr; + layer_to_print.support_layer = (idx_support_layer < object.support_layers().size()) ? object.support_layers()[idx_support_layer ++] : nullptr; if (layer_to_print.object_layer && layer_to_print.support_layer) { if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z - EPSILON) { layer_to_print.support_layer = nullptr; @@ -309,10 +309,10 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec size_t object_idx; size_t layer_idx; }; - std::vector<std::vector<LayerToPrint>> per_object(print.objects.size(), std::vector<LayerToPrint>()); + std::vector<std::vector<LayerToPrint>> per_object(print.objects().size(), std::vector<LayerToPrint>()); std::vector<OrderingItem> ordering; - for (size_t i = 0; i < print.objects.size(); ++ i) { - per_object[i] = collect_layers_to_print(*print.objects[i]); + for (size_t i = 0; i < print.objects().size(); ++ i) { + per_object[i] = collect_layers_to_print(*print.objects()[i]); OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -337,7 +337,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec std::pair<coordf_t, std::vector<LayerToPrint>> merged; // Assign an average print_z to the set of layers with nearly equal print_z. merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z); - merged.second.assign(print.objects.size(), LayerToPrint()); + merged.second.assign(print.objects().size(), LayerToPrint()); for (; i < j; ++ i) { const OrderingItem &oi = ordering[i]; assert(merged.second[oi.object_idx].layer() == nullptr); @@ -366,7 +366,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); try { - this->m_placeholder_parser_failed_templates.clear(); + m_placeholder_parser_failed_templates.clear(); this->_do_export(*print, file, preview_data); fflush(file); if (ferror(file)) { @@ -382,10 +382,10 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ throw; } fclose(file); - if (! this->m_placeholder_parser_failed_templates.empty()) { + if (! m_placeholder_parser_failed_templates.empty()) { // G-code export proceeded, but some of the PlaceholderParser substitutions failed. std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n"; - for (const std::string &name : this->m_placeholder_parser_failed_templates) + for (const std::string &name : m_placeholder_parser_failed_templates) msg += std::string("\t") + name + "\n"; msg += "\nPlease inspect the file "; msg += path_tmp + " for error messages enclosed between\n"; @@ -415,7 +415,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // resets time estimator m_time_estimator.reset(); - m_time_estimator.set_dialect(print.config.gcode_flavor); + m_time_estimator.set_dialect(print.config().gcode_flavor); // resets analyzer m_analyzer.reset(); @@ -429,14 +429,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. m_layer_count = 0; - if (print.config.complete_objects.value) { + if (print.config().complete_objects.value) { // Add each of the object's layers separately. - for (auto object : print.objects) { + for (auto object : print.objects()) { std::vector<coordf_t> zs; - zs.reserve(object->layers.size() + object->support_layers.size()); - for (auto layer : object->layers) + zs.reserve(object->layers().size() + object->support_layers().size()); + for (auto layer : object->layers()) zs.push_back(layer->print_z); - for (auto layer : object->support_layers) + for (auto layer : object->support_layers()) zs.push_back(layer->print_z); std::sort(zs.begin(), zs.end()); m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); @@ -444,11 +444,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } else { // Print all objects with the same print_z together. std::vector<coordf_t> zs; - for (auto object : print.objects) { - zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); - for (auto layer : object->layers) + for (auto object : print.objects()) { + zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); + for (auto layer : object->layers()) zs.push_back(layer->print_z); - for (auto layer : object->support_layers) + for (auto layer : object->support_layers()) zs.push_back(layer->print_z); } std::sort(zs.begin(), zs.end()); @@ -457,33 +457,33 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.throw_if_canceled(); m_enable_cooling_markers = true; - this->apply_print_config(print.config); + this->apply_print_config(print.config()); this->set_extruders(print.extruders()); // Initialize autospeed. { // get the minimum cross-section used in the print std::vector<double> mm3_per_mm; - for (auto object : print.objects) { - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - auto region = print.regions[region_id]; - for (auto layer : object->layers) { - auto layerm = layer->regions[region_id]; - if (region->config.get_abs_value("perimeter_speed" ) == 0 || - region->config.get_abs_value("small_perimeter_speed" ) == 0 || - region->config.get_abs_value("external_perimeter_speed" ) == 0 || - region->config.get_abs_value("bridge_speed" ) == 0) + for (auto object : print.objects()) { + for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { + auto region = print.regions()[region_id]; + for (auto layer : object->layers()) { + auto layerm = layer->regions()[region_id]; + if (region->config().get_abs_value("perimeter_speed" ) == 0 || + region->config().get_abs_value("small_perimeter_speed" ) == 0 || + region->config().get_abs_value("external_perimeter_speed" ) == 0 || + region->config().get_abs_value("bridge_speed" ) == 0) mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm()); - if (region->config.get_abs_value("infill_speed" ) == 0 || - region->config.get_abs_value("solid_infill_speed" ) == 0 || - region->config.get_abs_value("top_solid_infill_speed" ) == 0 || - region->config.get_abs_value("bridge_speed" ) == 0) + if (region->config().get_abs_value("infill_speed" ) == 0 || + region->config().get_abs_value("solid_infill_speed" ) == 0 || + region->config().get_abs_value("top_solid_infill_speed" ) == 0 || + region->config().get_abs_value("bridge_speed" ) == 0) mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm()); } } - if (object->config.get_abs_value("support_material_speed" ) == 0 || - object->config.get_abs_value("support_material_interface_speed" ) == 0) - for (auto layer : object->support_layers) + if (object->config().get_abs_value("support_material_speed" ) == 0 || + object->config().get_abs_value("support_material_interface_speed" ) == 0) + for (auto layer : object->support_layers()) mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm()); } print.throw_if_canceled(); @@ -495,20 +495,20 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // volumetric speed as the volumetric speed produced by printing the // smallest cross-section at the maximum speed: any larger cross-section // will need slower feedrates. - m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config.max_print_speed.value; + m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value; // limit such volumetric speed with max_volumetric_speed if set - if (print.config.max_volumetric_speed.value > 0) - m_volumetric_speed = std::min(m_volumetric_speed, print.config.max_volumetric_speed.value); + if (print.config().max_volumetric_speed.value > 0) + m_volumetric_speed = std::min(m_volumetric_speed, print.config().max_volumetric_speed.value); } } print.throw_if_canceled(); m_cooling_buffer = make_unique<CoolingBuffer>(*this); - if (print.config.spiral_vase.value) - m_spiral_vase = make_unique<SpiralVase>(print.config); - if (print.config.max_volumetric_extrusion_rate_slope_positive.value > 0 || - print.config.max_volumetric_extrusion_rate_slope_negative.value > 0) - m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config); + if (print.config().spiral_vase.value) + m_spiral_vase = make_unique<SpiralVase>(print.config()); + if (print.config().max_volumetric_extrusion_rate_slope_positive.value > 0 || + print.config().max_volumetric_extrusion_rate_slope_negative.value > 0) + m_pressure_equalizer = make_unique<PressureEqualizer>(&print.config()); m_enable_extrusion_role_markers = (bool)m_pressure_equalizer; // Write information on the generator. @@ -516,7 +516,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Write notes (content of the Print Settings tab -> Notes) { std::list<std::string> lines; - boost::split(lines, print.config.notes.value, boost::is_any_of("\n"), boost::token_compress_off); + boost::split(lines, print.config().notes.value, boost::is_any_of("\n"), boost::token_compress_off); for (auto line : lines) { // Remove the trailing '\r' from the '\r\n' sequence. if (! line.empty() && line.back() == '\r') @@ -529,11 +529,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.throw_if_canceled(); // Write some terse information on the slicing parameters. - const PrintObject *first_object = print.objects.front(); - const double layer_height = first_object->config.layer_height.value; - const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height); - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - auto region = print.regions[region_id]; + const PrintObject *first_object = print.objects().front(); + const double layer_height = first_object->config().layer_height.value; + const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height); + for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { + auto region = print.regions()[region_id]; _write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width); _write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width); _write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width); @@ -541,14 +541,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width); if (print.has_support_material()) _write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width); - if (print.config.first_layer_extrusion_width.value > 0) + if (print.config().first_layer_extrusion_width.value > 0) _write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width); _write_format(file, "\n"); } print.throw_if_canceled(); // Prepare the helper object for replacing placeholders in custom G-code and output filename. - m_placeholder_parser = print.placeholder_parser; + m_placeholder_parser = print.placeholder_parser(); m_placeholder_parser.update_timestamp(); // Get optimal tool ordering to minimize tool switches of a multi-exruder print. @@ -558,19 +558,19 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) unsigned int final_extruder_id = (unsigned int)-1; size_t initial_print_object_id = 0; bool has_wipe_tower = false; - if (print.config.complete_objects.value) { + if (print.config().complete_objects.value) { // Find the 1st printing object, find its tool ordering and the initial extruder ID. - for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) { - tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id); + for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) { + tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id); if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) break; } } else { // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. - tool_ordering = print.m_tool_ordering.empty() ? + tool_ordering = print.wipe_tower_data().tool_ordering.empty() ? ToolOrdering(print, initial_extruder_id) : - print.m_tool_ordering; + print.wipe_tower_data().tool_ordering; initial_extruder_id = tool_ordering.first_extruder(); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); } @@ -587,7 +587,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) m_cooling_buffer->set_current_extruder(initial_extruder_id); // Disable fan. - if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id)) + if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id)) _write(file, m_writer.set_fan(0, true)); // Let the start-up script prime the 1st printing tool. @@ -598,7 +598,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) m_placeholder_parser.set("current_object_idx", 0); // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); - std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id); + std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id); // Set bed temperature if the start G-code does not contain any bed temp control G-codes. this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); @@ -616,16 +616,16 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Write the custom start G-code _writeln(file, start_gcode); // Process filament-specific gcode in extruder order. - if (print.config.single_extruder_multi_material) { + if (print.config().single_extruder_multi_material) { if (has_wipe_tower) { // Wipe tower will control the extruder switching, it will call the start_filament_gcode. } else { // Only initialize the initial extruder. - _writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config.start_filament_gcode.values[initial_extruder_id], initial_extruder_id)); + _writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id)); } } else { - for (const std::string &start_gcode : print.config.start_filament_gcode.values) - _writeln(file, this->placeholder_parser_process("start_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front()))); + for (const std::string &start_gcode : print.config().start_filament_gcode.values) + _writeln(file, this->placeholder_parser_process("start_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front()))); } this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true); print.throw_if_canceled(); @@ -634,12 +634,12 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _write(file, this->preamble()); // Initialize a motion planner for object-to-object travel moves. - if (print.config.avoid_crossing_perimeters.value) { + if (print.config().avoid_crossing_perimeters.value) { // Collect outer contours of all objects over all layers. // Discard objects only containing thin walls (offset would fail on an empty polygon). Polygons islands; - for (const PrintObject *object : print.objects) - for (const Layer *layer : object->layers) + for (const PrintObject *object : print.objects()) + for (const Layer *layer : object->layers()) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->_shifted_copies) { islands.emplace_back(expoly.contour); @@ -651,16 +651,16 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } // Calculate wiping points if needed - if (print.config.ooze_prevention.value && ! print.config.single_extruder_multi_material) { + if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) { Points skirt_points; - for (const ExtrusionEntity *ee : print.skirt.entities) + for (const ExtrusionEntity *ee : print.skirt().entities) for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths) append(skirt_points, path.polyline.points); if (! skirt_points.empty()) { Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); Polygons skirts; for (unsigned int extruder_id : print.extruders()) { - const Pointf &extruder_offset = print.config.extruder_offset.get_at(extruder_id); + const Pointf &extruder_offset = print.config().extruder_offset.get_at(extruder_id); Polygon s(outer_skirt); s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y)); skirts.emplace_back(std::move(s)); @@ -685,10 +685,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _write(file, this->set_extruder(initial_extruder_id)); // Do all objects for each layer. - if (print.config.complete_objects.value) { + if (print.config().complete_objects.value) { // Print objects from the smallest to the tallest to avoid collisions // when moving onto next object starting point. - std::vector<PrintObject*> objects(print.objects); + std::vector<PrintObject*> objects(print.objects()); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; }); size_t finished_objects = 0; for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { @@ -722,7 +722,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // another one, set first layer temperatures. This happens before the Z move // is triggered, so machine has more time to reach such temperatures. m_placeholder_parser.set("current_object_idx", int(finished_objects)); - std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config.between_objects_gcode.value, initial_extruder_id); + std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id); // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature. this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false); @@ -751,7 +751,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Order objects using a nearest neighbor search. std::vector<size_t> object_indices; Points object_reference_points; - for (PrintObject *object : print.objects) + for (PrintObject *object : print.objects()) object_reference_points.push_back(object->_shifted_copies.front()); Slic3r::Geometry::chained_path(object_reference_points, object_indices); // Sort layers by Z. @@ -759,13 +759,13 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> layers_to_print = collect_layers_to_print(print); // Prusa Multi-Material wipe tower. if (has_wipe_tower && ! layers_to_print.empty()) { - m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); + m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); _write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height")); _write(file, m_wipe_tower->prime(*this)); // Verify, whether the print overaps the priming extrusions. BoundingBoxf bbox_print(get_print_extrusions_extents(print)); coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : print.objects) + for (const PrintObject *print_object : print.objects()) bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); @@ -813,14 +813,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } // Process filament-specific gcode in extruder order. - if (print.config.single_extruder_multi_material) { + if (print.config().single_extruder_multi_material) { // Process the end_filament_gcode for the active filament only. - _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id())); + _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id())); } else { - for (const std::string &end_gcode : print.config.end_filament_gcode.values) - _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); + for (const std::string &end_gcode : print.config().end_filament_gcode.values) + _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front()))); } - _writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id())); + _writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id())); _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% _write(file, m_writer.postamble()); print.throw_if_canceled(); @@ -829,31 +829,27 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) m_time_estimator.calculate_time(); // Get filament stats. - print.filament_stats.clear(); - print.total_used_filament = 0.; - print.total_extruded_volume = 0.; - print.total_weight = 0.; - print.total_cost = 0.; - print.estimated_print_time = m_time_estimator.get_time_hms(); + print.m_print_statistics.clear(); + print.m_print_statistics.estimated_print_time = m_time_estimator.get_time_hms(); for (const Extruder &extruder : m_writer.extruders()) { double used_filament = extruder.used_filament(); double extruded_volume = extruder.extruded_volume(); double filament_weight = extruded_volume * extruder.filament_density() * 0.001; double filament_cost = filament_weight * extruder.filament_cost() * 0.001; - print.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament)); + print.m_print_statistics.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament)); _write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001); if (filament_weight > 0.) { - print.total_weight = print.total_weight + filament_weight; + print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight; _write_format(file, "; filament used = %.1lf\n", filament_weight); if (filament_cost > 0.) { - print.total_cost = print.total_cost + filament_cost; + print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost; _write_format(file, "; filament cost = %.1lf\n", filament_cost); } } - print.total_used_filament = print.total_used_filament + used_filament; - print.total_extruded_volume = print.total_extruded_volume + extruded_volume; + print.m_print_statistics.total_used_filament = print.m_print_statistics.total_used_filament + used_filament; + print.m_print_statistics.total_extruded_volume = print.m_print_statistics.total_extruded_volume + extruded_volume; } - _write_format(file, "; total filament cost = %.1lf\n", print.total_cost); + _write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost); _write_format(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms().c_str()); // Append full config. @@ -879,7 +875,7 @@ std::string GCode::placeholder_parser_process(const std::string &name, const std return m_placeholder_parser.process(templ, current_extruder_id, config_override); } catch (std::runtime_error &err) { // Collect the names of failed template substitutions for error reporting. - this->m_placeholder_parser_failed_templates.insert(name); + m_placeholder_parser_failed_templates.insert(name); // Insert the macro error message into the G-code. return std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" + @@ -949,7 +945,7 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) { // Initial bed temperature based on the first extruder. - int temp = print.config.first_layer_bed_temperature.get_at(first_printing_extruder_id); + int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id); // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode); @@ -972,23 +968,23 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c int temp_by_gcode = -1; if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) { // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code. - int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id); + int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id); if (temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id); } else { // Custom G-code does not set the extruder temperature. Do it now. - if (print.config.single_extruder_multi_material.value) { + if (print.config().single_extruder_multi_material.value) { // Set temperature of the first printing extruder only. - int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id); + int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id); if (temp > 0) _write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id)); } else { // Set temperatures of all the printing extruders. for (unsigned int tool_id : print.extruders()) { - int temp = print.config.first_layer_temperature.get_at(tool_id); - if (print.config.ooze_prevention.value) - temp += print.config.standby_temperature_delta.value; + int temp = print.config().first_layer_temperature.get_at(tool_id); + if (print.config().ooze_prevention.value) + temp += print.config().standby_temperature_delta.value; if (temp > 0) _write(file, m_writer.set_temperature(temp, wait, tool_id)); } @@ -1061,15 +1057,15 @@ void GCode::process_layer( unsigned int first_extruder_id = layer_tools.extruders.front(); // Initialize config with the 1st object to be printed at this layer. - m_config.apply(layer.object()->config, true); + m_config.apply(layer.object()->config(), true); // Check whether it is possible to apply the spiral vase logic for this layer. // Just a reminder: A spiral vase mode is allowed for a single object, single material print only. if (m_spiral_vase && layers.size() == 1 && support_layer == nullptr) { - bool enable = (layer.id() > 0 || print.config.brim_width.value == 0.) && (layer.id() >= print.config.skirt_height.value && ! print.has_infinite_skirt()); + bool enable = (layer.id() > 0 || print.config().brim_width.value == 0.) && (layer.id() >= print.config().skirt_height.value && ! print.has_infinite_skirt()); if (enable) { - for (const LayerRegion *layer_region : layer.regions) - if (layer_region->region()->config.bottom_solid_layers.value > layer.id() || + for (const LayerRegion *layer_region : layer.regions()) + if (layer_region->region()->config().bottom_solid_layers.value > layer.id() || layer_region->perimeters.items_count() > 1 || layer_region->fills.items_count() > 0) { enable = false; @@ -1084,22 +1080,22 @@ void GCode::process_layer( std::string gcode; // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled. - if (! print.config.before_layer_gcode.value.empty()) { + if (! print.config().before_layer_gcode.value.empty()) { DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); gcode += this->placeholder_parser_process("before_layer_gcode", - print.config.before_layer_gcode.value, m_writer.extruder()->id(), &config) + print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } gcode += this->change_layer(print_z); // this will increase m_layer_index m_layer = &layer; - if (! print.config.layer_gcode.value.empty()) { + if (! print.config().layer_gcode.value.empty()) { DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); gcode += this->placeholder_parser_process("layer_gcode", - print.config.layer_gcode.value, m_writer.extruder()->id(), &config) + print.config().layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } @@ -1107,14 +1103,14 @@ void GCode::process_layer( // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent // first_layer_temperature vs. temperature settings. for (const Extruder &extruder : m_writer.extruders()) { - if (print.config.single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id()) + if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id()) // In single extruder multi material mode, set the temperature for the current extruder only. continue; - int temperature = print.config.temperature.get_at(extruder.id()); - if (temperature > 0 && temperature != print.config.first_layer_temperature.get_at(extruder.id())) + int temperature = print.config().temperature.get_at(extruder.id()); + if (temperature > 0 && temperature != print.config().first_layer_temperature.get_at(extruder.id())) gcode += m_writer.set_temperature(temperature, false, extruder.id()); } - gcode += m_writer.set_bed_temperature(print.config.bed_temperature.get_at(first_extruder_id)); + gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id)); // Mark the temperature transition from 1st to 2nd layer to be finished. m_second_layer_things_done = true; } @@ -1122,9 +1118,9 @@ void GCode::process_layer( // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. bool extrude_skirt = - ! print.skirt.entities.empty() && + ! print.skirt().entities.empty() && // Not enough skirt layers printed yet. - (m_skirt_done.size() < print.config.skirt_height.value || print.has_infinite_skirt()) && + (m_skirt_done.size() < print.config().skirt_height.value || print.has_infinite_skirt()) && // This print_z has not been extruded yet (m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON && // and this layer is the 1st layer, or it is an object layer, or it is a raft layer. @@ -1146,7 +1142,7 @@ void GCode::process_layer( extruder_ids.front() = first_extruder_id; break; } - size_t n_loops = print.skirt.entities.size(); + size_t n_loops = print.skirt().entities.size(); if (n_loops <= extruder_ids.size()) { for (size_t i = 0; i < n_loops; ++i) skirt_loops_per_extruder[extruder_ids[i]] = std::pair<size_t, size_t>(i, i + 1); @@ -1165,7 +1161,7 @@ void GCode::process_layer( } } else // Extrude all skirts with the current extruder. - skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config.skirts.value); + skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config().skirts.value); } // Group extrusions by an extruder, then by an object, an island and a region. @@ -1180,22 +1176,22 @@ void GCode::process_layer( bool has_support = role == erMixed || role == erSupportMaterial; bool has_interface = role == erMixed || role == erSupportMaterialInterface; // Extruder ID of the support base. -1 if "don't care". - unsigned int support_extruder = object.config.support_material_extruder.value - 1; + unsigned int support_extruder = object.config().support_material_extruder.value - 1; // Shall the support be printed with the active extruder, preferably with non-soluble, to avoid tool changes? - bool support_dontcare = object.config.support_material_extruder.value == 0; + bool support_dontcare = object.config().support_material_extruder.value == 0; // Extruder ID of the support interface. -1 if "don't care". - unsigned int interface_extruder = object.config.support_material_interface_extruder.value - 1; + unsigned int interface_extruder = object.config().support_material_interface_extruder.value - 1; // Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes? - bool interface_dontcare = object.config.support_material_interface_extruder.value == 0; + bool interface_dontcare = object.config().support_material_interface_extruder.value == 0; if (support_dontcare || interface_dontcare) { // Some support will be printed with "don't care" material, preferably non-soluble. // Is the current extruder assigned a soluble filament? unsigned int dontcare_extruder = first_extruder_id; - if (print.config.filament_soluble.get_at(dontcare_extruder)) { + if (print.config().filament_soluble.get_at(dontcare_extruder)) { // The last extruder printed on the previous layer extrudes soluble filament. // Try to find a non-soluble extruder on the same layer. for (unsigned int extruder_id : layer_tools.extruders) - if (! print.config.filament_soluble.get_at(extruder_id)) { + if (! print.config().filament_soluble.get_at(extruder_id)) { dontcare_extruder = extruder_id; break; } @@ -1242,11 +1238,11 @@ void GCode::process_layer( layer.slices.expolygons[i].contour.contains(point); }; - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - const LayerRegion *layerm = layer.regions[region_id]; + for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { + const LayerRegion *layerm = layer.regions()[region_id]; if (layerm == nullptr) continue; - const PrintRegion ®ion = *print.regions[region_id]; + const PrintRegion ®ion = *print.regions()[region_id]; // process perimeters for (const ExtrusionEntity *ee : layerm->perimeters.entities) { @@ -1258,7 +1254,7 @@ void GCode::process_layer( // Init by_extruder item only if we actually use the extruder. std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder( by_extruder, - std::max<int>(region.config.perimeter_extruder.value - 1, 0), + std::max<int>(region.config().perimeter_extruder.value - 1, 0), &layer_to_print - layers.data(), layers.size(), n_slices+1); for (size_t i = 0; i <= n_slices; ++ i) @@ -1267,7 +1263,7 @@ void GCode::process_layer( // perimeter_coll->first_point fits inside ith slice point_inside_surface(i, perimeter_coll->first_point())) { if (islands[i].by_region.empty()) - islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); + islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region()); islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities); break; } @@ -1285,7 +1281,7 @@ void GCode::process_layer( // This shouldn't happen but first_point() would fail. continue; // init by_extruder item only if we actually use the extruder - int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1); + int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1); // Init by_extruder item only if we actually use the extruder. std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder( by_extruder, @@ -1298,7 +1294,7 @@ void GCode::process_layer( // fill->first_point fits inside ith slice point_inside_surface(i, fill->first_point())) { if (islands[i].by_region.empty()) - islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); + islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region()); islands[i].by_region[region_id].infills.append(fill->entities); break; } @@ -1324,7 +1320,7 @@ void GCode::process_layer( Flow skirt_flow = print.skirt_flow(); for (size_t i = loops.first; i < loops.second; ++ i) { // Adjust flow according to this layer's layer height. - ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt.entities[i]); + ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]); Flow layer_skirt_flow(skirt_flow); layer_skirt_flow.height = (float)skirt_height; double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); @@ -1345,7 +1341,7 @@ void GCode::process_layer( if (! m_brim_done) { this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp = true; - for (const ExtrusionEntity *ee : print.brim.entities) + for (const ExtrusionEntity *ee : print.brim().entities) gcode += this->extrude_loop(*dynamic_cast<const ExtrusionLoop*>(ee), "brim", m_config.support_material_speed.value); m_brim_done = true; m_avoid_crossing_perimeters.use_external_mp = false; @@ -1363,7 +1359,7 @@ void GCode::process_layer( // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. continue; - m_config.apply(print_object->config, true); + m_config.apply(print_object->config(), true); m_layer = layers[layer_id].layer(); if (m_config.avoid_crossing_perimeters) m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true)); @@ -1389,7 +1385,7 @@ void GCode::process_layer( m_layer = layers[layer_id].layer(); } for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { - if (print.config.infill_first) { + if (print.config().infill_first) { gcode += this->extrude_infill(print, island.by_region); gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); } else { @@ -1430,7 +1426,7 @@ void GCode::apply_print_config(const PrintConfig &print_config) void GCode::append_full_config(const Print& print, std::string& str) { - const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config }; + const StaticPrintConfig *configs[] = { &print.config(), &print.default_object_config(), &print.default_region_config() }; for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { const StaticPrintConfig *cfg = configs[i]; for (const std::string &key : cfg->keys()) @@ -2015,7 +2011,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje { std::string gcode; for (const ObjectByExtruder::Island::Region ®ion : by_region) { - m_config.apply(print.regions[®ion - &by_region.front()]->config); + m_config.apply(print.regions()[®ion - &by_region.front()]->config()); for (ExtrusionEntity *ee : region.perimeters.entities) gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid); } @@ -2027,7 +2023,7 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy { std::string gcode; for (const ObjectByExtruder::Island::Region ®ion : by_region) { - m_config.apply(print.regions[®ion - &by_region.front()]->config); + m_config.apply(print.regions()[®ion - &by_region.front()]->config()); ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false); for (ExtrusionEntity *fill : chained.entities) { auto *eec = dynamic_cast<ExtrusionEntityCollection*>(fill); diff --git a/xs/src/libslic3r/GCode/PrintExtents.cpp b/xs/src/libslic3r/GCode/PrintExtents.cpp index 3c3f0f8d5..43352ee82 100644 --- a/xs/src/libslic3r/GCode/PrintExtents.cpp +++ b/xs/src/libslic3r/GCode/PrintExtents.cpp @@ -99,19 +99,19 @@ static BoundingBoxf extrusionentity_extents(const ExtrusionEntity *extrusion_ent BoundingBoxf get_print_extrusions_extents(const Print &print) { - BoundingBoxf bbox(extrusionentity_extents(print.brim)); - bbox.merge(extrusionentity_extents(print.skirt)); + BoundingBoxf bbox(extrusionentity_extents(print.brim())); + bbox.merge(extrusionentity_extents(print.skirt())); return bbox; } BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z) { BoundingBoxf bbox; - for (const Layer *layer : print_object.layers) { + for (const Layer *layer : print_object.layers()) { if (layer->print_z > max_print_z) break; BoundingBoxf bbox_this; - for (const LayerRegion *layerm : layer->regions) { + for (const LayerRegion *layerm : layer->regions()) { bbox_this.merge(extrusionentity_extents(layerm->perimeters)); for (const ExtrusionEntity *ee : layerm->fills.entities) // fill represents infill extrusions of a single island. @@ -135,7 +135,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z) { BoundingBoxf bbox; - for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) { + for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.wipe_tower_data().tool_changes) { if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z) break; for (const WipeTower::ToolChangeResult &tcr : tool_changes) { @@ -161,8 +161,8 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print) { BoundingBoxf bbox; - if (print.m_wipe_tower_priming) { - const WipeTower::ToolChangeResult &tcr = *print.m_wipe_tower_priming.get(); + if (print.wipe_tower_data().priming != nullptr) { + const WipeTower::ToolChangeResult &tcr = *print.wipe_tower_data().priming; for (size_t i = 1; i < tcr.extrusions.size(); ++ i) { const WipeTower::Extrusion &e = tcr.extrusions[i]; if (e.width > 0) { diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 271b75ef3..6e03d89c9 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -16,19 +16,19 @@ namespace Slic3r { // For the use case when each object is printed separately -// (print.config.complete_objects is true). +// (print.config().complete_objects is true). ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material) { - if (object.layers.empty()) + if (object.layers().empty()) return; // Initialize the print layers for just a single object. { std::vector<coordf_t> zs; - zs.reserve(zs.size() + object.layers.size() + object.support_layers.size()); - for (auto layer : object.layers) + zs.reserve(zs.size() + object.layers().size() + object.support_layers().size()); + for (auto layer : object.layers()) zs.emplace_back(layer->print_z); - for (auto layer : object.support_layers) + for (auto layer : object.support_layers()) zs.emplace_back(layer->print_z); this->initialize_layers(zs); } @@ -39,39 +39,39 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); - this->fill_wipe_tower_partitions(object.print()->config, object.layers.front()->print_z - object.layers.front()->height); + this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height); this->collect_extruder_statistics(prime_multi_material); } // For the use case when all objects are printed at once. -// (print.config.complete_objects is false). +// (print.config().complete_objects is false). ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { std::vector<coordf_t> zs; - for (auto object : print.objects) { - zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); - for (auto layer : object->layers) + for (auto object : print.objects()) { + zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); + for (auto layer : object->layers()) zs.emplace_back(layer->print_z); - for (auto layer : object->support_layers) + for (auto layer : object->support_layers()) zs.emplace_back(layer->print_z); - if (! object->layers.empty()) - object_bottom_z = object->layers.front()->print_z - object->layers.front()->height; + if (! object->layers().empty()) + object_bottom_z = object->layers().front()->print_z - object->layers().front()->height; } this->initialize_layers(zs); } // Collect extruders reuqired to print the layers. - for (auto object : print.objects) + for (auto object : print.objects()) this->collect_extruders(*object); // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); - this->fill_wipe_tower_partitions(print.config, object_bottom_z); + this->fill_wipe_tower_partitions(print.config(), object_bottom_z); this->collect_extruder_statistics(prime_multi_material); } @@ -111,13 +111,13 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs) void ToolOrdering::collect_extruders(const PrintObject &object) { // Collect the support extruders. - for (auto support_layer : object.support_layers) { + for (auto support_layer : object.support_layers()) { LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z); ExtrusionRole role = support_layer->support_fills.role(); bool has_support = role == erMixed || role == erSupportMaterial; bool has_interface = role == erMixed || role == erSupportMaterialInterface; - unsigned int extruder_support = object.config.support_material_extruder.value; - unsigned int extruder_interface = object.config.support_material_interface_extruder.value; + unsigned int extruder_support = object.config().support_material_extruder.value; + unsigned int extruder_interface = object.config().support_material_interface_extruder.value; if (has_support) layer_tools.extruders.push_back(extruder_support); if (has_interface) @@ -126,16 +126,16 @@ void ToolOrdering::collect_extruders(const PrintObject &object) layer_tools.has_support = true; } // Collect the object extruders. - for (auto layer : object.layers) { + for (auto layer : object.layers()) { LayerTools &layer_tools = this->tools_for_layer(layer->print_z); // What extruders are required to print this object layer? - for (size_t region_id = 0; region_id < object.print()->regions.size(); ++ region_id) { - const LayerRegion *layerm = (region_id < layer->regions.size()) ? layer->regions[region_id] : nullptr; + for (size_t region_id = 0; region_id < object.print()->regions().size(); ++ region_id) { + const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; if (layerm == nullptr) continue; - const PrintRegion ®ion = *object.print()->regions[region_id]; + const PrintRegion ®ion = *object.print()->regions()[region_id]; if (! layerm->perimeters.entities.empty()) { - layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + layer_tools.extruders.push_back(region.config().perimeter_extruder.value); layer_tools.has_object = true; } bool has_infill = false; @@ -150,9 +150,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object) has_infill = true; } if (has_solid_infill) - layer_tools.extruders.push_back(region.config.solid_infill_extruder); + layer_tools.extruders.push_back(region.config().solid_infill_extruder); if (has_infill) - layer_tools.extruders.push_back(region.config.infill_extruder); + layer_tools.extruders.push_back(region.config().infill_extruder); if (has_solid_infill || has_infill) layer_tools.has_object = true; } diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 99c6c757f..069f975dd 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -396,8 +396,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( } this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false); - this->m_num_layer_changes = 0; - this->m_current_tool = tools.front(); + m_num_layer_changes = 0; + m_current_tool = tools.front(); // The Prusa i3 MK2 has a working space of [0, -2.2] to [250, 210]. // Due to the XYZ calibration, this working space may shrink slightly from all directions, @@ -439,9 +439,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( if (last_wipe_inside_wipe_tower) { // Shrink the last wipe area to the area of the other purge areas, // remember the last initial wipe width to be purged into the 1st layer of the wipe tower. - this->m_initial_extra_wipe = std::max(0.f, wipe_area - (y_end + 0.5f * 0.85f * m_perimeter_width - cleaning_box.ld.y)); - cleaning_box.lu.y -= this->m_initial_extra_wipe; - cleaning_box.ru.y -= this->m_initial_extra_wipe; + m_initial_extra_wipe = std::max(0.f, wipe_area - (y_end + 0.5f * 0.85f * m_perimeter_width - cleaning_box.ld.y)); + cleaning_box.lu.y -= m_initial_extra_wipe; + cleaning_box.ru.y -= m_initial_extra_wipe; } toolchange_Wipe(writer, cleaning_box, false); } else { @@ -471,8 +471,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( m_idx_tool_change_in_layer = (unsigned int)(-1); ToolChangeResult result; - result.print_z = this->m_z_pos; - result.layer_height = this->m_layer_height; + result.print_z = m_z_pos; + result.layer_height = m_layer_height; result.gcode = writer.gcode(); result.elapsed_time = writer.elapsed_time(); result.extrusions = writer.extrusions(); @@ -612,8 +612,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo } ToolChangeResult result; - result.print_z = this->m_z_pos; - result.layer_height = this->m_layer_height; + result.print_z = m_z_pos; + result.layer_height = m_layer_height; result.gcode = writer.gcode(); result.elapsed_time = writer.elapsed_time(); result.extrusions = writer.extrusions(); @@ -718,8 +718,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b } ToolChangeResult result; - result.print_z = this->m_z_pos; - result.layer_height = this->m_layer_height; + result.print_z = m_z_pos; + result.layer_height = m_layer_height; result.gcode = writer.gcode(); result.elapsed_time = writer.elapsed_time(); result.extrusions = writer.extrusions(); @@ -1040,8 +1040,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer(Purpose purpose) } ToolChangeResult result; - result.print_z = this->m_z_pos; - result.layer_height = this->m_layer_height; + result.print_z = m_z_pos; + result.layer_height = m_layer_height; result.gcode = writer.gcode(); result.elapsed_time = writer.elapsed_time(); result.extrusions = writer.extrusions(); diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index 3dc2335d7..72ac371a2 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -12,24 +12,24 @@ namespace Slic3r { Layer::~Layer() { this->lower_layer = this->upper_layer = nullptr; - for (LayerRegion *region : this->regions) + for (LayerRegion *region : m_regions) delete region; - this->regions.clear(); + m_regions.clear(); } LayerRegion* Layer::add_region(PrintRegion* print_region) { - this->regions.emplace_back(new LayerRegion(this, print_region)); - return this->regions.back(); + m_regions.emplace_back(new LayerRegion(this, print_region)); + return m_regions.back(); } // merge all regions' slices to get islands void Layer::make_slices() { ExPolygons slices; - if (this->regions.size() == 1) { + if (m_regions.size() == 1) { // optimization: if we only have one region, take its slices - slices = this->regions.front()->slices; + slices = m_regions.front()->slices; } else { Polygons slices_p; FOREACH_LAYERREGION(this, layerm) { @@ -58,10 +58,10 @@ void Layer::make_slices() void Layer::merge_slices() { - if (this->regions.size() == 1) { + if (m_regions.size() == 1) { // Optimization, also more robust. Don't merge classified pieces of layerm->slices, // but use the non-split islands of a layer. For a single region print, these shall be equal. - this->regions.front()->slices.set(this->slices.expolygons, stInternal); + m_regions.front()->slices.set(this->slices.expolygons, stInternal); } else { FOREACH_LAYERREGION(this, layerm) { // without safety offset, artifacts are generated (GH #2494) @@ -81,18 +81,18 @@ void Layer::make_perimeters() std::set<size_t> done; FOREACH_LAYERREGION(this, layerm) { - size_t region_id = layerm - this->regions.begin(); + size_t region_id = layerm - m_regions.begin(); if (done.find(region_id) != done.end()) continue; BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id; done.insert(region_id); - const PrintRegionConfig &config = (*layerm)->region()->config; + const PrintRegionConfig &config = (*layerm)->region()->config(); // find compatible regions LayerRegionPtrs layerms; layerms.push_back(*layerm); - for (LayerRegionPtrs::const_iterator it = layerm + 1; it != this->regions.end(); ++it) { + for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) { LayerRegion* other_layerm = *it; - const PrintRegionConfig &other_config = other_layerm->region()->config; + const PrintRegionConfig &other_config = other_layerm->region()->config(); if (config.perimeter_extruder == other_config.perimeter_extruder && config.perimeters == other_config.perimeters @@ -104,7 +104,7 @@ void Layer::make_perimeters() && config.thin_walls == other_config.thin_walls && config.external_perimeters_first == other_config.external_perimeters_first) { layerms.push_back(other_layerm); - done.insert(it - this->regions.begin()); + done.insert(it - m_regions.begin()); } } @@ -150,7 +150,7 @@ void Layer::make_fills() #ifdef SLIC3R_DEBUG printf("Making fills for layer " PRINTF_ZU "\n", this->id()); #endif - for (LayerRegion *layerm : regions) { + for (LayerRegion *layerm : m_regions) { layerm->fills.clear(); make_fill(*layerm, layerm->fills); #ifndef NDEBUG @@ -163,18 +163,18 @@ void Layer::make_fills() void Layer::export_region_slices_to_svg(const char *path) const { BoundingBox bbox; - for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) - for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface) - bbox.merge(get_extents(surface->expolygon)); + for (const auto *region : m_regions) + for (const auto &surface : region->slices.surfaces) + bbox.merge(get_extents(surface.expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); Point legend_pos(bbox.min.x, bbox.max.y); bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); SVG svg(path, bbox); const float transparency = 0.5f; - for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) - for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface) - svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + for (const auto *region : m_regions) + for (const auto &surface : region->slices.surfaces) + svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency); export_surface_type_legend_to_svg(svg, legend_pos); svg.Close(); } @@ -189,18 +189,18 @@ void Layer::export_region_slices_to_svg_debug(const char *name) const void Layer::export_region_fill_surfaces_to_svg(const char *path) const { BoundingBox bbox; - for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) - for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface) - bbox.merge(get_extents(surface->expolygon)); + for (const auto *region : m_regions) + for (const auto &surface : region->slices.surfaces) + bbox.merge(get_extents(surface.expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); Point legend_pos(bbox.min.x, bbox.max.y); bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); SVG svg(path, bbox); const float transparency = 0.5f; - for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) - for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface) - svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + for (const auto *region : m_regions) + for (const auto &surface : region->slices.surfaces) + svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency); export_surface_type_legend_to_svg(svg, legend_pos); svg.Close(); } diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index f3b460443..8dbe850cc 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -15,95 +15,93 @@ class Layer; class PrintRegion; class PrintObject; -// TODO: make stuff private class LayerRegion { - friend class Layer; - public: - Layer* layer() { return this->_layer; } - const Layer* layer() const { return this->_layer; } - PrintRegion* region() { return this->_region; } - const PrintRegion* region() const { return this->_region; } + Layer* layer() { return m_layer; } + const Layer* layer() const { return m_layer; } + PrintRegion* region() { return m_region; } + const PrintRegion* region() const { return m_region; } // collection of surfaces generated by slicing the original geometry // divided by type top/bottom/internal - SurfaceCollection slices; + SurfaceCollection slices; // collection of extrusion paths/loops filling gaps // These fills are generated by the perimeter generator. // They are not printed on their own, but they are copied to this->fills during infill generation. - ExtrusionEntityCollection thin_fills; + ExtrusionEntityCollection thin_fills; // Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature") // and for re-starting of infills. - ExPolygons fill_expolygons; + ExPolygons fill_expolygons; // collection of surfaces for infill generation - SurfaceCollection fill_surfaces; + SurfaceCollection fill_surfaces; // Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces). // While not necessary, the memory consumption is meager and it speeds up calculation. // The perimeter_surfaces keep the IDs of the slices (top/bottom/) - SurfaceCollection perimeter_surfaces; + SurfaceCollection perimeter_surfaces; // collection of expolygons representing the bridged areas (thus not // needing support material) - Polygons bridged; + Polygons bridged; // collection of polylines representing the unsupported bridge edges - PolylineCollection unsupported_bridge_edges; + PolylineCollection unsupported_bridge_edges; // ordered collection of extrusion paths/loops to build all perimeters // (this collection contains only ExtrusionEntityCollection objects) - ExtrusionEntityCollection perimeters; + ExtrusionEntityCollection perimeters; // ordered collection of extrusion paths to fill surfaces // (this collection contains only ExtrusionEntityCollection objects) - ExtrusionEntityCollection fills; + ExtrusionEntityCollection fills; - Flow flow(FlowRole role, bool bridge = false, double width = -1) const; - void slices_to_fill_surfaces_clipped(); - void prepare_fill_surfaces(); - void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces); - void process_external_surfaces(const Layer* lower_layer); + Flow flow(FlowRole role, bool bridge = false, double width = -1) const; + void slices_to_fill_surfaces_clipped(); + void prepare_fill_surfaces(); + void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces); + void process_external_surfaces(const Layer* lower_layer); double infill_area_threshold() const; - void export_region_slices_to_svg(const char *path) const; - void export_region_fill_surfaces_to_svg(const char *path) const; + void export_region_slices_to_svg(const char *path) const; + void export_region_fill_surfaces_to_svg(const char *path) const; // Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. - void export_region_slices_to_svg_debug(const char *name) const; - void export_region_fill_surfaces_to_svg_debug(const char *name) const; + void export_region_slices_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? - 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: - Layer *_layer; - PrintRegion *_region; +protected: + friend class Layer; - LayerRegion(Layer *layer, PrintRegion *region) : _layer(layer), _region(region) {} + LayerRegion(Layer *layer, PrintRegion *region) : m_layer(layer), m_region(region) {} ~LayerRegion() {} + +private: + Layer *m_layer; + PrintRegion *m_region; }; typedef std::vector<LayerRegion*> LayerRegionPtrs; -class Layer { - friend class PrintObject; - +class Layer +{ public: - size_t id() const { return this->_id; } - void set_id(size_t id) { this->_id = id; } - PrintObject* object() { return this->_object; } - const PrintObject* object() const { return this->_object; } - - Layer *upper_layer; - Layer *lower_layer; - LayerRegionPtrs regions; - bool slicing_errors; - coordf_t slice_z; // Z used for slicing in unscaled coordinates - coordf_t print_z; // Z used for printing in unscaled coordinates - coordf_t height; // layer height in unscaled coordinates + size_t id() const { return m_id; } + void set_id(size_t id) { m_id = id; } + PrintObject* object() { return m_object; } + const PrintObject* object() const { return m_object; } + + Layer *upper_layer; + Layer *lower_layer; + bool slicing_errors; + coordf_t slice_z; // Z used for slicing in unscaled coordinates + coordf_t print_z; // Z used for printing in unscaled coordinates + coordf_t height; // layer height in unscaled coordinates // collection of expolygons generated by slicing the original geometry; // also known as 'islands' (all regions and surface types are merged here) @@ -111,57 +109,64 @@ public: // order will be recovered by the G-code generator. ExPolygonCollection slices; - size_t region_count() const { return this->regions.size(); } - const LayerRegion* get_region(int idx) const { return this->regions.at(idx); } - LayerRegion* get_region(int idx) { return this->regions.at(idx); } - LayerRegion* add_region(PrintRegion* print_region); + size_t region_count() const { return m_regions.size(); } + const LayerRegion* get_region(int idx) const { return m_regions.at(idx); } + LayerRegion* get_region(int idx) { return m_regions[idx]; } + LayerRegion* add_region(PrintRegion* print_region); + const LayerRegionPtrs& regions() const { return m_regions; } - void make_slices(); - void merge_slices(); + void make_slices(); + void merge_slices(); template <class T> bool any_internal_region_slice_contains(const T &item) const { - for (const LayerRegion *layerm : this->regions) if (layerm->slices.any_internal_contains(item)) return true; + for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_internal_contains(item)) return true; return false; } template <class T> bool any_bottom_region_slice_contains(const T &item) const { - for (const LayerRegion *layerm : this->regions) if (layerm->slices.any_bottom_contains(item)) return true; + for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_bottom_contains(item)) return true; return false; } - void make_perimeters(); - void make_fills(); + void make_perimeters(); + void make_fills(); - void export_region_slices_to_svg(const char *path) const; - void export_region_fill_surfaces_to_svg(const char *path) const; + void export_region_slices_to_svg(const char *path) const; + void export_region_fill_surfaces_to_svg(const char *path) const; // Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. - void export_region_slices_to_svg_debug(const char *name) const; - void export_region_fill_surfaces_to_svg_debug(const char *name) const; + void export_region_slices_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? - virtual bool has_extrusions() const { for (auto layerm : this->regions) if (layerm->has_extrusions()) return true; return false; } + virtual bool has_extrusions() const { for (auto layerm : m_regions) if (layerm->has_extrusions()) return true; return false; } protected: - size_t _id; // sequential number of layer, 0-based - PrintObject *_object; + friend class PrintObject; Layer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : upper_layer(nullptr), lower_layer(nullptr), slicing_errors(false), slice_z(slice_z), print_z(print_z), height(height), - _id(id), _object(object) {} + m_id(id), m_object(object) {} virtual ~Layer(); -}; -class SupportLayer : public Layer { - friend class PrintObject; +private: + // sequential number of layer, 0-based + size_t m_id; + PrintObject *m_object; + LayerRegionPtrs m_regions; +}; +class SupportLayer : public Layer +{ public: // Polygons covered by the supports: base, interface and contact areas. - ExPolygonCollection support_islands; + ExPolygonCollection support_islands; // Extrusion paths for the support base and for the support interface and contacts. - ExtrusionEntityCollection support_fills; + ExtrusionEntityCollection support_fills; // 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: + friend class PrintObject; -//protected: // The constructor has been made public to be able to insert additional support layers for the skirt or a wipe tower // between the raft and the object first layer. SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 68d1c5829..c576d7eec 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -18,13 +18,13 @@ namespace Slic3r { Flow LayerRegion::flow(FlowRole role, bool bridge, double width) const { - return this->_region->flow( + return m_region->flow( role, - this->_layer->height, + m_layer->height, bridge, - this->_layer->id() == 0, + m_layer->id() == 0, width, - *this->_layer->object() + *m_layer->object() ); } @@ -61,9 +61,9 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec &slices, this->layer()->height, this->flow(frPerimeter), - &this->region()->config, - &this->layer()->object()->config, - &this->layer()->object()->print()->config, + &this->region()->config(), + &this->layer()->object()->config(), + &this->layer()->object()->print()->config(), // output: &this->perimeters, @@ -116,7 +116,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) { // bottom_polygons are used to trim inflated top surfaces. fill_boundaries.reserve(number_polygons(surfaces)); - bool has_infill = this->region()->config.fill_density.value > 0.; + bool has_infill = this->region()->config().fill_density.value > 0.; for (const Surface &surface : this->fill_surfaces.surfaces) { if (surface.surface_type == stTop) { // Collect the top surfaces, inflate them and trim them by the bottom surfaces. @@ -259,9 +259,9 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) #ifdef SLIC3R_DEBUG printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); #endif - if (bd.detect_angle(Geometry::deg2rad(this->region()->config.bridge_angle.value))) { + if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) { bridges[idx_last].bridge_angle = bd.angle; - if (this->layer()->object()->config.support_material) { + if (this->layer()->object()->config().support_material) { polygons_append(this->bridged, bd.coverage()); this->unsupported_bridge_edges.append(bd.unsupported_edges()); } @@ -351,13 +351,13 @@ void LayerRegion::prepare_fill_surfaces() the only meaningful information returned by psPerimeters. */ // if no solid layers are requested, turn top/bottom surfaces to internal - if (this->region()->config.top_solid_layers == 0) { + if (this->region()->config().top_solid_layers == 0) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) if (surface->surface_type == stTop) - surface->surface_type = (this->layer()->object()->config.infill_only_where_needed) ? + surface->surface_type = (this->layer()->object()->config().infill_only_where_needed) ? stInternalVoid : stInternal; } - if (this->region()->config.bottom_solid_layers == 0) { + if (this->region()->config().bottom_solid_layers == 0) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge) surface->surface_type = stInternal; @@ -365,9 +365,9 @@ void LayerRegion::prepare_fill_surfaces() } // turn too small internal regions into solid regions according to the user setting - if (this->region()->config.fill_density.value > 0) { + if (this->region()->config().fill_density.value > 0) { // scaling an area requires two calls! - double min_area = scale_(scale_(this->region()->config.solid_infill_below_area.value)); + double min_area = scale_(scale_(this->region()->config().solid_infill_below_area.value)); for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { if (surface->surface_type == stInternal && surface->area() <= min_area) surface->surface_type = stInternalSolid; diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index ea9c73fa4..176f28926 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -6,8 +6,7 @@ namespace Slic3r { -void -PerimeterGenerator::process() +void PerimeterGenerator::process() { // other perimeters this->_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); diff --git a/xs/src/libslic3r/PerimeterGenerator.hpp b/xs/src/libslic3r/PerimeterGenerator.hpp index 04557a2c0..dd1f9b0ec 100644 --- a/xs/src/libslic3r/PerimeterGenerator.hpp +++ b/xs/src/libslic3r/PerimeterGenerator.hpp @@ -38,30 +38,30 @@ typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops; class PerimeterGenerator { public: // Inputs: - const SurfaceCollection* slices; - const ExPolygonCollection* lower_slices; - double layer_height; - int layer_id; - Flow perimeter_flow; - Flow ext_perimeter_flow; - Flow overhang_flow; - Flow solid_infill_flow; - PrintRegionConfig* config; - PrintObjectConfig* object_config; - PrintConfig* print_config; + const SurfaceCollection *slices; + const ExPolygonCollection *lower_slices; + double layer_height; + int layer_id; + Flow perimeter_flow; + Flow ext_perimeter_flow; + Flow overhang_flow; + Flow solid_infill_flow; + const PrintRegionConfig *config; + const PrintObjectConfig *object_config; + const PrintConfig *print_config; // Outputs: - ExtrusionEntityCollection* loops; - ExtrusionEntityCollection* gap_fill; - SurfaceCollection* fill_surfaces; + ExtrusionEntityCollection *loops; + ExtrusionEntityCollection *gap_fill; + SurfaceCollection *fill_surfaces; PerimeterGenerator( // Input: const SurfaceCollection* slices, double layer_height, Flow flow, - PrintRegionConfig* config, - PrintObjectConfig* object_config, - PrintConfig* print_config, + const PrintRegionConfig* config, + const PrintObjectConfig* object_config, + const PrintConfig* print_config, // Output: // Loops with the external thin walls ExtrusionEntityCollection* loops, @@ -79,15 +79,13 @@ public: void process(); private: - double _ext_mm3_per_mm; - double _mm3_per_mm; - double _mm3_per_mm_overhang; - Polygons _lower_slices_p; + double _ext_mm3_per_mm; + double _mm3_per_mm; + double _mm3_per_mm_overhang; + Polygons _lower_slices_p; - ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, - ThickPolylines &thin_walls) const; - ExtrusionEntityCollection _variable_width - (const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const; + ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const; + ExtrusionEntityCollection _variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const; }; } diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index 62b516935..848e7fd2a 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -69,7 +69,7 @@ PlaceholderParser::PlaceholderParser() this->update_timestamp(); } -void PlaceholderParser::update_timestamp() +void PlaceholderParser::update_timestamp(DynamicConfig &config) { time_t rawtime; time(&rawtime); @@ -84,14 +84,14 @@ void PlaceholderParser::update_timestamp() ss << std::setw(2) << std::setfill('0') << timeinfo->tm_hour; ss << std::setw(2) << std::setfill('0') << timeinfo->tm_min; ss << std::setw(2) << std::setfill('0') << timeinfo->tm_sec; - this->set("timestamp", ss.str()); + config.set_key_value("timestamp", new ConfigOptionString(ss.str())); } - this->set("year", 1900 + timeinfo->tm_year); - this->set("month", 1 + timeinfo->tm_mon); - this->set("day", timeinfo->tm_mday); - this->set("hour", timeinfo->tm_hour); - this->set("minute", timeinfo->tm_min); - this->set("second", timeinfo->tm_sec); + config.set_key_value("year", new ConfigOptionInt(1900 + timeinfo->tm_year)); + config.set_key_value("month", new ConfigOptionInt(1 + timeinfo->tm_mon)); + config.set_key_value("day", new ConfigOptionInt(timeinfo->tm_mday)); + config.set_key_value("hour", new ConfigOptionInt(timeinfo->tm_hour)); + config.set_key_value("minute", new ConfigOptionInt(timeinfo->tm_min)); + config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec)); } // Scalar configuration values are stored into m_single, diff --git a/xs/src/libslic3r/PlaceholderParser.hpp b/xs/src/libslic3r/PlaceholderParser.hpp index 4e0aa9ee2..49d53ec9e 100644 --- a/xs/src/libslic3r/PlaceholderParser.hpp +++ b/xs/src/libslic3r/PlaceholderParser.hpp @@ -14,7 +14,6 @@ class PlaceholderParser public: PlaceholderParser(); - void update_timestamp(); void apply_config(const DynamicPrintConfig &config); void apply_env_variables(); @@ -37,6 +36,11 @@ public: // Throws std::runtime_error on syntax or runtime error. static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr); + // Update timestamp, year, month, day, hour, minute, second variables at the provided config. + static void update_timestamp(DynamicConfig &config); + // Update timestamp, year, month, day, hour, minute, second variables at m_config. + void update_timestamp() { update_timestamp(m_config); } + private: DynamicConfig m_config; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index d67fe5884..e8a010a79 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -20,24 +20,27 @@ template class PrintState<PrintObjectStep, posCount>; void Print::clear_objects() { - for (int i = int(this->objects.size())-1; i >= 0; --i) + tbb::mutex::scoped_lock lock(m_mutex); + for (int i = int(m_objects.size())-1; i >= 0; --i) this->delete_object(i); - for (PrintRegion *region : this->regions) + for (PrintRegion *region : m_regions) delete region; - this->regions.clear(); + m_regions.clear(); } void Print::delete_object(size_t idx) { + tbb::mutex::scoped_lock lock(m_mutex); // destroy object and remove it from our container - delete this->objects[idx]; - this->objects.erase(this->objects.begin() + idx); + delete m_objects[idx]; + m_objects.erase(m_objects.begin() + idx); this->invalidate_all_steps(); // TODO: purge unused regions } void Print::reload_object(size_t /* idx */) { + tbb::mutex::scoped_lock lock(m_mutex); /* TODO: this method should check whether the per-object config and per-material configs have changed in such a way that regions need to be rearranged or we can just apply the diff and invalidate something. Same logic as apply_config() @@ -46,8 +49,8 @@ void Print::reload_object(size_t /* idx */) // collect all current model objects ModelObjectPtrs model_objects; - model_objects.reserve(this->objects.size()); - for (PrintObject *object : this->objects) + model_objects.reserve(m_objects.size()); + for (PrintObject *object : m_objects) model_objects.push_back(object->model_object()); // remove our print objects this->clear_objects(); @@ -63,15 +66,21 @@ void Print::reload_object(size_t /* idx */) bool Print::reload_model_instances() { bool invalidated = false; - for (PrintObject *object : this->objects) + for (PrintObject *object : m_objects) invalidated |= object->reload_model_instances(); return invalidated; } PrintRegion* Print::add_region() { - regions.push_back(new PrintRegion(this)); - return regions.back(); + m_regions.emplace_back(new PrintRegion(this)); + return m_regions.back(); +} + +PrintRegion* Print::add_region(const PrintRegionConfig &config) +{ + m_regions.emplace_back(new PrintRegion(this, config)); + return m_regions.back(); } // Called by Print::apply_config(). @@ -224,18 +233,18 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option invalidated |= this->invalidate_step(step); sort_remove_duplicates(osteps); for (PrintObjectStep ostep : osteps) - for (PrintObject *object : this->objects) + for (PrintObject *object : m_objects) invalidated |= object->invalidate_step(ostep); return invalidated; } bool Print::invalidate_step(PrintStep step) { - bool invalidated = m_state.invalidate(step); + bool invalidated = m_state.invalidate(step, m_mutex, m_cancel_callback); // Propagate to dependent steps. //FIXME Why should skirt invalidate brim? Shouldn't it be vice versa? if (step == psSkirt) - invalidated |= m_state.invalidate(psBrim); + invalidated |= m_state.invalidate(psBrim, m_mutex, m_cancel_callback); return invalidated; } @@ -243,9 +252,9 @@ bool Print::invalidate_step(PrintStep step) // and there's at least one object bool Print::is_step_done(PrintObjectStep step) const { - if (this->objects.empty()) + if (m_objects.empty()) return false; - for (const PrintObject *object : this->objects) + for (const PrintObject *object : m_objects) if (!object->m_state.is_done(step)) return false; return true; @@ -256,15 +265,15 @@ std::vector<unsigned int> Print::object_extruders() const { std::vector<unsigned int> extruders; - for (PrintRegion* region : this->regions) { + for (PrintRegion* region : m_regions) { // these checks reflect the same logic used in the GUI for enabling/disabling // extruder selection fields - if (region->config.perimeters.value > 0 || this->config.brim_width.value > 0) - extruders.push_back(region->config.perimeter_extruder - 1); - if (region->config.fill_density.value > 0) - extruders.push_back(region->config.infill_extruder - 1); - if (region->config.top_solid_layers.value > 0 || region->config.bottom_solid_layers.value > 0) - extruders.push_back(region->config.solid_infill_extruder - 1); + if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0) + extruders.push_back(region->config().perimeter_extruder - 1); + if (region->config().fill_density.value > 0) + extruders.push_back(region->config().infill_extruder - 1); + if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0) + extruders.push_back(region->config().solid_infill_extruder - 1); } sort_remove_duplicates(extruders); @@ -277,16 +286,16 @@ std::vector<unsigned int> Print::support_material_extruders() const std::vector<unsigned int> extruders; bool support_uses_current_extruder = false; - for (PrintObject *object : this->objects) { + for (PrintObject *object : m_objects) { if (object->has_support_material()) { - if (object->config.support_material_extruder == 0) + if (object->config().support_material_extruder == 0) support_uses_current_extruder = true; else - extruders.push_back(object->config.support_material_extruder - 1); - if (object->config.support_material_interface_extruder == 0) + extruders.push_back(object->config().support_material_extruder - 1); + if (object->config().support_material_interface_extruder == 0) support_uses_current_extruder = true; else - extruders.push_back(object->config.support_material_interface_extruder - 1); + extruders.push_back(object->config().support_material_interface_extruder - 1); } } @@ -309,10 +318,10 @@ std::vector<unsigned int> Print::extruders() const void Print::_simplify_slices(double distance) { - for (PrintObject *object : this->objects) { - for (Layer *layer : object->layers) { + for (PrintObject *object : m_objects) { + for (Layer *layer : object->m_layers) { layer->slices.simplify(distance); - for (LayerRegion *layerm : layer->regions) + for (LayerRegion *layerm : layer->regions()) layerm->slices.simplify(distance); } } @@ -322,7 +331,7 @@ double Print::max_allowed_layer_height() const { double nozzle_diameter_max = 0.; for (unsigned int extruder_id : this->extruders()) - nozzle_diameter_max = std::max(nozzle_diameter_max, this->config.nozzle_diameter.get_at(extruder_id)); + nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(extruder_id)); return nozzle_diameter_max; } @@ -333,10 +342,10 @@ void Print::add_model_object(ModelObject* model_object, int idx) // Initialize a new print object and store it at the given position. PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box()); if (idx != -1) { - delete this->objects[idx]; - this->objects[idx] = object; + delete m_objects[idx]; + m_objects[idx] = object; } else - this->objects.emplace_back(object); + m_objects.emplace_back(object); // Invalidate all print steps. this->invalidate_all_steps(); @@ -345,37 +354,42 @@ void Print::add_model_object(ModelObject* model_object, int idx) PrintRegionConfig config = this->_region_config_from_model_volume(*model_object->volumes[volume_id]); // Find an existing print region with the same config. size_t region_id = size_t(-1); - for (size_t i = 0; i < this->regions.size(); ++ i) - if (config.equals(this->regions[i]->config)) { + for (size_t i = 0; i < m_regions.size(); ++ i) + if (config.equals(m_regions[i]->config())) { region_id = i; break; } // If no region exists with the same config, create a new one. if (region_id == size_t(-1)) { - region_id = this->regions.size(); - this->add_region()->config.apply(config); + region_id = this->regions().size(); + this->add_region(config); } // Assign volume to a region. object->add_region_volume(region_id, volume_id); } // Apply config to print object. - object->config.apply(this->default_object_config); - normalize_and_apply_config(object->config, model_object->config); + object->config_apply(this->default_object_config()); + { + //normalize_and_apply_config(object->config(), model_object->config); + DynamicPrintConfig src_normalized(model_object->config); + src_normalized.normalize(); + object->config_apply(src_normalized, true); + } // update placeholders { // get the first input file name std::string input_file; std::vector<std::string> v_scale; - for (const PrintObject *object : this->objects) { + for (const PrintObject *object : m_objects) { const ModelObject &mobj = *object->model_object(); v_scale.push_back(boost::lexical_cast<std::string>(mobj.instances[0]->scaling_factor*100) + "%"); if (input_file.empty()) input_file = mobj.input_file; } - PlaceholderParser &pp = this->placeholder_parser; + PlaceholderParser &pp = m_placeholder_parser; pp.set("scale", v_scale); if (! input_file.empty()) { // get basename with and without suffix @@ -393,19 +407,19 @@ bool Print::apply_config(DynamicPrintConfig config) config.normalize(); // apply variables to placeholder parser - this->placeholder_parser.apply_config(config); + m_placeholder_parser.apply_config(config); // handle changes to print config - t_config_option_keys print_diff = this->config.diff(config); - this->config.apply_only(config, print_diff, true); + t_config_option_keys print_diff = m_config.diff(config); + m_config.apply_only(config, print_diff, true); bool invalidated = this->invalidate_state_by_config_options(print_diff); // handle changes to object config defaults - this->default_object_config.apply(config, true); - for (PrintObject *object : this->objects) { + m_default_object_config.apply(config, true); + for (PrintObject *object : m_objects) { // we don't assume that config contains a full ObjectConfig, // so we base it on the current print-wise default - PrintObjectConfig new_config = this->default_object_config; + PrintObjectConfig new_config = this->default_object_config(); // we override the new config with object-specific options normalize_and_apply_config(new_config, object->model_object()->config); // Force a refresh of a variable layer height profile at the PrintObject if it is not valid. @@ -417,13 +431,13 @@ bool Print::apply_config(DynamicPrintConfig config) invalidated = true; } // check whether the new config is different from the current one - t_config_option_keys diff = object->config.diff(new_config); - object->config.apply_only(new_config, diff, true); + t_config_option_keys diff = object->config().diff(new_config); + object->config_apply_only(new_config, diff, true); invalidated |= object->invalidate_state_by_config_options(diff); } // handle changes to regions config defaults - this->default_region_config.apply(config, true); + m_default_region_config.apply(config, true); // All regions now have distinct settings. // Check whether applying the new region config defaults we'd get different regions. @@ -432,11 +446,11 @@ bool Print::apply_config(DynamicPrintConfig config) // Collect the already visited region configs into other_region_configs, // so one may check for duplicates. std::vector<PrintRegionConfig> other_region_configs; - for (size_t region_id = 0; region_id < this->regions.size(); ++ region_id) { - PrintRegion ®ion = *this->regions[region_id]; + for (size_t region_id = 0; region_id < m_regions.size(); ++ region_id) { + PrintRegion ®ion = *m_regions[region_id]; PrintRegionConfig this_region_config; bool this_region_config_set = false; - for (PrintObject *object : this->objects) { + for (PrintObject *object : m_objects) { if (region_id < object->region_volumes.size()) { for (int volume_id : object->region_volumes[region_id]) { const ModelVolume &volume = *object->model_object()->volumes[volume_id]; @@ -466,10 +480,10 @@ bool Print::apply_config(DynamicPrintConfig config) } } if (this_region_config_set) { - t_config_option_keys diff = region.config.diff(this_region_config); + t_config_option_keys diff = region.config().diff(this_region_config); if (! diff.empty()) { - region.config.apply_only(this_region_config, diff); - for (PrintObject *object : this->objects) + region.config_apply_only(this_region_config, diff, false); + for (PrintObject *object : m_objects) if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty()) invalidated |= object->invalidate_state_by_config_options(diff); } @@ -484,8 +498,8 @@ exit_for_rearrange_regions: // The current subdivision of regions does not make sense anymore. // We need to remove all objects and re-add them. ModelObjectPtrs model_objects; - model_objects.reserve(this->objects.size()); - for (PrintObject *object : this->objects) + model_objects.reserve(m_objects.size()); + for (PrintObject *object : m_objects) model_objects.push_back(object->model_object()); this->clear_objects(); for (ModelObject *mo : model_objects) @@ -494,7 +508,7 @@ exit_for_rearrange_regions: } // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads. - for (PrintObject *object : this->objects) + for (PrintObject *object : m_objects) if (! object->layer_height_profile_valid) object->update_layer_height_profile(); @@ -503,32 +517,32 @@ exit_for_rearrange_regions: bool Print::has_infinite_skirt() const { - return (this->config.skirt_height == -1 && this->config.skirts > 0) - || (this->config.ooze_prevention && this->extruders().size() > 1); + return (m_config.skirt_height == -1 && m_config.skirts > 0) + || (m_config.ooze_prevention && this->extruders().size() > 1); } bool Print::has_skirt() const { - return (this->config.skirt_height > 0 && this->config.skirts > 0) + return (m_config.skirt_height > 0 && m_config.skirts > 0) || this->has_infinite_skirt(); } std::string Print::validate() const { - BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values)); - BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height)); + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(m_config.bed_shape.values)); + BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), m_config.max_print_height)); // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. print_volume.min.z = -1e10; - for (PrintObject *po : this->objects) { + for (PrintObject *po : m_objects) { if (! print_volume.contains(po->model_object()->tight_bounding_box(false))) return "Some objects are outside of the print volume."; } - if (this->config.complete_objects) { + if (m_config.complete_objects) { // Check horizontal clearance. { Polygons convex_hulls_other; - for (PrintObject *object : this->objects) { + for (PrintObject *object : m_objects) { // Get convex hull of all meshes assigned to this print object. Polygon convex_hull; { @@ -542,7 +556,7 @@ std::string Print::validate() const // Apply the same transformations we apply to the actual meshes when slicing them. object->model_object()->instances.front()->transform_polygon(&convex_hull); // Grow convex hull with the clearance margin. - convex_hull = offset(convex_hull, scale_(this->config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1)).front(); + convex_hull = offset(convex_hull, scale_(m_config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1)).front(); // Now we check that no instance of convex_hull intersects any of the previously checked object instances. for (const Point © : object->_shifted_copies) { Polygon p = convex_hull; @@ -556,47 +570,47 @@ std::string Print::validate() const // Check vertical clearance. { std::vector<coord_t> object_height; - for (const PrintObject *object : this->objects) + for (const PrintObject *object : m_objects) object_height.insert(object_height.end(), object->copies().size(), object->size.z); std::sort(object_height.begin(), object_height.end()); // Ignore the tallest *copy* (this is why we repeat height for all of them): // it will be printed as last one so its height doesn't matter. object_height.pop_back(); - if (! object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value)) + if (! object_height.empty() && object_height.back() > scale_(m_config.extruder_clearance_height.value)) return "Some objects are too tall and cannot be printed without extruder collisions."; } - } // end if (this->config.complete_objects) + } // end if (m_config.complete_objects) - if (this->config.spiral_vase) { + if (m_config.spiral_vase) { size_t total_copies_count = 0; - for (const PrintObject *object : this->objects) + for (const PrintObject *object : m_objects) total_copies_count += object->copies().size(); // #4043 - if (total_copies_count > 1 && ! this->config.complete_objects.value) + if (total_copies_count > 1 && ! m_config.complete_objects.value) return "The Spiral Vase option can only be used when printing a single object."; - if (this->regions.size() > 1) + if (m_regions.size() > 1) return "The Spiral Vase option can only be used when printing single material objects."; } - if (this->has_wipe_tower() && ! this->objects.empty()) { + if (this->has_wipe_tower() && ! m_objects.empty()) { #if 0 - for (auto dmr : this->config.nozzle_diameter.values) + for (auto dmr : m_config.nozzle_diameter.values) if (std::abs(dmr - 0.4) > EPSILON) return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter."; #endif - if (this->config.gcode_flavor != gcfRepRap && this->config.gcode_flavor != gcfMarlin) + if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfMarlin) return "The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors."; - if (! this->config.use_relative_e_distances) + if (! m_config.use_relative_e_distances) return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."; - SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters(); - for (PrintObject *object : this->objects) { + SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters(); + for (PrintObject *object : m_objects) { SlicingParameters slicing_params = object->slicing_parameters(); if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) return "The Wipe Tower is only supported for multiple objects if they have equal layer heigths"; if (slicing_params.raft_layers() != slicing_params0.raft_layers()) return "The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"; - if (object->config.support_material_contact_distance != this->objects.front()->config.support_material_contact_distance) + if (object->config().support_material_contact_distance != m_objects.front()->config().support_material_contact_distance) return "The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"; if (! equal_layering(slicing_params, slicing_params0)) return "The Wipe Tower is only supported for multiple objects if they are sliced equally."; @@ -605,7 +619,7 @@ std::string Print::validate() const object->layer_height_profile_valid = was_layer_height_profile_valid; for (size_t i = 5; i < object->layer_height_profile.size(); i += 2) if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON && - std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON) + std::abs(object->layer_height_profile[i] - object->config().layer_height) > EPSILON) return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed."; } } @@ -618,12 +632,12 @@ std::string Print::validate() const std::vector<double> nozzle_diameters; for (unsigned int extruder_id : extruders) - nozzle_diameters.push_back(this->config.nozzle_diameter.get_at(extruder_id)); + nozzle_diameters.push_back(m_config.nozzle_diameter.get_at(extruder_id)); double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end()); - for (PrintObject *object : this->objects) { - if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) && - (object->config.raft_layers > 0 || object->config.support_material.value)) { + for (PrintObject *object : m_objects) { + if ((object->config().support_material_extruder == -1 || object->config().support_material_interface_extruder == -1) && + (object->config().raft_layers > 0 || object->config().support_material.value)) { // The object has some form of support and either support_material_extruder or support_material_interface_extruder // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // are of the same diameter. @@ -634,16 +648,16 @@ std::string Print::validate() const } // validate first_layer_height - double first_layer_height = object->config.get_abs_value("first_layer_height"); + double first_layer_height = object->config().get_abs_value("first_layer_height"); double first_layer_min_nozzle_diameter; - if (object->config.raft_layers > 0) { + if (object->config().raft_layers > 0) { // if we have raft layers, only support material extruder is used on first layer - size_t first_layer_extruder = object->config.raft_layers == 1 - ? object->config.support_material_interface_extruder-1 - : object->config.support_material_extruder-1; + size_t first_layer_extruder = object->config().raft_layers == 1 + ? object->config().support_material_interface_extruder-1 + : object->config().support_material_extruder-1; first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ? min_nozzle_diameter : - this->config.nozzle_diameter.get_at(first_layer_extruder); + m_config.nozzle_diameter.get_at(first_layer_extruder); } else { // if we don't have raft layers, any nozzle diameter is potentially used in first layer first_layer_min_nozzle_diameter = min_nozzle_diameter; @@ -652,7 +666,7 @@ std::string Print::validate() const return "First layer height can't be greater than nozzle diameter"; // validate layer_height - if (object->config.layer_height.value > min_nozzle_diameter) + if (object->config().layer_height.value > min_nozzle_diameter) return "Layer height can't be greater than nozzle diameter"; } } @@ -665,7 +679,7 @@ std::string Print::validate() const BoundingBox Print::bounding_box() const { BoundingBox bb; - for (const PrintObject *object : this->objects) + for (const PrintObject *object : m_objects) for (Point copy : object->_shifted_copies) { bb.merge(copy); copy.translate(object->size); @@ -683,7 +697,7 @@ BoundingBox Print::total_bounding_box() const BoundingBox bb = this->bounding_box(); // we need to offset the objects bounding box by at least half the perimeters extrusion width - Flow perimeter_flow = this->objects.front()->get_layer(0)->get_region(0)->flow(frPerimeter); + Flow perimeter_flow = m_objects.front()->get_layer(0)->get_region(0)->flow(frPerimeter); double extra = perimeter_flow.width/2; // consider support material @@ -692,18 +706,18 @@ BoundingBox Print::total_bounding_box() const } // consider brim and skirt - if (this->config.brim_width.value > 0) { + if (m_config.brim_width.value > 0) { Flow brim_flow = this->brim_flow(); - extra = std::max(extra, this->config.brim_width.value + brim_flow.width/2); + extra = std::max(extra, m_config.brim_width.value + brim_flow.width/2); } if (this->has_skirt()) { - int skirts = this->config.skirts.value; + int skirts = m_config.skirts.value; if (skirts == 0 && this->has_infinite_skirt()) skirts = 1; Flow skirt_flow = this->skirt_flow(); extra = std::max( extra, - this->config.brim_width.value - + this->config.skirt_distance.value + m_config.brim_width.value + + m_config.skirt_distance.value + skirts * skirt_flow.spacing() + skirt_flow.width/2 ); @@ -717,17 +731,17 @@ BoundingBox Print::total_bounding_box() const double Print::skirt_first_layer_height() const { - if (this->objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects"); - return this->objects.front()->config.get_abs_value("first_layer_height"); + if (m_objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects"); + return m_objects.front()->config().get_abs_value("first_layer_height"); } Flow Print::brim_flow() const { - ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width; + ConfigOptionFloatOrPercent width = m_config.first_layer_extrusion_width; if (width.value == 0) - width = this->regions.front()->config.perimeter_extrusion_width; + width = m_regions.front()->config().perimeter_extrusion_width; if (width.value == 0) - width = this->objects.front()->config.extrusion_width; + width = m_objects.front()->config().extrusion_width; /* We currently use a random region's perimeter extruder. While this works for most cases, we should probably consider all of the perimeter @@ -737,7 +751,7 @@ Flow Print::brim_flow() const return Flow::new_from_config_width( frPerimeter, width, - this->config.nozzle_diameter.get_at(this->regions.front()->config.perimeter_extruder-1), + m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1), this->skirt_first_layer_height(), 0 ); @@ -745,11 +759,11 @@ Flow Print::brim_flow() const Flow Print::skirt_flow() const { - ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width; + ConfigOptionFloatOrPercent width = m_config.first_layer_extrusion_width; if (width.value == 0) - width = this->regions.front()->config.perimeter_extrusion_width; + width = m_regions.front()->config().perimeter_extrusion_width; if (width.value == 0) - width = this->objects.front()->config.extrusion_width; + width = m_objects.front()->config().extrusion_width; /* We currently use a random object's support material extruder. While this works for most cases, we should probably consider all of the support material @@ -759,7 +773,7 @@ Flow Print::skirt_flow() const return Flow::new_from_config_width( frPerimeter, width, - this->config.nozzle_diameter.get_at(this->objects.front()->config.support_material_extruder-1), + m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1), this->skirt_first_layer_height(), 0 ); @@ -767,7 +781,7 @@ Flow Print::skirt_flow() const PrintRegionConfig Print::_region_config_from_model_volume(const ModelVolume &volume) { - PrintRegionConfig config = this->default_region_config; + PrintRegionConfig config = this->default_region_config(); normalize_and_apply_config(config, volume.get_object()->config); normalize_and_apply_config(config, volume.config); if (! volume.material_id().empty()) @@ -777,7 +791,7 @@ PrintRegionConfig Print::_region_config_from_model_volume(const ModelVolume &vol bool Print::has_support_material() const { - for (const PrintObject *object : this->objects) + for (const PrintObject *object : m_objects) if (object->has_support_material()) return true; return false; @@ -791,7 +805,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const if (model_object->volumes.size() < 2) return; -// size_t extruders = this->config.nozzle_diameter.values.size(); +// size_t extruders = m_config.nozzle_diameter.values.size(); for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) { ModelVolume *volume = model_object->volumes[volume_id]; //FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned. @@ -804,44 +818,44 @@ void Print::auto_assign_extruders(ModelObject* model_object) const void Print::process() { BOOST_LOG_TRIVIAL(info) << "Staring the slicing process."; - for (PrintObject *obj : this->objects) + for (PrintObject *obj : m_objects) obj->make_perimeters(); this->throw_if_canceled(); this->set_status(70, "Infilling layers"); - for (PrintObject *obj : this->objects) + for (PrintObject *obj : m_objects) obj->infill(); this->throw_if_canceled(); - for (PrintObject *obj : this->objects) + for (PrintObject *obj : m_objects) obj->generate_support_material(); this->throw_if_canceled(); if (! m_state.is_done(psSkirt)) { this->set_started(psSkirt); - this->skirt.clear(); + m_skirt.clear(); if (this->has_skirt()) { this->set_status(88, "Generating skirt"); this->_make_skirt(); } - m_state.set_done(psSkirt); + this->set_done(psSkirt); } this->throw_if_canceled(); if (! m_state.is_done(psBrim)) { this->set_started(psBrim); - this->brim.clear(); - if (this->config.brim_width > 0) { + m_brim.clear(); + if (m_config.brim_width > 0) { this->set_status(88, "Generating brim"); this->_make_brim(); } - m_state.set_done(psBrim); + this->set_done(psBrim); } this->throw_if_canceled(); if (! m_state.is_done(psWipeTower)) { this->set_started(psWipeTower); - this->_clear_wipe_tower(); + m_wipe_tower_data.clear(); if (this->has_wipe_tower()) { //this->set_status(95, "Generating wipe tower"); this->_make_wipe_tower(); } - m_state.set_done(psWipeTower); + this->set_done(psWipeTower); } BOOST_LOG_TRIVIAL(info) << "Slicing process finished."; } @@ -883,20 +897,20 @@ void Print::_make_skirt() // prepended to the first 'n' layers (with 'n' = skirt_height). // $skirt_height_z in this case is the highest possible skirt height for safety. coordf_t skirt_height_z = 0.; - for (const PrintObject *object : this->objects) { + for (const PrintObject *object : m_objects) { size_t skirt_layers = this->has_infinite_skirt() ? object->layer_count() : - std::min(size_t(this->config.skirt_height.value), object->layer_count()); - skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z); + std::min(size_t(m_config.skirt_height.value), object->layer_count()); + skirt_height_z = std::max(skirt_height_z, object->m_layers[skirt_layers-1]->print_z); } // Collect points from all layers contained in skirt height. Points points; - for (const PrintObject *object : this->objects) { + for (const PrintObject *object : m_objects) { this->throw_if_canceled(); Points object_points; // Get object layers up to skirt_height_z. - for (const Layer *layer : object->layers) { + for (const Layer *layer : object->m_layers) { if (layer->print_z > skirt_height_z) break; for (const ExPolygon &expoly : layer->slices.expolygons) @@ -904,7 +918,7 @@ void Print::_make_skirt() append(object_points, expoly.contour.points); } // Get support layers up to skirt_height_z. - for (const SupportLayer *layer : object->support_layers) { + for (const SupportLayer *layer : object->support_layers()) { if (layer->print_z > skirt_height_z) break; for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities) @@ -942,18 +956,18 @@ void Print::_make_skirt() extruders_e_per_mm.reserve(set_extruders.size()); for (auto &extruder_id : set_extruders) { extruders.push_back(extruder_id); - extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, &this->config).e_per_mm(mm3_per_mm)); + extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, &m_config).e_per_mm(mm3_per_mm)); } } // Number of skirt loops per skirt layer. - int n_skirts = this->config.skirts.value; + int n_skirts = m_config.skirts.value; if (this->has_infinite_skirt() && n_skirts == 0) n_skirts = 1; // Initial offset of the brim inner edge from the object (possible with a support & raft). // The skirt will touch the brim if the brim is extruded. - coord_t distance = scale_(std::max(this->config.skirt_distance.value, this->config.brim_width.value)); + coord_t distance = scale_(std::max(m_config.skirt_distance.value, m_config.brim_width.value)); // Draw outlines from outside to inside. // Loop while we have less skirts than required or any extruder hasn't reached the min length if any. std::vector<coordf_t> extruded_length(extruders.size(), 0.); @@ -978,16 +992,16 @@ void Print::_make_skirt() first_layer_height // this will be overridden at G-code export time ))); eloop.paths.back().polyline = loop.split_at_first_point(); - this->skirt.append(eloop); - if (this->config.min_skirt_length.value > 0) { + m_skirt.append(eloop); + if (m_config.min_skirt_length.value > 0) { // The skirt length is limited. Sum the total amount of filament length extruded, in mm. extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx]; - if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) { + if (extruded_length[extruder_idx] < m_config.min_skirt_length.value) { // Not extruded enough yet with the current extruder. Add another loop. if (i == 1) ++ i; } else { - assert(extruded_length[extruder_idx] >= this->config.min_skirt_length.value); + assert(extruded_length[extruder_idx] >= m_config.min_skirt_length.value); // Enough extruded with the current extruder. Extrude with the next one, // until the prescribed number of skirt loops is extruded. if (extruder_idx + 1 < extruders.size()) @@ -998,7 +1012,7 @@ void Print::_make_skirt() } } // Brims were generated inside out, reverse to print the outmost contour first. - this->skirt.reverse(); + m_skirt.reverse(); } void Print::_make_brim() @@ -1006,13 +1020,13 @@ void Print::_make_brim() // Brim is only printed on first layer and uses perimeter extruder. Flow flow = this->brim_flow(); Polygons islands; - for (PrintObject *object : this->objects) { + for (PrintObject *object : m_objects) { this->throw_if_canceled(); Polygons object_islands; - for (ExPolygon &expoly : object->layers.front()->slices.expolygons) + for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons) object_islands.push_back(expoly.contour); - if (! object->support_layers.empty()) - object->support_layers.front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON)); + if (! object->support_layers().empty()) + object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON)); islands.reserve(islands.size() + object_islands.size() * object->_shifted_copies.size()); for (const Point &pt : object->_shifted_copies) for (Polygon &poly : object_islands) { @@ -1021,7 +1035,7 @@ void Print::_make_brim() } } Polygons loops; - size_t num_loops = size_t(floor(this->config.brim_width.value / flow.width)); + size_t num_loops = size_t(floor(m_config.brim_width.value / flow.width)); for (size_t i = 0; i < num_loops; ++ i) { this->throw_if_canceled(); islands = offset(islands, float(flow.scaled_spacing()), jtSquare); @@ -1037,32 +1051,24 @@ void Print::_make_brim() loops = union_pt_chained(loops, false); std::reverse(loops.begin(), loops.end()); - extrusion_entities_append_loops(this->brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height())); + extrusion_entities_append_loops(m_brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height())); } // Wipe tower support. bool Print::has_wipe_tower() const { return - this->config.single_extruder_multi_material.value && - ! this->config.spiral_vase.value && - this->config.wipe_tower.value && - this->config.nozzle_diameter.values.size() > 1; -} - -void Print::_clear_wipe_tower() -{ - m_tool_ordering.clear(); - m_wipe_tower_priming.reset(nullptr); - m_wipe_tower_tool_changes.clear(); - m_wipe_tower_final_purge.reset(nullptr); + m_config.single_extruder_multi_material.value && + ! m_config.spiral_vase.value && + m_config.wipe_tower.value && + m_config.nozzle_diameter.values.size() > 1; } void Print::_make_wipe_tower() { // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. - m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); - if (! m_tool_ordering.has_wipe_tower()) + m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); + if (! m_wipe_tower_data.tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. return; @@ -1072,33 +1078,31 @@ void Print::_make_wipe_tower() // see https://github.com/prusa3d/Slic3r/issues/607 { size_t idx_begin = size_t(-1); - size_t idx_end = m_tool_ordering.layer_tools().size(); + size_t idx_end = m_wipe_tower_data.tool_ordering.layer_tools().size(); // Find the first wipe tower layer, which does not have a counterpart in an object or a support layer. for (size_t i = 0; i < idx_end; ++ i) { - const ToolOrdering::LayerTools < = m_tool_ordering.layer_tools()[i]; + const ToolOrdering::LayerTools < = m_wipe_tower_data.tool_ordering.layer_tools()[i]; if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) { idx_begin = i; break; } } if (idx_begin != size_t(-1)) { - // Find the position in this->objects.first()->support_layers to insert these new support layers. - double wipe_tower_new_layer_print_z_first = m_tool_ordering.layer_tools()[idx_begin].print_z; - SupportLayerPtrs::iterator it_layer = this->objects.front()->support_layers.begin(); - SupportLayerPtrs::iterator it_end = this->objects.front()->support_layers.end(); + // Find the position in m_objects.first()->support_layers to insert these new support layers. + double wipe_tower_new_layer_print_z_first = m_wipe_tower_data.tool_ordering.layer_tools()[idx_begin].print_z; + SupportLayerPtrs::const_iterator it_layer = m_objects.front()->support_layers().begin(); + SupportLayerPtrs::const_iterator it_end = m_objects.front()->support_layers().end(); for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer); // Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer. for (size_t i = idx_begin; i < idx_end; ++ i) { - ToolOrdering::LayerTools < = const_cast<ToolOrdering::LayerTools&>(m_tool_ordering.layer_tools()[i]); + ToolOrdering::LayerTools < = const_cast<ToolOrdering::LayerTools&>(m_wipe_tower_data.tool_ordering.layer_tools()[i]); if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support)) break; lt.has_support = true; // Insert the new support layer. - double height = lt.print_z - m_tool_ordering.layer_tools()[i-1].print_z; + double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z; //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway. - auto *new_layer = new SupportLayer(size_t(-1), this->objects.front(), - height, lt.print_z, lt.print_z - 0.5 * height); - it_layer = this->objects.front()->support_layers.insert(it_layer, new_layer); + it_layer = m_objects.front()->insert_support_layer(it_layer, size_t(-1), height, lt.print_z, lt.print_z - 0.5 * height); ++ it_layer; } } @@ -1107,9 +1111,9 @@ void Print::_make_wipe_tower() // Initialize the wipe tower. WipeTowerPrusaMM wipe_tower( - float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value), - float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value), - m_tool_ordering.first_extruder()); + float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value), + float(m_config.wipe_tower_width.value), float(m_config.wipe_tower_per_color_wipe.value), + m_wipe_tower_data.tool_ordering.first_extruder()); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); @@ -1118,29 +1122,29 @@ void Print::_make_wipe_tower() for (size_t i = 0; i < 4; ++ i) wipe_tower.set_extruder( i, - WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()), - this->config.temperature.get_at(i), - this->config.first_layer_temperature.get_at(i)); + WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()), + m_config.temperature.get_at(i), + m_config.first_layer_temperature.get_at(i)); // When printing the first layer's wipe tower, the first extruder is expected to be active and primed. - // Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer. + // Therefore the number of wipe sections at the wipe tower will be (m_wipe_tower_data.tool_ordering.front().extruders-1) at the 1st layer. // The following variable is true if the last priming section cannot be squeezed inside the wipe tower. - bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions; + bool last_priming_wipe_full = m_wipe_tower_data.tool_ordering.front().extruders.size() > m_wipe_tower_data.tool_ordering.front().wipe_tower_partitions; - m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>( - wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE)); + m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>( + wipe_tower.prime(this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE)); // Generate the wipe tower layers. - m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size()); + m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size()); // Set current_extruder_id to the last extruder primed. - unsigned int current_extruder_id = m_tool_ordering.all_extruders().back(); - for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) { + unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back(); + for (const ToolOrdering::LayerTools &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { this->throw_if_canceled(); if (! layer_tools.has_wipe_tower) // This is a support only layer, or the wipe tower does not reach to this height. continue; - bool first_layer = &layer_tools == &m_tool_ordering.front(); - bool last_layer = &layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0; + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + bool last_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0; wipe_tower.set_layer( float(layer_tools.print_z), float(layer_tools.wipe_tower_layer_height), @@ -1151,7 +1155,7 @@ void Print::_make_wipe_tower() for (unsigned int extruder_id : layer_tools.extruders) // Call the wipe_tower.tool_change() at the first layer for the initial extruder // to extrude the wipe tower brim, - if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || + if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || // or when an extruder shall be switched. extruder_id != current_extruder_id) { tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE)); @@ -1175,48 +1179,49 @@ void Print::_make_wipe_tower() tool_changes.pop_back(); } } - m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes)); + m_wipe_tower_data.tool_changes.emplace_back(std::move(tool_changes)); if (last_layer) break; } // Unload the current filament over the purge tower. - coordf_t layer_height = this->objects.front()->config.layer_height.value; - if (m_tool_ordering.back().wipe_tower_partitions > 0) { + coordf_t layer_height = m_objects.front()->config().layer_height.value; + if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) { // The wipe tower goes up to the last layer of the print. if (wipe_tower.layer_finished()) { // The wipe tower is printed to the top of the print and it has no space left for the final extruder purge. // Lift Z to the next layer. - wipe_tower.set_layer(float(m_tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, true); + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, true); } else { // There is yet enough space at this layer of the wipe tower for the final purge. } } else { // The wipe tower does not reach the last print layer, perform the pruge at the last print layer. - assert(m_tool_ordering.back().wipe_tower_partitions == 0); - wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true); + assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0); + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z), float(layer_height), 0, false, true); } - m_wipe_tower_final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>( + m_wipe_tower_data.final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>( wipe_tower.tool_change((unsigned int)-1, false, WipeTower::PURPOSE_EXTRUDE)); } -std::string Print::output_filename() +std::string Print::output_filename() const { - this->placeholder_parser.update_timestamp(); + DynamicConfig cfg_timestamp; + PlaceholderParser::update_timestamp(cfg_timestamp); try { - return this->placeholder_parser.process(this->config.output_filename_format.value, 0); + return this->placeholder_parser().process(m_config.output_filename_format.value, 0, &cfg_timestamp); } catch (std::runtime_error &err) { throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what()); } } -std::string Print::output_filepath(const std::string &path) +std::string Print::output_filepath(const std::string &path) const { // if we were supplied no path, generate an automatic one based on our first object's input file if (path.empty()) { // get the first input file name std::string input_file; - for (const PrintObject *object : this->objects) { + for (const PrintObject *object : m_objects) { input_file = object->model_object()->input_file; if (! input_file.empty()) break; diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 1162c9b0f..71711b31e 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -51,7 +51,7 @@ template <class StepType, size_t COUNT> class PrintState { public: - PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i] = INVALID; } + PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); } enum State { INVALID, @@ -59,24 +59,58 @@ public: DONE, }; + // With full memory barrier. bool is_done(StepType step) const { return m_state[step] == DONE; } - // set_started() will lock the provided mutex before setting the state. + + // Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. // This is necessary to block until the Print::apply_config() updates its state, which may // influence the processing step being entered. - void set_started(StepType step, tbb::mutex &mtx) { mtx.lock(); m_state[step] = STARTED; mtx.unlock(); } - void set_done(StepType step) { m_state[step] = DONE; } - bool invalidate(StepType step) { - bool invalidated = m_state[step] != INVALID; - m_state[step] = INVALID; + void set_started(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(STARTED, std::memory_order_relaxed); + mtx.unlock(); + } + + // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. + void set_done(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(DONE, std::memory_order_relaxed); + mtx.unlock(); + } + + // Make the step invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case the step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template<typename CancelationCallback> + bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback &cancel) { + bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { + mtx.unlock(); + cancel(); + mtx.lock(); + } return invalidated; } - bool invalidate_all() { + + // Make all steps invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case any step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template<typename CancelationCallback> + bool invalidate_all(tbb::mutex &mtx, CancelationCallback &cancel) { bool invalidated = false; for (size_t i = 0; i < COUNT; ++ i) - if (m_state[i] != INVALID) { - invalidated = true; - m_state[i] = INVALID; - break; + if (m_state[i].load(std::memory_order_relaxed) != INVALID) { + if (! invalidated) { + mtx.unlock(); + cancel(); + mtx.lock(); + invalidated = true; + } + m_state[i].store(INVALID, std::memory_order_relaxed); } return invalidated; } @@ -91,17 +125,24 @@ class PrintRegion { friend class Print; +// Methods NOT modifying the PrintRegion's state: public: - PrintRegionConfig config; + const Print* print() const { return m_print; } + const PrintRegionConfig& config() const { return m_config; } + Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const; + coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const; - Print* print() { return this->_print; } - 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; +// Methods modifying the PrintRegion's state: +public: + Print* print() { return m_print; } + void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } private: - Print* _print; + Print *m_print; + PrintRegionConfig m_config; - PrintRegion(Print* print) : _print(print) {} + PrintRegion(Print* print) : m_print(print) {} + PrintRegion(Print* print, const PrintRegionConfig &config) : m_print(print), m_config(config) {} ~PrintRegion() {} }; @@ -117,7 +158,6 @@ class PrintObject public: // vector of (vectors of volume ids), indexed by region_id std::vector<std::vector<int>> region_volumes; - PrintObjectConfig config; t_layer_height_ranges layer_height_ranges; // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. @@ -144,15 +184,17 @@ public: // Slic3r::Point objects in scaled G-code coordinates in our coordinates Points _shifted_copies; - LayerPtrs layers; - SupportLayerPtrs support_layers; - - Print* print() { return this->_print; } - const Print* print() const { return this->_print; } - ModelObject* model_object() { return this->_model_object; } - const ModelObject* model_object() const { return this->_model_object; } - - const Points& copies() const { return this->_copies; } + Print* print() { return m_print; } + const Print* print() const { return m_print; } + ModelObject* model_object() { return m_model_object; } + const ModelObject* model_object() const { return m_model_object; } + const PrintObjectConfig& config() const { return m_config; } + void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } + void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } + const LayerPtrs& layers() const { return m_layers; } + const SupportLayerPtrs& support_layers() const { return m_support_layers; } + + const Points& copies() const { return m_copies; } bool add_copy(const Pointf &point); bool delete_last_copy(); bool delete_all_copies() { return this->set_copies(Points()); } @@ -171,24 +213,25 @@ public: // this value is not supposed to be compared with Layer::id // since they have different semantics. size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); } - size_t layer_count() const { return this->layers.size(); } + size_t layer_count() const { return m_layers.size(); } void clear_layers(); - Layer* get_layer(int idx) { return this->layers.at(idx); } - const Layer* get_layer(int idx) const { return this->layers.at(idx); } + Layer* get_layer(int idx) { return m_layers[idx]; } + const Layer* get_layer(int idx) const { return m_layers[idx]; } // print_z: top of the layer; slice_z: center of the layer. Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z); - size_t support_layer_count() const { return this->support_layers.size(); } + size_t support_layer_count() const { return m_support_layers.size(); } void clear_support_layers(); - SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); } + SupportLayer* get_support_layer(int idx) { return m_support_layers[idx]; } SupportLayer* add_support_layer(int id, coordf_t height, coordf_t print_z); + SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z); void delete_support_layer(int idx); // methods for handling state bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_step(PrintObjectStep step); - bool invalidate_all_steps() { return m_state.invalidate_all(); } + bool invalidate_all_steps(); bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); } // To be used over the layer_height_profile of both the PrintObject and ModelObject @@ -229,9 +272,14 @@ private: void combine_infill(); void _generate_support_material(); - Print* _print; - ModelObject* _model_object; - Points _copies; // Slic3r::Point objects in scaled G-code coordinates + Print *m_print; + ModelObject *m_model_object; + PrintObjectConfig m_config; + // Slic3r::Point objects in scaled G-code coordinates + Points m_copies; + + LayerPtrs m_layers; + SupportLayerPtrs m_support_layers; PrintState<PrintObjectStep, posCount> m_state; // Mutex used for synchronization of the worker thread with the UI thread: @@ -245,9 +293,49 @@ private: ~PrintObject() {} void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); } + void set_done(PrintObjectStep step) { m_state.set_done(step, m_mutex); } std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier); }; +struct WipeTowerData +{ + // Following section will be consumed by the GCodeGenerator. + // Tool ordering of a non-sequential print has to be known to calculate the wipe tower. + // Cache it here, so it does not need to be recalculated during the G-code generation. + ToolOrdering tool_ordering; + // Cache of tool changes per print layer. + std::unique_ptr<WipeTower::ToolChangeResult> priming; + std::vector<std::vector<WipeTower::ToolChangeResult>> tool_changes; + std::unique_ptr<WipeTower::ToolChangeResult> final_purge; + + void clear() { + tool_ordering.clear(); + priming.reset(nullptr); + tool_changes.clear(); + final_purge.reset(nullptr); + } +}; + +struct PrintStatistics +{ + PrintStatistics() { clear(); } + std::string estimated_print_time; + double total_used_filament; + double total_extruded_volume; + double total_cost; + double total_weight; + std::map<size_t, float> filament_stats; + + void clear() { + estimated_print_time.clear(); + total_used_filament = 0.; + total_extruded_volume = 0.; + total_weight = 0.; + total_cost = 0.; + filament_stats.clear(); + } +}; + typedef std::vector<PrintObject*> PrintObjectPtrs; typedef std::vector<PrintRegion*> PrintRegionPtrs; @@ -255,110 +343,115 @@ typedef std::vector<PrintRegion*> PrintRegionPtrs; class Print { public: - PrintConfig config; - PrintObjectConfig default_object_config; - PrintRegionConfig default_region_config; - PrintObjectPtrs objects; - PrintRegionPtrs regions; - PlaceholderParser placeholder_parser; - std::string estimated_print_time; - double total_used_filament, total_extruded_volume, total_cost, total_weight; - std::map<size_t, float> filament_stats; - - // ordered collections of extrusion paths to build skirt loops and brim - ExtrusionEntityCollection skirt, brim; - - Print() : total_used_filament(0), total_extruded_volume(0) { restart(); } + Print() { restart(); } ~Print() { clear_objects(); } - // methods for handling objects - void clear_objects(); - PrintObject* get_object(size_t idx) { return objects.at(idx); } - const PrintObject* get_object(size_t idx) const { return objects.at(idx); } - - void delete_object(size_t idx); - void reload_object(size_t idx); - bool reload_model_instances(); + // Methods, 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 delete_object(size_t idx); + void reload_object(size_t idx); + bool reload_model_instances(); + void add_model_object(ModelObject* model_object, int idx = -1); + bool apply_config(DynamicPrintConfig config); + void process(); + void export_gcode(const std::string &path_template, GCodePreviewData *preview_data); - // methods for handling regions - PrintRegion* get_region(size_t idx) { return regions.at(idx); } - const PrintRegion* get_region(size_t idx) const { return regions.at(idx); } - PrintRegion* add_region(); - // methods for handling state - bool invalidate_step(PrintStep step); - bool invalidate_all_steps() { return m_state.invalidate_all(); } - bool is_step_done(PrintStep step) const { return m_state.is_done(step); } - bool is_step_done(PrintObjectStep step) const; - - void add_model_object(ModelObject* model_object, int idx = -1); - bool apply_config(DynamicPrintConfig config); - bool has_infinite_skirt() const; - bool has_skirt() const; + bool is_step_done(PrintStep step) const { return m_state.is_done(step); } + bool is_step_done(PrintObjectStep step) const; + + bool has_infinite_skirt() const; + bool has_skirt() const; // Returns an empty string if valid, otherwise returns an error message. - std::string validate() const; - BoundingBox bounding_box() const; - BoundingBox total_bounding_box() const; - double skirt_first_layer_height() const; - Flow brim_flow() const; - Flow skirt_flow() const; + std::string validate() const; + BoundingBox bounding_box() const; + BoundingBox total_bounding_box() const; + double skirt_first_layer_height() const; + Flow brim_flow() const; + Flow skirt_flow() const; std::vector<unsigned int> object_extruders() const; std::vector<unsigned int> support_material_extruders() const; std::vector<unsigned int> extruders() const; - void _simplify_slices(double distance); - double max_allowed_layer_height() const; - bool has_support_material() const; - void auto_assign_extruders(ModelObject* model_object) const; + double max_allowed_layer_height() const; + bool has_support_material() const; + // Make sure the background processing has no access to this model_object during this call! + void auto_assign_extruders(ModelObject* model_object) const; + + const PrintConfig& config() const { return m_config; } + const PrintObjectConfig& default_object_config() const { return m_default_object_config; } + const PrintRegionConfig& default_region_config() const { return m_default_region_config; } + const PrintObjectPtrs& objects() const { return m_objects; } + const PrintRegionPtrs& regions() const { return m_regions; } + const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; } + + const ExtrusionEntityCollection& skirt() const { return m_skirt; } + const ExtrusionEntityCollection& brim() const { return m_brim; } - void process(); - void export_gcode(const std::string &path_template, GCodePreviewData *preview_data); + const PrintStatistics& print_statistics() const { return m_print_statistics; } // Wipe tower support. - bool has_wipe_tower() const; - // Tool ordering of a non-sequential print has to be known to calculate the wipe tower. - // Cache it here, so it does not need to be recalculated during the G-code generation. - ToolOrdering m_tool_ordering; - // Cache of tool changes per print layer. - std::unique_ptr<WipeTower::ToolChangeResult> m_wipe_tower_priming; - std::vector<std::vector<WipeTower::ToolChangeResult>> m_wipe_tower_tool_changes; - std::unique_ptr<WipeTower::ToolChangeResult> m_wipe_tower_final_purge; + bool has_wipe_tower() const; + const WipeTowerData& wipe_tower_data() const { return m_wipe_tower_data; } - std::string output_filename(); - std::string output_filepath(const std::string &path); + std::string output_filename() const; + std::string output_filepath(const std::string &path) const; typedef std::function<void(int, const std::string&)> status_callback_type; // Default status console print out in the form of percent => message. - void set_status_default() { m_status_callback = nullptr; } + void set_status_default() { m_status_callback = nullptr; } // No status output or callback whatsoever, useful mostly for automatic tests. - void set_status_silent() { m_status_callback = [](int, const std::string&){}; } + void set_status_silent() { m_status_callback = [](int, const std::string&){}; } // Register a custom status callback. - void set_status_callback(status_callback_type cb) { m_status_callback = cb; } + void set_status_callback(status_callback_type cb) { m_status_callback = cb; } // Calls a registered callback to update the status, or print out the default message. - void set_status(int percent, const std::string &message) { + void set_status(int percent, const std::string &message) { if (m_status_callback) m_status_callback(percent, message); else printf("%d => %s\n", percent, message.c_str()); } + + typedef std::function<void()> cancel_callback_type; + // Various methods will call this callback to stop the background processing (the Print::process() call) + // in case a successive change of the Print / PrintObject / PrintRegion instances changed + // the state of the finished or running calculations. + void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } + // Has the calculation been canceled? + bool canceled() const { return m_canceled; } // Cancel the running computation. Stop execution of all the background threads. - void cancel() { m_canceled = true; } + void cancel() { m_canceled = true; } // Cancel the running computation. Stop execution of all the background threads. - void restart() { m_canceled = false; } - // Has the calculation been canceled? - bool canceled() { return m_canceled; } - void throw_if_canceled() { if (m_canceled) throw CanceledException(); } + void restart() { m_canceled = false; } + + // Accessed by SupportMaterial + const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } protected: - void set_started(PrintStep step) { m_state.set_started(step, m_mutex); } - void set_done(PrintStep step) { m_state.set_done(step); } + void set_started(PrintStep step) { m_state.set_started(step, m_mutex); } + void set_done(PrintStep step) { m_state.set_done(step, m_mutex); } + bool invalidate_step(PrintStep step); + bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); } + + // methods for handling regions + PrintRegion* get_region(size_t idx) { return m_regions[idx]; } + PrintRegion* add_region(); + PrintRegion* add_region(const PrintRegionConfig &config); private: - bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); - PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); + bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); + PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); - void _make_skirt(); - void _make_brim(); - void _clear_wipe_tower(); - void _make_wipe_tower(); + // If the background processing stop was requested, throw CanceledException. + // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. + void throw_if_canceled() { if (m_canceled) throw CanceledException(); } + + void _make_skirt(); + void _make_brim(); + void _make_wipe_tower(); + void _simplify_slices(double distance); PrintState<PrintStep, psCount> m_state; // Mutex used for synchronization of the worker thread with the UI thread: @@ -370,15 +463,36 @@ private: // Callback to be evoked regularly to update state of the UI thread. status_callback_type m_status_callback; + // Callback to be evoked to stop the background processing before a state is updated. + cancel_callback_type m_cancel_callback = [](){}; + + PrintConfig m_config; + PrintObjectConfig m_default_object_config; + PrintRegionConfig m_default_region_config; + PrintObjectPtrs m_objects; + PrintRegionPtrs m_regions; + PlaceholderParser m_placeholder_parser; + + // Ordered collections of extrusion paths to build skirt loops and brim. + ExtrusionEntityCollection m_skirt; + ExtrusionEntityCollection m_brim; + + // Following section will be consumed by the GCodeGenerator. + WipeTowerData m_wipe_tower_data; + + // Estimated print time, filament consumed. + PrintStatistics m_print_statistics; + // To allow GCode to set the Print's GCodeExport step status. friend class GCode; + // Allow PrintObject to access m_mutex and m_cancel_callback. + friend class PrintObject; }; #define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) -#define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region) -#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) -#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->layers, layer) -#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->regions, layerm) +#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->m_objects, object) +#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->m_layers, layer) +#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->m_regions, layerm) } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index ff1e983fd..ba2521cd7 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -35,8 +35,8 @@ namespace Slic3r { PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) : typed_slices(false), - _print(print), - _model_object(model_object), + m_print(print), + m_model_object(model_object), layer_height_profile_valid(false) { // Compute the translation to be applied to our meshes so that we work with smaller coordinates @@ -60,21 +60,21 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding bool PrintObject::add_copy(const Pointf &point) { - Points points = this->_copies; + Points points = m_copies; points.push_back(Point::new_scale(point.x, point.y)); return this->set_copies(points); } bool PrintObject::delete_last_copy() { - Points points = this->_copies; + Points points = m_copies; points.pop_back(); return this->set_copies(points); } bool PrintObject::set_copies(const Points &points) { - this->_copies = points; + m_copies = points; // order copies with a nearest neighbor search and translate them by _copies_shift this->_shifted_copies.clear(); @@ -90,16 +90,16 @@ bool PrintObject::set_copies(const Points &points) this->_shifted_copies.push_back(copy); } - bool invalidated = this->_print->invalidate_step(psSkirt); - invalidated |= this->_print->invalidate_step(psBrim); + bool invalidated = m_print->invalidate_step(psSkirt); + invalidated |= m_print->invalidate_step(psBrim); return invalidated; } bool PrintObject::reload_model_instances() { Points copies; - copies.reserve(this->_model_object->instances.size()); - for (const ModelInstance *mi : this->_model_object->instances) + copies.reserve(m_model_object->instances.size()); + for (const ModelInstance *mi : m_model_object->instances) copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y)); return this->set_copies(copies); } @@ -118,21 +118,21 @@ void PrintObject::slice() if (m_state.is_done(posSlice)) return; this->set_started(posSlice); - this->_print->set_status(10, "Processing triangulated mesh"); + m_print->set_status(10, "Processing triangulated mesh"); this->_slice(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // Fix the model. //FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend. std::string warning = this->_fix_slicing_errors(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); if (! warning.empty()) BOOST_LOG_TRIVIAL(info) << warning; // Simplify slices if required. - if (this->_print->config.resolution) - this->_simplify_slices(scale_(this->_print->config.resolution)); - if (this->layers.empty()) + if (m_print->config().resolution) + this->_simplify_slices(scale_(this->print()->config().resolution)); + if (m_layers.empty()) throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n"); - m_state.set_done(posSlice); + this->set_done(posSlice); } // 1) Merges typed region slices into stInternal type. @@ -147,17 +147,17 @@ void PrintObject::make_perimeters() return; this->set_started(posPerimeters); - this->_print->set_status(20, "Generating perimeters"); + m_print->set_status(20, "Generating perimeters"); BOOST_LOG_TRIVIAL(info) << "Generating perimeters..."; // merge slices if they were split into types if (this->typed_slices) { FOREACH_LAYER(this, layer_it) { (*layer_it)->merge_slices(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } this->typed_slices = false; - m_state.invalidate(posPrepareInfill); +// m_state.invalidate(posPrepareInfill); } // compare each layer to the one below, and mark those slices needing @@ -167,24 +167,23 @@ void PrintObject::make_perimeters() // but we don't generate any extra perimeter if fill density is zero, as they would be floating // inside the object - infill_only_where_needed should be the method of choice for printing // hollow objects - FOREACH_REGION(this->_print, region_it) { - size_t region_id = region_it - this->_print->regions.begin(); - const PrintRegion ®ion = **region_it; + for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + const PrintRegion ®ion = *m_print->regions()[region_id]; - if (!region.config.extra_perimeters - || region.config.perimeters == 0 - || region.config.fill_density == 0 + if (!region.config().extra_perimeters + || region.config().perimeters == 0 + || region.config().fill_density == 0 || this->layer_count() < 2) continue; BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size() - 1), + tbb::blocked_range<size_t>(0, m_layers.size() - 1), [this, ®ion, region_id](const tbb::blocked_range<size_t>& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { - this->_print->throw_if_canceled(); - LayerRegion &layerm = *this->layers[layer_idx]->regions[region_id]; - const LayerRegion &upper_layerm = *this->layers[layer_idx+1]->regions[region_id]; + m_print->throw_if_canceled(); + LayerRegion &layerm = *m_layers[layer_idx]->m_regions[region_id]; + const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->m_regions[region_id]; const Polygons upper_layerm_polygons = upper_layerm.slices; // Filter upper layer polygons in intersection_ppl by their bounding boxes? // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ]; @@ -198,7 +197,7 @@ void PrintObject::make_perimeters() for (;;) { // compute the total thickness of perimeters const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2 - + (region.config.perimeters-1 + slice.extra_perimeters) * perimeter_spacing; + + (region.config().perimeters-1 + slice.extra_perimeters) * perimeter_spacing; // define a critical area where we don't want the upper slice to fall into // (it should either lay over our perimeters or outside this area) const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5); @@ -231,21 +230,21 @@ void PrintObject::make_perimeters() } } }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end"; } BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t>& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { - this->_print->throw_if_canceled(); - this->layers[layer_idx]->make_perimeters(); + m_print->throw_if_canceled(); + m_layers[layer_idx]->make_perimeters(); } } ); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end"; /* @@ -255,7 +254,7 @@ void PrintObject::make_perimeters() ###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION); */ - m_state.set_done(posPerimeters); + this->set_done(posPerimeters); } void PrintObject::prepare_infill() @@ -264,23 +263,23 @@ void PrintObject::prepare_infill() return; this->set_started(posPrepareInfill); - this->_print->set_status(30, "Preparing infill"); + m_print->set_status(30, "Preparing infill"); // This will assign a type (top/bottom/internal) to $layerm->slices. // Then the classifcation of $layerm->slices is transfered onto // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces // by the cummulative area of the previous $layerm->fill_surfaces. this->detect_surfaces_type(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // Decide what surfaces are to be filled. // Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured. // Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID. BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..."; - for (auto *layer : this->layers) - for (auto *region : layer->regions) { + for (auto *layer : m_layers) + for (auto *region : layer->m_regions) { region->prepare_fill_surfaces(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } // this will detect bridges and reverse bridges @@ -293,17 +292,17 @@ void PrintObject::prepare_infill() // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps. //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties. this->process_external_surfaces(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // Add solid fills to ensure the shell vertical thickness. this->discover_vertical_shells(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // Debugging output. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (const Layer *layer : this->layers) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (const Layer *layer : m_layers) { + LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("6_discover_vertical_shells-final"); layerm->export_region_fill_surfaces_to_svg_debug("6_discover_vertical_shells-final"); } // for each layer @@ -317,12 +316,12 @@ void PrintObject::prepare_infill() // to close these surfaces reliably. //FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters? this->discover_horizontal_shells(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (const Layer *layer : this->layers) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (const Layer *layer : m_layers) { + LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final"); layerm->export_region_fill_surfaces_to_svg_debug("7_discover_horizontal_shells-final"); } // for each layer @@ -336,12 +335,12 @@ void PrintObject::prepare_infill() // Likely the sparse infill will not be anchored correctly, so it will not work as intended. // Also one wishes the perimeters to be supported by a full infill. this->clip_fill_surfaces(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (const Layer *layer : this->layers) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (const Layer *layer : m_layers) { + LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final"); layerm->export_region_fill_surfaces_to_svg_debug("8_clip_surfaces-final"); } // for each layer @@ -351,27 +350,27 @@ void PrintObject::prepare_infill() // the following step needs to be done before combination because it may need // to remove only half of the combined infill this->bridge_over_infill(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // combine fill surfaces to honor the "infill every N layers" option this->combine_infill(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (const Layer *layer : this->layers) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (const Layer *layer : m_layers) { + LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("9_prepare_infill-final"); layerm->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final"); } // for each layer } // for each region - for (const Layer *layer : this->layers) { + for (const Layer *layer : m_layers) { layer->export_region_slices_to_svg_debug("9_prepare_infill-final"); layer->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final"); } // for each layer #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - m_state.set_done(posPrepareInfill); + this->set_done(posPrepareInfill); } void PrintObject::infill() @@ -383,20 +382,20 @@ void PrintObject::infill() this->set_started(posInfill); BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t>& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { - this->_print->throw_if_canceled(); - this->layers[layer_idx]->make_fills(); + m_print->throw_if_canceled(); + m_layers[layer_idx]->make_fills(); } } ); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end"; /* we could free memory now, but this would make this step not idempotent ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers}; */ - m_state.set_done(posInfill); + this->set_done(posInfill); } } @@ -405,39 +404,44 @@ void PrintObject::generate_support_material() if (! m_state.is_done(posSupportMaterial)) { this->set_started(posSupportMaterial); this->clear_support_layers(); - if ((this->config.support_material || this->config.raft_layers > 0) && this->layers.size() > 1) { - this->_print->set_status(85, "Generating support material"); + if ((m_config.support_material || m_config.raft_layers > 0) && m_layers.size() > 1) { + m_print->set_status(85, "Generating support material"); this->_generate_support_material(); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } - m_state.set_done(posSupportMaterial); + this->set_done(posSupportMaterial); } } void PrintObject::clear_layers() { - for (Layer *l : this->layers) + for (Layer *l : m_layers) delete l; - this->layers.clear(); + m_layers.clear(); } Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z) { - layers.push_back(new Layer(id, this, height, print_z, slice_z)); - return layers.back(); + m_layers.emplace_back(new Layer(id, this, height, print_z, slice_z)); + return m_layers.back(); } void PrintObject::clear_support_layers() { - for (Layer *l : this->support_layers) + for (Layer *l : m_support_layers) delete l; - this->support_layers.clear(); + m_support_layers.clear(); } SupportLayer* PrintObject::add_support_layer(int id, coordf_t height, coordf_t print_z) { - support_layers.emplace_back(new SupportLayer(id, this, height, print_z, -1)); - return support_layers.back(); + m_support_layers.emplace_back(new SupportLayer(id, this, height, print_z, -1)); + return m_support_layers.back(); +} + +SupportLayerPtrs::const_iterator PrintObject::insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z) +{ + return m_support_layers.insert(pos, new SupportLayer(id, this, height, print_z, slice_z)); } // Called by Print::apply_config(). @@ -545,8 +549,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_ // these options only affect G-code export, so nothing to invalidate } else { // for legacy, if we can't handle this option let's invalidate all steps + this->invalidate_all_steps(); this->reset_layer_height_profile(); - this->invalidate_all_steps(); invalidated = true; } } @@ -559,37 +563,42 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_ bool PrintObject::invalidate_step(PrintObjectStep step) { - bool invalidated = m_state.invalidate(step); + bool invalidated = m_state.invalidate(step, m_print->m_mutex, m_print->m_cancel_callback); // propagate to dependent steps if (step == posPerimeters) { invalidated |= this->invalidate_step(posPrepareInfill); - invalidated |= this->_print->invalidate_step(psSkirt); - invalidated |= this->_print->invalidate_step(psBrim); + invalidated |= m_print->invalidate_step(psSkirt); + invalidated |= m_print->invalidate_step(psBrim); } else if (step == posPrepareInfill) { invalidated |= this->invalidate_step(posInfill); } else if (step == posInfill) { - invalidated |= this->_print->invalidate_step(psSkirt); - invalidated |= this->_print->invalidate_step(psBrim); + invalidated |= m_print->invalidate_step(psSkirt); + invalidated |= m_print->invalidate_step(psBrim); } else if (step == posSlice) { invalidated |= this->invalidate_step(posPerimeters); invalidated |= this->invalidate_step(posSupportMaterial); - invalidated |= this->_print->invalidate_step(psWipeTower); + invalidated |= m_print->invalidate_step(psWipeTower); } else if (step == posSupportMaterial) { - invalidated |= this->_print->invalidate_step(psSkirt); - invalidated |= this->_print->invalidate_step(psBrim); + invalidated |= m_print->invalidate_step(psSkirt); + invalidated |= m_print->invalidate_step(psBrim); } // Wipe tower depends on the ordering of extruders, which in turn depends on everything. - invalidated |= this->_print->invalidate_step(psWipeTower); + invalidated |= m_print->invalidate_step(psWipeTower); return invalidated; } +bool PrintObject::invalidate_all_steps() +{ + return m_state.invalidate_all(m_print->m_mutex, m_print->m_cancel_callback); +} + bool PrintObject::has_support_material() const { - return this->config.support_material - || this->config.raft_layers > 0 - || this->config.support_material_enforce_layers > 0; + return m_config.support_material + || m_config.raft_layers > 0 + || m_config.support_material_enforce_layers > 0; } // This function analyzes slices of a region (SurfaceCollection slices). @@ -610,42 +619,42 @@ void PrintObject::detect_surfaces_type() // are completely hidden inside a collective body of intersecting parts. // This is useful if one of the parts is to be dissolved, or if it is transparent and the internal shells // should be visible. - bool interface_shells = this->config.interface_shells.value; + bool interface_shells = m_config.interface_shells.value; - for (int idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) { + for (int idx_region = 0; idx_region < m_print->m_regions.size(); ++ idx_region) { BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " in parallel - start"; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (Layer *layer : this->layers) - layer->regions[idx_region]->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial"); + for (Layer *layer : m_layers) + layer->m_regions[idx_region]->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial"); #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ // If interface shells are allowed, the region->surfaces cannot be overwritten as they may be used by other threads. // Cache the result of the following parallel_loop. std::vector<Surfaces> surfaces_new; if (interface_shells) - surfaces_new.assign(this->layers.size(), Surfaces()); + surfaces_new.assign(m_layers.size(), Surfaces()); tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this, idx_region, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) { // If we have raft layers, consider bottom layer as a bridge just like any other bottom surface lying on the void. SurfaceType surface_type_bottom_1st = - (this->config.raft_layers.value > 0 && this->config.support_material_contact_distance.value > 0) ? + (m_config.raft_layers.value > 0 && m_config.support_material_contact_distance.value > 0) ? stBottomBridge : stBottom; // If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating // the support from the print. SurfaceType surface_type_bottom_other = - (this->config.support_material.value && this->config.support_material_contact_distance.value == 0) ? + (m_config.support_material.value && m_config.support_material_contact_distance.value == 0) ? stBottom : stBottomBridge; for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << idx_region << " and layer " << layer->print_z; - Layer *layer = this->layers[idx_layer]; + Layer *layer = m_layers[idx_layer]; LayerRegion *layerm = layer->get_region(idx_region); // comparison happens against the *full* slices (considering all regions) // unless internal shells are requested - Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? this->layers[idx_layer + 1] : nullptr; - Layer *lower_layer = (idx_layer > 0) ? this->layers[idx_layer - 1] : nullptr; + Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr; + Layer *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr; // collapse very narrow parts (using the safety offset in the diff is not enough) float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f; @@ -763,29 +772,29 @@ void PrintObject::detect_surfaces_type() } } ); // for each layer of a region - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); if (interface_shells) { // Move surfaces_new to layerm->slices.surfaces - for (size_t idx_layer = 0; idx_layer < this->layers.size(); ++ idx_layer) - this->layers[idx_layer]->get_region(idx_region)->slices.surfaces = std::move(surfaces_new[idx_layer]); + for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++ idx_layer) + m_layers[idx_layer]->get_region(idx_region)->slices.surfaces = std::move(surfaces_new[idx_layer]); } BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start"; // Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces. tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this, idx_region, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { - this->_print->throw_if_canceled(); - LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region); + m_print->throw_if_canceled(); + LayerRegion *layerm = m_layers[idx_layer]->get_region(idx_region); layerm->slices_to_fill_surfaces_clipped(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final"); #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ } // for each layer of a region }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - end"; } // for each this->print->region_count @@ -797,21 +806,21 @@ void PrintObject::process_external_surfaces() { BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..."; - FOREACH_REGION(this->_print, region) { - int region_id = int(region - this->_print->regions.begin()); + for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + const PrintRegion ®ion = *m_print->regions()[region_id]; BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this, region_id](const tbb::blocked_range<size_t>& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { - this->_print->throw_if_canceled(); - // BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << this->layers[layer_idx]->print_z; - this->layers[layer_idx]->get_region(region_id)->process_external_surfaces((layer_idx == 0) ? NULL : this->layers[layer_idx - 1]); + m_print->throw_if_canceled(); + // BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << m_layers[layer_idx]->print_z; + m_layers[layer_idx]->get_region(region_id)->process_external_surfaces((layer_idx == 0) ? NULL : m_layers[layer_idx - 1]); } } ); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end"; } } @@ -829,17 +838,17 @@ void PrintObject::discover_vertical_shells() Polygons bottom_surfaces; Polygons holes; }; - std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(this->layers.size(), DiscoverVerticalShellsCacheEntry()); - bool top_bottom_surfaces_all_regions = this->_print->regions.size() > 1 && ! this->config.interface_shells.value; + std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(m_layers.size(), DiscoverVerticalShellsCacheEntry()); + bool top_bottom_surfaces_all_regions = m_print->regions().size() > 1 && ! m_config.interface_shells.value; if (top_bottom_surfaces_all_regions) { // This is a multi-material print and interface_shells are disabled, meaning that the vertical shell thickness // is calculated over all materials. // Is the "ensure vertical wall thickness" applicable to any region? bool has_extra_layers = false; - for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) { - const PrintRegion ®ion = *this->_print->get_region(idx_region); - if (region.config.ensure_vertical_shell_thickness.value && - (region.config.top_solid_layers.value > 1 || region.config.bottom_solid_layers.value > 1)) { + for (size_t idx_region = 0; idx_region < m_print->regions().size(); ++ idx_region) { + const PrintRegion ®ion = *m_print->get_region(idx_region); + if (region.config().ensure_vertical_shell_thickness.value && + (region.config().top_solid_layers.value > 1 || region.config().bottom_solid_layers.value > 1)) { has_extra_layers = true; } } @@ -848,15 +857,15 @@ void PrintObject::discover_vertical_shells() return; BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - start : cache top / bottom"; //FIXME Improve the heuristics for a grain size. - size_t grain_size = std::max(this->layers.size() / 16, size_t(1)); + size_t grain_size = std::max(m_layers.size() / 16, size_t(1)); tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size(), grain_size), + tbb::blocked_range<size_t>(0, m_layers.size(), grain_size), [this, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) { const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge }; - const size_t num_regions = this->_print->regions.size(); + const size_t num_regions = m_print->regions().size(); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { - this->_print->throw_if_canceled(); - const Layer &layer = *this->layers[idx_layer]; + m_print->throw_if_canceled(); + const Layer &layer = *m_layers[idx_layer]; DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[idx_layer]; // Simulate single set of perimeters over all merged regions. float perimeter_offset = 0.f; @@ -866,7 +875,7 @@ void PrintObject::discover_vertical_shells() ++ debug_idx; #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ for (size_t idx_region = 0; idx_region < num_regions; ++ idx_region) { - LayerRegion &layerm = *layer.regions[idx_region]; + LayerRegion &layerm = *layer.m_regions[idx_region]; float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. append(cache.top_surfaces, offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing)); @@ -879,7 +888,7 @@ void PrintObject::discover_vertical_shells() unsigned int perimeters = 0; for (Surface &s : layerm.slices.surfaces) perimeters = std::max<unsigned int>(perimeters, s.extra_perimeters); - perimeters += layerm.region()->config.perimeters.value; + perimeters += layerm.region()->config().perimeters.value; // Then calculate the infill offset. if (perimeters > 0) { Flow extflow = layerm.flow(frExternalPerimeter); @@ -910,38 +919,38 @@ void PrintObject::discover_vertical_shells() cache.holes = union_(cache.holes, false); } }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom"; } - for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) { + for (size_t idx_region = 0; idx_region < m_print->regions().size(); ++ idx_region) { PROFILE_BLOCK(discover_vertical_shells_region); - const PrintRegion ®ion = *this->_print->get_region(idx_region); - if (! region.config.ensure_vertical_shell_thickness.value) + const PrintRegion ®ion = *m_print->get_region(idx_region); + if (! region.config().ensure_vertical_shell_thickness.value) // This region will be handled by discover_horizontal_shells(). continue; - int n_extra_top_layers = std::max(0, region.config.top_solid_layers.value - 1); - int n_extra_bottom_layers = std::max(0, region.config.bottom_solid_layers.value - 1); + int n_extra_top_layers = std::max(0, region.config().top_solid_layers.value - 1); + int n_extra_bottom_layers = std::max(0, region.config().bottom_solid_layers.value - 1); if (n_extra_top_layers + n_extra_bottom_layers == 0) // Zero or 1 layer, there is no additional vertical wall thickness enforced. continue; //FIXME Improve the heuristics for a grain size. - size_t grain_size = std::max(this->layers.size() / 16, size_t(1)); + size_t grain_size = std::max(m_layers.size() / 16, size_t(1)); if (! top_bottom_surfaces_all_regions) { // This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness // is calculated over a single material. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : cache top / bottom"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size(), grain_size), + tbb::blocked_range<size_t>(0, m_layers.size(), grain_size), [this, idx_region, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) { const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge }; for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { - this->_print->throw_if_canceled(); - Layer &layer = *this->layers[idx_layer]; - LayerRegion &layerm = *layer.regions[idx_region]; + m_print->throw_if_canceled(); + Layer &layer = *m_layers[idx_layer]; + LayerRegion &layerm = *layer.m_regions[idx_region]; float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. auto &cache = cache_top_botom_regions[idx_layer]; @@ -952,31 +961,31 @@ void PrintObject::discover_vertical_shells() append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); // Holes over all regions. Only collect them once, they are valid for all idx_region iterations. if (cache.holes.empty()) { - for (size_t idx_region = 0; idx_region < layer.regions.size(); ++ idx_region) - polygons_append(cache.holes, to_polygons(layer.regions[idx_region]->fill_expolygons)); + for (size_t idx_region = 0; idx_region < layer.regions().size(); ++ idx_region) + polygons_append(cache.holes, to_polygons(layer.regions()[idx_region]->fill_expolygons)); } } }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end : cache top / bottom"; } BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size(), grain_size), + tbb::blocked_range<size_t>(0, m_layers.size(), grain_size), [this, idx_region, n_extra_top_layers, n_extra_bottom_layers, &cache_top_botom_regions] (const tbb::blocked_range<size_t>& range) { // printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end()); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { PROFILE_BLOCK(discover_vertical_shells_region_layer); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING static size_t debug_idx = 0; ++ debug_idx; #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - Layer *layer = this->layers[idx_layer]; - LayerRegion *layerm = layer->regions[idx_region]; + Layer *layer = m_layers[idx_layer]; + LayerRegion *layerm = layer->m_regions[idx_region]; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-initial"); @@ -999,9 +1008,9 @@ void PrintObject::discover_vertical_shells() { Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box()); for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) { - if (n < 0 || n >= (int)this->layers.size()) + if (n < 0 || n >= (int)m_layers.size()) continue; - ExPolygons &expolys = this->layers[n]->perimeter_expolygons; + ExPolygons &expolys = m_layers[n]->perimeter_expolygons; for (size_t i = 0; i < expolys.size(); ++ i) { Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i])); svg.draw(expolys[i]); @@ -1019,8 +1028,8 @@ void PrintObject::discover_vertical_shells() // Reset the top / bottom inflated regions caches of entries, which are out of the moving window. bool hole_first = true; for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) - if (n >= 0 && n < (int)this->layers.size()) { - Layer &neighbor_layer = *this->layers[n]; + if (n >= 0 && n < (int)m_layers.size()) { + Layer &neighbor_layer = *m_layers[n]; const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[n]; if (hole_first) { hole_first = false; @@ -1183,12 +1192,12 @@ void PrintObject::discover_vertical_shells() layerm->fill_surfaces.append(new_internal_solid, stInternalSolid); } // for each layer }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end"; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t idx_layer = 0; idx_layer < this->layers.size(); ++idx_layer) { - LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region); + for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++idx_layer) { + LayerRegion *layerm = m_layers[idx_layer]->get_region(idx_region); layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-final"); layerm->export_region_fill_surfaces_to_svg_debug("4_discover_vertical_shells-final"); } @@ -1206,14 +1215,14 @@ void PrintObject::bridge_over_infill() { BOOST_LOG_TRIVIAL(info) << "Bridge over infill..."; - FOREACH_REGION(this->_print, region) { - size_t region_id = region - this->_print->regions.begin(); + for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + const PrintRegion ®ion = *m_print->regions()[region_id]; // skip bridging in case there are no voids - if ((*region)->config.fill_density.value == 100) continue; + if (region.config().fill_density.value == 100) continue; // get bridge flow - Flow bridge_flow = (*region)->flow( + Flow bridge_flow = region.flow( frSolidInfill, -1, // layer height, not relevant for bridge flow true, // bridge @@ -1224,10 +1233,10 @@ void PrintObject::bridge_over_infill() FOREACH_LAYER(this, layer_it) { // skip first layer - if (layer_it == this->layers.begin()) continue; + if (layer_it == m_layers.begin()) continue; Layer* layer = *layer_it; - LayerRegion* layerm = layer->regions[region_id]; + LayerRegion* layerm = layer->m_regions[region_id]; // extract the stInternalSolid surfaces that might be transformed into bridges Polygons internal_solid; @@ -1242,8 +1251,8 @@ void PrintObject::bridge_over_infill() // iterate through lower layers spanned by bridge_flow double bottom_z = layer->print_z - bridge_flow.height; - for (int i = int(layer_it - this->layers.begin()) - 1; i >= 0; --i) { - const Layer* lower_layer = this->layers[i]; + for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) { + const Layer* lower_layer = m_layers[i]; // stop iterating if layer is lower than bottom_z if (lower_layer->print_z < bottom_z) break; @@ -1323,7 +1332,7 @@ void PrintObject::bridge_over_infill() layerm->export_region_slices_to_svg_debug("7_bridge_over_infill"); layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill"); #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } } } @@ -1331,7 +1340,7 @@ void PrintObject::bridge_over_infill() SlicingParameters PrintObject::slicing_parameters() const { return SlicingParameters::create_from_config( - this->print()->config, this->config, + this->print()->config(), m_config, unscale(this->size.z), this->print()->object_extruders()); } @@ -1422,39 +1431,39 @@ void PrintObject::_slice() layer->lower_layer = prev; } // Make sure all layers contain layer region objects for all regions. - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) - layer->add_region(this->print()->regions[region_id]); + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) + layer->add_region(this->print()->regions()[region_id]); prev = layer; } } // Slice all non-modifier volumes. - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id; std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start"; for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) - this->layers[layer_id]->regions[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal); - this->_print->throw_if_canceled(); + m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end"; } // Slice all modifier volumes. - if (this->print()->regions.size() > 1) { - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { + if (this->print()->regions().size() > 1) { + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id; std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); // loop through the other regions and 'steal' the slices belonging to this one BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " start"; - for (size_t other_region_id = 0; other_region_id < this->print()->regions.size(); ++ other_region_id) { + for (size_t other_region_id = 0; other_region_id < this->print()->regions().size(); ++ other_region_id) { if (region_id == other_region_id) continue; for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) { - Layer *layer = layers[layer_id]; - LayerRegion *layerm = layer->regions[region_id]; - LayerRegion *other_layerm = layer->regions[other_region_id]; + Layer *layer = this->layers()[layer_id]; + LayerRegion *layerm = layer->m_regions[region_id]; + LayerRegion *other_layerm = layer->m_regions[other_region_id]; if (layerm == nullptr || other_layerm == nullptr) continue; Polygons other_slices = to_polygons(other_layerm->slices); @@ -1467,59 +1476,59 @@ void PrintObject::_slice() layerm->slices.append(std::move(my_parts), stInternal); } } - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " end"; } } BOOST_LOG_TRIVIAL(debug) << "Slicing objects - removing top empty layers"; - while (! this->layers.empty()) { - const Layer *layer = this->layers.back(); - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) - if (layer->regions[region_id] != nullptr && ! layer->regions[region_id]->slices.empty()) + while (! m_layers.empty()) { + const Layer *layer = m_layers.back(); + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) + if (layer->m_regions[region_id] != nullptr && ! layer->m_regions[region_id]->slices.empty()) // Non empty layer. goto end; delete layer; - this->layers.pop_back(); - if (! this->layers.empty()) - this->layers.back()->upper_layer = nullptr; + m_layers.pop_back(); + if (! m_layers.empty()) + m_layers.back()->upper_layer = nullptr; } - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); end: ; BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - begin"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t>& range) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { - this->_print->throw_if_canceled(); - Layer *layer = this->layers[layer_id]; + m_print->throw_if_canceled(); + Layer *layer = m_layers[layer_id]; // Apply size compensation and perform clipping of multi-part objects. - float delta = float(scale_(this->config.xy_size_compensation.value)); + float delta = float(scale_(m_config.xy_size_compensation.value)); if (layer_id == 0) - delta -= float(scale_(this->config.elefant_foot_compensation.value)); + delta -= float(scale_(m_config.elefant_foot_compensation.value)); bool scale = delta != 0.f; - bool clip = this->config.clip_multipart_objects.value || delta > 0.f; - if (layer->regions.size() == 1) { + bool clip = m_config.clip_multipart_objects.value || delta > 0.f; + if (layer->m_regions.size() == 1) { if (scale) { // Single region, growing or shrinking. - LayerRegion *layerm = layer->regions.front(); + LayerRegion *layerm = layer->m_regions.front(); layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal); } } else if (scale || clip) { // Multiple regions, growing, shrinking or just clipping one region by the other. // When clipping the regions, priority is given to the first regions. Polygons processed; - for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { + LayerRegion *layerm = layer->m_regions[region_id]; ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces)); if (scale) slices = offset_ex(slices, delta); if (region_id > 0 && clip) // Trim by the slices of already processed regions. slices = diff_ex(to_polygons(std::move(slices)), processed); - if (clip && region_id + 1 < layer->regions.size()) + if (clip && region_id + 1 < layer->m_regions.size()) // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); layerm->slices.set(std::move(slices), stInternal); @@ -1529,7 +1538,7 @@ end: layer->make_slices(); } }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } @@ -1546,7 +1555,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std:: ModelVolume *volume = this->model_object()->volumes[volume_id]; if (volume->modifier == modifier) mesh.merge(volume->mesh); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } if (mesh.stl.stats.number_of_facets > 0) { // transform mesh @@ -1561,7 +1570,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std:: auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); mslicer.init(&mesh, callback); mslicer.slice(z, &layers, callback); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } } } @@ -1573,9 +1582,9 @@ std::string PrintObject::_fix_slicing_errors() // Collect layers with slicing errors. // These layers will be fixed in parallel. std::vector<size_t> buggy_layers; - buggy_layers.reserve(this->layers.size()); - for (size_t idx_layer = 0; idx_layer < this->layers.size(); ++ idx_layer) - if (this->layers[idx_layer]->slicing_errors) + buggy_layers.reserve(m_layers.size()); + for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++ idx_layer) + if (m_layers[idx_layer]->slicing_errors) buggy_layers.push_back(idx_layer); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - begin"; @@ -1583,25 +1592,25 @@ std::string PrintObject::_fix_slicing_errors() tbb::blocked_range<size_t>(0, buggy_layers.size()), [this, &buggy_layers](const tbb::blocked_range<size_t>& range) { for (size_t buggy_layer_idx = range.begin(); buggy_layer_idx < range.end(); ++ buggy_layer_idx) { - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); size_t idx_layer = buggy_layers[buggy_layer_idx]; - Layer *layer = this->layers[idx_layer]; + Layer *layer = m_layers[idx_layer]; assert(layer->slicing_errors); // Try to repair the layer surfaces by merging all contours and all holes from neighbor layers. // BOOST_LOG_TRIVIAL(trace) << "Attempting to repair layer" << idx_layer; - for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) { - LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { + LayerRegion *layerm = layer->m_regions[region_id]; // Find the first valid layer below / above the current layer. const Surfaces *upper_surfaces = nullptr; const Surfaces *lower_surfaces = nullptr; - for (size_t j = idx_layer + 1; j < this->layers.size(); ++ j) - if (! this->layers[j]->slicing_errors) { - upper_surfaces = &this->layers[j]->regions[region_id]->slices.surfaces; + for (size_t j = idx_layer + 1; j < m_layers.size(); ++ j) + if (! m_layers[j]->slicing_errors) { + upper_surfaces = &m_layers[j]->regions()[region_id]->slices.surfaces; break; } for (int j = int(idx_layer) - 1; j >= 0; -- j) - if (! this->layers[j]->slicing_errors) { - lower_surfaces = &this->layers[j]->regions[region_id]->slices.surfaces; + if (! m_layers[j]->slicing_errors) { + lower_surfaces = &m_layers[j]->regions()[region_id]->slices.surfaces; break; } // Collect outer contours and holes from the valid layers above & below. @@ -1634,16 +1643,16 @@ std::string PrintObject::_fix_slicing_errors() layer->make_slices(); } }); - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end"; // remove empty layers from bottom - while (! this->layers.empty() && this->layers.front()->slices.expolygons.empty()) { - delete this->layers.front(); - this->layers.erase(this->layers.begin()); - this->layers.front()->lower_layer = nullptr; - for (size_t i = 0; i < this->layers.size(); ++ i) - this->layers[i]->set_id(this->layers[i]->id() - 1); + while (! m_layers.empty() && m_layers.front()->slices.expolygons.empty()) { + delete m_layers.front(); + m_layers.erase(m_layers.begin()); + m_layers.front()->lower_layer = nullptr; + for (size_t i = 0; i < m_layers.size(); ++ i) + m_layers[i]->set_id(m_layers[i]->id() - 1); } return buggy_layers.empty() ? "" : @@ -1658,13 +1667,13 @@ void PrintObject::_simplify_slices(double distance) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - begin"; tbb::parallel_for( - tbb::blocked_range<size_t>(0, this->layers.size()), + tbb::blocked_range<size_t>(0, m_layers.size()), [this, distance](const tbb::blocked_range<size_t>& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { - this->_print->throw_if_canceled(); - Layer *layer = this->layers[layer_idx]; - for (size_t region_idx = 0; region_idx < layer->regions.size(); ++ region_idx) - layer->regions[region_idx]->slices.simplify(distance); + m_print->throw_if_canceled(); + Layer *layer = m_layers[layer_idx]; + for (size_t region_idx = 0; region_idx < layer->m_regions.size(); ++ region_idx) + layer->m_regions[region_idx]->slices.simplify(distance); layer->slices.simplify(distance); } }); @@ -1681,18 +1690,18 @@ void PrintObject::_simplify_slices(double distance) // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries. void PrintObject::clip_fill_surfaces() { - if (! this->config.infill_only_where_needed.value || - ! std::any_of(this->print()->regions.begin(), this->print()->regions.end(), - [](const PrintRegion *region) { return region->config.fill_density > 0; })) + if (! m_config.infill_only_where_needed.value || + ! std::any_of(this->print()->regions().begin(), this->print()->regions().end(), + [](const PrintRegion *region) { return region->config().fill_density > 0; })) return; // We only want infill under ceilings; this is almost like an // internal support material. // Proceed top-down, skipping the bottom layer. Polygons upper_internal; - for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; -- layer_id) { - Layer *layer = this->layers[layer_id]; - Layer *lower_layer = this->layers[layer_id - 1]; + for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) { + Layer *layer = m_layers[layer_id]; + Layer *lower_layer = m_layers[layer_id - 1]; // Detect things that we need to support. // Cummulative slices. Polygons slices; @@ -1702,7 +1711,7 @@ void PrintObject::clip_fill_surfaces() Polygons fill_surfaces; // Solid surfaces to be supported. Polygons overhangs; - for (const LayerRegion *layerm : layer->regions) + for (const LayerRegion *layerm : layer->m_regions) for (const Surface &surface : layerm->fill_surfaces.surfaces) { Polygons polygons = to_polygons(surface.expolygon); if (surface.is_solid()) @@ -1711,7 +1720,7 @@ void PrintObject::clip_fill_surfaces() } Polygons lower_layer_fill_surfaces; Polygons lower_layer_internal_surfaces; - for (const LayerRegion *layerm : lower_layer->regions) + for (const LayerRegion *layerm : lower_layer->m_regions) for (const Surface &surface : layerm->fill_surfaces.surfaces) { Polygons polygons = to_polygons(surface.expolygon); if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) @@ -1727,7 +1736,7 @@ void PrintObject::clip_fill_surfaces() //FIXME Offset2 eats out from both sides, while the perimeters are create outside in. //Should the pw not be half of the current value? float pw = FLT_MAX; - for (const LayerRegion *layerm : layer->regions) + for (const LayerRegion *layerm : layer->m_regions) pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width()); // Append such thick perimeters to the areas that need support polygons_append(overhangs, offset2(perimeters, -pw, +pw)); @@ -1736,8 +1745,8 @@ void PrintObject::clip_fill_surfaces() polygons_append(overhangs, std::move(upper_internal)); upper_internal = intersection(overhangs, lower_layer_internal_surfaces); // Apply new internal infill to regions. - for (LayerRegion *layerm : lower_layer->regions) { - if (layerm->region()->config.fill_density.value == 0) + for (LayerRegion *layerm : lower_layer->m_regions) { + if (layerm->region()->config().fill_density.value == 0) continue; SurfaceType internal_surface_types[] = { stInternal, stInternalVoid }; Polygons internal; @@ -1754,7 +1763,7 @@ void PrintObject::clip_fill_surfaces() layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces"); #endif } - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); } } @@ -1762,11 +1771,11 @@ void PrintObject::discover_horizontal_shells() { BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()"; - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (int i = 0; i < int(this->layers.size()); ++ i) { - this->_print->throw_if_canceled(); - LayerRegion *layerm = this->layers[i]->regions[region_id]; - PrintRegionConfig ®ion_config = layerm->region()->config; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (int i = 0; i < int(m_layers.size()); ++ i) { + m_print->throw_if_canceled(); + LayerRegion *layerm = m_layers[i]->regions()[region_id]; + const PrintRegionConfig ®ion_config = layerm->region()->config(); if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 && (i % region_config.solid_infill_every_layers) == 0) { // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge. @@ -1781,7 +1790,7 @@ void PrintObject::discover_horizontal_shells() continue; for (int idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) { - this->_print->throw_if_canceled(); + m_print->throw_if_canceled(); SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge; // Find slices of current type for current layer. // Use slices instead of fill_surfaces, because they also include the perimeter area, @@ -1810,11 +1819,11 @@ void PrintObject::discover_horizontal_shells() size_t solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value; for (int n = (type == stTop) ? i-1 : i+1; std::abs(n - i) < solid_layers; (type == stTop) ? -- n : ++ n) { - if (n < 0 || n >= int(this->layers.size())) + if (n < 0 || n >= int(m_layers.size())) continue; // Slic3r::debugf " looking for neighbors on layer %d...\n", $n; // Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface. - LayerRegion *neighbor_layerm = this->layers[n]->regions[region_id]; + LayerRegion *neighbor_layerm = m_layers[n]->regions()[region_id]; // find intersection between neighbor and current layer's surfaces // intersections have contours and holes @@ -1936,9 +1945,9 @@ void PrintObject::discover_horizontal_shells() } // for each region #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - for (const Layer *layer : this->layers) { - const LayerRegion *layerm = layer->regions[region_id]; + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (const Layer *layer : m_layers) { + const LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells"); layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells"); } // for each layer @@ -1952,24 +1961,24 @@ void PrintObject::discover_horizontal_shells() void PrintObject::combine_infill() { // Work on each region separately. - for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) { - const PrintRegion *region = this->print()->regions[region_id]; - const int every = region->config.infill_every_layers.value; - if (every < 2 || region->config.fill_density == 0.) + for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + const PrintRegion *region = this->print()->regions()[region_id]; + const int every = region->config().infill_every_layers.value; + if (every < 2 || region->config().fill_density == 0.) continue; // Limit the number of combined layers to the maximum height allowed by this regions' nozzle. //FIXME limit the layer height to max_layer_height double nozzle_diameter = std::min( - this->print()->config.nozzle_diameter.get_at(region->config.infill_extruder.value - 1), - this->print()->config.nozzle_diameter.get_at(region->config.solid_infill_extruder.value - 1)); + this->print()->config().nozzle_diameter.get_at(region->config().infill_extruder.value - 1), + this->print()->config().nozzle_diameter.get_at(region->config().solid_infill_extruder.value - 1)); // define the combinations - std::vector<size_t> combine(this->layers.size(), 0); + std::vector<size_t> combine(m_layers.size(), 0); { double current_height = 0.; size_t num_layers = 0; - for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) { - this->_print->throw_if_canceled(); - const Layer *layer = this->layers[layer_idx]; + for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) { + m_print->throw_if_canceled(); + const Layer *layer = m_layers[layer_idx]; if (layer->id() == 0) // Skip first print layer (which may not be first layer in array because of raft). continue; @@ -1986,12 +1995,12 @@ void PrintObject::combine_infill() } // Append lower layers (if any) to uppermost layer. - combine[this->layers.size() - 1] = num_layers; + combine[m_layers.size() - 1] = num_layers; } // loop through layers to which we have assigned layers to combine - for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) { - this->_print->throw_if_canceled(); + for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) { + m_print->throw_if_canceled(); size_t num_layers = combine[layer_idx]; if (num_layers <= 1) continue; @@ -1999,7 +2008,7 @@ void PrintObject::combine_infill() std::vector<LayerRegion*> layerms; layerms.reserve(num_layers); for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++ i) - layerms.emplace_back(this->layers[i]->regions[region_id]); + layerms.emplace_back(m_layers[i]->regions()[region_id]); // We need to perform a multi-layer intersection, so let's split it in pairs. // Initialize the intersection with the candidates of the lowest layer. ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal)); @@ -2028,10 +2037,10 @@ void PrintObject::combine_infill() 0.5f * layerms.back()->flow(frPerimeter).scaled_width() + // Because fill areas for rectilinear and honeycomb are grown // later to overlap perimeters, we need to counteract that too. - ((region->config.fill_pattern == ipRectilinear || - region->config.fill_pattern == ipGrid || - region->config.fill_pattern == ipLine || - region->config.fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * + ((region->config().fill_pattern == ipRectilinear || + region->config().fill_pattern == ipGrid || + region->config().fill_pattern == ipLine || + region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * layerms.back()->flow(frSolidInfill).scaled_width(); for (ExPolygon &expoly : intersection) polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); diff --git a/xs/src/libslic3r/PrintRegion.cpp b/xs/src/libslic3r/PrintRegion.cpp index 2fcf69166..cdc8c532a 100644 --- a/xs/src/libslic3r/PrintRegion.cpp +++ b/xs/src/libslic3r/PrintRegion.cpp @@ -12,48 +12,48 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir } else { // otherwise, get extrusion width from configuration // (might be an absolute value, or a percent value, or zero for auto) - if (first_layer && this->_print->config.first_layer_extrusion_width.value > 0) { - config_width = this->_print->config.first_layer_extrusion_width; + if (first_layer && m_print->config().first_layer_extrusion_width.value > 0) { + config_width = m_print->config().first_layer_extrusion_width; } else if (role == frExternalPerimeter) { - config_width = this->config.external_perimeter_extrusion_width; + config_width = m_config.external_perimeter_extrusion_width; } else if (role == frPerimeter) { - config_width = this->config.perimeter_extrusion_width; + config_width = m_config.perimeter_extrusion_width; } else if (role == frInfill) { - config_width = this->config.infill_extrusion_width; + config_width = m_config.infill_extrusion_width; } else if (role == frSolidInfill) { - config_width = this->config.solid_infill_extrusion_width; + config_width = m_config.solid_infill_extrusion_width; } else if (role == frTopSolidInfill) { - config_width = this->config.top_infill_extrusion_width; + config_width = m_config.top_infill_extrusion_width; } else { CONFESS("Unknown role"); } } if (config_width.value == 0) { - config_width = object.config.extrusion_width; + config_width = object.config().extrusion_width; } // get the configured nozzle_diameter for the extruder associated // to the flow role requested size_t extruder = 0; // 1-based if (role == frPerimeter || role == frExternalPerimeter) { - extruder = this->config.perimeter_extruder; + extruder = m_config.perimeter_extruder; } else if (role == frInfill) { - extruder = this->config.infill_extruder; + extruder = m_config.infill_extruder; } else if (role == frSolidInfill || role == frTopSolidInfill) { - extruder = this->config.solid_infill_extruder; + extruder = m_config.solid_infill_extruder; } else { CONFESS("Unknown role $role"); } - double nozzle_diameter = this->_print->config.nozzle_diameter.get_at(extruder-1); + double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1); - return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)this->config.bridge_flow_ratio : 0.0); + return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0); } coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const { - return (print_config.nozzle_diameter.get_at(this->config.perimeter_extruder.value - 1) + - print_config.nozzle_diameter.get_at(this->config.infill_extruder.value - 1) + - print_config.nozzle_diameter.get_at(this->config.solid_infill_extruder.value - 1)) / 3.; + return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) + + print_config.nozzle_diameter.get_at(m_config.infill_extruder.value - 1) + + print_config.nozzle_diameter.get_at(m_config.solid_infill_extruder.value - 1)) / 3.; } } diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 0cecf0014..d18f9d710 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -142,8 +142,8 @@ void export_print_z_polygons_and_extrusions_to_svg( PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) : m_object (object), - m_print_config (&object->print()->config), - m_object_config (&object->config), + m_print_config (&object->print()->config()), + m_object_config (&object->config()), m_slicing_params (slicing_params), m_first_layer_flow (support_material_1st_layer_flow(object, float(slicing_params.first_print_layer_height))), m_support_material_flow (support_material_flow(object, float(slicing_params.layer_height))), @@ -164,7 +164,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object coordf_t external_perimeter_width = 0.; for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { if (! object->region_volumes[region_id].empty()) { - const PrintRegionConfig &config = object->print()->get_region(region_id)->config; + const PrintRegionConfig &config = object->print()->get_region(region_id)->config(); coordf_t width = config.external_perimeter_extrusion_width.get_abs_value(slicing_params.layer_height); if (width <= 0.) width = m_print_config->nozzle_diameter.get_at(config.perimeter_extruder-1); @@ -226,7 +226,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) coordf_t max_object_layer_height = 0.; for (size_t i = 0; i < object.layer_count(); ++ i) - max_object_layer_height = std::max(max_object_layer_height, object.layers[i]->height); + max_object_layer_height = std::max(max_object_layer_height, object.layers()[i]->height); // Layer instances will be allocated by std::deque and they will be kept until the end of this function call. // The layers will be referenced by various LayersPtr (of type std::vector<Layer*>) @@ -266,9 +266,9 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) layer_support_areas); #ifdef SLIC3R_DEBUG - for (size_t layer_id = 0; layer_id < object.layers.size(); ++ layer_id) + for (size_t layer_id = 0; layer_id < object.layers().size(); ++ layer_id) Slic3r::SVG::export_expolygons( - debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers[layer_id]->print_z), + debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers()[layer_id]->print_z), union_ex(layer_support_areas[layer_id], false)); #endif /* SLIC3R_DEBUG */ @@ -354,7 +354,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) // Sort the layers lexicographically by a raising print_z and a decreasing height. std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare()); int layer_id = 0; - assert(object.support_layers.empty()); + assert(object.support_layers().empty()); for (int i = 0; i < int(layers_sorted.size());) { // Find the last layer with roughly the same print_z, find the minimum layer height of all. // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should. @@ -420,8 +420,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t { // 1) Count the new polygons first. size_t n_polygons_new = 0; - for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { - const LayerRegion ®ion = *(*it_region); + for (const LayerRegion* pregion : layer.regions()) { + const LayerRegion ®ion = *pregion; const SurfaceCollection &slices = region.slices; for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { const Surface &surface = *it; @@ -433,8 +433,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t // 2) Collect the new polygons. Polygons out; out.reserve(n_polygons_new); - for (LayerRegionPtrs::const_iterator it_region = layer.regions.begin(); it_region != layer.regions.end(); ++ it_region) { - const LayerRegion ®ion = *(*it_region); + for (const LayerRegion *pregion : layer.regions()) { + const LayerRegion ®ion = *pregion; const SurfaceCollection &slices = region.slices; for (Surfaces::const_iterator it = slices.surfaces.begin(); it != slices.surfaces.end(); ++ it) { const Surface &surface = *it; @@ -658,9 +658,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ std::vector<Polygons> buildplate_covered; if (buildplate_only) { BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() - collecting regions covering the print bed."; - buildplate_covered.assign(object.layers.size(), Polygons()); - for (size_t layer_id = 1; layer_id < object.layers.size(); ++ layer_id) { - const Layer &lower_layer = *object.layers[layer_id-1]; + buildplate_covered.assign(object.layers().size(), Polygons()); + for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) { + const Layer &lower_layer = *object.layers()[layer_id-1]; // Merge the new slices with the preceding slices. // Apply the safety offset to the newly added polygons, so they will connect // with the polygons collected before, @@ -686,7 +686,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ [this, &object, &buildplate_covered, threshold_rad, &layer_storage, &layer_storage_mutex, &contact_out](const tbb::blocked_range<size_t>& range) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { - const Layer &layer = *object.layers[layer_id]; + const Layer &layer = *object.layers()[layer_id]; // Detect overhangs and contact areas needed to support them. // Collect overhangs and contacts of all regions of this layer supported by the layer immediately below. @@ -703,13 +703,13 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ contact_polygons = offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN)); } else { // Generate overhang / contact_polygons for non-raft layers. - const Layer &lower_layer = *object.layers[layer_id-1]; - for (LayerRegion *layerm : layer.regions) { + const Layer &lower_layer = *object.layers()[layer_id-1]; + for (LayerRegion *layerm : layer.regions()) { // Extrusion width accounts for the roundings of the extrudates. // It is the maximum widh of the extrudate. float fw = float(layerm->flow(frExternalPerimeter).scaled_width()); float lower_layer_offset = - (layer_id < this->m_object_config->support_material_enforce_layers.value) ? + (layer_id < m_object_config->support_material_enforce_layers.value) ? // Enforce a full possible support, ignore the overhang angle. 0.f : (threshold_rad > 0. ? @@ -762,14 +762,14 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ } #endif /* SLIC3R_DEBUG */ - if (this->m_object_config->dont_support_bridges) { + if (m_object_config->dont_support_bridges) { // compute the area of bridging perimeters // Note: this is duplicate code from GCode.pm, we need to refactor if (true) { Polygons bridged_perimeters; { Flow bridge_flow = layerm->flow(frPerimeter, true); - coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(layerm->region()->config.perimeter_extruder-1); + coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder-1); Polygons lower_grown_slices = offset(lower_layer_polygons, 0.5f*float(scale_(nozzle_diameter)), SUPPORT_SURFACES_OFFSET_PARAMETERS); // Collect perimeters of this layer. @@ -894,8 +894,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ } else { // Interface layer will be synchronized with the object. assert(layer_id > 0); - new_layer.height = object.layers[layer_id - 1]->height; - new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers[layer_id - 2]->print_z; + new_layer.height = object.layers()[layer_id - 1]->height; + new_layer.bottom_z = (layer_id == 1) ? m_slicing_params.object_print_z_min : object.layers()[layer_id - 2]->print_z; } } else { // Contact layer will be printed with a normal flow, but @@ -904,9 +904,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // In the future we may switch to a normal extrusion flow for the supported bridges. // Get the average nozzle diameter used on this layer. coordf_t nozzle_dmr = 0.; - for (const LayerRegion *region : layer.regions) + for (const LayerRegion *region : layer.regions()) nozzle_dmr += region->region()->nozzle_dmr_avg(*m_print_config); - nozzle_dmr /= coordf_t(layer.regions.size()); + nozzle_dmr /= coordf_t(layer.regions().size()); new_layer.print_z = layer.print_z - nozzle_dmr - m_object_config->support_material_contact_distance; new_layer.bottom_z = new_layer.print_z; new_layer.height = 0.; @@ -1048,10 +1048,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta // top shapes so this can be done here layer_new.height = m_slicing_params.soluble_interface ? // Align the interface layer with the object's layer height. - object.layers[layer_id + 1]->height : + object.layers()[layer_id + 1]->height : // Place a bridge flow interface layer over the top surface. m_support_material_interface_flow.nozzle_diameter; - layer_new.print_z = m_slicing_params.soluble_interface ? object.layers[layer_id + 1]->print_z : + layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z : layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value; layer_new.bottom_z = layer.print_z; layer_new.idx_object_layer_below = layer_id; @@ -1062,16 +1062,16 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta // Walk the top surfaces, snap the top of the new bottom surface to the closest top of the top surface, // so there will be no support surfaces generated with thickness lower than m_support_layer_height_min. for (size_t top_idx = size_t(std::max<int>(0, contact_idx)); - top_idx < top_contacts.size() && top_contacts[top_idx]->print_z < layer_new.print_z + this->m_support_layer_height_min; + top_idx < top_contacts.size() && top_contacts[top_idx]->print_z < layer_new.print_z + m_support_layer_height_min; ++ top_idx) { - if (top_contacts[top_idx]->print_z > layer_new.print_z - this->m_support_layer_height_min) { + if (top_contacts[top_idx]->print_z > layer_new.print_z - m_support_layer_height_min) { // A top layer has been found, which is close to the new bottom layer. coordf_t diff = layer_new.print_z - top_contacts[top_idx]->print_z; - assert(std::abs(diff) <= this->m_support_layer_height_min); + assert(std::abs(diff) <= m_support_layer_height_min); if (diff > 0.) { // The top contact layer is below this layer. Make the bridging layer thinner to align with the existing top layer. assert(diff < layer_new.height + EPSILON); - assert(layer_new.height - diff >= this->m_support_layer_height_min - EPSILON); + assert(layer_new.height - diff >= m_support_layer_height_min - EPSILON); layer_new.print_z = top_contacts[top_idx]->print_z; layer_new.height -= diff; } else { @@ -1093,7 +1093,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta // Trim the already created base layers above the current layer intersecting with the new bottom contacts layer. touching = offset(touching, float(SCALED_EPSILON)); for (int layer_id_above = layer_id + 1; layer_id_above < int(object.total_layer_count()); ++ layer_id_above) { - const Layer &layer_above = *object.layers[layer_id_above]; + const Layer &layer_above = *object.layers()[layer_id_above]; if (layer_above.print_z > layer_new.print_z + EPSILON) break; if (! layer_support_areas[layer_id_above].empty()) { @@ -1320,7 +1320,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int // Verify that the extremes are separated by m_support_layer_height_min. for (size_t i = 1; i < extremes.size(); ++ i) { assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() == 0. || - extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > this->m_support_layer_height_min - EPSILON); + extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > m_support_layer_height_min - EPSILON); assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > 0. || extremes[i]->layer_type == extremes[i-1]->layer_type || (extremes[i]->layer_type == sltBottomContact && extremes[i - 1]->layer_type == sltTopContact)); @@ -1344,7 +1344,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int // This is a bottom of a synchronized (or soluble) top contact layer, its height has been decided in this->top_contact_layers(). assert(extr2->layer_type == sltTopContact); assert(extr2->bottom_z == m_slicing_params.first_print_layer_height); - assert(extr2->print_z >= m_slicing_params.first_print_layer_height + this->m_support_layer_height_min - EPSILON); + assert(extr2->print_z >= m_slicing_params.first_print_layer_height + m_support_layer_height_min - EPSILON); if (intermediate_layers.empty() || intermediate_layers.back()->print_z < m_slicing_params.first_print_layer_height) { MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate); layer_new.bottom_z = 0.; @@ -1384,7 +1384,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int if (synchronize) { // Emit support layers synchronized with the object layers. // Find the first object layer, which has its print_z in this support Z range. - while (idx_layer_object < object.layers.size() && object.layers[idx_layer_object]->print_z < extr1z + EPSILON) + while (idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr1z + EPSILON) ++ idx_layer_object; if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) { // Insert one base support layer below the object. @@ -1395,11 +1395,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int intermediate_layers.push_back(&layer_new); } // Emit all intermediate support layers synchronized with object layers up to extr2z. - for (; idx_layer_object < object.layers.size() && object.layers[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) { + for (; idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) { MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate); - layer_new.print_z = object.layers[idx_layer_object]->print_z; - layer_new.height = object.layers[idx_layer_object]->height; - layer_new.bottom_z = (idx_layer_object > 0) ? object.layers[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height); + layer_new.print_z = object.layers()[idx_layer_object]->print_z; + layer_new.height = object.layers()[idx_layer_object]->height; + layer_new.bottom_z = (idx_layer_object > 0) ? object.layers()[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height); assert(intermediate_layers.empty() || intermediate_layers.back()->print_z < layer_new.print_z + EPSILON); intermediate_layers.push_back(&layer_new); } @@ -1409,10 +1409,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int assert(n_layers_extra > 0); coordf_t step = dist / coordf_t(n_layers_extra); if (extr1 != nullptr && extr1->layer_type == sltTopContact && - extr1->print_z + this->m_support_layer_height_min > extr1->bottom_z + step) { + extr1->print_z + m_support_layer_height_min > extr1->bottom_z + step) { // The bottom extreme is a bottom of a top surface. Ensure that the gap // between the 1st intermediate layer print_z and extr1->print_z is not too small. - assert(extr1->bottom_z + this->m_support_layer_height_min < extr1->print_z + EPSILON); + assert(extr1->bottom_z + m_support_layer_height_min < extr1->print_z + EPSILON); // Generate the first intermediate layer. MyLayer &layer_new = layer_allocate(layer_storage, sltIntermediate); layer_new.bottom_z = extr1->bottom_z; @@ -1509,7 +1509,7 @@ void PrintObjectSupportMaterial::generate_base_layers( Polygons polygons_new; // Use the precomputed layer_support_areas. - idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers, idx_object_layer_above, + idx_object_layer_above = std::max(0, idx_lower_or_equal(object.layers(), idx_object_layer_above, [&layer_intermediate](const Layer *layer){ return layer->print_z <= layer_intermediate.print_z + EPSILON; })); polygons_new = layer_support_areas[idx_object_layer_above]; @@ -1644,24 +1644,24 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( // Find the overlapping object layers including the extra above / below gap. coordf_t z_threshold = support_layer.print_z - support_layer.height - gap_extra_below + EPSILON; idx_object_layer_overlapping = idx_higher_or_equal( - object.layers, idx_object_layer_overlapping, + object.layers(), idx_object_layer_overlapping, [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; }); // Collect all the object layers intersecting with this layer. Polygons polygons_trimming; size_t i = idx_object_layer_overlapping; - for (; i < object.layers.size(); ++ i) { - const Layer &object_layer = *object.layers[i]; + for (; i < object.layers().size(); ++ i) { + const Layer &object_layer = *object.layers()[i]; if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON) break; polygons_append(polygons_trimming, (Polygons)object_layer.slices); } - if (! this->m_slicing_params.soluble_interface) { + if (! m_slicing_params.soluble_interface) { // Collect all bottom surfaces, which will be extruded with a bridging flow. - for (; i < object.layers.size(); ++ i) { - const Layer &object_layer = *object.layers[i]; + for (; i < object.layers().size(); ++ i) { + const Layer &object_layer = *object.layers()[i]; bool some_region_overlaps = false; - for (LayerRegion* region : object_layer.regions) { - coordf_t nozzle_dmr = region->region()->nozzle_dmr_avg(*this->m_print_config); + for (LayerRegion* region : object_layer.regions()) { + coordf_t nozzle_dmr = region->region()->nozzle_dmr_avg(*m_print_config); if (object_layer.print_z - nozzle_dmr > support_layer.print_z + gap_extra_above - EPSILON) break; some_region_overlaps = true; @@ -1764,7 +1764,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf // Expand the bases of the support columns in the 1st layer. columns_base->polygons = diff( offset(columns_base->polygons, inflate_factor_1st_layer), - offset(m_object->layers.front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); + offset(m_object->layers().front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (contacts != nullptr) columns_base->polygons = diff(columns_base->polygons, interface_polygons); } @@ -1909,8 +1909,8 @@ struct MyLayerExtruded else *m_polygons_to_extrude = std::move(polygons); } - Polygons& polygons_to_extrude() { return (this->m_polygons_to_extrude == nullptr) ? layer->polygons : *this->m_polygons_to_extrude; } - const Polygons& polygons_to_extrude() const { return (this->m_polygons_to_extrude == nullptr) ? layer->polygons : *this->m_polygons_to_extrude; } + Polygons& polygons_to_extrude() { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; } + const Polygons& polygons_to_extrude() const { return (m_polygons_to_extrude == nullptr) ? layer->polygons : *m_polygons_to_extrude; } bool could_merge(const MyLayerExtruded &other) const { return ! this->empty() && ! other.empty() && @@ -1923,21 +1923,21 @@ struct MyLayerExtruded assert(this->could_merge(other)); // 1) Merge the rest polygons to extrude, if there are any. if (other.m_polygons_to_extrude != nullptr) { - if (this->m_polygons_to_extrude == nullptr) { + if (m_polygons_to_extrude == nullptr) { // This layer has no extrusions generated yet, if it has no m_polygons_to_extrude (its area to extrude was not reduced yet). assert(this->extrusions.empty()); - this->m_polygons_to_extrude = new Polygons(this->layer->polygons); + m_polygons_to_extrude = new Polygons(this->layer->polygons); } - Slic3r::polygons_append(*this->m_polygons_to_extrude, std::move(*other.m_polygons_to_extrude)); - *this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true); + Slic3r::polygons_append(*m_polygons_to_extrude, std::move(*other.m_polygons_to_extrude)); + *m_polygons_to_extrude = union_(*m_polygons_to_extrude, true); delete other.m_polygons_to_extrude; other.m_polygons_to_extrude = nullptr; - } else if (this->m_polygons_to_extrude != nullptr) { + } else if (m_polygons_to_extrude != nullptr) { assert(other.m_polygons_to_extrude == nullptr); // The other layer has no extrusions generated yet, if it has no m_polygons_to_extrude (its area to extrude was not reduced yet). assert(other.extrusions.empty()); - Slic3r::polygons_append(*this->m_polygons_to_extrude, other.layer->polygons); - *this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true); + Slic3r::polygons_append(*m_polygons_to_extrude, other.layer->polygons); + *m_polygons_to_extrude = union_(*m_polygons_to_extrude, true); } // 2) Merge the extrusions. this->extrusions.insert(this->extrusions.end(), other.extrusions.begin(), other.extrusions.end()); @@ -2535,7 +2535,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { assert(support_layer_id < raft_layers.size()); - SupportLayer &support_layer = *object.support_layers[support_layer_id]; + SupportLayer &support_layer = *object.support_layers()[support_layer_id]; assert(support_layer.support_fills.entities.empty()); MyLayer &raft_layer = *raft_layers[support_layer_id]; @@ -2631,9 +2631,9 @@ void PrintObjectSupportMaterial::generate_toolpaths( MyLayerExtruded interface_layer; std::vector<LayerCacheItem> overlaps; }; - std::vector<LayerCache> layer_caches(object.support_layers.size(), LayerCache()); + std::vector<LayerCache> layer_caches(object.support_layers().size(), LayerCache()); - tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers.size()), + tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers().size()), [this, &object, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &layer_caches, &loop_interface_processor, infill_pattern, &bbox_object, support_density, interface_density, interface_angle, &angles, link_max_length_factor, with_sheath] (const tbb::blocked_range<size_t>& range) { @@ -2648,7 +2648,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( filler_support->set_bounding_box(bbox_object); for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { - SupportLayer &support_layer = *object.support_layers[support_layer_id]; + SupportLayer &support_layer = *object.support_layers()[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; // Find polygons with the same print_z. @@ -2844,11 +2844,11 @@ void PrintObjectSupportMaterial::generate_toolpaths( }); // Now modulate the support layer height in parallel. - tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers.size()), + tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, object.support_layers().size()), [this, &object, &layer_caches] (const tbb::blocked_range<size_t>& range) { for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { - SupportLayer &support_layer = *object.support_layers[support_layer_id]; + SupportLayer &support_layer = *object.support_layers()[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id]; for (LayerCacheItem &layer_cache_item : layer_cache.overlaps) { modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping); diff --git a/xs/src/libslic3r/SupportMaterial.hpp b/xs/src/libslic3r/SupportMaterial.hpp index 968763446..e20d7c69f 100644 --- a/xs/src/libslic3r/SupportMaterial.hpp +++ b/xs/src/libslic3r/SupportMaterial.hpp @@ -208,7 +208,7 @@ private: // Produce the actual G-code. void generate_toolpaths( - const PrintObject &object, + const PrintObject &object, const MyLayersPtr &raft_layers, const MyLayersPtr &bottom_contacts, const MyLayersPtr &top_contacts, |