Merge upstream main: multi-variant printers, X-Ray view, preview and startup work

The two conflicts are both places where upstream landed on top of IDEX/IQEX
code. In GCode.cpp the relocated file header block meets the IMEX placeholder
block, and the placeholders are set first: file_start_gcode is processed through
the placeholder parser now, which throws on a name it does not know, so a script
naming {imex_mode} would abort the export if the header ran first. In
test_multifilament.cpp both sides appended a case at the end of the file.
This commit is contained in:
Clifford Garwood
2026-09-28 17:12:53 -04:00
5610 changed files with 235531 additions and 279338 deletions
+54 -16
View File
@@ -9,12 +9,12 @@
namespace Slic3r {
// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new
// Add or remove support and Precise Seam 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.
// Other volume types must already match model_object_new in the correct order.
// Friend to ModelVolume to allow copying.
// static is not accepted by gcc if declared as a friend of ModelObject.
/* static */ void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_new)
/* static */ void model_volume_list_update_supports_and_seams(ModelObject &model_object_dst, const ModelObject &model_object_new)
{
typedef std::pair<const ModelVolume*, bool> ModelVolumeWithStatus;
std::vector<ModelVolumeWithStatus> old_volumes;
@@ -34,18 +34,22 @@ namespace Slic3r {
assert(! it->second); // not consumed yet
it->second = true;
ModelVolume *model_volume_dst = const_cast<ModelVolume*>(it->first);
// For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) || model_volume_dst->type() == model_volume_src->type());
// Type may switch within support family, within precise_seam family, or between them.
assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) ||
(model_volume_dst->is_precise_seam() && model_volume_src->is_precise_seam()) ||
(model_volume_dst->is_support_modifier() && model_volume_src->is_precise_seam()) ||
(model_volume_dst->is_precise_seam() && model_volume_src->is_support_modifier()) ||
model_volume_dst->type() == model_volume_src->type());
model_object_dst.volumes.emplace_back(model_volume_dst);
if (model_volume_dst->is_support_modifier()) {
// For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
if (model_volume_dst->is_support_modifier() || model_volume_dst->is_precise_seam()) {
// Type may have been switched within or between support/precise_seam families.
model_volume_dst->set_type(model_volume_src->type());
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());
assert(model_volume_src->is_support_modifier() || model_volume_src->is_precise_seam());
model_object_dst.volumes.emplace_back(new ModelVolume(*model_volume_src));
model_object_dst.volumes.back()->set_model_object(&model_object_dst);
}
@@ -56,17 +60,20 @@ namespace Slic3r {
delete mv_with_status.first;
}
static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolumeType type)
// Copy configs of ModelVolumes matching type_filter predicate from src to dst.
// Mirrors the template pattern of model_volume_list_changed() in Model.cpp.
template<typename TypeFilterFn>
static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, TypeFilterFn type_filter)
{
size_t i_src, i_dst;
for (i_src = 0, i_dst = 0; i_src < model_object_src.volumes.size() && i_dst < model_object_dst.volumes.size();) {
const ModelVolume &mv_src = *model_object_src.volumes[i_src];
ModelVolume &mv_dst = *model_object_dst.volumes[i_dst];
if (mv_src.type() != type) {
if (! type_filter(mv_src.type())) {
++ i_src;
continue;
}
if (mv_dst.type() != type) {
if (! type_filter(mv_dst.type())) {
++ i_dst;
continue;
}
@@ -89,6 +96,20 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
}
}
// Convenience overload: single volume type.
static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolumeType type)
{
model_volume_list_copy_configs(model_object_dst, model_object_src, [type](const ModelVolumeType t) { return t == type; });
}
// Convenience overload: multiple volume types at once (e.g. all precise seam types).
static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const std::initializer_list<ModelVolumeType> &types)
{
model_volume_list_copy_configs(model_object_dst, model_object_src, [&types](const ModelVolumeType t) {
return std::find(types.begin(), types.end(), t) != types.end();
});
}
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());
@@ -1297,7 +1318,9 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
extruder_count, extruder_volume_type_count, filament_keys,
"filament_self_index", "filament_extruder_variant",
&dynamic_slot_indices);
else if ((extruder_count > 1) || different_extruder)
// Orca: also on a printer with a single extruder variant once a filament defines several
// (e.g. Standard and High Flow), so each filament takes its variant for that extruder.
else if ((extruder_count > 1) || different_extruder || new_full_config.has_multi_variant_filament())
new_full_config.update_values_to_printer_extruders_for_multiple_filaments(m_ori_full_print_config, extruder_count, extruder_volume_type_count, filament_keys,
"filament_self_index", "filament_extruder_variant");
}
@@ -1648,6 +1671,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// 3) Synchronize ModelObjects & PrintObjects.
const std::initializer_list<ModelVolumeType> solid_or_modifier_types { ModelVolumeType::MODEL_PART, ModelVolumeType::NEGATIVE_VOLUME, ModelVolumeType::PARAMETER_MODIFIER };
const std::initializer_list<ModelVolumeType> precise_seam_types {
ModelVolumeType::PRECISE_SEAM_CENTER, ModelVolumeType::PRECISE_SEAM_LEFT,
ModelVolumeType::PRECISE_SEAM_RIGHT, ModelVolumeType::PRECISE_SEAM_ENFORCED,
ModelVolumeType::PRECISE_SEAM_BLOCKED, ModelVolumeType::PRECISE_SEAM_NEUTRAL
};
for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) {
ModelObject &model_object = *m_model.objects[idx_model_object];
ModelObjectStatus &model_object_status = const_cast<ModelObjectStatus&>(model_object_status_db.reuse(model_object));
@@ -1665,6 +1693,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
model_fuzzy_skin_data_changed(model_object, model_object_new);
bool supports_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER) ||
model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
bool precise_seam_differ = model_volume_list_changed(model_object, model_object_new, precise_seam_types);
bool layer_height_ranges_differ = ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty());
bool model_origin_translation_differ = model_object.origin_translation != model_object_new.origin_translation;
bool brim_points_differ = model_brim_points_data_changed(model_object, model_object_new);
@@ -1707,13 +1736,20 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// Invalidate just the supports step.
for (const PrintObjectStatus &print_object_status : print_objects_range)
update_apply_status(print_object_status.print_object->invalidate_step(posSupportMaterial));
if (supports_differ) {
// Copy just the support volumes.
model_volume_list_update_supports(model_object, model_object_new);
}
}
if (precise_seam_differ) {
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
this->call_cancel_callback();
update_apply_status(false);
// Invalidate seam placement (affects G-code export).
update_apply_status(this->invalidate_step(psGCodeExport));
} else if (model_custom_seam_data_changed(model_object, model_object_new)) {
update_apply_status(this->invalidate_step(psGCodeExport));
}
// Synchronize both families once, after cancellation and all affected-step invalidations.
// This also handles type changes between supports and Precise Seam before copying configs below.
if (supports_differ || precise_seam_differ)
model_volume_list_update_supports_and_seams(model_object, model_object_new);
if (brim_points_differ) {
model_object.brim_points = model_object_new.brim_points;
update_apply_status(this->invalidate_all_steps());
@@ -1738,6 +1774,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
//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);
// Synchronize Precise Seam modifier volumes
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, precise_seam_types);
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;