diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index fdc17c1ff6..5717aa0bb3 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -517,6 +517,7 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector Polygon { - const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth); + const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, m_wipe_tower_cone_angle); - double r = std::tan(Geometry::deg2rad(15.)) * (m_wipe_tower_height - m_layer_info->z); + double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle/2.f)) * (m_wipe_tower_height - m_layer_info->z); Vec2f center = (wt_box.lu + wt_box.rd) / 2.; double w = wt_box.lu.y() - wt_box.ld.y(); enum Type { @@ -1320,10 +1321,9 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() } // Static method to get the radius and x-scaling of the stabilizing cone base. -std::pair WipeTower::get_wipe_tower_cone_base(double width, double height, double depth) +std::pair WipeTower::get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg) { - const double angle_deg = 15.; - double R = std::tan(Geometry::deg2rad(angle_deg)) * height; + double R = std::tan(Geometry::deg2rad(angle_deg/2.)) * height; double fake_width = 0.66 * width; double diag = std::hypot(fake_width / 2., depth / 2.); double support_scale = 1.; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index e23c6645f4..15b07f3d8c 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -23,7 +23,7 @@ class WipeTower public: static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; } - static std::pair get_wipe_tower_cone_base(double width, double height, double depth); + static std::pair get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg); struct Extrusion { @@ -257,6 +257,7 @@ private: float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower float m_wipe_tower_height = 0.f; + float m_wipe_tower_cone_angle = 0.f; float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index d9ed8af968..b364271752 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -460,7 +460,7 @@ static std::vector s_Preset_print_options { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", + "wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", "wipe_tower_no_sparse_layers", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits", "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "wall_distribution_count", "min_feature_size", "min_bead_width" diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 9d9f46cfff..f2143857ae 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -205,6 +205,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wipe_tower" || opt_key == "wipe_tower_width" || opt_key == "wipe_tower_brim_width" + || opt_key == "wipe_tower_cone_angle" || opt_key == "wipe_tower_bridging" || opt_key == "wipe_tower_extra_spacing" || opt_key == "wipe_tower_no_sparse_layers" @@ -1150,7 +1151,7 @@ std::vector Print::first_layer_wipe_tower_corners() const // Now the stabilization cone. Vec2d center = (pts[0] + pts[2])/2.; - const auto [cone_R, cone_x_scale] = WipeTower::get_wipe_tower_cone_base(m_config.wipe_tower_width, m_wipe_tower_data.height, m_wipe_tower_data.depth); + const auto [cone_R, cone_x_scale] = WipeTower::get_wipe_tower_cone_base(m_config.wipe_tower_width, m_wipe_tower_data.height, m_wipe_tower_data.depth, m_config.wipe_tower_cone_angle); double r = cone_R + m_wipe_tower_data.brim_width; for (double alpha = 0.; alpha<2*M_PI; alpha += M_PI/20.) pts.emplace_back(center + r*Vec2d(std::cos(alpha)/cone_x_scale, std::sin(alpha))); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fcb78bc53c..68e27f4d1f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3150,6 +3150,16 @@ void PrintConfigDef::init_fff_params() def->min = 0.; def->set_default_value(new ConfigOptionFloat(2.)); + def = this->add("wipe_tower_cone_angle", coFloat); + def->label = L("Stabilization cone apex angle"); + def->tooltip = L("Angle at the apex of the cone that is used to stabilize the wipe tower. " + "Larger angle means wider base."); + def->sidetext = L("°"); + def->mode = comAdvanced; + def->min = 0.; + def->max = 90.; + def->set_default_value(new ConfigOptionFloat(0.)); + def = this->add("wipe_tower_extra_spacing", coPercent); def->label = L("Wipe tower purge lines spacing"); def->tooltip = L("Spacing of purge lines on the wipe tower."); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 4027eef362..52924bf91f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -823,6 +823,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, wipe_tower_per_color_wipe)) ((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, wipe_tower_brim_width)) + ((ConfigOptionFloat, wipe_tower_cone_angle)) ((ConfigOptionPercent, wipe_tower_extra_spacing)) ((ConfigOptionFloat, wipe_tower_bridging)) ((ConfigOptionFloats, wiping_volumes_matrix)) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4659bf0f07..f5cf9de7a2 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -480,11 +480,11 @@ int GLVolumeCollection::load_object_volume( #if ENABLE_OPENGL_ES int GLVolumeCollection::load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh) #else int GLVolumeCollection::load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width) #endif // ENABLE_OPENGL_ES { @@ -545,16 +545,18 @@ int GLVolumeCollection::load_wipe_tower_preview( mesh.merge(brim_mesh); // Now the stabilization cone and its base. - const auto [R, scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth); - TriangleMesh cone_mesh(its_make_cone(R, height)); - cone_mesh.scale(Vec3f(1.f/scale_x, 1.f, 1.f)); + const auto [R, scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle); + if (R > 0.) { + TriangleMesh cone_mesh(its_make_cone(R, height)); + cone_mesh.scale(Vec3f(1.f/scale_x, 1.f, 1.f)); - TriangleMesh disk_mesh(its_make_cylinder(R, brim_height)); - disk_mesh.scale(Vec3f(1. / scale_x, 1., 1.)); // Now it matches the base, which may be elliptic. - disk_mesh.scale(Vec3f(1.f + scale_x*brim_width/R, 1.f + brim_width/R, 1.f)); // Scale so the brim is not deformed. - cone_mesh.merge(disk_mesh); - cone_mesh.translate(width / 2., depth / 2., 0.); - mesh.merge(cone_mesh); + TriangleMesh disk_mesh(its_make_cylinder(R, brim_height)); + disk_mesh.scale(Vec3f(1. / scale_x, 1., 1.)); // Now it matches the base, which may be elliptic. + disk_mesh.scale(Vec3f(1.f + scale_x*brim_width/R, 1.f + brim_width/R, 1.f)); // Scale so the brim is not deformed. + cone_mesh.merge(disk_mesh); + cone_mesh.translate(width / 2., depth / 2., 0.); + mesh.merge(cone_mesh); + } volumes.emplace_back(new GLVolume(color)); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 9791a0fafb..d685d64897 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -424,10 +424,10 @@ public: #if ENABLE_OPENGL_ES int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); #else int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width); #endif // ENABLE_OPENGL_ES GLVolume* new_toolpath_volume(const ColorRGBA& rgba); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 5312d52ec1..1bc2280d5f 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -319,7 +319,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("standby_temperature_delta", have_ooze_prevention); bool have_wipe_tower = config->opt_bool("wipe_tower"); - for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" }) toggle_field(el, have_wipe_tower); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 74f7bf50e1..62d4314dbf 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2253,7 +2253,7 @@ void GCodeViewer::load_shells(const Print& print) const WipeTowerData& wipe_tower_data = print.wipe_tower_data(extruders_count); const float depth = wipe_tower_data.depth; const float brim_width = wipe_tower_data.brim_width; - m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, + m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_cone_angle, config.wipe_tower_rotation_angle, !print.is_step_done(psWipeTower), brim_width); } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e369e0f400..6924667e6b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2035,17 +2035,18 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; const float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; const float bw = dynamic_cast(m_config->option("wipe_tower_brim_width"))->value; + const float ca = dynamic_cast(m_config->option("wipe_tower_cone_angle"))->value; const Print *print = m_process->fff_print(); const float depth = print->wipe_tower_data(extruders_count).depth; #if ENABLE_OPENGL_ES int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), + x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower), bw, &m_wipe_tower_mesh); #else int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), + x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower), bw); #endif // ENABLE_OPENGL_ES if (volume_idx_wipe_tower_old != -1) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6ecfa23391..6a17c4ee5a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2016,7 +2016,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "brim_width", "brim_separation", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material", - "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_extra_spacing", + "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "extruder_colour", "filament_colour", "material_colour", "max_print_height", "printer_model", "printer_technology", // These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor. "layer_height", "first_layer_height", "min_layer_height", "max_layer_height", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3f479030bc..6e4f64a99e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1602,6 +1602,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_brim_width"); optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("wipe_tower_cone_angle"); optgroup->append_single_option_line("wipe_tower_extra_spacing"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("single_extruder_multi_material_priming");