diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index a5e8bd954..e603537f5 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1920,7 +1920,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou #endif } } - + // extrude all loops ccw //no! this was decided in perimeter_generator bool was_clockwise = false;// loop.make_counter_clockwise(); @@ -1934,7 +1934,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou Point last_pos = this->last_pos(); if (m_config.spiral_vase) { loop.split_at(last_pos, false); - } else if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear) { + } else if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear || seam_position == spHidden) { Polygon polygon = loop.polygon(); const coordf_t nozzle_dmr = EXTRUDER_CONFIG(nozzle_diameter); const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5); @@ -1949,11 +1949,18 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou last_pos_weight = 1.f; } break; + case spNearest: + last_pos_weight = 5.f; + break; case spRear: last_pos = m_layer->object()->bounding_box().center(); last_pos.y += coord_t(3. * m_layer->object()->bounding_box().radius()); last_pos_weight = 5.f; break; + case spHidden: + last_pos_weight = 0.1f; + break; + } // Insert a projection of last_pos into the polygon. @@ -1975,7 +1982,16 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou const float penaltySeam = 1.3f; const float penaltyOverhangHalf = 10.f; // Penalty for visible seams. - for (size_t i = 0; i < polygon.points.size(); ++ i) { + float dist_max = 0.1f * lengths.back();// 5.f * nozzle_dmr + if (this->config().seam_travel) { + dist_max = 0; + for (size_t i = 0; i < polygon.points.size(); ++i) { + dist_max = std::max(dist_max, (float)polygon.points[i].distance_to(last_pos_proj)); + } + } + //TODO: ignore the angle penalty if the new point is not in an external path (bot/top/ext_peri) + for (size_t i = 0; i < polygon.points.size(); ++i) { + //std::cout << "check point @" << unscale(polygon.points[i].x) << ":" << unscale(polygon.points[i].y); float ccwAngle = penalties[i]; if (was_clockwise) ccwAngle = - ccwAngle; @@ -1996,13 +2012,15 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // Interpolate penalty between maximum and the penalty for a convex vertex. penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle * float(PI * 2. / 3.)); } - // Give a negative penalty for points close to the last point or the prefered seam location. - //float dist_to_last_pos_proj = last_pos_proj.distance_to(polygon.points[i]); - float dist_to_last_pos_proj = (i < last_pos_proj_idx) ? - std::min(lengths[last_pos_proj_idx] - lengths[i], lengths.back() - lengths[last_pos_proj_idx] + lengths[i]) : - std::min(lengths[i] - lengths[last_pos_proj_idx], lengths.back() - lengths[i] + lengths[last_pos_proj_idx]); - float dist_max = 0.1f * lengths.back(); // 5.f * nozzle_dmr - penalty -= last_pos_weight * bspline_kernel(dist_to_last_pos_proj / dist_max); + if (this->config().seam_travel) { + penalty += last_pos_weight * polygon.points[i].distance_to(last_pos_proj) / dist_max; + }else{ + // Give a negative penalty for points close to the last point or the prefered seam location. + float dist_to_last_pos_proj = (i < last_pos_proj_idx) ? + std::min(lengths[last_pos_proj_idx] - lengths[i], lengths.back() - lengths[last_pos_proj_idx] + lengths[i]) : + std::min(lengths[i] - lengths[last_pos_proj_idx], lengths.back() - lengths[i] + lengths[last_pos_proj_idx]); + penalty -= last_pos_weight * bspline_kernel(dist_to_last_pos_proj / dist_max); + } penalties[i] = std::max(0.f, penalty); } diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index 87b031851..7f96dd523 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -45,9 +45,9 @@ public: int idx = -1; if (! this->points.empty()) { idx = 0; - double dist_min = this->points.front().distance_to(point); + double dist_min = this->points.front().distance_to_sq(point); for (int i = 1; i < int(this->points.size()); ++ i) { - double d = this->points[i].distance_to(point); + double d = this->points[i].distance_to_sq(point); if (d < dist_min) { dist_min = d; idx = i; diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index 7763fa159..5b50b9dad 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -644,10 +644,10 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( } PerimeterIntersectionPoint -get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) { +PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const { //find best points of intersections PerimeterIntersectionPoint intersect; - intersect.distance = 0x7FFFFFFF; + intersect.distance = 0x7FFFFFFF; // ! assumption on intersect type & max value intersect.idx_polyline_outter = -1; intersect.idx_children = -1; for (size_t idx_child = 0; idx_child < children.size(); idx_child++) { @@ -656,23 +656,54 @@ get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPoly if (myPolylines.paths[idx_poly].extruder_id == (unsigned int)-1) continue; if (myPolylines.paths[idx_poly].length() < dist_cut + SCALED_RESOLUTION) continue; - //first, try to find 2 point near enough - for (size_t idx_point = 0; idx_point < myPolylines.paths[idx_poly].polyline.points.size(); idx_point++) { - const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point]; - const Point &nearest_p = *child.polygon.closest_point(p); - const coord_t dist = (coord_t)nearest_p.distance_to(p); - if (dist + SCALED_EPSILON / 2 < intersect.distance) { - //ok, copy the idx - intersect.distance = dist; - intersect.idx_children = idx_child; - intersect.idx_polyline_outter = idx_poly; - intersect.outter_best = p; - intersect.child_best = nearest_p; + if ((myPolylines.paths[idx_poly].role() == erExternalPerimeter || child.is_external() ) + && this->object_config->seam_position.value != SeamPosition::spRandom) { + //first, try to find 2 point near enough + for (size_t idx_point = 0; idx_point < myPolylines.paths[idx_poly].polyline.points.size(); idx_point++) { + const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point]; + const Point &nearest_p = *child.polygon.closest_point(p); + const double dist = nearest_p.distance_to(p); + //Try to find a point in the far side, aligning them + if (dist + dist_cut / 20 < intersect.distance || + (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter <0 || p.y > intersect.outter_best.y) + && dist <= max_dist && intersect.distance + dist_cut / 20)) { + //ok, copy the idx + intersect.distance = (coord_t)nearest_p.distance_to(p); + intersect.idx_children = idx_child; + intersect.idx_polyline_outter = idx_poly; + intersect.outter_best = p; + intersect.child_best = nearest_p; + } + } + } else { + //first, try to find 2 point near enough + for (size_t idx_point = 0; idx_point < myPolylines.paths[idx_poly].polyline.points.size(); idx_point++) { + const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point]; + const Point &nearest_p = *child.polygon.closest_point(p); + const double dist = nearest_p.distance_to(p); + if (dist + SCALED_EPSILON < intersect.distance || + (config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter<0 || p.y < intersect.outter_best.y) + && dist <= max_dist && intersect.distance + dist_cut / 20)) { + //ok, copy the idx + intersect.distance = (coord_t)nearest_p.distance_to(p); + intersect.idx_children = idx_child; + intersect.idx_polyline_outter = idx_poly; + intersect.outter_best = p; + intersect.child_best = nearest_p; + } } } - if (intersect.distance <= max_dist) { - return intersect; - } + } + } + if (intersect.distance <= max_dist) { + return intersect; + } + + for (size_t idx_child = 0; idx_child < children.size(); idx_child++) { + const PerimeterGeneratorLoop &child = children[idx_child]; + for (size_t idx_poly = 0; idx_poly < myPolylines.paths.size(); idx_poly++) { + if (myPolylines.paths[idx_poly].extruder_id == (unsigned int)-1) continue; + if (myPolylines.paths[idx_poly].length() < dist_cut + SCALED_RESOLUTION) continue; //second, try to check from one of my points //don't check the last point, as it's used to go outter, can't use it to go inner. @@ -692,9 +723,18 @@ get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPoly intersect.child_best = nearest_p; } } - if (intersect.distance <= max_dist) { - return intersect; - } + } + } + if (intersect.distance <= max_dist) { + return intersect; + } + + for (size_t idx_child = 0; idx_child < children.size(); idx_child++) { + const PerimeterGeneratorLoop &child = children[idx_child]; + for (size_t idx_poly = 0; idx_poly < myPolylines.paths.size(); idx_poly++) { + if (myPolylines.paths[idx_poly].extruder_id == (unsigned int)-1) continue; + if (myPolylines.paths[idx_poly].length() < dist_cut + SCALED_RESOLUTION) continue; + //lastly, try to check from one of his points for (size_t idx_point = 0; idx_point < child.polygon.points.size(); idx_point++) { const Point &p = child.polygon.points[idx_point]; @@ -898,17 +938,14 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, //TODO change this->external_perimeter_flow.scaled_width() if it's the first one! const coord_t max_width_extrusion = this->perimeter_flow.scaled_width(); ExtrusionLoop my_loop = _extrude_and_cut_loop(loop, entry_point); - vector path_is_ccw; - - for (size_t idx_poly = 0; idx_poly < my_loop.paths.size(); idx_poly++) { - path_is_ccw.push_back(true); - } + int child_idx = 0; //Polylines myPolylines = { myPolyline }; //iterate on each point ot find the best place to go into the child vector childs = children; while (!childs.empty()) { - PerimeterIntersectionPoint nearest = get_nearest_point(childs, my_loop, this->perimeter_flow.scaled_width(), this->perimeter_flow.scaled_width()* 0.8); + child_idx++; + PerimeterIntersectionPoint nearest = this->_get_nearest_point(childs, my_loop, this->perimeter_flow.scaled_width(), this->perimeter_flow.scaled_width()* 1.42); if (nearest.idx_children == (size_t)-1) { //return ExtrusionEntityCollection(); break; @@ -920,9 +957,7 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, //PerimeterGeneratorLoops less_childs = childs; //less_childs.erase(less_childs.begin() + nearest.idx_children); //create new node with recursive ask for the inner perimeter & COPY of the points, ready to be cut - const bool cut_path_is_ccw = path_is_ccw[nearest.idx_polyline_outter]; my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, my_loop.paths[nearest.idx_polyline_outter]); - path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, cut_path_is_ccw); ExtrusionPath *outer_start = &my_loop.paths[nearest.idx_polyline_outter]; ExtrusionPath *outer_end = &my_loop.paths[nearest.idx_polyline_outter + 1]; @@ -981,7 +1016,6 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const size_t child_paths_size = child_loop.paths.size(); if (child_paths_size == 0) continue; my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, child_loop.paths.begin(), child_loop.paths.end()); - for (size_t i = 0; i < child_paths_size; i++) path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, !cut_path_is_ccw); //add paths into my_loop => need to re-get the refs outer_start = &my_loop.paths[nearest.idx_polyline_outter]; @@ -1005,8 +1039,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, else inner_start->polyline.clip_start(inner_start->polyline.length()/2); } else { - coord_t length_poly_1 = outer_start->polyline.length(); - coord_t length_poly_2 = outer_end->polyline.length(); + double length_poly_1 = outer_start->polyline.length(); + double length_poly_2 = outer_end->polyline.length(); coord_t length_trim_1 = outer_start_spacing / 2; coord_t length_trim_2 = outer_end_spacing / 2; if (length_poly_1 < length_trim_1) { @@ -1065,9 +1099,9 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, my_loop.paths[idx].reverse(); } outer_start = &my_loop.paths[nearest.idx_polyline_outter]; - outer_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size + 1]; inner_start = &my_loop.paths[nearest.idx_polyline_outter + 1]; inner_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size]; + outer_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size + 1]; } } @@ -1152,7 +1186,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, travel_path_end[0].polyline.append(outer_end->polyline.points.front()); } //check if we add path or reuse bits - if (outer_start->polyline.points.size() == 1) { + //FIXME + /*if (outer_start->polyline.points.size() == 1) { outer_start->polyline = travel_path_begin.front().polyline; travel_path_begin.erase(travel_path_begin.begin()); outer_start->extruder_id = -1; @@ -1160,15 +1195,13 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, outer_end->polyline = travel_path_end.back().polyline; travel_path_end.erase(travel_path_end.end() - 1); outer_end->extruder_id = -1; - } + }*/ //add paths into my_loop => after that all ref are wrong! for (int i = travel_path_end.size() - 1; i >= 0; i--) { my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + child_paths_size + 1, travel_path_end[i]); - path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + child_paths_size + 1, cut_path_is_ccw); } for (int i = travel_path_begin.size() - 1; i >= 0; i--) { my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, travel_path_begin[i]); - path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, cut_path_is_ccw); } } diff --git a/xs/src/libslic3r/PerimeterGenerator.hpp b/xs/src/libslic3r/PerimeterGenerator.hpp index 57d5f7d13..0aae5bdb1 100644 --- a/xs/src/libslic3r/PerimeterGenerator.hpp +++ b/xs/src/libslic3r/PerimeterGenerator.hpp @@ -103,6 +103,7 @@ private: ThickPolylines &thin_walls) const; ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const; ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const; + PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const; ExtrusionEntityCollection _variable_width (const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const; }; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index a77fbb15a..413f27dc2 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -400,13 +400,25 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionBool(false); def = this->add("perimeter_loop", coBool); - def->label = L("Looping perimeters"); + def->label = L(" "); def->category = L("Layers and Perimeters"); def->tooltip = L("Join the perimeters to create only one continuous extrusion without any z-hop." " Long inside travel (from external to holes) are not extruded to give some place to the infill."); def->cli = "loop-perimeter!"; def->default_value = new ConfigOptionBool(false); - + + def = this->add("perimeter_loop_seam", coEnum); + def->label = L("Seam position"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("Position of perimeters starting points."); + def->cli = "perimeter-seam-position=s"; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("nearest"); + def->enum_values.push_back("rear"); + def->enum_labels.push_back(L("Nearest")); + def->enum_labels.push_back(L("Rear")); + def->default_value = new ConfigOptionEnum(spRear); + def = this->add("extra_perimeters", coBool); def->label = L("Extra perimeters if needed"); def->category = L("Layers and Perimeters"); @@ -1600,12 +1612,21 @@ PrintConfigDef::PrintConfigDef() def->enum_values.push_back("nearest"); def->enum_values.push_back("aligned"); def->enum_values.push_back("rear"); + def->enum_values.push_back("hidden"); def->enum_labels.push_back(L("Random")); def->enum_labels.push_back(L("Nearest")); def->enum_labels.push_back(L("Aligned")); - def->enum_labels.push_back(L("Rear")); + def->enum_labels.push_back(L("Rear")); + def->enum_labels.push_back(L("Hidden")); def->default_value = new ConfigOptionEnum(spAligned); + def = this->add("seam_travel", coBool); + def->label = L("Travel move reduced"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("Add a big cost to travel paths when possible (when going into a loop), so it will prefer a less optimal seam posistion if it's nearer."); + def->cli = "seam-travel!"; + def->default_value = new ConfigOptionBool(false); + #if 0 def = this->add("seam_preferred_direction", coFloat); // def->gui_type = "slider"; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index d870786d6..56314a6e0 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -42,7 +42,7 @@ enum SupportMaterialPattern { }; enum SeamPosition { - spRandom, spNearest, spAligned, spRear + spRandom, spNearest, spAligned, spRear, spHidden }; enum FilamentType { @@ -120,6 +120,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum::get_enum keys_map["nearest"] = spNearest; keys_map["aligned"] = spAligned; keys_map["rear"] = spRear; + keys_map["hidden"] = spHidden; } return keys_map; } @@ -350,6 +351,7 @@ public: ConfigOptionFloat layer_height; ConfigOptionInt raft_layers; ConfigOptionEnum seam_position; + ConfigOptionBool seam_travel; // ConfigOptionFloat seam_preferred_direction; // ConfigOptionFloat seam_preferred_direction_jitter; ConfigOptionBool support_material; @@ -395,6 +397,7 @@ protected: OPT_PTR(layer_height); OPT_PTR(raft_layers); OPT_PTR(seam_position); + OPT_PTR(seam_travel); // OPT_PTR(seam_preferred_direction); // OPT_PTR(seam_preferred_direction_jitter); OPT_PTR(support_material); @@ -444,6 +447,7 @@ public: ConfigOptionFloatOrPercent external_perimeter_speed; ConfigOptionBool external_perimeters_first; ConfigOptionBool perimeter_loop; + ConfigOptionEnum perimeter_loop_seam; ConfigOptionBool extra_perimeters; ConfigOptionBool only_one_perimeter_top; ConfigOptionFloat fill_angle; @@ -499,6 +503,7 @@ protected: OPT_PTR(external_perimeter_speed); OPT_PTR(external_perimeters_first); OPT_PTR(perimeter_loop); + OPT_PTR(perimeter_loop_seam); OPT_PTR(extra_perimeters); OPT_PTR(only_one_perimeter_top); OPT_PTR(fill_angle); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 1425b8574..e9a4e1e2d 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -157,6 +157,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector::get_enum_values(); + for (auto it : map_names) { + if (val == it.second) { + key = it.first; + break; + } + } + + size_t idx = 0; + for (auto el : m_opt.enum_values) { + if (el.compare(key) == 0) + break; + ++idx; + } + + val = idx == m_opt.enum_values.size() ? 0 : idx; + } else + val = 3; + } dynamic_cast(window)->SetSelection(val); break; } @@ -588,10 +609,18 @@ boost::any& Choice::get_value() else if (m_opt_id.compare("gcode_flavor") == 0) m_value = static_cast(ret_enum); else if (m_opt_id.compare("support_material_pattern") == 0) - m_value = static_cast(ret_enum); - else if (m_opt_id.compare("seam_position") == 0) + m_value = static_cast(ret_enum); + else if (m_opt_id.compare("seam_position") == 0) m_value = static_cast(ret_enum); - else if (m_opt_id.compare("host_type") == 0) + else if (m_opt_id.compare("perimeter_loop_seam") == 0) { + if (!m_opt.enum_values.empty()) { + std::string key = m_opt.enum_values[ret_enum]; + t_config_enum_values map_names = ConfigOptionEnum::get_enum_values(); + int value = map_names.at(key); + m_value = static_cast(value); + } else + m_value = static_cast(3); + } else if (m_opt_id.compare("host_type") == 0) m_value = static_cast(ret_enum); else if (m_opt_id.compare("infill_dense_algo") == 0) m_value = static_cast(ret_enum); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index ff4ebd280..751af5d66 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -602,9 +602,9 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt else if (opt_key.compare("gcode_flavor") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("support_material_pattern") == 0) - config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); - else if (opt_key.compare("seam_position") == 0) - config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("seam_position") == 0 || opt_key.compare("perimeter_loop_seam") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("host_type") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("infill_dense_algo") == 0) diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp index 4c4595517..fe9310fba 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.cpp +++ b/xs/src/slic3r/GUI/OptionsGroup.cpp @@ -458,10 +458,10 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config } else if (opt_key.compare("support_material_pattern") == 0){ ret = static_cast(config.option>(opt_key)->value); - } - else if (opt_key.compare("seam_position") == 0){ - ret = static_cast(config.option>(opt_key)->value); - } + } + else if (opt_key.compare("seam_position") == 0 || opt_key.compare("perimeter_loop_seam") == 0) { + ret = static_cast(config.option>(opt_key)->value); + } else if (opt_key.compare("host_type") == 0){ ret = static_cast(config.option>(opt_key)->value); } diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index e3570fc6a..d0159dfb8 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -307,7 +307,7 @@ const std::vector& Preset::print_options() "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "only_one_perimeter_top", "single_extruder_multi_material_priming", "compatible_printers", "compatible_printers_condition", "inherits", "infill_dense", "infill_dense_algo", "no_perimeter_unsupported", "min_perimeter_unsupported", "noperi_bridge_only", - "support_material_solid_first_layer", "perimeter_loop" + "support_material_solid_first_layer", "perimeter_loop", "perimeter_loop_seam", "seam_travel" }; return s_opts; } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 18b556bff..ad7f235db 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -818,10 +818,16 @@ void TabPrint::build() line.append_option(optgroup->get_option("noperi_bridge_only")); optgroup->append_line(line); - optgroup = page->new_optgroup(_(L("Advanced"))); - optgroup->append_single_option_line("seam_position"); + optgroup = page->new_optgroup(_(L("Advanced"))); + line = { _(L("Avoid unsupported perimeters")), "" }; + line.append_option(optgroup->get_option("seam_position")); + line.append_option(optgroup->get_option("seam_travel")); + optgroup->append_line(line); optgroup->append_single_option_line("external_perimeters_first"); - optgroup->append_single_option_line("perimeter_loop"); + line = { _(L("Looping perimeter")), "" }; + line.append_option(optgroup->get_option("perimeter_loop")); + line.append_option(optgroup->get_option("perimeter_loop_seam")); + optgroup->append_line(line); page = add_options_page(_(L("Infill")), "infill.png"); optgroup = page->new_optgroup(_(L("Infill"))); @@ -1167,11 +1173,13 @@ void TabPrint::update() } } - bool have_perimeters = m_config->opt_int("perimeters") > 0; - for (auto el : {"extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", - "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", - "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop" }) - get_field(el)->toggle(have_perimeters); + bool have_perimeters = m_config->opt_int("perimeters") > 0; + for (auto el : { "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", + "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" }) + get_field(el)->toggle(have_perimeters); + + get_field("perimeter_loop_seam")->toggle(m_config->opt_bool("perimeter_loop")); bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported"); for (auto el : { "min_perimeter_unsupported", "noperi_bridge_only" })