New parameter "Slicing Mode" for supporting 3DLabPrint airplane models.

S3D's strategy for merging self intersecting models is "Even / Odd"
which PrusaSlicer now supports as an alternative to "Positive" rule.
Also added a "Close Holes" option to fill in all internal structures.
3D-Labprint Models aren't sliceable (till years) #3062 #3708
This commit is contained in:
Vojtech Bubnik 2021-06-01 11:10:12 +02:00
parent df87f1b929
commit 20ba7c0a1f
12 changed files with 96 additions and 33 deletions

View file

@ -487,8 +487,8 @@ Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons
{ return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ApplySafetyOffset::No); }
template <typename TSubject, typename TClip>
static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset)
{ return PolyTreeToExPolygons(_clipper_do_polytree2(clipType, std::forward<TSubject>(subject), std::forward<TClip>(clip), ClipperLib::pftNonZero, do_safety_offset)); }
static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset, ClipperLib::PolyFillType fill_type = ClipperLib::pftPositive)
{ return PolyTreeToExPolygons(_clipper_do_polytree2(clipType, std::forward<TSubject>(subject), std::forward<TClip>(clip), fill_type, do_safety_offset)); }
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
@ -531,8 +531,9 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
{ return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); }
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject)
{ return _clipper_ex(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); }
// May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative).
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
{ return _clipper_ex(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No, fill_type); }
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject)
{ return PolyTreeToExPolygons(_clipper_do_polytree2(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); }
Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject)

View file

@ -356,7 +356,8 @@ inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r::
Slic3r::Polygons union_(const Slic3r::Polygons &subject);
Slic3r::Polygons union_(const Slic3r::ExPolygons &subject);
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2);
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject);
// May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative).
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type = ClipperLib::pftPositive);
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject);
Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject);

View file

