diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 3e52e7623..354d71dc4 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -370,7 +370,7 @@ protected: friend class Print; friend class ModelObject; - explicit ModelVolume(ModelVolume &rhs) = default; + explicit ModelVolume(const ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } private: diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f0538fda0..c661da5ca 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -260,6 +260,8 @@ bool Print::invalidate_step(PrintStep step) //FIXME Why should skirt invalidate brim? Shouldn't it be vice versa? if (step == psSkirt) invalidated |= Inherited::invalidate_step(psBrim); + if (step != psGCodeExport) + invalidated |= Inherited::invalidate_step(psGCodeExport); return invalidated; } @@ -612,27 +614,45 @@ static inline bool model_volume_list_changed(const ModelObject &model_object_old return false; } -void Print::model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src) +// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new +// in the exact order and with the same IDs. +// It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order. +void Print::model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_new) { - // 1) Delete the support volumes from model_object_dst. - { - std::vector dst; - dst.reserve(model_object_dst.volumes.size()); - for (ModelVolume *vol : model_object_dst.volumes) { - if (vol->is_support_modifier()) - dst.emplace_back(vol); - else - delete vol; + typedef std::pair ModelVolumeWithStatus; + std::vector old_volumes; + old_volumes.reserve(model_object_dst.volumes.size()); + for (const ModelVolume *model_volume : model_object_dst.volumes) + old_volumes.emplace_back(ModelVolumeWithStatus(model_volume, false)); + auto model_volume_lower = [](const ModelVolumeWithStatus &mv1, const ModelVolumeWithStatus &mv2){ return mv1.first->id() < mv2.first->id(); }; + auto model_volume_equal = [](const ModelVolumeWithStatus &mv1, const ModelVolumeWithStatus &mv2){ return mv1.first->id() == mv2.first->id(); }; + std::sort(old_volumes.begin(), old_volumes.end(), model_volume_lower); + model_object_dst.volumes.clear(); + model_object_dst.volumes.reserve(model_object_new.volumes.size()); + for (const ModelVolume *model_volume_src : model_object_new.volumes) { + ModelVolumeWithStatus key(model_volume_src, false); + auto it = std::lower_bound(old_volumes.begin(), old_volumes.end(), key, model_volume_lower); + if (it != old_volumes.end() && model_volume_equal(*it, key)) { + // The volume was found in the old list. Just copy it. + assert(! it->second); // not consumed yet + it->second = true; + ModelVolume *model_volume_dst = const_cast(it->first); + assert(model_volume_dst->type() == model_volume_src->type()); + model_object_dst.volumes.emplace_back(model_volume_dst); + if (model_volume_dst->is_support_modifier()) + model_volume_dst->set_transformation(model_volume_src->get_transformation()); + assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix())); + } else { + // The volume was not found in the old list. Create a new copy. + assert(model_volume_src->is_support_modifier()); + model_object_dst.volumes.emplace_back(new ModelVolume(*model_volume_src)); + model_object_dst.volumes.back()->set_model_object(&model_object_dst); } - model_object_dst.volumes = std::move(dst); - } - // 2) Copy the support volumes from model_object_src to the end of model_object_dst. - for (ModelVolume *vol : model_object_src.volumes) { - if (vol->is_support_modifier()) { - model_object_dst.volumes.emplace_back(new ModelVolume(*vol)); - model_object_dst.volumes.back()->set_model_object(&model_object_dst); - } } + // Release the non-consumed old volumes (those were deleted from the new list). + for (ModelVolumeWithStatus &mv_with_status : old_volumes) + if (! mv_with_status.second) + delete mv_with_status.first; } static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolume::Type type) @@ -852,7 +872,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. this->call_cancell_callback(); - this->invalidate_step(psGCodeExport); + update_apply_status(this->invalidate_step(psGCodeExport)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); m_model.objects.clear(); @@ -962,6 +982,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. this->call_cancell_callback(); + update_apply_status(false); // Invalidate just the supports step. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) @@ -1067,6 +1088,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } if (m_objects != print_objects_new) { this->call_cancell_callback(); + update_apply_status(this->invalidate_all_steps()); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. bool deleted_objects = false; @@ -1131,7 +1153,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co int ireg = 0; for (const std::vector &volumes : print_object->region_volumes) { if (! volumes.empty()) - -- m_regions[ireg]; + -- m_regions[ireg]->m_refcnt; ++ ireg; } print_object->region_volumes.clear(); @@ -1164,21 +1186,24 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // Get the config applied to this volume. PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume); // Find an existing print region with the same config. - for (int i = 0; i < (int)m_regions.size(); ++ i) - if (config.equals(m_regions[i]->config())) { + int idx_empty_slot = -1; + for (int i = 0; i < (int)m_regions.size(); ++ i) { + if (m_regions[i]->m_refcnt == 0) + 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 == size_t(-1)) { - for (region_id = 0; region_id < m_regions.size(); ++ region_id) - if (m_regions[region_id]->m_refcnt == 0) { - // An empty slot was found. - m_regions[region_id]->set_config(std::move(config)); - break; - } - if (region_id == m_regions.size()) - this->add_region(config); + 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 diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ea34ef23a..b2f9f9501 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -174,6 +174,8 @@ protected: bool set_copies(const Points &points); // Invalidates the step, and its depending steps in PrintObject and Print. bool invalidate_step(PrintObjectStep step); + // Invalidates all PrintObject and Print steps. + bool invalidate_all_steps(); private: void make_perimeters(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f0361ba01..a71fa194f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -570,9 +570,16 @@ bool PrintObject::invalidate_step(PrintObjectStep step) // It also decides about what the wipe_into_infill / wipe_into_object features will do, // and that too depends on many of the settings. invalidated |= m_print->invalidate_step(psWipeTower); + // Invalidate G-code export in any case. + invalidated |= m_print->invalidate_step(psGCodeExport); return invalidated; } +bool PrintObject::invalidate_all_steps() +{ + return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps(); +} + bool PrintObject::has_support_material() const { return m_config.support_material