diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 75952e4c2..fbdef29b9 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -126,7 +126,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) Polygons surfaces_polygons = to_polygons(surfaces); Polygons collapsed = diff( surfaces_polygons, - offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2), + offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2), true); Polygons to_subtract; to_subtract.reserve(collapsed.size() + number_polygons(surfaces)); @@ -137,7 +137,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) surfaces_append( surfaces, intersection_ex( - offset(collapsed, distance_between_surfaces), + offset(collapsed, (float)distance_between_surfaces), to_subtract, true), stInternalSolid); @@ -219,14 +219,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) f->z = layerm.layer()->print_z; 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); + f->link_max_length = (coord_t)scale_(link_max_length); // Used by the concentric infill pattern to clip the loops to create extrusion paths. - f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER; + f->loop_clipping = coord_t(scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); // f->layer_height = h; // apply half spacing using this flow's own spacing and generate infill FillParams params; - params.density = 0.01 * density; + params.density = float(0.01 * density); // params.dont_adjust = true; params.dont_adjust = false; Polylines polylines = f->fill_surface(&surface, params); @@ -240,7 +240,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // so we can safely ignore the slight variation that might have // been applied to $f->flow_spacing } else { - flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow()); + flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow()); } // Save into layer. diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 002e125c7..45b8fe52f 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -2031,7 +2031,7 @@ namespace Slic3r { return false; } - vertices_count += its.vertices.size(); + vertices_count += (int)its.vertices.size(); const Transform3d& matrix = volume->get_matrix(); @@ -2061,7 +2061,7 @@ namespace Slic3r { // updates triangle offsets volume_it->second.first_triangle_id = triangles_count; - triangles_count += its.indices.size(); + triangles_count += (int)its.indices.size(); volume_it->second.last_triangle_id = triangles_count - 1; for (size_t i = 0; i < its.indices.size(); ++ i) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 4f0a402ea..90a538731 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -192,7 +192,7 @@ struct AMFParserContext }; // Version of the amf file - unsigned int m_version; + unsigned int m_version; // Current Expat XML parser instance. XML_Parser m_parser; // Model to receive objects extracted from an AMF file. @@ -616,7 +616,7 @@ void AMFParserContext::endElement(const char * /* name */) if (end != nullptr) *end = 0; - point(coord_idx) = atof(p); + point(coord_idx) = float(atof(p)); if (++coord_idx == 5) { m_object->sla_support_points.push_back(sla::SupportPoint(point)); coord_idx = 0; @@ -628,8 +628,8 @@ void AMFParserContext::endElement(const char * /* name */) m_object->sla_points_status = sla::PointsStatus::UserModified; } else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE && - m_object && strcmp(opt_key, "layer_height_ranges") == 0) { - // Parse object's layer_height_ranges, a semicolon separated doubles. + m_object && strcmp(opt_key, "layer_height_range") == 0) { + // Parse object's layer_height_range, a semicolon separated doubles. char* p = const_cast(m_value[1].c_str()); char* end = strchr(p, ';'); *end = 0; @@ -946,7 +946,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) for (auto range : config_ranges) { stream << " \n"; - stream << " "; + stream << " "; stream << range.first.first << ";" << range.first.second << "\n"; for (const std::string& key : range.second.keys()) @@ -994,7 +994,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; stream << " \n"; } - num_vertices += its.vertices.size(); + num_vertices += (int)its.vertices.size(); } stream << " \n"; for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 1f9efbc56..90725f31e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -593,7 +593,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->config = rhs.config; this->sla_support_points = rhs.sla_support_points; this->sla_points_status = rhs.sla_points_status; - this->layer_height_ranges = rhs.layer_height_ranges; this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment this->layer_height_profile = rhs.layer_height_profile; this->origin_translation = rhs.origin_translation; @@ -630,7 +629,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->config = std::move(rhs.config); this->sla_support_points = std::move(rhs.sla_support_points); this->sla_points_status = std::move(rhs.sla_points_status); - this->layer_height_ranges = std::move(rhs.layer_height_ranges); this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment this->layer_height_profile = std::move(rhs.layer_height_profile); this->origin_translation = std::move(rhs.origin_translation); @@ -1809,7 +1807,7 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) return true; - ++i_old; + ++ i_old; ++ i_new; } for (; i_old < model_object_old.volumes.size(); ++ i_old) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 22d43dbc7..c1850df98 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -179,10 +179,8 @@ public: ModelVolumePtrs volumes; // Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings. DynamicPrintConfig config; - // Variation of a layer thickness for spans of Z coordinates. - t_layer_height_ranges layer_height_ranges; - // Variation of a layer thickness for spans of Z coordinates. - t_layer_config_ranges layer_config_ranges; + // Variation of a layer thickness for spans of Z coordinates + optional parameter overrides. + t_layer_config_ranges layer_config_ranges; // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // The pairs of are packed into a 1D array. std::vector layer_height_profile; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ed4af3995..5e4f25334 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -41,36 +41,6 @@ void Print::clear() m_model.clear_objects(); } -// Only used by the Perl test cases. -void Print::reload_object(size_t /* idx */) -{ - ModelObjectPtrs model_objects; - { - tbb::mutex::scoped_lock lock(this->state_mutex()); - // The following call should stop background processing if it is running. - this->invalidate_all_steps(); - /* 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() - For now we just re-add all objects since we haven't implemented this incremental logic yet. - This should also check whether object volumes (parts) have changed. */ - // collect all current model objects - model_objects.reserve(m_objects.size()); - for (PrintObject *object : m_objects) - model_objects.push_back(object->model_object()); - // remove our print objects - for (PrintObject *object : m_objects) - delete object; - m_objects.clear(); - for (PrintRegion *region : m_regions) - delete region; - m_regions.clear(); - } - // re-add model objects - for (ModelObject *mo : model_objects) - this->add_model_object(mo); -} - PrintRegion* Print::add_region() { m_regions.emplace_back(new PrintRegion(this)); @@ -335,7 +305,7 @@ unsigned int Print::num_object_instances() const { unsigned int instances = 0; for (const PrintObject *print_object : m_objects) - instances += print_object->copies().size(); + instances += (unsigned int)print_object->copies().size(); return instances; } @@ -360,7 +330,7 @@ double Print::max_allowed_layer_height() const // 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) +void Print::add_model_object_perl_tests_only(ModelObject* model_object, int idx) { tbb::mutex::scoped_lock lock(this->state_mutex()); // Add a copy of this ModelObject to this Print. @@ -389,26 +359,26 @@ void Print::add_model_object(ModelObject* model_object, int idx) object->set_trafo(trafo); } - size_t volume_id = 0; + int volume_id = 0; for (const ModelVolume *volume : model_object->volumes) { if (! volume->is_model_part() && ! volume->is_modifier()) continue; // Get the config applied to this volume. - PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999); + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, nullptr, *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) + int region_id = -1; + for (int i = 0; i < (int)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 = m_regions.size(); + if (region_id == -1) { + region_id = (int)m_regions.size(); this->add_region(config); } // Assign volume to a region. - object->add_region_volume(region_id, volume_id); + object->add_region_volume((unsigned int)region_id, volume_id, t_layer_height_range(0, DBL_MAX)); ++ volume_id; } @@ -489,18 +459,18 @@ bool Print::apply_config_perl_tests_only(DynamicPrintConfig config) bool this_region_config_set = false; 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]; + for (const std::pair &volume_and_range : object->region_volumes[region_id]) { + const ModelVolume &volume = *object->model_object()->volumes[volume_and_range.second]; if (this_region_config_set) { // 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(PrintObject::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, nullptr, volume, 99999))) { rearrange_regions = true; goto exit_for_rearrange_regions; } } else { - this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999); + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, nullptr, volume, 99999); this_region_config_set = true; } for (const PrintRegionConfig &cfg : other_region_configs) { @@ -540,7 +510,7 @@ exit_for_rearrange_regions: model_objects.push_back(object->model_object()); this->clear(); for (ModelObject *mo : model_objects) - this->add_model_object(mo); + this->add_model_object_perl_tests_only(mo); invalidated = true; } @@ -620,6 +590,20 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, } } +static inline void layer_height_ranges_copy_configs(t_layer_config_ranges &lr_dst, const t_layer_config_ranges &lr_src) +{ + assert(lr_dst.size() == lr_src.size()); + auto it_src = lr_src.cbegin(); + for (auto &kvp_dst : lr_dst) { + const auto &kvp_src = *it_src ++; + assert(std::abs(kvp_dst.first.first - kvp_src.first.first ) <= EPSILON); + assert(std::abs(kvp_dst.first.second - kvp_src.first.second) <= EPSILON); + // Layer heights are allowed do differ in case the layer height table is being overriden by the smooth profile. + // assert(std::abs(kvp_dst.second.option("layer_height")->getFloat() - kvp_src.second.option("layer_height")->getFloat()) <= EPSILON); + kvp_dst.second = kvp_src.second; + } +} + static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs) { typedef Transform3d::Scalar T; @@ -674,6 +658,23 @@ static std::vector print_objects_from_model_object(const ModelOb return std::vector(trafos.begin(), trafos.end()); } +// Compare just the layer ranges and their layer heights, not the associated configs. +// Ignore the layer heights if check_layer_heights is false. +bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height) +{ + if (lr1.size() != lr2.size()) + return false; + auto it2 = lr2.begin(); + for (const auto &kvp1 : lr1) { + const auto &kvp2 = *it2 ++; + if (std::abs(kvp1.first.first - kvp2.first.first ) > EPSILON || + std::abs(kvp1.first.second - kvp2.first.second) > EPSILON || + (check_layer_height && std::abs(kvp1.second.option("layer_height")->getFloat() - kvp2.second.option("layer_height")->getFloat()) > EPSILON)) + return false; + } + return true; +} + Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in) { #ifdef _DEBUG @@ -724,6 +725,50 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // Handle changes to regions config defaults m_default_region_config.apply_only(config, region_diff, true); + class LayerRanges + { + public: + LayerRanges() {} + // Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs. + void assign(const t_layer_config_ranges &in) { + m_ranges.clear(); + m_ranges.reserve(in.size()); + // Input ranges are sorted lexicographically. First range trims the other ranges. + coordf_t last_z = 0; + for (const std::pair &range : in) { +// for (auto &range : in) { + if (range.first.second > last_z) { + coordf_t min_z = std::max(range.first.first, 0.); + if (min_z > last_z + EPSILON) { + m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr); + last_z = min_z; + } + if (range.first.second > last_z + EPSILON) { + const DynamicPrintConfig* cfg = &range.second; + m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg); + last_z = range.first.second; + } + } + } + if (m_ranges.empty()) + m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr); + else if (m_ranges.back().second == nullptr) + m_ranges.back().first.second = DBL_MAX; + else + m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr); + } + const DynamicPrintConfig* config(const t_layer_height_range &range) const { + auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr)); + assert(it != m_ranges.end()); + assert(it == m_ranges.end() || std::abs(it->first.first - range.first ) < EPSILON); + assert(it == m_ranges.end() || std::abs(it->first.second - range.second) < EPSILON); + return (it == m_ranges.end()) ? nullptr : it->second; + } + auto begin() const { return m_ranges.cbegin(); } + auto end() const { return m_ranges.cend(); } + private: + std::vector> m_ranges; + }; struct ModelObjectStatus { enum Status { Unknown, @@ -733,8 +778,9 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co Deleted, }; ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {} - ModelID id; - Status status; + ModelID id; + Status status; + LayerRanges layer_ranges; // Search by id. bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; } }; @@ -861,22 +907,23 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); assert(it_status != model_object_status.end()); assert(it_status->status != ModelObjectStatus::Deleted); + const ModelObject& model_object_new = *model.objects[idx_model_object]; + const_cast(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges); if (it_status->status == ModelObjectStatus::New) // PrintObject instances will be added in the next loop. continue; // Update the ModelObject instance, possibly invalidate the linked PrintObjects. assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); - const ModelObject &model_object_new = *model.objects[idx_model_object]; // Check whether a model part volume was added or removed, their transformations or order changed. + // Only volume IDs, volume types and their order are checked, configuration and other parameters are NOT checked. bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER); bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER); bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER); 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_config_ranges != model_object_new.layer_config_ranges || // #ys_FIXME_experiment - model_object.layer_height_profile != model_object_new.layer_height_profile) { + model_object.layer_height_profile != model_object_new.layer_height_profile || + ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty())) { // 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) { @@ -916,7 +963,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co //FIXME What to do with m_material_id? model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART); model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER); - // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. + layer_height_ranges_copy_configs(model_object.layer_config_ranges /* dst */, model_object_new.layer_config_ranges /* src */); + // Copy the ModelObject name, input_file and instances. The instances will be compared against PrintObject instances in the next step. model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; model_object.clear_instances(); @@ -1028,19 +1076,27 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co PrintRegionConfig this_region_config; bool this_region_config_set = false; for (PrintObject *print_object : m_objects) { + const LayerRanges *layer_ranges; + { + auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id())); + assert(it_status != model_object_status.end()); + assert(it_status->status != ModelObjectStatus::Deleted); + layer_ranges = &it_status->layer_ranges; + } if (region_id < print_object->region_volumes.size()) { - for (int volume_id : print_object->region_volumes[region_id]) { - const ModelVolume &volume = *print_object->model_object()->volumes[volume_id]; + for (const std::pair &volume_and_range : print_object->region_volumes[region_id]) { + const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second]; + const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first); if (this_region_config_set) { // 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(PrintObject::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, layer_range_config, volume, num_extruders))) // Regions were split. Reset this print_object. goto print_object_end; } else { - 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) { + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_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)) // Regions were merged. Reset this print_object. @@ -1055,7 +1111,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(print_object->invalidate_all_steps()); // Decrease the references to regions from this volume. int ireg = 0; - for (const std::vector &volumes : print_object->region_volumes) { + for (const std::vector> &volumes : print_object->region_volumes) { if (! volumes.empty()) -- m_regions[ireg]->m_refcnt; ++ ireg; @@ -1077,52 +1133,65 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) { PrintObject &print_object0 = *m_objects[idx_print_object]; const ModelObject &model_object = *print_object0.model_object(); - std::vector map_volume_to_region(model_object.volumes.size(), -1); + const LayerRanges *layer_ranges; + { + auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); + assert(it_status != model_object_status.end()); + assert(it_status->status != ModelObjectStatus::Deleted); + layer_ranges = &it_status->layer_ranges; + } + std::vector regions_in_object; + regions_in_object.reserve(64); for (size_t i = idx_print_object; i < m_objects.size() && m_objects[i]->model_object() == &model_object; ++ i) { PrintObject &print_object = *m_objects[i]; bool fresh = print_object.region_volumes.empty(); unsigned int volume_id = 0; + unsigned int idx_region_in_object = 0; for (const ModelVolume *volume : model_object.volumes) { if (! volume->is_model_part() && ! volume->is_modifier()) { ++ volume_id; continue; } - int region_id = -1; - if (&print_object == &print_object0) { - // Get the config applied to this volume. - 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) { - if (m_regions[i]->m_refcnt == 0) { - if (idx_empty_slot == -1) - idx_empty_slot = i; - } else if (config.equals(m_regions[i]->config())) { - region_id = i; - break; + // Filter the layer ranges, so they do not overlap and they contain at least a single layer. + // Now insert a volume with a layer range to its own region. + for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) { + int region_id = -1; + if (&print_object == &print_object0) { + // Get the config applied to this volume. + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *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) { + if (m_regions[i]->m_refcnt == 0) { + if (idx_empty_slot == -1) + idx_empty_slot = i; + } else 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 == -1) { + if (idx_empty_slot == -1) { + region_id = (int)m_regions.size(); + this->add_region(config); + } else { + region_id = idx_empty_slot; + m_regions[region_id]->set_config(std::move(config)); + } } - } - // If no region exists with the same config, create a new one. - if (region_id == -1) { - if (idx_empty_slot == -1) { - region_id = (int)m_regions.size(); - this->add_region(config); - } else { - region_id = idx_empty_slot; - m_regions[region_id]->set_config(std::move(config)); - } - } - map_volume_to_region[volume_id] = region_id; - } else - region_id = map_volume_to_region[volume_id]; - // Assign volume to a region. - if (fresh) { - if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty()) - ++ m_regions[region_id]->m_refcnt; - print_object.add_region_volume(region_id, volume_id); - } - ++ volume_id; - } + regions_in_object.emplace_back(region_id); + } else + region_id = regions_in_object[idx_region_in_object ++]; + // Assign volume to a region. + if (fresh) { + if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty()) + ++ m_regions[region_id]->m_refcnt; + print_object.add_region_volume(region_id, volume_id, it_range->first); + } + } + ++ volume_id; + } } } @@ -1176,7 +1245,7 @@ std::string Print::validate() const Polygon convex_hull0 = offset( print_object->model_object()->convex_hull_2d( Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())), - scale_(m_config.extruder_clearance_radius.value) / 2., jtRound, scale_(0.1)).front(); + float(scale_(0.5 * m_config.extruder_clearance_radius.value)), jtRound, float(scale_(0.1))).front(); // Now we check that no instance of convex_hull intersects any of the previously checked object instances. for (const Point © : print_object->m_copies) { Polygon convex_hull = convex_hull0; @@ -1228,7 +1297,6 @@ std::string Print::validate() const bool has_custom_layering = false; std::vector> 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(); has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment if (has_custom_layering) { layer_height_profiles.assign(m_objects.size(), std::vector()); @@ -1437,9 +1505,9 @@ Flow Print::brim_flow() const generation as well. */ return Flow::new_from_config_width( frPerimeter, - width, - m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1), - this->skirt_first_layer_height(), + width, + (float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1), + (float)this->skirt_first_layer_height(), 0 ); } @@ -1459,9 +1527,9 @@ Flow Print::skirt_flow() const generation as well. */ return Flow::new_from_config_width( frPerimeter, - width, - m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1), - this->skirt_first_layer_height(), + width, + (float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1), + (float)this->skirt_first_layer_height(), 0 ); } @@ -1636,20 +1704,20 @@ void Print::_make_skirt() // 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. - Flow brim_flow = this->brim_flow(); + Flow brim_flow = this->brim_flow(); double actual_brim_width = brim_flow.spacing() * floor(m_config.brim_width.value / brim_flow.spacing()); - coord_t distance = scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.); + auto distance = float(scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.)); // 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 extruded_length(extruders.size(), 0.); for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) { this->throw_if_canceled(); // Offset the skirt outside. - distance += coord_t(scale_(spacing)); + distance += float(scale_(spacing)); // Generate the skirt centerline. Polygon loop; { - Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, scale_(0.1)); + Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, float(scale_(0.1))); Geometry::simplify_polygons(loops, scale_(0.05), &loops); if (loops.empty()) break; @@ -1660,9 +1728,9 @@ void Print::_make_skirt() eloop.paths.emplace_back(ExtrusionPath( ExtrusionPath( erSkirt, - mm3_per_mm, // this will be overridden at G-code export time + (float)mm3_per_mm, // this will be overridden at G-code export time flow.width, - first_layer_height // this will be overridden at G-code export time + (float)first_layer_height // this will be overridden at G-code export time ))); eloop.paths.back().polyline = loop.split_at_first_point(); m_skirt.append(eloop); @@ -1788,7 +1856,7 @@ void Print::_make_wipe_tower() // Insert the new support layer. 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. - 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 = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height); ++ it_layer; } } @@ -1815,19 +1883,19 @@ void Print::_make_wipe_tower() 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), - m_config.filament_loading_speed.get_at(i), - m_config.filament_loading_speed_start.get_at(i), - m_config.filament_unloading_speed.get_at(i), - m_config.filament_unloading_speed_start.get_at(i), - m_config.filament_toolchange_delay.get_at(i), + (float)m_config.filament_loading_speed.get_at(i), + (float)m_config.filament_loading_speed_start.get_at(i), + (float)m_config.filament_unloading_speed.get_at(i), + (float)m_config.filament_unloading_speed_start.get_at(i), + (float)m_config.filament_toolchange_delay.get_at(i), m_config.filament_cooling_moves.get_at(i), - m_config.filament_cooling_initial_speed.get_at(i), - m_config.filament_cooling_final_speed.get_at(i), + (float)m_config.filament_cooling_initial_speed.get_at(i), + (float)m_config.filament_cooling_final_speed.get_at(i), m_config.filament_ramming_parameters.get_at(i), - m_config.nozzle_diameter.get_at(i)); + (float)m_config.nozzle_diameter.get_at(i)); m_wipe_tower_data.priming = Slic3r::make_unique( - wipe_tower.prime(this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); + wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); // Lets go through the wipe tower layers and determine pairs of extruder changes for each // to pass to wipe_tower (so that it can use it for planning the layout of the tower) @@ -1836,21 +1904,21 @@ void Print::_make_wipe_tower() for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); - wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false); + wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false); for (const auto extruder_id : layer_tools.extruders) { if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange // Not all of that can be used for infill purging: - volume_to_wipe -= m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + volume_to_wipe -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); // try to assign some infills/objects for the wiping: volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_wipe); // add back the minimal amount toforce on the wipe tower: - volume_to_wipe += m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + volume_to_wipe += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); // request a toolchange at the wipe tower with at least volume_to_wipe purging amount - wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, + wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 53d6d692d..c024a3ad2 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -80,8 +80,8 @@ private: // Prevents erroneous use by other classes. typedef PrintObjectBaseWithState Inherited; public: - // vector of (vectors of volume ids), indexed by region_id - std::vector> region_volumes; + // vector of (layer height ranges and vectors of volume ids), indexed by region_id + std::vector>> region_volumes; // this is set to true when LayerRegion->slices is split in top/internal/bottom // so that next call to make_perimeters() performs a union() before computing loops @@ -99,10 +99,10 @@ public: BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); } // adds region_id, too, if necessary - void add_region_volume(unsigned int region_id, int volume_id) { + void add_region_volume(unsigned int region_id, int volume_id, const t_layer_height_range &layer_range) { if (region_id >= region_volumes.size()) region_volumes.resize(region_id + 1); - region_volumes[region_id].emplace_back(volume_id); + region_volumes[region_id].emplace_back(layer_range, volume_id); } // This is the *total* layer count (including support layers) // this value is not supposed to be compared with Layer::id @@ -141,8 +141,9 @@ public: void slice(); // Helpers to slice support enforcer / blocker meshes by the support generator. - std::vector slice_support_enforcers() const; - std::vector slice_support_blockers() const; + std::vector slice_support_volumes(const ModelVolumeType &model_volume_type) const; + std::vector slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); } + std::vector slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); } protected: // to be called from Print only. @@ -165,7 +166,7 @@ protected: void update_slicing_parameters(); static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders); - static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders); + static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders); private: void make_perimeters(); @@ -201,9 +202,11 @@ private: LayerPtrs m_layers; SupportLayerPtrs m_support_layers; - std::vector _slice_region(size_t region_id, const std::vector &z, bool modifier); - std::vector _slice_volumes(const std::vector &z, const std::vector &volumes) const; - std::vector _slice_volume(const std::vector &z, const ModelVolume &volume) const; + std::vector slice_region(size_t region_id, const std::vector &z) const; + std::vector slice_modifiers(size_t region_id, const std::vector &z) const; + std::vector slice_volumes(const std::vector &z, const std::vector &volumes) const; + std::vector slice_volume(const std::vector &z, const ModelVolume &volume) const; + std::vector slice_volume(const std::vector &z, const std::vector &ranges, const ModelVolume &volume) const; }; struct WipeTowerData @@ -292,8 +295,7 @@ public: ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; // The following three methods are used by the Perl tests only. Get rid of them! - void reload_object(size_t idx); - void add_model_object(ModelObject* model_object, int idx = -1); + void add_model_object_perl_tests_only(ModelObject* model_object, int idx = -1); bool apply_config_perl_tests_only(DynamicPrintConfig config); void process() override; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 3add19021..f7d6f891d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -49,7 +49,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta { // Translate meshes so that our toolpath generation algorithms work with smaller // XY coordinates; this translation is an optimization and not strictly required. - // A cloned mesh will be aligned to 0 before slicing in _slice_region() since we + // A cloned mesh will be aligned to 0 before slicing in slice_region() since we // don't assume it's already aligned and we don't alter the original position in model. // We store the XY translation so that we can place copies correctly in the output G-code // (copies are expressed in G-code coordinates and this translation is not publicly exposed). @@ -590,7 +590,12 @@ bool PrintObject::invalidate_step(PrintObjectStep step) bool PrintObject::invalidate_all_steps() { - return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps(); + // First call the "invalidate" functions, which may cancel background processing. + bool result = Inherited::invalidate_all_steps() | m_print->invalidate_all_steps(); + // Then reset some of the depending values. + this->m_slicing_params.valid = false; + this->region_volumes.clear(); + return result; } bool PrintObject::has_support_material() const @@ -1354,10 +1359,12 @@ PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObject return config; } -PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders) +PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders) { PrintRegionConfig config = default_region_config; normalize_and_apply_config(config, volume.get_object()->config); + if (layer_range_config != nullptr) + normalize_and_apply_config(config, *layer_range_config); normalize_and_apply_config(config, volume.config); if (! volume.material_id().empty()) normalize_and_apply_config(config, volume.material()->config); @@ -1375,28 +1382,37 @@ void PrintObject::update_slicing_parameters() this->print()->config(), m_config, unscale(this->size(2)), this->object_extruders()); } -SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z) +SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z) { - PrintConfig print_config; - PrintObjectConfig object_config; - PrintRegionConfig default_region_config; - print_config .apply(full_config, true); - object_config.apply(full_config, true); - default_region_config.apply(full_config, true); - size_t num_extruders = print_config.nozzle_diameter.size(); - object_config = object_config_from_model_object(object_config, model_object, num_extruders); + PrintConfig print_config; + PrintObjectConfig object_config; + PrintRegionConfig default_region_config; + print_config.apply(full_config, true); + object_config.apply(full_config, true); + default_region_config.apply(full_config, true); + size_t num_extruders = print_config.nozzle_diameter.size(); + object_config = object_config_from_model_object(object_config, model_object, num_extruders); - std::vector object_extruders; - for (const ModelVolume *model_volume : model_object.volumes) - if (model_volume->is_model_part()) - PrintRegion::collect_object_printing_extruders( - print_config, - region_config_from_model_volume(default_region_config, *model_volume, num_extruders), - object_extruders); + std::vector object_extruders; + for (const ModelVolume* model_volume : model_object.volumes) + if (model_volume->is_model_part()) { + PrintRegion::collect_object_printing_extruders( + print_config, + region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders), + object_extruders); + for (const std::pair &range_and_config : model_object.layer_config_ranges) + if (range_and_config.second.has("perimeter_extruder") || + range_and_config.second.has("infill_extruder") || + range_and_config.second.has("solid_infill_extruder")) + PrintRegion::collect_object_printing_extruders( + print_config, + region_config_from_model_volume(default_region_config, &range_and_config.second, *model_volume, num_extruders), + object_extruders); + } sort_remove_duplicates(object_extruders); if (object_max_z <= 0.f) - object_max_z = model_object.raw_bounding_box().size().z(); + object_max_z = (float)model_object.raw_bounding_box().size().z(); return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders); } @@ -1430,13 +1446,12 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c layer_height_profile.clear(); if (layer_height_profile.empty()) { - if (0) + if (0) // if (this->layer_height_profile.empty()) - layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes); + layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); else -// layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges); - layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment - updated = true; + layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment + updated = true; } return updated; } @@ -1490,22 +1505,28 @@ void PrintObject::_slice(const std::vector &layer_height_profile) } // Count model parts and modifier meshes, check whether the model parts are of the same region. - int single_volume_region = -2; // not set yet + int all_volumes_single_region = -2; // not set yet + bool has_z_ranges = false; size_t num_volumes = 0; size_t num_modifiers = 0; - std::vector map_volume_to_region(this->model_object()->volumes.size()); for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) { - for (int volume_id : this->region_volumes[region_id]) { + int last_volume_id = -1; + for (const std::pair &volume_and_range : this->region_volumes[region_id]) { + const int volume_id = volume_and_range.second; const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; if (model_volume->is_model_part()) { - map_volume_to_region[volume_id] = region_id; - if (single_volume_region == -2) - // first model volume met - single_volume_region = region_id; - else if (single_volume_region != region_id) - // multiple volumes met and they are not equal - single_volume_region = -1; - ++ num_volumes; + if (last_volume_id == volume_id) { + has_z_ranges = true; + } else { + last_volume_id = volume_id; + if (all_volumes_single_region == -2) + // first model volume met + all_volumes_single_region = region_id; + else if (all_volumes_single_region != region_id) + // multiple volumes met and they are not equal + all_volumes_single_region = -1; + ++ num_volumes; + } } else if (model_volume->is_modifier()) ++ num_modifiers; } @@ -1515,13 +1536,13 @@ void PrintObject::_slice(const std::vector &layer_height_profile) // Slice all non-modifier volumes. bool clipped = false; bool upscaled = false; - if (! m_config.clip_multipart_objects.value || single_volume_region >= 0) { + if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) { // Cheap path: Slice regions without mutual clipping. // The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region. for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id; // slicing in parallel - std::vector expolygons_by_layer = this->_slice_region(region_id, slice_zs, false); + std::vector expolygons_by_layer = this->slice_region(region_id, slice_zs); 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) @@ -1542,15 +1563,29 @@ void PrintObject::_slice(const std::vector &layer_height_profile) }; std::vector sliced_volumes; sliced_volumes.reserve(num_volumes); - for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) - for (int volume_id : this->region_volumes[region_id]) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { + const std::vector> &volumes_and_ranges = this->region_volumes[region_id]; + for (size_t i = 0; i < volumes_and_ranges.size(); ) { + int volume_id = volumes_and_ranges[i].second; const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; if (model_volume->is_model_part()) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id; + // Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume. + std::vector ranges; + ranges.emplace_back(volumes_and_ranges[i].first); + size_t j = i + 1; + for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) + if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON) + ranges.back().second = volumes_and_ranges[j].first.second; + else + ranges.emplace_back(volumes_and_ranges[j].first); // slicing in parallel - sliced_volumes.emplace_back(volume_id, map_volume_to_region[volume_id], this->_slice_volume(slice_zs, *model_volume)); - } + sliced_volumes.emplace_back(volume_id, (int)region_id, this->slice_volume(slice_zs, ranges, *model_volume)); + i = j; + } else + ++ i; } + } // Second clip the volumes in the order they are presented at the user interface. BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start"; tbb::parallel_for( @@ -1604,7 +1639,7 @@ void PrintObject::_slice(const std::vector &layer_height_profile) for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id; // slicing in parallel - std::vector expolygons_by_layer = this->_slice_region(region_id, slice_zs, true); + std::vector expolygons_by_layer = this->slice_modifiers(region_id, slice_zs); m_print->throw_if_canceled(); if (expolygons_by_layer.empty()) continue; @@ -1620,7 +1655,7 @@ void PrintObject::_slice(const std::vector &layer_height_profile) Layer *layer = m_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) + if (layerm == nullptr || other_layerm == nullptr || other_layerm->slices.empty() || expolygons_by_layer[layer_id].empty()) continue; Polygons other_slices = to_polygons(other_layerm->slices); ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id])); @@ -1753,46 +1788,127 @@ end: BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } -std::vector PrintObject::_slice_region(size_t region_id, const std::vector &z, bool modifier) +// To be used only if there are no layer span specific configurations applied, which would lead to z ranges being generated for this region. +std::vector PrintObject::slice_region(size_t region_id, const std::vector &z) const { - std::vector volumes; + std::vector volumes; if (region_id < this->region_volumes.size()) { - for (int volume_id : this->region_volumes[region_id]) { - const ModelVolume *volume = this->model_object()->volumes[volume_id]; - if (modifier ? volume->is_modifier() : volume->is_model_part()) - volumes.emplace_back(volume); - } + for (const std::pair &volume_and_range : this->region_volumes[region_id]) { + const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second]; + if (volume->is_model_part()) + volumes.emplace_back(volume); + } } - return this->_slice_volumes(z, volumes); + return this->slice_volumes(z, volumes); } -std::vector PrintObject::slice_support_enforcers() const +// Z ranges are not applicable to modifier meshes, therefore a sinle volume will be found in volume_and_range at most once. +std::vector PrintObject::slice_modifiers(size_t region_id, const std::vector &slice_zs) const +{ + std::vector out; + if (region_id < this->region_volumes.size()) + { + std::vector> volume_ranges; + const std::vector> &volumes_and_ranges = this->region_volumes[region_id]; + volume_ranges.reserve(volumes_and_ranges.size()); + for (size_t i = 0; i < volumes_and_ranges.size(); ) { + int volume_id = volumes_and_ranges[i].second; + const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; + if (model_volume->is_modifier()) { + std::vector ranges; + ranges.emplace_back(volumes_and_ranges[i].first); + size_t j = i + 1; + for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) { + if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON) + ranges.back().second = volumes_and_ranges[j].first.second; + else + ranges.emplace_back(volumes_and_ranges[j].first); + } + volume_ranges.emplace_back(std::move(ranges)); + i = j; + } else + ++ i; + } + + if (! volume_ranges.empty()) + { + bool equal_ranges = true; + for (size_t i = 1; i < volume_ranges.size(); ++ i) { + assert(! volume_ranges[i].empty()); + if (volume_ranges.front() != volume_ranges[i]) { + equal_ranges = false; + break; + } + } + + if (equal_ranges && volume_ranges.front().size() == 1 && volume_ranges.front().front() == t_layer_height_range(0, DBL_MAX)) { + // No modifier in this region was split to layer spans. + std::vector volumes; + for (const std::pair &volume_and_range : this->region_volumes[region_id]) { + const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second]; + if (volume->is_modifier()) + volumes.emplace_back(volume); + } + out = this->slice_volumes(slice_zs, volumes); + } else { + // Some modifier in this region was split to layer spans. + std::vector merge; + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { + const std::vector> &volumes_and_ranges = this->region_volumes[region_id]; + for (size_t i = 0; i < volumes_and_ranges.size(); ) { + int volume_id = volumes_and_ranges[i].second; + const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; + if (model_volume->is_modifier()) { + BOOST_LOG_TRIVIAL(debug) << "Slicing modifiers - volume " << volume_id; + // Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume. + std::vector ranges; + ranges.emplace_back(volumes_and_ranges[i].first); + size_t j = i + 1; + for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) + ranges.emplace_back(volumes_and_ranges[j].first); + // slicing in parallel + std::vector this_slices = this->slice_volume(slice_zs, ranges, *model_volume); + if (out.empty()) { + out = std::move(this_slices); + merge.assign(out.size(), false); + } else { + for (size_t i = 0; i < out.size(); ++ i) + if (! this_slices[i].empty()) + if (! out[i].empty()) { + append(out[i], this_slices[i]); + merge[i] = true; + } else + out[i] = std::move(this_slices[i]); + } + i = j; + } else + ++ i; + } + } + for (size_t i = 0; i < merge.size(); ++ i) + if (merge[i]) + out[i] = union_ex(out[i]); + } + } + } + + return out; +} + +std::vector PrintObject::slice_support_volumes(const ModelVolumeType &model_volume_type) const { std::vector volumes; for (const ModelVolume *volume : this->model_object()->volumes) - if (volume->is_support_enforcer()) + if (volume->type() == model_volume_type) volumes.emplace_back(volume); std::vector zs; zs.reserve(this->layers().size()); for (const Layer *l : this->layers()) zs.emplace_back((float)l->slice_z); - return this->_slice_volumes(zs, volumes); + return this->slice_volumes(zs, volumes); } -std::vector PrintObject::slice_support_blockers() const -{ - std::vector volumes; - for (const ModelVolume *volume : this->model_object()->volumes) - if (volume->is_support_blocker()) - volumes.emplace_back(volume); - std::vector zs; - zs.reserve(this->layers().size()); - for (const Layer *l : this->layers()) - zs.emplace_back((float)l->slice_z); - return this->_slice_volumes(zs, volumes); -} - -std::vector PrintObject::_slice_volumes(const std::vector &z, const std::vector &volumes) const +std::vector PrintObject::slice_volumes(const std::vector &z, const std::vector &volumes) const { std::vector layers; if (! volumes.empty()) { @@ -1829,34 +1945,71 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, return layers; } -std::vector PrintObject::_slice_volume(const std::vector &z, const ModelVolume &volume) const +std::vector PrintObject::slice_volume(const std::vector &z, const ModelVolume &volume) const { std::vector layers; - // Compose mesh. - //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh(volume.mesh()); - mesh.transform(volume.get_matrix(), true); - if (mesh.repaired) { - //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. - stl_check_facets_exact(&mesh.stl); + if (! z.empty()) { + // Compose mesh. + //FIXME better to split the mesh into separate shells, perform slicing over each shell separately and then to use a Boolean operation to merge them. + TriangleMesh mesh(volume.mesh()); + mesh.transform(volume.get_matrix(), true); + if (mesh.repaired) { + //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. + stl_check_facets_exact(&mesh.stl); + } + if (mesh.stl.stats.number_of_facets > 0) { + mesh.transform(m_trafo, true); + // apply XY shift + mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); + // perform actual slicing + TriangleMeshSlicer mslicer; + const Print *print = this->print(); + auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); + // TriangleMeshSlicer needs the shared vertices. + mesh.require_shared_vertices(); + mslicer.init(&mesh, callback); + mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); + m_print->throw_if_canceled(); + } } - if (mesh.stl.stats.number_of_facets > 0) { - mesh.transform(m_trafo, true); - // apply XY shift - mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); - // perform actual slicing - TriangleMeshSlicer mslicer; - const Print *print = this->print(); - auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); - // TriangleMeshSlicer needs the shared vertices. - mesh.require_shared_vertices(); - mslicer.init(&mesh, callback); - mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); - m_print->throw_if_canceled(); - } return layers; } +// Filter the zs not inside the ranges. The ranges are closed at the botton and open at the top, they are sorted lexicographically and non overlapping. +std::vector PrintObject::slice_volume(const std::vector &z, const std::vector &ranges, const ModelVolume &volume) const +{ + std::vector out; + if (! z.empty() && ! ranges.empty()) { + if (ranges.size() == 1 && z.front() >= ranges.front().first && z.back() < ranges.front().second) { + // All layers fit into a single range. + out = this->slice_volume(z, volume); + } else { + std::vector z_filtered; + std::vector> n_filtered; + z_filtered.reserve(z.size()); + n_filtered.reserve(2 * ranges.size()); + size_t i = 0; + for (const t_layer_height_range &range : ranges) { + for (; i < z.size() && z[i] < range.first; ++ i) ; + size_t first = i; + for (; i < z.size() && z[i] < range.second; ++ i) + z_filtered.emplace_back(z[i]); + if (i > first) + n_filtered.emplace_back(std::make_pair(first, i)); + } + if (! n_filtered.empty()) { + std::vector layers = this->slice_volume(z_filtered, volume); + out.assign(z.size(), ExPolygons()); + i = 0; + for (const std::pair &span : n_filtered) + for (size_t j = span.first; j < span.second; ++ j) + out[j] = std::move(layers[i ++]); + } + } + } + return out; +} + std::string PrintObject::_fix_slicing_errors() { // Collect layers with slicing errors. @@ -2120,7 +2273,7 @@ void PrintObject::clip_fill_surfaces() //Should the pw not be half of the current value? float pw = FLT_MAX; for (const LayerRegion *layerm : layer->m_regions) - pw = std::min(pw, layerm->flow(frPerimeter).scaled_width()); + pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width()); // Append such thick perimeters to the areas that need support polygons_append(overhangs, offset2(perimeters, -pw, +pw)); } diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 1c6476eae..6b0e3f895 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -153,29 +153,33 @@ SlicingParameters SlicingParameters::create_from_config( return params; } -// Convert layer_height_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for +std::vector> layer_height_ranges(const t_layer_config_ranges &config_ranges) +{ + std::vector> out; + out.reserve(config_ranges.size()); + for (const auto &kvp : config_ranges) + out.emplace_back(kvp.first, kvp.second.option("layer_height")->getFloat()); + return out; +} + +// Convert layer_config_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for // in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation. std::vector layer_height_profile_from_ranges( const SlicingParameters &slicing_params, -// const t_layer_height_ranges &layer_height_ranges) const t_layer_config_ranges &layer_config_ranges) // #ys_FIXME_experiment { // 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed. std::vector> ranges_non_overlapping; -// ranges_non_overlapping.reserve(layer_height_ranges.size() * 4); ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); // #ys_FIXME_experiment if (slicing_params.first_object_layer_height_fixed()) ranges_non_overlapping.push_back(std::pair( t_layer_height_range(0., slicing_params.first_object_layer_height), slicing_params.first_object_layer_height)); // The height ranges are sorted lexicographically by low / high layer boundaries. -// for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) { - for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); - it_range != layer_config_ranges.end(); ++ it_range) { // #ys_FIXME_experiment + for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) { coordf_t lo = it_range->first.first; coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height()); -// coordf_t height = it_range->second; - coordf_t height = it_range->second.option("layer_height")->getFloat(); // #ys_FIXME_experiment + coordf_t height = it_range->second.option("layer_height")->getFloat(); if (! ranges_non_overlapping.empty()) // Trim current low with the last high. lo = std::max(lo, ranges_non_overlapping.back().first.second); @@ -224,7 +228,7 @@ std::vector layer_height_profile_from_ranges( // Fill layer_height_profile by heights ensuring a prescribed maximum cusp height. std::vector layer_height_profile_adaptive( const SlicingParameters &slicing_params, - const t_layer_height_ranges &layer_height_ranges, + const t_layer_config_ranges & /* layer_config_ranges */, const ModelVolumePtrs &volumes) { // 1) Initialize the SlicingAdaptive class with the object meshes. diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index ea5413e9c..7ebb3f329 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -130,17 +130,17 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters } typedef std::pair t_layer_height_range; -typedef std::map t_layer_height_ranges; typedef std::map t_layer_config_ranges; +extern std::vector> layer_height_ranges(const t_layer_config_ranges &config_ranges); + extern std::vector layer_height_profile_from_ranges( const SlicingParameters &slicing_params, -// const t_layer_height_ranges &layer_height_ranges); const t_layer_config_ranges &layer_config_ranges); extern std::vector layer_height_profile_adaptive( const SlicingParameters &slicing_params, - const t_layer_height_ranges &layer_height_ranges, + const t_layer_config_ranges &layer_config_ranges, const ModelVolumePtrs &volumes); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index fde35ca1e..0ad4f816a 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -829,7 +829,7 @@ namespace SupportMaterialInternal { assert(expansion_scaled >= 0.f); for (const ExtrusionPath &ep : loop.paths) if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) { - float exp = 0.5f * scale_(ep.width) + expansion_scaled; + float exp = 0.5f * (float)scale_(ep.width) + expansion_scaled; if (ep.is_closed()) { if (ep.size() >= 3) { // This is a complete loop. @@ -2214,7 +2214,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, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (contacts != nullptr) columns_base->polygons = diff(columns_base->polygons, interface_polygons); } @@ -3226,7 +3226,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // TODO: use brim ordering algorithm Polygons to_infill_polygons = to_polygons(to_infill); // TODO: use offset2_ex() - to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing())); + to_infill = offset_ex(to_infill, - 0.4f * float(flow.scaled_spacing())); extrusion_entities_append_paths( base_layer.extrusions, to_polylines(std::move(to_infill_polygons)), diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 8392e534a..d9bb67f57 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -600,12 +600,12 @@ void Bed3D::render_prusa_shader(bool transparent) const if (position_id != -1) { glsafe(::glEnableVertexAttribArray(position_id)); - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset())); } if (tex_coords_id != -1) { glsafe(::glEnableVertexAttribArray(tex_coords_id)); - glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); + glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset())); } glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count())); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e8973f6e3..84a4db965 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1922,9 +1922,6 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode } object->ensure_on_bed(); - - // print.auto_assign_extruders(object); - // print.add_model_object(object); } #ifdef AUTOPLACEMENT_ON_LOAD diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 402b4248f..e681b8af1 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1129,7 +1129,6 @@ void Selection::copy_to_clipboard() dst_object->config = src_object->config; dst_object->sla_support_points = src_object->sla_support_points; dst_object->sla_points_status = src_object->sla_points_status; -// dst_object->layer_height_ranges = src_object->layer_height_ranges; dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment dst_object->layer_height_profile = src_object->layer_height_profile; dst_object->origin_translation = src_object->origin_translation; diff --git a/t/print.t b/t/print.t index be2db3431..e76d226af 100644 --- a/t/print.t +++ b/t/print.t @@ -1,4 +1,4 @@ -use Test::More tests => 6; +use Test::More tests => 2; use strict; use warnings; @@ -31,6 +31,8 @@ use Slic3r::Test; ok abs(unscale($center->[Y]) - $print_center->[Y]) < 0.005, 'print is centered around print_center (Y)'; } +# This is really testing a path, which is no more used by the slicer, just by the test cases. +if (0) { # this represents the aggregate config from presets my $config = Slic3r::Config::new_from_defaults; @@ -40,7 +42,7 @@ use Slic3r::Test; # user sets a per-region option $print->print->objects->[0]->model_object->config->set('fill_density', 100); - $print->print->reload_object(0); +# $print->print->reload_object(0); is $print->print->regions->[0]->config->fill_density, 100, 'region config inherits model object config'; # user exports G-code, thus the default config is reapplied @@ -51,7 +53,7 @@ use Slic3r::Test; # user assigns object extruders $print->print->objects->[0]->model_object->config->set('extruder', 3); $print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2); - $print->print->reload_object(0); +# $print->print->reload_object(0); is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded'; is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders'; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index c35f967f8..70313ff5e 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -100,7 +100,6 @@ _constant() %code%{ RETVAL = const_cast(&THIS->objects()); %}; Ref get_object(int idx) %code%{ RETVAL = THIS->objects()[idx]; %}; - void reload_object(int idx); size_t object_count() %code%{ RETVAL = THIS->objects().size(); %}; @@ -141,7 +140,6 @@ _constant() } %}; - void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config_perl_tests_only(DynamicPrintConfig* config) %code%{ RETVAL = THIS->apply_config_perl_tests_only(*config); %}; bool has_infinite_skirt();