@ -416,7 +416,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
const std::vector<std::string>& Preset::print_options()
{
static std::vector<std::string> s_opts {
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius",
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
"extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
@ -543,6 +543,7 @@ const std::vector<std::string>& Preset::sla_print_options()
"support_points_density_relative",
"support_points_minimal_distance",
"slice_closing_radius",
"slicing_mode",
"pad_enable",
"pad_wall_thickness",
"pad_wall_height",

View file

@ -116,6 +116,13 @@ static t_config_enum_values s_keys_map_IroningType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(IroningType)
static t_config_enum_values s_keys_map_SlicingMode {
{ "regular", int(SlicingMode::Regular) },
{ "even_odd", int(SlicingMode::EvenOdd) },
{ "close_holes", int(SlicingMode::CloseHoles) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SlicingMode)
static t_config_enum_values s_keys_map_SupportMaterialPattern {
{ "rectilinear", smpRectilinear },
{ "rectilinear-grid", smpRectilinearGrid },
@ -235,16 +242,6 @@ void PrintConfigDef::init_common_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(200.0));
def = this->add("slice_closing_radius", coFloat);
def->label = L("Slice gap closing radius");
def->category = L("Advanced");
def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. "
"The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.049));
def = this->add("print_host", coString);
def->label = L("Hostname, IP or URL");
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
@ -2359,6 +2356,30 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("slice_closing_radius", coFloat);
def->label = L("Slice gap closing radius");
def->category = L("Advanced");
def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. "
"The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.049));
def = this->add("slicing_mode", coEnum);
def->label = L("Slicing Mode");
def->category = L("Advanced");
def->tooltip = L("Use \"Even / Odd\" for 3DLabPrint airplane models. Use \"Close holes\" to close all holes in the model.");
def->enum_keys_map = &ConfigOptionEnum<SlicingMode>::get_enum_values();
def->enum_values.push_back("regular");
def->enum_values.push_back("even_odd");
def->enum_values.push_back("close_holes");
def->enum_labels.push_back(L("Regular"));
def->enum_labels.push_back(L("Even / Odd"));
def->enum_labels.push_back(L("Close holes"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SlicingMode>(SlicingMode::Regular));
def = this->add("support_material", coBool);
def->label = L("Generate support material");
def->category = L("Support material");

View file

@ -69,6 +69,16 @@ enum class IroningType {
Count,
};
enum class SlicingMode
{
// Regular, applying ClipperLib::pftPositive rule when creating ExPolygons.
Regular,
// Compatible with 3DLabPrint models, applying ClipperLib::pftEvenOdd rule when creating ExPolygons.
EvenOdd,
// Orienting all contours CCW, thus closing all holes.
CloseHoles,
};
enum SupportMaterialPattern {
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
};
@ -123,6 +133,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AuthorizationType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern)
@ -453,6 +464,7 @@ PRINT_CONFIG_CLASS_DEFINE(
// ((ConfigOptionFloat, seam_preferred_direction))
// ((ConfigOptionFloat, seam_preferred_direction_jitter))
((ConfigOptionFloat, slice_closing_radius))
((ConfigOptionEnum<SlicingMode>, slicing_mode))
((ConfigOptionBool, support_material))
// Automatic supports (generated based on support_material_threshold).
((ConfigOptionBool, support_material_auto))
@ -758,6 +770,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionInt, faded_layers))/*= 10*/
((ConfigOptionFloat, slice_closing_radius))
((ConfigOptionEnum<SlicingMode>, slicing_mode))
// Enabling or disabling support creation
((ConfigOptionBool, supports_enable))

View file

@ -525,7 +525,8 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "mmu_segmented_region_max_width"
|| opt_key == "raft_layers"
|| opt_key == "raft_contact_distance"
|| opt_key == "slice_closing_radius") {
|| opt_key == "slice_closing_radius"
|| opt_key == "slicing_mode") {
steps.emplace_back(posSlice);
} else if (
opt_key == "clip_multipart_objects"

View file

@ -169,6 +169,14 @@ static std::vector<VolumeSlices> slice_volumes_inner(
params_base.trafo = object_trafo;
params_base.resolution = print_config.resolution.value;
switch (print_object_config.slicing_mode.value) {
case SlicingMode::Regular: params_base.mode = MeshSlicingParams::SlicingMode::Regular; break;
case SlicingMode::EvenOdd: params_base.mode = MeshSlicingParams::SlicingMode::EvenOdd; break;
case SlicingMode::CloseHoles: params_base.mode = MeshSlicingParams::SlicingMode::Positive; break;
}
params_base.mode_below = params_base.mode;
const auto extra_offset = std::max(0.f, float(print_object_config.xy_size_compensation.value));
for (const ModelVolume *model_volume : model_volumes)
@ -184,7 +192,6 @@ static std::vector<VolumeSlices> slice_volumes_inner(
params.mode = MeshSlicingParams::SlicingMode::PositiveLargestContour;
// Slice the bottom layers with SlicingMode::Regular.
// This needs to be in sync with LayerRegion::make_perimeters() spiral_vase!
params.mode_below = MeshSlicingParams::SlicingMode::Regular;
const PrintRegionConfig &region_config = it->region->config();
params.slicing_mode_normal_below_layer = size_t(region_config.bottom_solid_layers.value);
for (; params.slicing_mode_normal_below_layer < zs.size() && zs[params.slicing_mode_normal_below_layer] < region_config.bottom_solid_min_thickness - EPSILON;

View file

@ -930,10 +930,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|| opt_key == "support_object_elevation"
|| opt_key == "pad_around_object"
|| opt_key == "pad_around_object_everywhere"
|| opt_key == "slice_closing_radius") {
|| opt_key == "slice_closing_radius"
|| opt_key == "slicing_mode") {
steps.emplace_back(slaposObjectSlice);
} else if (
opt_key == "support_points_density_relative"
|| opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints);

View file

@ -472,11 +472,17 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
po.m_model_height_levels.emplace_back(it->slice_level());
po.m_model_slices.clear();
float closing_r = float(po.config().slice_closing_radius.value);
MeshSlicingParamsEx params;
params.closing_radius = float(po.config().slice_closing_radius.value);
switch (po.config().slicing_mode.value) {
case SlicingMode::Regular: params.mode = MeshSlicingParams::SlicingMode::Regular; break;
case SlicingMode::EvenOdd: params.mode = MeshSlicingParams::SlicingMode::EvenOdd; break;
case SlicingMode::CloseHoles: params.mode = MeshSlicingParams::SlicingMode::Positive; break;
}
auto thr = [this]() { m_print->throw_if_canceled(); };
auto &slice_grid = po.m_model_height_levels;
assert(mesh.has_shared_vertices());
po.m_model_slices = slice_mesh_ex(mesh.its, slice_grid, closing_r, thr);
po.m_model_slices = slice_mesh_ex(mesh.its, slice_grid, params, thr);
sla::Interior *interior = po.m_hollowing_data ?
po.m_hollowing_data->interior.get() :
@ -486,7 +492,8 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
TriangleMesh interiormesh = sla::get_mesh(*interior);
interiormesh.repaired = false;
interiormesh.repair(true);
std::vector<ExPolygons> interior_slices = slice_mesh_ex(interiormesh.its, slice_grid, closing_r, thr);
params.mode = MeshSlicingParams::SlicingMode::Regular;
std::vector<ExPolygons> interior_slices = slice_mesh_ex(interiormesh.its, slice_grid, params, thr);
sla::ccr::for_each(size_t(0), interior_slices.size(),
[&po, &interior_slices] (size_t i) {

View file

@ -967,7 +967,7 @@ static ExPolygons make_expolygons_simple(std::vector<IntersectionLine> &lines)
return slices;
}
static void make_expolygons(const Polygons &loops, const float closing_radius, const float extra_offset, ExPolygons* slices)
static void make_expolygons(const Polygons &loops, const float closing_radius, const float extra_offset, ClipperLib::PolyFillType fill_type, ExPolygons* slices)
{
/*
Input loops are not suitable for evenodd nor nonzero fill types, as we might get
@ -1049,10 +1049,10 @@ static void make_expolygons(const Polygons &loops, const float closing_radius, c
// append to the supplied collection
expolygons_append(*slices,
offset_out > 0 && offset_in < 0 ? offset2_ex(union_ex(loops), offset_out, offset_in) :
offset_out > 0 ? offset_ex(union_ex(loops), offset_out) :
offset_in < 0 ? offset_ex(union_ex(loops), offset_in) :
union_ex(loops));
offset_out > 0 && offset_in < 0 ? offset2_ex(union_ex(loops, fill_type), offset_out, offset_in) :
offset_out > 0 ? offset_ex(union_ex(loops, fill_type), offset_out) :
offset_in < 0 ? offset_ex(union_ex(loops, fill_type), offset_in) :
union_ex(loops, fill_type));
}
std::vector<Polygons> slice_mesh(
@ -1175,9 +1175,13 @@ std::vector<ExPolygons> slice_mesh_ex(
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
throw_on_cancel();
ExPolygons &expolygons = layers[layer_id];
Slic3r::make_expolygons(layers_p[layer_id], params.closing_radius, params.extra_offset, &expolygons);
//FIXME simplify
const auto this_mode = layer_id < params.slicing_mode_normal_below_layer ? params.mode_below : params.mode;
Slic3r::make_expolygons(
layers_p[layer_id], params.closing_radius, params.extra_offset,
this_mode == MeshSlicingParams::SlicingMode::EvenOdd ? ClipperLib::pftEvenOdd :
this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour ? ClipperLib::pftNonZero : ClipperLib::pftPositive,
&expolygons);
//FIXME simplify
if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour)
keep_largest_contour_only(expolygons);
if (resolution != 0.)

View file

@ -12,8 +12,13 @@ struct MeshSlicingParams
{
enum class SlicingMode : uint32_t {
// Regular slicing, maintain all contours and their orientation.
// slice_mesh_ex() applies ClipperLib::pftPositive rule to the result of slice_mesh().
Regular,
// Maintain all contours, orient all contours CCW, therefore all holes are being closed.
// For slicing 3DLabPrints plane models (aka to be compatible with S3D default strategy).
// slice_mesh_ex() applies ClipperLib::pftEvenOdd rule. slice_mesh() slices EvenOdd as Regular.
EvenOdd,
// Maintain all contours, orient all contours CCW.
// slice_mesh_ex() applies ClipperLib::pftPositive rule, thus holes will be closed.
Positive,
// Orient all contours CCW and keep only the contour with the largest area.
// This mode is useful for slicing complex objects in vase mode.

View file

@ -1610,6 +1610,7 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Slicing"));
optgroup->append_single_option_line("slice_closing_radius");
optgroup->append_single_option_line("slicing_mode");
optgroup->append_single_option_line("resolution");
optgroup->append_single_option_line("xy_size_compensation");
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");
@ -4318,6 +4319,7 @@ void TabSLAPrint::build()
page = add_options_page(L("Advanced"), "wrench");
optgroup = page->new_optgroup(L("Slicing"));
optgroup->append_single_option_line("slice_closing_radius");
optgroup->append_single_option_line("slicing_mode");
page = add_options_page(L("Output options"), "output+page_white");
optgroup = page->new_optgroup(L("Output file"));