Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions src/libslic3r/Arachne/PerimeterOrder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,10 @@ static std::vector<size_t> order_of_grouped_perimeter_extrusions_to_minimize_dis
return grouped_extrusions_order;
}

static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterExtrusions &sorted_perimeter_extrusions, const bool external_perimeters_first) {
static PerimeterExtrusions extract_ordered_perimeter_extrusions(
const PerimeterExtrusions &sorted_perimeter_extrusions,
const PerimeterGenerator::Parameters &params
) {
// Extrusions are ordered inside each group.
std::vector<GroupedPerimeterExtrusions> grouped_extrusions;

Expand Down Expand Up @@ -260,8 +263,28 @@ static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterE
}
}

if (!external_perimeters_first)
std::reverse(grouped_extrusions.back().extrusions.begin(), grouped_extrusions.back().extrusions.end());
// Make the order inner->outer by default.
// This causes a potential double reverse, but this way the conditions are consistent with
// the classic perimeter generator
std::reverse(
grouped_extrusions.back().extrusions.begin(), grouped_extrusions.back().extrusions.end()
);
// if brim will be printed, reverse the order of perimeters so that
// we continue inwards after having finished the brim
const bool first_layer_with_brim = params.layer_id == 0 &&
params.object_config.brim_width.value > 0 &&
params.object_config.brim_separation == 0 && params.object_config.brim_type != btNoBrim;
if (params.config.perimeters_order == PerimetersOrder::OuterInner || first_layer_with_brim)
std::reverse(
grouped_extrusions.back().extrusions.begin(),
grouped_extrusions.back().extrusions.end()
);
if (params.config.perimeters_order == PerimetersOrder::InnerOuterInner &&
!first_layer_with_brim && grouped_extrusions.back().extrusions.size() > 1)
std::swap(
*std::prev(grouped_extrusions.back().extrusions.end(), 1),
*std::prev(grouped_extrusions.back().extrusions.end(), 2)
);
}

const std::vector<size_t> grouped_extrusion_order = order_of_grouped_perimeter_extrusions_to_minimize_distances(grouped_extrusions, Point::Zero());
Expand All @@ -277,11 +300,13 @@ static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterE

// FIXME: From the point of better patch planning, it should be better to do ordering when we have generated all extrusions (for now, when G-Code is exported).
// FIXME: It would be better to extract the adjacency graph of extrusions from the SkeletalTrapezoidation graph.
PerimeterExtrusions ordered_perimeter_extrusions(const Perimeters &perimeters, const bool external_perimeters_first) {
PerimeterExtrusions ordered_perimeter_extrusions(
const Perimeters &perimeters, const PerimeterGenerator::Parameters &params
) {
PerimeterExtrusions sorted_perimeter_extrusions = get_sorted_perimeter_extrusions_by_area(perimeters);
construct_perimeter_extrusions_adjacency_graph(sorted_perimeter_extrusions);
assign_nearest_external_perimeter(sorted_perimeter_extrusions);
return extract_ordered_perimeter_extrusions(sorted_perimeter_extrusions, external_perimeters_first);
return extract_ordered_perimeter_extrusions(sorted_perimeter_extrusions, params);
}

} // namespace Slic3r::Arachne::PerimeterOrder
5 changes: 4 additions & 1 deletion src/libslic3r/Arachne/PerimeterOrder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>
#include <cstddef>

#include "libslic3r/PerimeterGenerator.hpp"
#include "libslic3r/Arachne/utils/ExtrusionLine.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/Polygon.hpp"
Expand Down Expand Up @@ -44,7 +45,9 @@ struct PerimeterExtrusion

using PerimeterExtrusions = std::vector<PerimeterExtrusion>;

PerimeterExtrusions ordered_perimeter_extrusions(const Perimeters &perimeters, bool external_perimeters_first);
PerimeterExtrusions ordered_perimeter_extrusions(
const Perimeters &perimeters, const PerimeterGenerator::Parameters &params
);

} // namespace Slic3r::Arachne::PerimeterOrder

Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/GCode/SeamPlacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
*outter_scarf_start_point
};

