diff options
Diffstat (limited to 'src/libslic3r/Print.cpp')
-rw-r--r-- | src/libslic3r/Print.cpp | 167 |
1 files changed, 74 insertions, 93 deletions
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f89c316da..9a210abaa 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -13,6 +13,7 @@ #include "PrintExport.hpp" #include <algorithm> +#include <limits> #include <unordered_set> #include <boost/filesystem/path.hpp> #include <boost/log/trivial.hpp> @@ -292,18 +293,8 @@ std::vector<unsigned int> Print::object_extruders() const { std::vector<unsigned int> extruders; extruders.reserve(m_regions.size() * 3); - - for (const 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 || m_config.brim_width.value > 0) - extruders.emplace_back(region->config().perimeter_extruder - 1); - if (region->config().fill_density.value > 0) - extruders.emplace_back(region->config().infill_extruder - 1); - if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0) - extruders.emplace_back(region->config().solid_infill_extruder - 1); - } - + for (const PrintRegion *region : m_regions) + region->collect_object_printing_extruders(extruders); sort_remove_duplicates(extruders); return extruders; } @@ -371,37 +362,6 @@ double Print::max_allowed_layer_height() const return nozzle_diameter_max; } -static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders) -{ - if (opt.value > (int)num_extruders) - // assign the default extruder - opt.value = 1; -} - -static PrintObjectConfig object_config_from_model(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders) -{ - PrintObjectConfig config = default_object_config; - normalize_and_apply_config(config, object.config); - // Clamp invalid extruders to the default extruder (with index 1). - clamp_exturder_to_default(config.support_material_extruder, num_extruders); - clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders); - return config; -} - -static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders) -{ - PrintRegionConfig config = default_region_config; - normalize_and_apply_config(config, volume.get_object()->config); - normalize_and_apply_config(config, volume.config); - if (! volume.material_id().empty()) - normalize_and_apply_config(config, volume.material()->config); - // Clamp invalid extruders to the default extruder (with index 1). - clamp_exturder_to_default(config.infill_extruder, num_extruders); - clamp_exturder_to_default(config.perimeter_extruder, num_extruders); - clamp_exturder_to_default(config.solid_infill_extruder, num_extruders); - return config; -} - // Caller is responsible for supplying models whose objects don't collide // and have explicit instance positions. void Print::add_model_object(ModelObject* model_object, int idx) @@ -438,7 +398,7 @@ void Print::add_model_object(ModelObject* model_object, int idx) if (! volume->is_model_part() && ! volume->is_modifier()) continue; // Get the config applied to this volume. - PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, 99999); + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999); // Find an existing print region with the same config. size_t region_id = size_t(-1); for (size_t i = 0; i < m_regions.size(); ++ i) @@ -519,12 +479,12 @@ bool Print::apply_config(DynamicPrintConfig config) // If the new config for this volume differs from the other // volume configs currently associated to this region, it means // the region subdivision does not make sense anymore. - if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, 99999))) { + if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) { rearrange_regions = true; goto exit_for_rearrange_regions; } } else { - this_region_config = region_config_from_model_volume(m_default_region_config, volume, 99999); + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999); this_region_config_set = true; } for (const PrintRegionConfig &cfg : other_region_configs) { @@ -568,10 +528,6 @@ exit_for_rearrange_regions: invalidated = true; } - // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads. - for (PrintObject *object : m_objects) - object->update_layer_height_profile(); - return invalidated; } @@ -893,8 +849,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (model_parts_differ || modifiers_differ || model_object.origin_translation != model_object_new.origin_translation || model_object.layer_height_ranges != model_object_new.layer_height_ranges || - model_object.layer_height_profile != model_object_new.layer_height_profile || - model_object.layer_height_profile_valid != model_object_new.layer_height_profile_valid) { + model_object.layer_height_profile != model_object_new.layer_height_profile) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { @@ -920,7 +875,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (object_config_changed) model_object.config = model_object_new.config; if (! object_diff.empty() || object_config_changed) { - PrintObjectConfig new_config = object_config_from_model(m_default_object_config, model_object, num_extruders); + PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders); auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { t_config_option_keys diff = it->print_object->config().diff(new_config); @@ -962,7 +917,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co old.emplace_back(&(*it)); } // Generate a list of trafos and XY offsets for instances of a ModelObject - PrintObjectConfig config = object_config_from_model(m_default_object_config, *model_object, num_extruders); + PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders); std::vector<PrintInstances> new_print_instances = print_objects_from_model_object(*model_object); if (old.empty()) { // Simple case, just generate new instances. @@ -1053,11 +1008,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // If the new config for this volume differs from the other // volume configs currently associated to this region, it means // the region subdivision does not make sense anymore. - if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, num_extruders))) + if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders))) // Regions were split. Reset this print_object. goto print_object_end; } else { - this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders); + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders); for (size_t i = 0; i < region_id; ++i) { const PrintRegion ®ion_other = *m_regions[i]; if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config)) @@ -1108,7 +1063,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co int region_id = -1; if (&print_object == &print_object0) { // Get the config applied to this volume. - PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, num_extruders); + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders); // Find an existing print region with the same config. int idx_empty_slot = -1; for (int i = 0; i < (int)m_regions.size(); ++ i) { @@ -1144,13 +1099,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } } - // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads. - for (PrintObject *object : m_objects) - if (! object->layer_height_profile_valid) - // No need to call the next line as the step should already be invalidated above. - // update_apply_status(object->invalidate_step(posSlice)); - object->update_layer_height_profile(); - //FIXME there may be a race condition with the G-code export running at the background thread. this->update_object_placeholders(); @@ -1183,7 +1131,7 @@ std::string Print::validate() const // Check horizontal clearance. { Polygons convex_hulls_other; - for (PrintObject *object : m_objects) { + for (const PrintObject *object : m_objects) { // Get convex hull of all meshes assigned to this print object. Polygon convex_hull; { @@ -1244,15 +1192,24 @@ std::string Print::validate() const return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors."); if (! m_config.use_relative_e_distances) return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); - SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters(); - - const PrintObject* tallest_object = m_objects.front(); // let's find the tallest object - for (const auto* object : m_objects) - if (*(object->layer_height_profile.end()-2) > *(tallest_object->layer_height_profile.end()-2) ) - tallest_object = object; - for (PrintObject *object : m_objects) { - SlicingParameters slicing_params = object->slicing_parameters(); + if (m_objects.size() > 1) { + bool has_custom_layering = false; + std::vector<std::vector<coordf_t>> layer_height_profiles; + for (const PrintObject *object : m_objects) { + has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); + if (has_custom_layering) { + layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>()); + break; + } + } + SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters(); + size_t tallest_object_idx = 0; + if (has_custom_layering) + PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front()); + for (size_t i = 1; i < m_objects.size(); ++ i) { + const PrintObject *object = m_objects[i]; + const 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 L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths"); @@ -1264,42 +1221,54 @@ std::string Print::validate() const return L("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 L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); + if (has_custom_layering) { + PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]); + if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2)) + tallest_object_idx = i; + } + } - if ( m_config.variable_layer_height ) { // comparing layer height profiles + if (has_custom_layering) { + const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx]; + for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) { + const PrintObject *object = m_objects[idx_object]; + const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object]; bool failed = false; - // layer_height_profile should be set by Print::apply(). - if (tallest_object->layer_height_profile.size() >= object->layer_height_profile.size() ) { + if (layer_height_profile_tallest.size() >= layer_height_profile.size()) { int i = 0; - while ( i < object->layer_height_profile.size() && i < tallest_object->layer_height_profile.size()) { - if (std::abs(tallest_object->layer_height_profile[i] - object->layer_height_profile[i])) { + while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) { + if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) { failed = true; break; } - ++i; - if (i == object->layer_height_profile.size()-2) // this element contains this objects max z - if (tallest_object->layer_height_profile[i] > object->layer_height_profile[i]) // the difference does not matter in this case - ++i; + ++ i; + if (i == layer_height_profile.size() - 2) // this element contains this objects max z + if (layer_height_profile_tallest[i] > layer_height_profile[i]) // the difference does not matter in this case + ++ i; } - } - else + } else failed = true; - if (failed) return L("The Wipe tower is only supported if all objects have the same layer height profile"); } } } + } { // find the smallest nozzle diameter std::vector<unsigned int> extruders = this->extruders(); if (extruders.empty()) return L("The supplied settings will cause an empty print."); - - std::vector<double> nozzle_diameters; - for (unsigned int extruder_id : extruders) - 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()); + + // Find the smallest used nozzle diameter and the number of unique nozzle diameters. + double min_nozzle_diameter = std::numeric_limits<double>::max(); + double max_nozzle_diameter = 0; + for (unsigned int extruder_id : extruders) { + double dmr = m_config.nozzle_diameter.get_at(extruder_id); + min_nozzle_diameter = std::min(min_nozzle_diameter, dmr); + max_nozzle_diameter = std::max(max_nozzle_diameter, dmr); + } #if 0 // We currently allow one to assign extruders with a higher index than the number @@ -1311,16 +1280,28 @@ std::string Print::validate() const #endif 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)) { + if (object->config().raft_layers > 0 || object->config().support_material.value) { + if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { // 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. - if (nozzle_diameters.size() > 1) return L("Printing with multiple extruders of differing nozzle diameters. " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " "all nozzles have to be of the same diameter."); } + if (this->has_wipe_tower()) { + if (object->config().support_material_contact_distance == 0) { + // Soluble interface + if (object->config().support_material_contact_distance == 0 && ! object->config().support_material_synchronize_layers) + return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); + } else { + // Non-soluble interface + if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0) + return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " + "(both support_material_extruder and support_material_interface_extruder need to be set to 0)."); + } + } + } // validate first_layer_height double first_layer_height = object->config().get_abs_value(L("first_layer_height")); |