diff --git a/CMakeLists.txt b/CMakeLists.txt index aa53ba06ec..c530a9c3fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,9 @@ cmake_minimum_required(VERSION 3.13) if (APPLE) # if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 11.3 if (NOT CMAKE_OSX_DEPLOYMENT_TARGET) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version") + set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version" FORCE) endif () + message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}") endif () project(OrcaSlicer) diff --git a/deps/Boost/Boost.cmake b/deps/Boost/Boost.cmake index a48b5f017e..767ca563aa 100644 --- a/deps/Boost/Boost.cmake +++ b/deps/Boost/Boost.cmake @@ -2,12 +2,12 @@ include(ExternalProject) # Use boost 1.78 for Windows, to support VS2022 if (WIN32) - set(_boost_url "https://boostorg.jfrog.io/artifactory/main/release/1.78.0/source/boost_1_78_0.tar.gz") + set(_boost_url "https://github.com/SoftFever/OrcaSlicer_deps/releases/download/boost/boost_1_78_0.tar.gz") set(_boost_hash 94CED8B72956591C4775AE2207A9763D3600B30D9D7446562C552F0A14A63BE7) set(_bootstrap_cmd bootstrap.bat) set(_build_cmd b2.exe) else() - set(_boost_url "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz") + set(_boost_url "https://github.com/SoftFever/OrcaSlicer_deps/releases/download/boost/boost_1_75_0.tar.gz") set(_boost_hash AEB26F80E80945E82EE93E5939BAEBDCA47B9DEE80A07D3144BE1E1A6A66DD6A) set(_bootstrap_cmd ./bootstrap.sh) set(_build_cmd ./b2) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 4352668633..8b693b28cc 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -24,8 +24,10 @@ cmake_minimum_required(VERSION 3.2) if (APPLE) # if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 11.3 if (NOT CMAKE_OSX_DEPLOYMENT_TARGET) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version") + set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version" FORCE) endif () + message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif () project(OrcaSlicer-deps) diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index a147e3f36d..bb01050c10 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -31,6 +31,11 @@ WallToolPathsParams make_paths_params(const int layer_id, const PrintObjectConfi if (const auto &min_feature_size_opt = print_object_config.min_feature_size) input_params.min_feature_size = min_feature_size_opt.value * 0.01 * min_nozzle_diameter; + if (const auto &min_wall_length_factor_opt = print_object_config.min_length_factor) + input_params.min_length_factor = min_wall_length_factor_opt.value; + else + input_params.min_length_factor = 0.5f; + if (layer_id == 0) { if (const auto &initial_layer_min_bead_width_opt = print_object_config.initial_layer_min_bead_width) input_params.min_bead_width = initial_layer_min_bead_width_opt.value * 0.01 * min_nozzle_diameter; @@ -47,6 +52,8 @@ WallToolPathsParams make_paths_params(const int layer_id, const PrintObjectConfi input_params.wall_transition_angle = print_object_config.wall_transition_angle.value; input_params.wall_distribution_count = print_object_config.wall_distribution_count.value; + + input_params.is_top_or_bottom_layer = false; // Set to default value } return input_params; @@ -671,7 +678,8 @@ void WallToolPaths::removeSmallLines(std::vector &toolpaths) coord_t min_width = std::numeric_limits::max(); for (const ExtrusionJunction &j : line) min_width = std::min(min_width, j.w); - if (line.is_odd && !line.is_closed && shorterThan(line, min_width / 2)) { // remove line + // Only use min_length_factor for non-topmost, to prevent top gaps. Otherwise use default value. + if (line.is_odd && !line.is_closed && shorterThan(line, m_params.is_top_or_bottom_layer ? (min_width / 2) : (min_width * m_params.min_length_factor))) { // remove line line = std::move(inset.back()); inset.erase(--inset.end()); line_idx--; // reconsider the current position diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index 02e780ff35..09e2ae5508 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -25,10 +25,12 @@ class WallToolPathsParams public: float min_bead_width; float min_feature_size; + float min_length_factor; float wall_transition_length; float wall_transition_angle; float wall_transition_filter_deviation; int wall_distribution_count; + bool is_top_or_bottom_layer; }; WallToolPathsParams make_paths_params(const int layer_id, const PrintObjectConfig &print_object_config, const PrintConfig &print_config); @@ -109,7 +111,7 @@ protected: /*! * Remove polylines shorter than half the smallest line width along that polyline. */ - static void removeSmallLines(std::vector &toolpaths); + void removeSmallLines(std::vector &toolpaths); /*! * Simplifies the variable-width toolpaths by calling the simplify on every line in the toolpath using the provided diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index b9ab63cf86..02586fbcb2 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1941,10 +1941,15 @@ void PerimeterGenerator::process_arachne() int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops if (this->config->alternate_extra_wall && this->layer_id % 2 == 1 && !m_spiral_vase) // add alternating extra wall loop_number++; - if (this->layer_id == 0 && this->config->only_one_wall_first_layer) + + // Set the bottommost layer to be one wall + const bool is_bottom_layer = (this->layer_id == 0) ? true : false; + if (is_bottom_layer && this->config->only_one_wall_first_layer) loop_number = 0; + // Orca: set the topmost layer to be one wall according to the config - if (loop_number > 0 && config->only_one_wall_top && this->upper_slices == nullptr) + const bool is_topmost_layer = (this->upper_slices == nullptr) ? true : false; + if (is_topmost_layer && loop_number > 0 && config->only_one_wall_top) loop_number = 0; // Orca: properly adjust offset for the outer wall if precise_outer_wall is enabled. ExPolygons last = offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution), @@ -1952,6 +1957,9 @@ void PerimeterGenerator::process_arachne() : -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); Arachne::WallToolPathsParams input_params = Arachne::make_paths_params(this->layer_id, *object_config, *print_config); + // Set params is_top_or_bottom_layer for adjusting short-wall removal sensitivity. + input_params.is_top_or_bottom_layer = (is_bottom_layer || is_topmost_layer) ? true : false; + coord_t wall_0_inset = 0; if (config->precise_outer_wall) wall_0_inset = -coord_t(ext_perimeter_width / 2 - ext_perimeter_spacing / 2); @@ -1959,29 +1967,45 @@ void PerimeterGenerator::process_arachne() std::vector out_shell; ExPolygons top_fills; ExPolygons fill_clip; - if (loop_number > 0 && config->only_one_wall_top && !surface.is_bridge() && this->upper_slices != nullptr) { - // Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces) - ExPolygons non_top_polygons; - this->split_top_surfaces(last, top_fills, non_top_polygons, fill_clip); - if (top_fills.empty()) { + // Check if we're on a top surface, and make adjustments where needed + if (!surface.is_bridge() && !is_topmost_layer) { + ExPolygons non_top_polygons; + // Temporary storage, in the event all we need to do is set is_top_or_bottom_layer + ExPolygons top_fills_tmp; + ExPolygons fill_clip_tmp; + // Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces) + this->split_top_surfaces(last, top_fills_tmp, non_top_polygons, fill_clip_tmp); + + if (top_fills_tmp.empty()) { // No top surfaces, no special handling needed } else { - // First we slice the outer shell - Polygons last_p = to_polygons(last); - Arachne::WallToolPaths wallToolPaths(last_p, bead_width_0, perimeter_spacing, coord_t(1), - wall_0_inset, layer_height, input_params); - out_shell = wallToolPaths.getToolPaths(); - // Make sure infill not overlap with wall - top_fills = intersection_ex(top_fills, wallToolPaths.getInnerContour()); + // Use single-wall on top-surfaces if configured + if (loop_number > 0 && config->only_one_wall_top) { + // Adjust arachne input params to prevent removal of larger short walls, which could lead to gaps + Arachne::WallToolPathsParams input_params_tmp = input_params; + input_params_tmp.is_top_or_bottom_layer = true; + + // Swap in the temporary storage + top_fills.swap(top_fills_tmp); + fill_clip.swap(fill_clip_tmp); + + // First we slice the outer shell + Polygons last_p = to_polygons(last); + Arachne::WallToolPaths wallToolPaths(last_p, bead_width_0, perimeter_spacing, coord_t(1), + wall_0_inset, layer_height, input_params_tmp); + out_shell = wallToolPaths.getToolPaths(); + // Make sure infill not overlap with wall + top_fills = intersection_ex(top_fills, wallToolPaths.getInnerContour()); - if (!top_fills.empty()) { - // Then get the inner part that needs more walls - last = intersection_ex(non_top_polygons, wallToolPaths.getInnerContour()); - loop_number--; - } else { - // Give up the outer shell because we don't have any meaningful top surface - out_shell.clear(); + if (!top_fills.empty()) { + // Then get the inner part that needs more walls + last = intersection_ex(non_top_polygons, wallToolPaths.getInnerContour()); + loop_number--; + } else { + // Give up the outer shell because we don't have any meaningful top surface + out_shell.clear(); + } } } } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index dba5cf05e5..519b7ee090 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -804,7 +804,7 @@ static std::vector s_Preset_print_options { "initial_layer_infill_speed", "only_one_wall_top", "timelapse_type", "wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", - "wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", + "wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "min_length_factor", "small_perimeter_speed", "small_perimeter_threshold","bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface", "default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk", "top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer", "print_flow_ratio", "seam_gap", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index cdf811b236..ed6d80aec5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4540,6 +4540,20 @@ def = this->add("filament_loading_speed", coFloats); def->min = 0; def->set_default_value(new ConfigOptionPercent(25)); + def = this->add("min_length_factor", coFloat); + def->label = L("Minimum wall length"); + def->category = L("Quality"); + def->tooltip = L("Adjust this value to prevent short, unclosed walls from being printed, which could increase print time. " + "Higher values remove more and longer walls.\n\n" + "NOTE: Bottom and top surfaces will not be affected by this value to prevent visual gaps on the ouside of the model. " + "Adjust 'One wall threshold' in the Advanced settings below to adjust the sensitivity of what is considered a top-surface. " + "'One wall threshold' is only visibile if this setting is set above the default value of 0.5, or if single-wall top surfaces is enabled."); + def->sidetext = L(""); + def->mode = comAdvanced; + def->min = 0.0; + def->max = 25.0; + def->set_default_value(new ConfigOptionFloat(0.5)); + def = this->add("initial_layer_min_bead_width", coPercent); def->label = L("First layer minimum wall width"); def->category = L("Quality"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 43a3a30eb2..41d8830ca6 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -784,6 +784,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionPercent, tree_support_top_rate)) ((ConfigOptionFloat, tree_support_branch_diameter_organic)) ((ConfigOptionFloat, tree_support_branch_angle_organic)) + ((ConfigOptionFloat, min_length_factor)) // Move all acceleration and jerk settings to object ((ConfigOptionFloat, default_acceleration)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 28c8c45cc4..9af5df80b6 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1127,6 +1127,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "wall_transition_angle" || opt_key == "wall_distribution_count" || opt_key == "min_feature_size" + || opt_key == "min_length_factor" || opt_key == "min_bead_width") { steps.emplace_back(posSlice); } else if ( diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2e0d224fde..aebb56f97c 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -90,13 +90,18 @@ std::vector get_extruders_colors() } float FullyTransparentMaterialThreshold = 0.1f; float FullTransparentModdifiedToFixAlpha = 0.3f; +float FULL_BLACK_THRESHOLD = 0.18f; Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) { if (colors.a() < FullyTransparentMaterialThreshold) { // completely transparent return {1, 1, 1, FullTransparentModdifiedToFixAlpha}; } - return colors; + else if(colors.r() < FULL_BLACK_THRESHOLD && colors.g() < FULL_BLACK_THRESHOLD && colors.b() < FULL_BLACK_THRESHOLD) { // black + return {FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, colors.a()}; + } + else + return colors; } namespace Slic3r { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 79ba0dc7b7..3a0b5fe390 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -695,7 +695,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", - "min_feature_size", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) + "min_feature_size", "min_length_factor", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) toggle_line(el, have_arachne); toggle_field("detect_thin_wall", !have_arachne); @@ -712,8 +712,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("make_overhang_printable_angle", have_make_overhang_printable); toggle_line("make_overhang_printable_hole_size", have_make_overhang_printable); - toggle_line("min_width_top_surface",config->opt_bool("only_one_wall_top")); - + toggle_line("min_width_top_surface", config->opt_bool("only_one_wall_top") || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value + for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" }) toggle_line(el, config->opt_bool("hole_to_polyhole")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 9f5e957982..fa13dd8316 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -2484,7 +2484,7 @@ bool GLGizmoEmboss::rev_checkbox(const std::string &name, // draw offseted input auto draw_offseted_input = [this, &offset = m_gui_cfg->advanced_input_offset, &name, &value](){ ImGui::SameLine(offset); - return m_imgui->bbl_checkbox(("##" + name).c_str(), value); + return m_imgui->bbl_checkbox(wxString::FromUTF8("##" + name), value); }; float undo_offset = ImGui::GetStyle().WindowPadding.x; return revertible(name, value, default_value, undo_tooltip, diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6f2ba8aef4..25c2096ad0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1975,6 +1975,7 @@ void TabPrint::build() optgroup->append_single_option_line("initial_layer_min_bead_width"); optgroup->append_single_option_line("min_bead_width"); optgroup->append_single_option_line("min_feature_size"); + optgroup->append_single_option_line("min_length_factor"); optgroup = page->new_optgroup(L("Walls and surfaces"), L"param_advanced"); optgroup->append_single_option_line("wall_sequence"); diff --git a/version.inc b/version.inc index ac8f089327..71abeaf37e 100644 --- a/version.inc +++ b/version.inc @@ -10,7 +10,7 @@ endif() if(NOT DEFINED BBL_INTERNAL_TESTING) set(BBL_INTERNAL_TESTING "0") endif() -set(SoftFever_VERSION "1.9.0-beta") +set(SoftFever_VERSION "2.0.0-dev") string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" SoftFever_VERSION_MATCH ${SoftFever_VERSION}) set(ORCA_VERSION_MAJOR ${CMAKE_MATCH_1})