if (region->config().external_perimeters_first.value) {
if (region->config().perimeters_order.value != PerimetersOrder::InnerOuter) {
const auto external_first_offset_direction{
offset_direction == Geometry::Direction1D::forward ?
Geometry::Direction1D::backward :
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ inline bool has_compatible_layer_regions(const PrintRegionConfig &config, const
config.overhangs == other_config.overhangs &&
config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width") &&
config.thin_walls == other_config.thin_walls &&
config.external_perimeters_first == other_config.external_perimeters_first &&
config.perimeters_order == other_config.perimeters_order &&
config.infill_overlap == other_config.infill_overlap &&
has_compatible_dynamic_overhang_speed(config, other_config);
}
Expand Down
13 changes: 10 additions & 3 deletions src/libslic3r/PerimeterGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,8 @@ void PerimeterGenerator::process_arachne(
return true;
}());

Arachne::PerimeterOrder::PerimeterExtrusions ordered_extrusions = Arachne::PerimeterOrder::ordered_perimeter_extrusions(perimeters, params.config.external_perimeters_first);
Arachne::PerimeterOrder::PerimeterExtrusions ordered_extrusions =
Arachne::PerimeterOrder::ordered_perimeter_extrusions(perimeters, params);

if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty())
out_loops.append(extrusion_coll);
Expand Down Expand Up @@ -1452,9 +1453,15 @@ void PerimeterGenerator::process_classic(
// if brim will be printed, reverse the order of perimeters so that
// we continue inwards after having finished the brim
// TODO: add test for perimeter order
if (params.config.external_perimeters_first ||
(params.layer_id == 0 && params.object_config.brim_width.value > 0))
const bool first_layer_with_brim = params.layer_id == 0 &&
params.object_config.brim_width.value > 0 &&
params.object_config.brim_separation == 0 && params.object_config.brim_type != btNoBrim;
if (params.config.perimeters_order == PerimetersOrder::OuterInner || first_layer_with_brim)
entities.reverse();
if (params.config.perimeters_order == PerimetersOrder::InnerOuterInner &&
!first_layer_with_brim && entities.size() > 1)
std::swap(*std::prev(entities.end(), 1), *std::prev(entities.end(), 2));

// append perimeters for this slice as a collection
if (! entities.empty())
out_loops.append(entities);
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ static std::vector<std::string> s_Preset_print_options {
"ensure_vertical_shell_thickness", "extra_perimeters", "extra_perimeters_on_overhangs",
"avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"seam_position", "staggered_inner_seams", "seam_gap_distance",
"external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
"perimeters_order", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
"scarf_seam_placement", "scarf_seam_only_on_smooth", "scarf_seam_start_height", "scarf_seam_entire_loop", "scarf_seam_length", "scarf_seam_max_segment_length", "scarf_seam_on_inner_perimeters",
"infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle",
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
Expand Down
31 changes: 26 additions & 5 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,13 @@ static const t_config_enum_values s_keys_map_ForwardCompatibilitySubstitutionRul
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule)

static t_config_enum_values s_keys_map_PerimetersOrder {
{"inner_outer", int(PerimetersOrder::InnerOuter)},
{"outer_inner", int(PerimetersOrder::OuterInner)},
{"inner_outer_inner", int(PerimetersOrder::InnerOuterInner)}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimetersOrder)

static t_config_enum_values s_keys_map_PerimeterGeneratorType {
{ "classic", int(PerimeterGeneratorType::Classic) },
{ "arachne", int(PerimeterGeneratorType::Arachne) }
Expand Down Expand Up @@ -1157,13 +1164,20 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(50, true));

def = this->add("external_perimeters_first", coBool);
def->label = L("External perimeters first");
def = this->add("perimeters_order", coEnum);
def->label = L("Perimeters order");
def->category = L("Layers and Perimeters");
def->tooltip = L("Print contour perimeters from the outermost one to the innermost one "
"instead of the default inverse order.");
def->tooltip = L(
"Determines printing order of the contour perimeters. If the number of perimeters is less "
"than three, the Inner>Outer>Inner option behaves like Outer>Inner"
);
def->set_enum<PerimetersOrder>(
{{"inner_outer", L("Inner>Outer")},
{"outer_inner", L("Outer>Inner")},
{"inner_outer_inner", L("Inner>Outer>Inner")}}
);
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def->set_default_value(new ConfigOptionEnum<PerimetersOrder>(PerimetersOrder::InnerOuter));

def = this->add("extra_perimeters", coBool);
def->label = L("Extra perimeters if needed");
Expand Down Expand Up @@ -5363,6 +5377,13 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
// Values other than 0/1 are replaced with "partial" for handling values from different slicers.
value = "partial";
}
} else if (opt_key == "external_perimeters_first") {
opt_key = "perimeters_order";
if (value == "0") {
value = "inner_outer";
} else {
value = "outer_inner";
}
}

