mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
sublayers and more
This commit is contained in:
+162
-4
@@ -5355,9 +5355,16 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
|
||||
p->editing_filament = -1;
|
||||
}
|
||||
|
||||
// update_num_filaments() shrinks filament_is_mixed along with the other per-filament arrays,
|
||||
// so snapshot it first — the paint cleanup below needs to know which slots were mixed
|
||||
// *before* the delete to avoid discarding assignments to still-valid mixed slots.
|
||||
std::vector<unsigned char> is_mixed_snapshot;
|
||||
if (auto* opt = wxGetApp().preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed"))
|
||||
is_mixed_snapshot = opt->values;
|
||||
|
||||
wxGetApp().preset_bundle->update_num_filaments(filament_id);
|
||||
wxGetApp().plater()->get_partplate_list().on_filament_deleted(filament_count, filament_id);
|
||||
wxGetApp().plater()->on_filaments_delete(filament_count, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id);
|
||||
wxGetApp().plater()->on_filaments_delete(filament_count, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id, is_mixed_snapshot);
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
|
||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||
|
||||
@@ -5374,6 +5381,36 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
|
||||
|
||||
void Sidebar::change_filament(size_t from_id, size_t to_id)
|
||||
{
|
||||
// Merging a physical filament into a mixed one that lists it as a component would delete
|
||||
// the very filament the mix depends on, leaving it broken. Warn before doing so.
|
||||
auto& pb = *wxGetApp().preset_bundle;
|
||||
bool from_is_physical = !pb.is_mixed_filament(from_id);
|
||||
bool to_is_mixed = pb.is_mixed_filament(to_id);
|
||||
|
||||
if (from_is_physical && to_is_mixed) {
|
||||
auto* comp_opt = pb.project_config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||
if (comp_opt && to_id < comp_opt->values.size()) {
|
||||
auto comps = Slic3r::parse_mixed_components(comp_opt->values[to_id]);
|
||||
unsigned int from_1based = (unsigned int)from_id + 1;
|
||||
bool target_uses_source = false;
|
||||
for (unsigned int c : comps) {
|
||||
if (c == from_1based) {
|
||||
target_uses_source = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target_uses_source) {
|
||||
int ret = wxMessageBox(
|
||||
_L("The target mixed filament uses this physical filament as a component. "
|
||||
"Merging will remove this physical filament and may invalidate the mixed filament. Continue?"),
|
||||
_L("Warning"),
|
||||
wxOK | wxCANCEL | wxICON_WARNING);
|
||||
if (ret != wxOK)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete_filament(from_id, int(to_id));
|
||||
}
|
||||
|
||||
@@ -9744,7 +9781,11 @@ void Plater::priv::object_list_changed()
|
||||
|
||||
// BBS
|
||||
//sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances());
|
||||
bool can_slice = !model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances();
|
||||
// A mixed filament with deleted or type-mismatched components cannot be resolved at slicing
|
||||
// time, so block the slice buttons the same way MainFrame::get_enable_slice_status() does.
|
||||
bool mixed_broken = sidebar->has_broken_mixed_filament();
|
||||
bool can_slice = !model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances()
|
||||
&& !mixed_broken;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": can_slice %1%, model_fits= %2%, export_in_progress %3%, has_printable_instances %4% ")%can_slice %model_fits %export_in_progress %part_plate->has_printable_instances();
|
||||
main_frame->update_slice_print_status(MainFrame::eEventObjectUpdate, can_slice);
|
||||
|
||||
@@ -13963,6 +14004,25 @@ bool Plater::priv::can_layers_editing() const
|
||||
|
||||
void Plater::priv::on_action_layersediting(SimpleEvent&)
|
||||
{
|
||||
// Sub-layer splitting divides each layer by the mix ratio, so an adaptive layer profile makes
|
||||
// those sub-layer heights vary and degrades the blend. ConfigManipulation warns when the
|
||||
// option is switched on with a variable profile already present; this is the other direction,
|
||||
// warning when variable layer editing is switched on while the option is active. Both honour
|
||||
// the same do-not-show-again flag.
|
||||
if (!view3D->is_layers_editing_enabled()) {
|
||||
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
|
||||
if (wxGetApp().app_config->get("no_warn_mixed_sublayer_variable_layer") != "1") {
|
||||
MessageDialog dlg(q,
|
||||
_L("Using variable layer height together with mixed color sublayer may result in poor color mixing quality."),
|
||||
_L("Warning"), wxICON_WARNING | wxOK);
|
||||
dlg.show_dsa_button();
|
||||
dlg.ShowModal();
|
||||
if (dlg.get_checkbox_state())
|
||||
wxGetApp().app_config->set("no_warn_mixed_sublayer_variable_layer", "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
view3D->enable_layers_editing(!view3D->is_layers_editing_enabled());
|
||||
notification_manager->set_move_from_overlay(view3D->is_layers_editing_enabled());
|
||||
}
|
||||
@@ -19385,7 +19445,7 @@ void Plater::on_filament_count_change(size_t num_filaments)
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int replace_filament_id)
|
||||
void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int replace_filament_id, const std::vector<unsigned char>& is_mixed_before_delete)
|
||||
{
|
||||
// only update elements in plater
|
||||
update_filament_colors_in_full_config();
|
||||
@@ -19399,9 +19459,15 @@ void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int r
|
||||
}*/
|
||||
|
||||
// update mmu info
|
||||
// A volume assigned to a mixed slot legitimately sits past the physical filament count, so
|
||||
// the paint cleanup must know which slots were mixed. Callers that already shrank the arrays
|
||||
// pass the pre-delete flags; otherwise read the current ones.
|
||||
const auto &is_mixed = is_mixed_before_delete.empty()
|
||||
? wxGetApp().preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed")->values
|
||||
: is_mixed_before_delete;
|
||||
for (ModelObject *mo : wxGetApp().model().objects) {
|
||||
for (ModelVolume *mv : mo->volumes) {
|
||||
mv->update_extruder_count_when_delete_filament(num_filaments, filament_id + 1, replace_filament_id + 1); // this function is 1 base
|
||||
mv->update_extruder_count_when_delete_filament(num_filaments, filament_id + 1, replace_filament_id + 1, is_mixed); // this function is 1 base
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19740,6 +19806,63 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config(const GC
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A gradient mixed filament fades between its two components over Z, so the UI shows it as a
|
||||
// two-tone swatch rather than one blended colour. Resolve each slot to its from/to endpoint
|
||||
// colours; non-gradient slots are left untouched.
|
||||
struct MixedGradientSlot {
|
||||
bool is_gradient = false;
|
||||
std::string color_from;
|
||||
std::string color_to;
|
||||
};
|
||||
|
||||
std::vector<MixedGradientSlot> parse_mixed_gradient_slots(const Slic3r::DynamicPrintConfig& config, size_t slot_count)
|
||||
{
|
||||
std::vector<MixedGradientSlot> result(slot_count);
|
||||
const auto* is_mixed = config.option<ConfigOptionBools>("filament_is_mixed");
|
||||
const auto* mixed_grad = config.option<ConfigOptionBools>("filament_mixed_gradient");
|
||||
const auto* mixed_comp = config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||
const auto* grad_range = config.option<ConfigOptionStrings>("filament_mixed_gradient_range");
|
||||
const auto* fil_colour = config.option<ConfigOptionStrings>("filament_colour");
|
||||
if (!is_mixed || !mixed_grad || !mixed_comp || !fil_colour) return result;
|
||||
|
||||
for (size_t i = 0; i < slot_count && i < is_mixed->values.size(); ++i) {
|
||||
if (!is_mixed->values[i]) continue;
|
||||
if (i >= mixed_grad->values.size() || !mixed_grad->values[i]) continue;
|
||||
if (i >= mixed_comp->values.size()) continue;
|
||||
|
||||
std::vector<unsigned int> comp_ids;
|
||||
std::istringstream iss(mixed_comp->values[i]);
|
||||
std::string tok;
|
||||
while (std::getline(iss, tok, ',')) {
|
||||
unsigned int v = 0;
|
||||
if (std::sscanf(tok.c_str(), "%u", &v) == 1)
|
||||
comp_ids.push_back(v);
|
||||
}
|
||||
if (comp_ids.size() != 2) continue;
|
||||
|
||||
int direction = 0;
|
||||
if (grad_range && i < grad_range->values.size()) {
|
||||
CNumericLocalesSetter c_locale_setter;
|
||||
float v0 = 0, v1 = 0;
|
||||
if (std::sscanf(grad_range->values[i].c_str(), "%f,%f", &v0, &v1) == 2)
|
||||
direction = (v0 > v1) ? 0 : 1;
|
||||
}
|
||||
|
||||
unsigned int from_id = (direction == 0) ? comp_ids[0] : comp_ids[1];
|
||||
unsigned int to_id = (direction == 0) ? comp_ids[1] : comp_ids[0];
|
||||
result[i].is_gradient = true;
|
||||
result[i].color_from = (from_id >= 1 && from_id <= fil_colour->values.size())
|
||||
? fil_colour->values[from_id - 1] : "#D9D9D9";
|
||||
result[i].color_to = (to_id >= 1 && to_id <= fil_colour->values.size())
|
||||
? fil_colour->values[to_id - 1] : "#D9D9D9";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::vector<std::string> Plater::get_filament_colors_render_info() const
|
||||
{
|
||||
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
|
||||
@@ -19747,6 +19870,13 @@ std::vector<std::string> Plater::get_filament_colors_render_info() const
|
||||
if (!config->has("filament_multi_colour")) return color_packs;
|
||||
|
||||
color_packs = (config->option<ConfigOptionStrings>("filament_multi_colour"))->values;
|
||||
|
||||
auto slots = parse_mixed_gradient_slots(*config, color_packs.size());
|
||||
for (size_t i = 0; i < color_packs.size(); ++i) {
|
||||
if (slots[i].is_gradient)
|
||||
color_packs[i] = slots[i].color_from + " " + slots[i].color_to;
|
||||
}
|
||||
|
||||
return color_packs;
|
||||
}
|
||||
|
||||
@@ -19757,9 +19887,37 @@ std::vector<std::string> Plater::get_filament_color_render_type() const
|
||||
if (!config->has("filament_colour_type")) return ctype;
|
||||
|
||||
ctype = (config->option<ConfigOptionStrings>("filament_colour_type"))->values;
|
||||
|
||||
auto slots = parse_mixed_gradient_slots(*config, ctype.size());
|
||||
while (ctype.size() < slots.size()) ctype.push_back("1");
|
||||
for (size_t i = 0; i < ctype.size() && i < slots.size(); ++i) {
|
||||
if (slots[i].is_gradient)
|
||||
ctype[i] = "0";
|
||||
}
|
||||
|
||||
return ctype;
|
||||
}
|
||||
|
||||
std::vector<Plater::FilamentGradientInfo> Plater::get_filament_gradient_info() const
|
||||
{
|
||||
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
|
||||
size_t n = get_extruder_colors_from_plater_config().size();
|
||||
std::vector<FilamentGradientInfo> info(n);
|
||||
|
||||
auto slots = parse_mixed_gradient_slots(*config, n);
|
||||
unsigned char rgba[4] = {};
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (!slots[i].is_gradient) continue;
|
||||
info[i].is_gradient = true;
|
||||
Slic3r::GUI::BitmapCache::parse_color4(slots[i].color_from, rgba);
|
||||
info[i].color_from = {rgba[0] / 255.f, rgba[1] / 255.f, rgba[2] / 255.f, rgba[3] / 255.f};
|
||||
Slic3r::GUI::BitmapCache::parse_color4(slots[i].color_to, rgba);
|
||||
info[i].color_to = {rgba[0] / 255.f, rgba[1] / 255.f, rgba[2] / 255.f, rgba[3] / 255.f};
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
|
||||
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user