diff --git a/resources/profiles/Artillery.idx b/resources/profiles/Artillery.idx index b76f62584..0c45cb2e3 100644 --- a/resources/profiles/Artillery.idx +++ b/resources/profiles/Artillery.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.3.1-beta +0.0.4 Fixed first layer height in 0.28mm profile. 0.0.3 Fixed Genius bed size. 0.0.2 Updated start g-code. 0.0.1 Initial Artillery bundle diff --git a/resources/profiles/Artillery.ini b/resources/profiles/Artillery.ini index d58d71c60..82c7daddc 100644 --- a/resources/profiles/Artillery.ini +++ b/resources/profiles/Artillery.ini @@ -11,7 +11,7 @@ name = Artillery # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 0.0.3 +config_version = 0.0.4 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Artillery/ # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -300,6 +300,7 @@ top_solid_layers = 4 [print:*0.28mm*] inherits = *common* layer_height = 0.28 +first_layer_height = 0.36 top_infill_extrusion_width = 0.45 first_layer_extrusion_width = 0.75 bottom_solid_layers = 3 diff --git a/resources/profiles/INAT.idx b/resources/profiles/INAT.idx index 47632c29a..a756b34b5 100644 --- a/resources/profiles/INAT.idx +++ b/resources/profiles/INAT.idx @@ -1,3 +1,4 @@ min_slic3r_version = 2.3.1-beta -0.0.1 Initial version +0.0.3 Set default filament profile. 0.0.2 Improved start gcode, changed filename format +0.0.1 Initial version diff --git a/resources/profiles/INAT.ini b/resources/profiles/INAT.ini index 81a4f90ef..3c1a753b5 100644 --- a/resources/profiles/INAT.ini +++ b/resources/profiles/INAT.ini @@ -3,7 +3,7 @@ [vendor] # Vendor name will be shown by the Config Wizard. name = INAT -config_version = 0.0.2 +config_version = 0.0.3 config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/INAT/ ### @@ -15,12 +15,14 @@ name = INAT Proton X Rail variants = 0.4 technology = FFF family = Proton +default_materials = PLA @PROTON_X [printer_model:PROTON_X_ROD] name = INAT Proton X Rod variants = 0.4 technology = FFF family = Proton +default_materials = PLA @PROTON_X ### diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index 216b61698..f8fcef76f 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -216,6 +216,11 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con } } + if (num_above == 0) + // Special case, the object is completely below the print bed, thus it is outside, + // however we want to allow an object to be still printable if some of its parts are completely below the print bed. + return BuildVolume::ObjectState::Below; + // 2) Calculate intersections of triangle edges with the build surface. inside = num_inside > 0; outside = num_inside < num_above; @@ -303,7 +308,9 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 &vol BoundingBox3Base build_volume = this->bounding_volume().inflated(SceneEpsilon); if (m_max_print_height == 0) build_volume.max.z() = std::numeric_limits::max(); - return build_volume.contains(volume_bbox) ? ObjectState::Inside : build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; + return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below : + build_volume.contains(volume_bbox) ? ObjectState::Inside : + build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; } bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const BoundingBoxf3 &paths_bbox) const diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index ff3041eb7..e75710882 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -68,7 +68,10 @@ public: // Colliding with the build volume boundary, thus not printable and error is shown. Colliding, // Outside of the build volume means the object is ignored: Not printed and no error is shown. - Outside + Outside, + // Completely below the print bed. The same as Outside, but an object with one printable part below the print bed + // and at least one part above the print bed is still printable. + Below, }; // 1) Tests called on the plater. diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index a8f920ae2..9e271238e 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -19,6 +19,7 @@ #include "libslic3r/SLA/RasterBase.hpp" #include "libslic3r/miniz_extension.hpp" #include "libslic3r/PNGReadWrite.hpp" +#include "libslic3r/LocalesUtils.hpp" #include #include @@ -321,11 +322,13 @@ ConfigSubstitutions import_sla_archive( lh_opt != arch.config.not_found()) { auto lh_str = lh_opt->second.data(); - try { - double lh = std::stod(lh_str); // TODO replace with std::from_chars + + size_t pos; + double lh = string_to_double_decimal_point(lh_str, &pos); + if (pos) { // TODO: verify that pos is 0 when parsing fails profile_out.set("layer_height", lh); profile_out.set("initial_layer_height", lh); - } catch(...) {} + } } } diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index ce9e19a57..35dcdaa36 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -533,9 +533,8 @@ std::string GCodeWriter::set_fan(unsigned int speed) const return GCodeWriter::set_fan(this->config.gcode_flavor, this->config.gcode_comments, speed); } - void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) { - assert(digits <= 6); + assert(digits <= 9); static constexpr const std::array pow_10{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; *ptr_err.ptr++ = ' '; *ptr_err.ptr++ = axis; @@ -576,6 +575,21 @@ void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) { if ((this->ptr_err.ptr + 1) == base_ptr || *this->ptr_err.ptr == '-') *(++this->ptr_err.ptr) = '0'; this->ptr_err.ptr++; + +#if 0 // #ifndef NDEBUG + { + // Verify that the optimized formatter produces the same result as the standard sprintf(). + double v1 = atof(std::string(base_ptr, this->ptr_err.ptr).c_str()); + char buf[2048]; + sprintf(buf, "%.*lf", int(digits), v); + double v2 = atof(buf); + // Numbers may differ when rounding at exactly or very close to 0.5 due to numerical issues when scaling the double to an integer. + // Thus the complex assert. +// assert(v1 == v2); + assert(std::abs(v1 - v) * pow_10[digits] < 0.50001); + assert(std::abs(v2 - v) * pow_10[digits] < 0.50001); + } +#endif // NDEBUG } } // namespace Slic3r diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index 346d7a954..00ee1717f 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -12,11 +12,6 @@ #include #include #include -#include -#include -#include -#include -#include #include namespace Slic3r { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 3b6731337..b900a6298 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -182,6 +182,8 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); CustomGCode::check_mode_for_custom_gcode_per_print_z(model.custom_gcode_per_print_z); + handle_legacy_sla(*config); + return model; } @@ -1544,15 +1546,21 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */); if (state == BuildVolume::ObjectState::Inside) + // Volume is completely inside. inside_outside |= INSIDE; else if (state == BuildVolume::ObjectState::Outside) + // Volume is completely outside. inside_outside |= OUTSIDE; - else + else if (state == BuildVolume::ObjectState::Below) { + // Volume below the print bed, thus it is completely outside, however this does not prevent the object to be printable + // if some of its volumes are still inside the build volume. + } else + // Volume colliding with the build volume. inside_outside |= INSIDE | OUTSIDE; } model_instance->print_volume_state = - (inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside : - (inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; + inside_outside == (INSIDE | OUTSIDE) ? ModelInstancePVS_Partly_Outside : + inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; if (inside_outside == INSIDE) ++num_printable; } diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 7041f7b82..737514901 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1723,10 +1723,21 @@ std::vector> multi_material_segmentation_by_painting(con }); // end of parallel_for BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - end"; + std::vector layer_bboxes(num_layers); for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { throw_on_cancel_callback(); - BoundingBox bbox(get_extents(layers[layer_idx]->regions())); - bbox.merge(get_extents(input_expolygons[layer_idx])); + layer_bboxes[layer_idx] = get_extents(layers[layer_idx]->regions()); + layer_bboxes[layer_idx].merge(get_extents(input_expolygons[layer_idx])); + } + + for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { + throw_on_cancel_callback(); + BoundingBox bbox = layer_bboxes[layer_idx]; + // Projected triangles could, in rare cases (as in GH issue #7299), belongs to polygons printed in the previous or the next layer. + // Let's merge the bounding box of the current layer with bounding boxes of the previous and the next layer to ensure that + // every projected triangle will be inside the resulting bounding box. + if (layer_idx > 1) bbox.merge(layer_bboxes[layer_idx - 1]); + if (layer_idx < num_layers - 1) bbox.merge(layer_bboxes[layer_idx + 1]); // Projected triangles may slightly exceed the input polygons. bbox.offset(20 * SCALED_EPSILON); edge_grids[layer_idx].set_bbox(bbox); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index eff6c8a8d..a19eb4d52 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -303,6 +303,8 @@ void Preset::normalize(DynamicPrintConfig &config) first_layer_height->value = first_layer_height->get_abs_value(layer_height->value); first_layer_height->percent = false; } + + handle_legacy_sla(config); } std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config) @@ -544,6 +546,9 @@ static std::vector s_Preset_sla_material_options { "exposure_time", "initial_exposure_time", "material_correction", + "material_correction_x", + "material_correction_y", + "material_correction_z", "material_notes", "material_vendor", "default_sla_material_profile", @@ -559,6 +564,9 @@ static std::vector s_Preset_sla_printer_options { "display_orientation", "fast_tilt_time", "slow_tilt_time", "area_fill", "relative_correction", + "relative_correction_x", + "relative_correction_y", + "relative_correction_z", "absolute_correction", "elefant_foot_compensation", "elefant_foot_min_width", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6315bdc52..14d48368f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3146,7 +3146,31 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Printer scaling correction"); def->min = 0; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloats( { 1., 1. } )); + def->set_default_value(new ConfigOptionFloats( { 1., 1.} )); + + def = this->add("relative_correction_x", coFloat); + def->label = L("Printer scaling correction in X axis"); + def->full_label = L("Printer scaling X axis correction"); + def->tooltip = L("Printer scaling correction in X axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); + + def = this->add("relative_correction_y", coFloat); + def->label = L("Printer scaling correction in Y axis"); + def->full_label = L("Printer scaling X axis correction"); + def->tooltip = L("Printer scaling correction in Y axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); + + def = this->add("relative_correction_z", coFloat); + def->label = L("Printer scaling correction in Z axis"); + def->full_label = L("Printer scaling X axis correction"); + def->tooltip = L("Printer scaling correction in Z axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); def = this->add("absolute_correction", coFloat); def->label = L("Printer absolute correction"); @@ -3292,7 +3316,28 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Correction for expansion"); def->min = 0; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloats( { 1. , 1. } )); + def->set_default_value(new ConfigOptionFloats( { 1., 1., 1. } )); + + def = this->add("material_correction_x", coFloat); + def->full_label = L("Correction for expansion in X axis"); + def->tooltip = L("Correction for expansion in X axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); + + def = this->add("material_correction_y", coFloat); + def->full_label = L("Correction for expansion in Y axis"); + def->tooltip = L("Correction for expansion in Y axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); + + def = this->add("material_correction_z", coFloat); + def->full_label = L("Correction for expansion in Z axis"); + def->tooltip = L("Correction for expansion in Z axis"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1.)); def = this->add("material_notes", coString); def->label = L("SLA print material notes"); @@ -3749,7 +3794,16 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = "printhost_apikey"; } else if (opt_key == "preset_name") { opt_key = "preset_names"; - } + } /*else if (opt_key == "material_correction" || opt_key == "relative_correction") { + ConfigOptionFloats p; + p.deserialize(value); + + if (p.values.size() < 3) { + double firstval = p.values.front(); + p.values.emplace(p.values.begin(), firstval); + value = p.serialize(); + } + }*/ // Ignore the following obsolete configuration keys: static std::set ignore = { @@ -3866,6 +3920,28 @@ void DynamicPrintConfig::normalize_fdm() } } +void handle_legacy_sla(DynamicPrintConfig &config) +{ + for (std::string corr : {"relative_correction", "material_correction"}) { + if (config.has(corr)) { + if (std::string corr_x = corr + "_x"; !config.has(corr_x)) { + auto* opt = config.opt(corr_x, true); + opt->value = config.opt(corr)->values[0]; + } + + if (std::string corr_y = corr + "_y"; !config.has(corr_y)) { + auto* opt = config.opt(corr_y, true); + opt->value = config.opt(corr)->values[0]; + } + + if (std::string corr_z = corr + "_z"; !config.has(corr_z)) { + auto* opt = config.opt(corr_z, true); + opt->value = config.opt(corr)->values[1]; + } + } + } +} + void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders) { const auto &defaults = FullPrintConfig::defaults(); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d7409d12c..8297f9d2f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -224,6 +224,8 @@ public: { PrintConfigDef::handle_legacy(opt_key, value); } }; +void handle_legacy_sla(DynamicPrintConfig &config); + class StaticPrintConfig : public StaticConfig { public: @@ -924,6 +926,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, exposure_time)) ((ConfigOptionFloat, initial_exposure_time)) ((ConfigOptionFloats, material_correction)) + ((ConfigOptionFloat, material_correction_x)) + ((ConfigOptionFloat, material_correction_y)) + ((ConfigOptionFloat, material_correction_z)) ) PRINT_CONFIG_CLASS_DEFINE( @@ -940,6 +945,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, display_mirror_x)) ((ConfigOptionBool, display_mirror_y)) ((ConfigOptionFloats, relative_correction)) + ((ConfigOptionFloat, relative_correction_x)) + ((ConfigOptionFloat, relative_correction_y)) + ((ConfigOptionFloat, relative_correction_z)) ((ConfigOptionFloat, absolute_correction)) ((ConfigOptionFloat, elefant_foot_compensation)) ((ConfigOptionFloat, elefant_foot_min_width)) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 43ac958b5..55acd3846 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -807,7 +807,13 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps_full = { "initial_layer_height", "material_correction", + "material_correction_x", + "material_correction_y", + "material_correction_z", "relative_correction", + "relative_correction_x", + "relative_correction_y", + "relative_correction_z", "absolute_correction", "elefant_foot_compensation", "elefant_foot_min_width", @@ -1047,15 +1053,15 @@ Vec3d SLAPrint::relative_correction() const Vec3d corr(1., 1., 1.); if(printer_config().relative_correction.values.size() >= 2) { - corr.x() = printer_config().relative_correction.values[0]; - corr.y() = corr.x(); - corr.z() = printer_config().relative_correction.values[1]; + corr.x() = printer_config().relative_correction_x.value; + corr.y() = printer_config().relative_correction_y.value; + corr.z() = printer_config().relative_correction_z.value; } if(material_config().material_correction.values.size() >= 2) { - corr.x() *= material_config().material_correction.values[0]; - corr.y() = corr.x(); - corr.z() *= material_config().material_correction.values[1]; + corr.x() *= material_config().material_correction_x.value; + corr.y() *= material_config().material_correction_y.value; + corr.z() *= material_config().material_correction_z.value; } return corr; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 9a5252949..f0c2338e9 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -189,6 +189,7 @@ set(SLIC3R_GUI_SOURCES GUI/Mouse3DController.hpp GUI/DoubleSlider.cpp GUI/DoubleSlider.hpp + GUI/DoubleSlider_Utils.hpp GUI/Notebook.cpp GUI/Notebook.hpp GUI/ObjectDataViewModel.cpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a96ea2d17..6aa12431c 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -932,9 +932,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state) const { const Model& model = GUI::wxGetApp().plater()->model(); + auto volume_below = [](GLVolume& volume) -> bool + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed(); }; // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used. auto volume_sinking = [](GLVolume& volume) -> bool - { return volume.is_sinking() && volume.object_idx() != -1 && volume.volume_idx() != -1; }; + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking(); }; // Cached bounding box of a volume above the print bed. auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 { return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; @@ -948,21 +950,26 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo for (GLVolume* volume : this->volumes) if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { BuildVolume::ObjectState state; - switch (build_volume.type()) { - case BuildVolume::Type::Rectangle: - //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. - state = build_volume.volume_state_bbox(volume_bbox(*volume)); - break; - case BuildVolume::Type::Circle: - case BuildVolume::Type::Convex: - //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. - case BuildVolume::Type::Custom: - state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); - break; - default: - // Ignore, don't produce any collision. - state = BuildVolume::ObjectState::Inside; - break; + if (volume_below(*volume)) + state = BuildVolume::ObjectState::Below; + else { + switch (build_volume.type()) { + case BuildVolume::Type::Rectangle: + //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. + state = build_volume.volume_state_bbox(volume_bbox(*volume)); + break; + case BuildVolume::Type::Circle: + case BuildVolume::Type::Convex: + //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. + case BuildVolume::Type::Custom: + state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); + break; + default: + // Ignore, don't produce any collision. + state = BuildVolume::ObjectState::Inside; + break; + } + assert(state != BuildVolume::ObjectState::Below); } volume->is_outside = state != BuildVolume::ObjectState::Inside; if (volume->printable) { diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index fc47484b5..363dadf1e 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1,5 +1,6 @@ #include "libslic3r/libslic3r.h" #include "DoubleSlider.hpp" +#include "DoubleSlider_Utils.hpp" #include "libslic3r/GCode.hpp" #include "GUI.hpp" #include "GUI_App.hpp" @@ -2546,12 +2547,70 @@ bool Control::check_ticks_changed_event(Type type) std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder) { if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) { +#if 1 + if (ticks.empty()) + return get_opposite_color((*m_colors)[0]); + + auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick); + if (before_tick_it == ticks.end()) + { + while (before_tick_it != ticks.begin()) + if (--before_tick_it; before_tick_it->type == ColorChange) + break; + if (before_tick_it->type == ColorChange) + return get_opposite_color(before_tick_it->color); + return get_opposite_color((*m_colors)[0]); + } + + if (before_tick_it == ticks.begin()) + { + const std::string& frst_color = (*m_colors)[0]; + if (before_tick_it->type == ColorChange) + return get_opposite_color(frst_color, before_tick_it->color); + + auto next_tick_it = before_tick_it; + while (next_tick_it != ticks.end()) + if (++next_tick_it; next_tick_it->type == ColorChange) + break; + if (next_tick_it->type == ColorChange) + return get_opposite_color(frst_color, next_tick_it->color); + + return get_opposite_color(frst_color); + } + + std::string frst_color = ""; + if (before_tick_it->type == ColorChange) + frst_color = before_tick_it->color; + else { + auto next_tick_it = before_tick_it; + while (next_tick_it != ticks.end()) + if (++next_tick_it; next_tick_it->type == ColorChange) { + frst_color = next_tick_it->color; + break; + } + } + + while (before_tick_it != ticks.begin()) + if (--before_tick_it; before_tick_it->type == ColorChange) + break; + + if (before_tick_it->type == ColorChange) { + if (frst_color.empty()) + return get_opposite_color(before_tick_it->color); + return get_opposite_color(before_tick_it->color, frst_color); + } + + if (frst_color.empty()) + return get_opposite_color((*m_colors)[0]); + return get_opposite_color((*m_colors)[0], frst_color); +#else const std::vector& colors = ColorPrintColors::get(); if (ticks.empty()) return colors[0]; m_default_color_idx++; return colors[m_default_color_idx % colors.size()]; +#endif } std::string color = (*m_colors)[extruder - 1]; diff --git a/src/slic3r/GUI/DoubleSlider_Utils.hpp b/src/slic3r/GUI/DoubleSlider_Utils.hpp new file mode 100644 index 000000000..704eb5a87 --- /dev/null +++ b/src/slic3r/GUI/DoubleSlider_Utils.hpp @@ -0,0 +1,173 @@ +#include +#include "wx/colour.h" + +// next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both + +typedef struct { + double r; // a fraction between 0 and 1 + double g; // a fraction between 0 and 1 + double b; // a fraction between 0 and 1 +} rgb; + +typedef struct { + double h; // angle in degrees + double s; // a fraction between 0 and 1 + double v; // a fraction between 0 and 1 +} hsv; + +static hsv rgb2hsv(rgb in); +static rgb hsv2rgb(hsv in); + +hsv rgb2hsv(rgb in) +{ + hsv out; + double min, max, delta; + + min = in.r < in.g ? in.r : in.g; + min = min < in.b ? min : in.b; + + max = in.r > in.g ? in.r : in.g; + max = max > in.b ? max : in.b; + + out.v = max; // v + delta = max - min; + if (delta < 0.00001) + { + out.s = 0; + out.h = 0; // undefined, maybe nan? + return out; + } + if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash + out.s = (delta / max); // s + } else { + // if max is 0, then r = g = b = 0 + // s = 0, h is undefined + out.s = 0.0; + out.h = NAN; // its now undefined + return out; + } + if( in.r >= max ) // > is bogus, just keeps compilor happy + out.h = ( in.g - in.b ) / delta; // between yellow & magenta + else + if( in.g >= max ) + out.h = 2.0 + ( in.b - in.r ) / delta; // between cyan & yellow + else + out.h = 4.0 + ( in.r - in.g ) / delta; // between magenta & cyan + + out.h *= 60.0; // degrees + + if( out.h < 0.0 ) + out.h += 360.0; + + return out; +} + +hsv rgb2hsv(const std::string& str_clr_in) +{ + wxColour clr(str_clr_in); + rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 }; + return rgb2hsv(in); +} + + +rgb hsv2rgb(hsv in) +{ + double hh, p, q, t, ff; + long i; + rgb out; + + if(in.s <= 0.0) { // < is bogus, just shuts up warnings + out.r = in.v; + out.g = in.v; + out.b = in.v; + return out; + } + hh = in.h; + if (hh >= 360.0) hh -= 360.0;//hh = 0.0; + hh /= 60.0; + i = (long)hh; + ff = hh - i; + p = in.v * (1.0 - in.s); + q = in.v * (1.0 - (in.s * ff)); + t = in.v * (1.0 - (in.s * (1.0 - ff))); + + switch(i) { + case 0: + out.r = in.v; + out.g = t; + out.b = p; + break; + case 1: + out.r = q; + out.g = in.v; + out.b = p; + break; + case 2: + out.r = p; + out.g = in.v; + out.b = t; + break; + + case 3: + out.r = p; + out.g = q; + out.b = in.v; + break; + case 4: + out.r = t; + out.g = p; + out.b = in.v; + break; + case 5: + default: + out.r = in.v; + out.g = p; + out.b = q; + break; + } + return out; +} + +double rand_val() +{ + return 0.1 * (10 - rand() % 8); +} + +std::string get_opposite_color(const std::string& color) +{ + std::string opp_color = ""; + + hsv hsv_clr = rgb2hsv(color); + hsv_clr.h += 65; // 65 instead 60 to avoid circle values + hsv_clr.s = rand_val(); + hsv_clr.v = rand_val(); + + rgb rgb_opp_color = hsv2rgb(hsv_clr); + + wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); + opp_color = clr_str.ToStdString(); + + return opp_color; +} + +std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd) +{ + std::string opp_color = ""; + + hsv hsv_frst = rgb2hsv(color_frst); + hsv hsv_scnd = rgb2hsv(color_scnd); + + double delta_h = fabs(hsv_frst.h - hsv_scnd.h); + double start_h = delta_h > 180 ? std::min(hsv_scnd.h, hsv_frst.h) : std::max(hsv_scnd.h, hsv_frst.h); + start_h += 5; // to avoid circle change of colors for 120 deg + if (delta_h < 180) + delta_h = 360 - delta_h; + + hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() }; + rgb rgb_opp_color = hsv2rgb(hsv_opp); + + wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); + opp_color = clr_str.ToStdString(); + + return opp_color; +} \ No newline at end of file diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ee1db4802..407d57030 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4721,7 +4721,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() std::string curr_additional_tooltip; m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); - std::string new_additional_tooltip = ""; + std::string new_additional_tooltip; if (can_undo) { std::string action; wxGetApp().plater()->undo_redo_topmost_string_getter(true, action); @@ -4759,7 +4759,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() std::string curr_additional_tooltip; m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); - std::string new_additional_tooltip = ""; + std::string new_additional_tooltip; if (can_redo) { std::string action; wxGetApp().plater()->undo_redo_topmost_string_getter(false, action); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 4571b7346..94f099567 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -992,22 +992,13 @@ bool GUI_App::OnInit() bool GUI_App::on_init_inner() { -// win32 build on win64 and viceversa -#ifdef _WIN64 - if (wxPlatformInfo::Get().GetArchName().substr(0, 2) == "") { - RichMessageDialog dlg(nullptr, - _L("You have started PrusaSlicer for 64-bit architecture on 32-bit system." - "\nPlease download and install correct version at https://www.prusa3d.cz/prusaslicer/." - "\nDo you wish to continue?"), - "PrusaSlicer", wxICON_QUESTION | wxYES_NO); - if (dlg.ShowModal() != wxID_YES) - return false; - } -#elif _WIN32 +#if defined(_WIN32) && ! defined(_WIN64) + // Win32 32bit build. if (wxPlatformInfo::Get().GetArchName().substr(0, 2) == "64") { RichMessageDialog dlg(nullptr, - _L("You have started PrusaSlicer for 32-bit architecture on 64-bit system." - "\nPlease download and install correct version at https://www.prusa3d.cz/prusaslicer/." + _L("You are running a 32 bit build of PrusaSlicer on 64-bit Windows." + "\n32 bit build of PrusaSlicer will likely not be able to utilize all the RAM available in the system." + "\nPlease download and install a 64 bit build of PrusaSlice from https://www.prusa3d.cz/prusaslicer/." "\nDo you wish to continue?"), "PrusaSlicer", wxICON_QUESTION | wxYES_NO); if (dlg.ShowModal() != wxID_YES) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 69c855872..020026e4d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -911,21 +911,14 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me toggle_printable_state(); else if (title == _("Editing")) show_context_menu(evt_context_menu); - else if (title == _("Name")) - { - if (wxOSX) - show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909) - - if (is_windows10()) - { - int obj_idx, vol_idx; - get_selected_item_indexes(obj_idx, vol_idx, item); - - if (m_objects_model->HasWarningIcon(item) && - mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit()) - fix_through_netfabb(); - } - } + else if (title == _("Name")) + { + if (is_windows10() && m_objects_model->HasWarningIcon(item) && + mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit()) + fix_through_netfabb(); + else + show_context_menu(evt_context_menu); // show context menu for "Name" column too + } // workaround for extruder editing under OSX else if (wxOSX && evt_context_menu && title == _("Extruder")) extruder_editing(); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 9409ce6c4..c92ddd3b5 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -181,17 +181,16 @@ bool ObjectSettings::update_settings_list() bool ObjectSettings::add_missed_options(ModelConfig* config_to, const DynamicPrintConfig& config_from) { + const DynamicPrintConfig& print_config = wxGetApp().plater()->printer_technology() == ptFFF ? + wxGetApp().preset_bundle->prints.get_edited_preset().config : + wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; bool is_added = false; - if (wxGetApp().plater()->printer_technology() == ptFFF) - { - if (config_to->has("fill_density") && !config_to->has("fill_pattern")) - { - if (config_from.option("fill_density")->value == 100) { - config_to->set_key_value("fill_pattern", config_from.option("fill_pattern")->clone()); - is_added = true; - } + + for (auto opt_key : config_from.diff(print_config)) + if (!config_to->has(opt_key)) { + config_to->set_key_value(opt_key, config_from.option(opt_key)->clone()); + is_added = true; } - } return is_added; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 6c2c6afaf..66ca4fca2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -136,6 +136,8 @@ public: bool is_selectable() const { return on_is_selectable(); } CommonGizmosDataID get_requirements() const { return on_get_requirements(); } virtual bool wants_enter_leave_snapshots() const { return false; } + virtual std::string get_gizmo_entering_text() const { assert(false); return ""; } + virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; } virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); } void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index e0dea8806..cb8ccf282 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -133,8 +133,13 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); - float window_width = minimal_slider_width + sliders_left_width; + const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); +#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; +#else + float window_width = minimal_slider_width + sliders_left_width; +#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); window_width = std::max(window_width, split_triangles_checkbox_width); @@ -163,18 +168,19 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l "Degree sign to use in the respective slider in FDM supports gizmo," "placed after the number with no whitespace in between."); ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width); float slider_height = m_imgui->get_slider_float_height(); // Makes slider to be aligned to bottom of the multi-line text. - float slider_start_position = std::max(position_before_text_y, position_after_text_y - slider_height); - ImGui::SetCursorPosY(slider_start_position); + float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height); + ImGui::SetCursorPosY(slider_start_position_y); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when " "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]); if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) { #else + ImGui::PushItemWidth(window_width - sliders_left_width); if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data())) { #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg); @@ -274,10 +280,11 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); #else + ImGui::PushItemWidth(window_width - sliders_left_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width); @@ -295,10 +302,11 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(m_desc["smart_fill_angle"] + ":"); ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) #else + ImGui::PushItemWidth(window_width - sliders_left_width); if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data())) #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT for (auto &triangle_selector : m_triangle_selectors) { @@ -325,13 +333,14 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l } } - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width); auto clp_dist = float(m_c->object_clipper()->get_position()); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) m_c->object_clipper()->set_position(clp_dist, true); #else + ImGui::PushItemWidth(window_width - sliders_left_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 69966b0f2..4929714a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -18,6 +18,9 @@ protected: std::string on_get_name() const override; wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; + + std::string get_gizmo_entering_text() const override { return _u8L("Entering Paint-on supports"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Paint-on supports"); } std::string get_action_snapshot_name() override { return _u8L("Paint-on supports editing"); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 576f23520..285089357 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -311,8 +311,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - float sliders_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left)); - float window_width = minimal_slider_width + sliders_width; + const float sliders_left_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left)); +#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; +#else + float window_width = minimal_slider_width + sliders_left_width; +#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); window_width = std::max(window_width, split_triangles_checkbox_width); @@ -439,11 +444,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(sliders_width); - ImGui::PushItemWidth(window_width - sliders_width); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); #else + ImGui::PushItemWidth(window_width - sliders_left_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width); @@ -462,11 +468,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc["smart_fill_angle"] + ":"); std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in MMU gizmo," "placed after the number with no whitespace in between."); - ImGui::SameLine(sliders_width); - ImGui::PushItemWidth(window_width - sliders_width); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) #else + ImGui::PushItemWidth(window_width - sliders_left_width); if(m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data())) #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT for (auto &triangle_selector : m_triangle_selectors) { @@ -491,13 +498,14 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott } } - ImGui::SameLine(sliders_width); - ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) m_c->object_clipper()->set_position(clp_dist, true); #else + ImGui::PushItemWidth(window_width - sliders_left_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 9475f9ba6..0eaf9cf0a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -113,6 +113,9 @@ protected: bool on_is_activable() const override; wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; + + std::string get_gizmo_entering_text() const override { return _u8L("Entering Multimaterial painting"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Multimaterial painting"); } std::string get_action_snapshot_name() override { return _u8L("Multimaterial painting editing"); } size_t m_first_selected_extruder_idx = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index b4378319c..b11a8bffd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -104,8 +104,13 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - float sliders_width = std::max(cursor_size_slider_left, clipping_slider_left); - float window_width = minimal_slider_width + sliders_width; + const float sliders_left_width = std::max(cursor_size_slider_left, clipping_slider_left); +#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; +#else + float window_width = minimal_slider_width + sliders_left_width; +#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_sphere + cursor_type_radio_circle); @@ -126,11 +131,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(sliders_width); - ImGui::PushItemWidth(window_width - sliders_width); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); #else + ImGui::PushItemWidth(window_width - sliders_left_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width); @@ -169,13 +175,14 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) } } - ImGui::SameLine(sliders_width); - ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); + ImGui::SameLine(sliders_left_width); #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) m_c->object_clipper()->set_position(clp_dist, true); #else + ImGui::PushItemWidth(window_width - sliders_left_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index 624a197bd..408c2ec4c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -20,6 +20,8 @@ protected: wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; + std::string get_gizmo_entering_text() const override { return _u8L("Entering Seam painting"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Seam painting"); } std::string get_action_snapshot_name() override { return _u8L("Paint-on seam editing"); } private: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 8e30aa6b8..35e6a7308 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -68,6 +68,8 @@ public: void reslice_SLA_supports(bool postpone_error_messages = false) const; bool wants_enter_leave_snapshots() const override { return true; } + std::string get_gizmo_entering_text() const override { return _u8L("Entering SLA support points"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving SLA support points"); } private: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 7eea8315f..514db73c0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -653,7 +653,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined) { // mouse is outside the toolbar - m_tooltip = ""; + m_tooltip.clear(); if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) { if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) @@ -1230,16 +1230,14 @@ bool GLGizmosManager::activate_gizmo(EType type) if (! m_parent.get_gizmos_manager().is_serializing() && old_gizmo->wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), - Slic3r::format(_CTX_utf8("Leaving %1%", "undo/redo action name, placeholder " - "expands to a name of a gizmo being closed"), old_gizmo->get_name(false)), + old_gizmo->get_gizmo_leaving_text(), UndoRedo::SnapshotType::LeavingGizmoWithAction); } if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing() && new_gizmo->wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), - Slic3r::format(_CTX_utf8("Entering %1%", "undo/redo action name, placeholder " - "expands to a name of a gizmo being opened"), new_gizmo->get_name(false)), + new_gizmo->get_gizmo_entering_text(), UndoRedo::SnapshotType::EnteringGizmo); m_current = type; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f6e927df0..894cff3a2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -483,6 +483,11 @@ void ImGuiWrapper::tooltip(const wxString &label, float wrap_width) } #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT +ImVec2 ImGuiWrapper::get_slider_icon_size() const +{ + return this->calc_button_size(std::wstring(&ImGui::SliderFloatEditBtnIcon, 1)); +} + bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/, const wxString& tooltip /*= ""*/, bool show_edit_btn /*= true*/) { const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index acad85c27..590ef95b0 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -96,9 +96,10 @@ public: // Float sliders: Manually inserted values aren't clamped by ImGui.Using this wrapper function does (when clamp==true). #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = "", bool show_edit_btn = true); - bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = "", bool show_edit_btn = true); - bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = "", bool show_edit_btn = true); + ImVec2 get_slider_icon_size() const; + bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); + bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); + bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); #else bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 0c1e91c56..1e6812319 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -80,10 +80,9 @@ void MeshClipper::render_cut() void MeshClipper::recalculate_triangles() { const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); - const Vec3f& scaling = m_trafo.get_scaling_factor().cast(); // Calculate clipping plane normal in mesh coordinates. const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast(); - const Vec3d up (up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); + const Vec3d up = up_noscale.cast().cwiseProduct(m_trafo.get_scaling_factor()); // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). const float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 904a21cc6..ef299bf09 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -393,6 +393,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons std::string line; for (size_t i = 0; i < (m_multiline ? m_endlines.size() : std::min(m_endlines.size(), (size_t)2)); i++) { + if (m_endlines[i] > m_text1.size()) + break; line.clear(); ImGui::SetCursorPosX(x_offset); ImGui::SetCursorPosY(starting_y + i * shift_y); @@ -788,73 +790,20 @@ void NotificationManager::ProgressBarNotification::init() } else { m_lines_count = 2; m_endlines.push_back(m_endlines.back()); + m_multiline = false; } if(m_state == EState::Shown) m_state = EState::NotFading; } - -void NotificationManager::ProgressBarNotification::count_lines() -{ - std::string text = m_text1 + " " + m_hypertext; - size_t last_end = 0; - m_lines_count = 0; - - m_endlines.clear(); - while (last_end < text.length() - 1) - { - size_t next_hard_end = text.find_first_of('\n', last_end); - if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) { - //next line is ended by '/n' - m_endlines.push_back(next_hard_end); - last_end = next_hard_end + 1; - } - else { - // find next suitable endline - if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) { - // more than one line till end - size_t next_space = text.find_first_of(' ', last_end); - if (next_space > 0) { - size_t next_space_candidate = text.find_first_of(' ', next_space + 1); - while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) { - next_space = next_space_candidate; - next_space_candidate = text.find_first_of(' ', next_space + 1); - } - // when one word longer than line. Or the last space is too early. - if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset || - ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3 - ) { - float width_of_a = ImGui::CalcTextSize("a").x; - int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a); - while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) { - letter_count++; - } - m_endlines.push_back(last_end + letter_count); - last_end += letter_count; - } - else { - m_endlines.push_back(next_space); - last_end = next_space + 1; - } - } - } - else { - m_endlines.push_back(text.length()); - last_end = text.length(); - } - - } - m_lines_count++; - } -} - - - void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - // line1 - we do not print any more text than what fits on line 1. Line 2 is bar. + // hypertext is not rendered at all. If it is needed, it needs to be added here. + // m_endlines should have endline for each line and then for hypertext thus m_endlines[1] should always be in m_text1 if (m_multiline) { - // two lines text, one line bar + if(m_endlines[0] > m_text1.size() || m_endlines[1] > m_text1.size()) + return; + // two lines text (what doesnt fit, wont show), one line bar ImGui::SetCursorPosX(m_left_indentation); ImGui::SetCursorPosY(m_line_height / 4); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); @@ -866,6 +815,8 @@ void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& img render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } else { + if (m_endlines[0] > m_text1.size()) + return; //one line text, one line bar ImGui::SetCursorPosX(m_left_indentation); ImGui::SetCursorPosY(/*win_size_y / 2 - win_size_y / 6 -*/ m_line_height / 4); @@ -1173,7 +1124,7 @@ void NotificationManager::SlicingProgressNotification::set_status_text(const std break; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: { - NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + ".", m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") }; + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + "." }; update(data); m_state = EState::NotFading; } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ee7986999..0030937d7 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -438,9 +438,7 @@ private: ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) { } virtual void set_percentage(float percent) { m_percentage = percent; } protected: - virtual void init() override; - virtual void count_lines() override; - + virtual void init() override; virtual void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; @@ -548,13 +546,6 @@ private: void set_export_possible(bool b) { m_export_possible = b; } protected: void init() override; - void count_lines() override - { - if (m_sp_state == SlicingProgressState::SP_PROGRESS) - ProgressBarNotification::count_lines(); - else - PopNotification::count_lines(); - } void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; void render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 3d528df4b..b2983f97f 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -528,16 +528,21 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) std::string preset_name = prstft->get_preset_name(); if (Preset* preset = wxGetApp().preset_bundle->printers.find_preset(preset_name)) { std::string model_id = preset->config.opt_string("printer_model"); - if (preset->vendor && preset->vendor->name == "Prusa Research") { - const std::vector& models = preset->vendor->models; - auto it = std::find_if(models.begin(), models.end(), - [model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; }); - if (it != models.end() && (it->family == "MK3" || it->family == "MINI")) - continue; - } else if (!preset->vendor && (boost::starts_with(model_id, "MK3") || boost::starts_with(model_id, "MINI"))) { + auto model_supports_prusalink = [](const std::string &model) { + return model.size() >= 3 && + ((boost::starts_with(model, "MK") && model[2] > '2' && model[2] <= '9') || + boost::starts_with(model, "MINI")); + }; + if (preset->vendor) { + if (preset->vendor->name == "Prusa Research") { + const std::vector& models = preset->vendor->models; + auto it = std::find_if(models.begin(), models.end(), + [model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; }); + if (it != models.end() && model_supports_prusalink(it->family)) + continue; + } + } else if (model_supports_prusalink(model_id)) continue; - } - } all_presets_are_from_mk3_family = false; break; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 7b9c9846c..2b53883be 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -786,8 +786,8 @@ void PlaterPresetComboBox::update() std::map nonsys_presets; - wxString selected_user_preset = ""; - wxString tooltip = ""; + wxString selected_user_preset; + wxString tooltip; const std::deque& presets = m_collection->get_presets(); if (!presets.front().is_visible) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 038a513d1..6c820cff3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2479,14 +2479,11 @@ void TabPrinter::build_sla() optgroup = page->new_optgroup(L("Corrections")); line = Line{ m_config->def()->get("relative_correction")->full_label, "" }; -// std::vector axes{ "X", "Y", "Z" }; - std::vector axes{ "XY", "Z" }; - int id = 0; + std::vector axes{ "X", "Y", "Z" }; for (auto& axis : axes) { - auto opt = optgroup->get_option("relative_correction", id); + auto opt = optgroup->get_option(std::string("relative_correction_") + char(std::tolower(axis[0]))); opt.opt.label = axis; line.append_option(opt); - ++id; } optgroup->append_line(line); optgroup->append_single_option_line("absolute_correction"); @@ -4204,21 +4201,16 @@ void TabSLAMaterial::build() optgroup->append_single_option_line("initial_exposure_time"); optgroup = page->new_optgroup(L("Corrections")); - std::vector corrections = {"material_correction"}; -// std::vector axes{ "X", "Y", "Z" }; - std::vector axes{ "XY", "Z" }; - for (auto& opt_key : corrections) { - auto line = Line{ m_config->def()->get(opt_key)->full_label, "" }; - int id = 0; - for (auto& axis : axes) { - auto opt = optgroup->get_option(opt_key, id); - opt.opt.label = axis; - line.append_option(opt); - ++id; - } - optgroup->append_line(line); + auto line = Line{ m_config->def()->get("material_correction")->full_label, "" }; + std::vector axes{ "X", "Y", "Z" }; + for (auto& axis : axes) { + auto opt = optgroup->get_option(std::string("material_correction_") + char(std::tolower(axis[0]))); + opt.opt.label = axis; + line.append_option(opt); } + optgroup->append_line(line); + page = add_options_page(L("Notes"), "note.png"); optgroup = page->new_optgroup(L("Notes"), 0); optgroup->label_width = 0;