// In PrusaSlicer 2.3.0-alpha0 the "monotonous" infill was introduced, which was later renamed to "monotonic".
Expand Down
9 changes: 8 additions & 1 deletion src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ enum class LabelObjectsStyle {
Disabled, Octoprint, Firmware
};

enum class PerimetersOrder
{
InnerOuter,
OuterInner,
InnerOuterInner
};

enum class PerimeterGeneratorType
{
// Classic perimeter generator using Clipper offsets with constant extrusion width.
Expand Down Expand Up @@ -754,7 +761,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloatOrPercent, overhang_speed_1))
((ConfigOptionFloatOrPercent, overhang_speed_2))
((ConfigOptionFloatOrPercent, overhang_speed_3))
((ConfigOptionBool, external_perimeters_first))
((ConfigOptionEnum<PerimetersOrder>, perimeters_order))
((ConfigOptionBool, extra_perimeters))
((ConfigOptionBool, extra_perimeters_on_overhangs))
((ConfigOptionFloat, fill_angle))
Expand Down
4 changes: 3 additions & 1 deletion src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ bool PrintObject::invalidate_state_by_config_options(
if ( opt_key == "brim_width"
|| opt_key == "brim_separation"
|| opt_key == "brim_type") {
// Brim can affect the first layer perimeters order so they have to be invalidated
steps.emplace_back(posPerimeters);
steps.emplace_back(posSupportSpotsSearch);
// Brim is printed below supports, support invalidates brim and skirt.
steps.emplace_back(posSupportMaterial);
Expand All @@ -730,7 +732,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "first_layer_extrusion_width"
|| opt_key == "perimeter_extrusion_width"
|| opt_key == "infill_overlap"
|| opt_key == "external_perimeters_first"
|| opt_key == "perimeters_order"
|| opt_key == "arc_fitting"
|| opt_key == "top_one_perimeter_type"
|| opt_key == "only_one_perimeter_first_layer") {
Expand Down
2 changes: 1 addition & 1 deletion src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
{
bool have_perimeters = config->opt_int("perimeters") > 0;
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "thin_walls", "overhangs",
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
"seam_position","staggered_inner_seams", "perimeters_order", "external_perimeter_extrusion_width",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds"})
toggle_field(el, have_perimeters);

Expand Down
2 changes: 1 addition & 1 deletion src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,7 @@ void TabPrint::build()
optgroup->append_single_option_line("scarf_seam_max_segment_length", scarf_seam_path + "max-scarf-joint-segment-length");
optgroup->append_single_option_line("scarf_seam_on_inner_perimeters", scarf_seam_path + "scarf-joint-on-inner-perimeters");

optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first");
optgroup->append_single_option_line("perimeters_order", category_path + "perimeters-order");
optgroup->append_single_option_line("gap_fill_enabled", category_path + "fill-gaps");
optgroup->append_single_option_line("perimeter_generator");

Expand Down