Skip to content
Closed
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
15 changes: 15 additions & 0 deletions src/libslic3r/ClipperUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,13 @@ Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Pol
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
//Orca
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset)
{
Slic3r::ExPolygons clip_temp;
clip_temp.push_back(clip);
return diff_ex(subject, clip_temp, do_safety_offset);
}

Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Expand All @@ -788,6 +795,10 @@ 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); }
//Orca
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset);}

// 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); }
Expand All @@ -803,6 +814,10 @@ Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject, const Slic3r::Pol
{ return PolyTreeToExPolygons(clipper_do_polytree(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ClipperLib::pftNonZero)); }
Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject)
{ return PolyTreeToExPolygons(clipper_do_polytree(ClipperLib::ctUnion, ClipperUtils::SurfacesProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); }
//Orca
Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset) {
return _clipper_ex(ClipperLib::ctXor, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset);
}

template<typename PathsProvider1, typename PathsProvider2>
Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip)
Expand Down
9 changes: 9 additions & 0 deletions src/libslic3r/ClipperUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,9 @@ Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surf
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
//Orca
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);

Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
Expand Down Expand Up @@ -482,6 +485,9 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
//Orca
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);

Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
Expand Down Expand Up @@ -522,6 +528,9 @@ Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject);
ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject);
ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject);

//Orca
Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);

Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject);

ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes);
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
static std::vector<std::string> s_Preset_print_options {
"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", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"extra_perimeters", "extra_perimeters_on_overhangs", "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
"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
2 changes: 2 additions & 0 deletions src/libslic3r/Print.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ class PrintObject : public PrintObjectBaseWithState<Print, PrintObjectStep, posC

std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> m_adaptive_fill_octrees;
FillLightning::GeneratorPtr m_lightning_generator;
//Orca
void apply_conical_overhang();
};


Expand Down
29 changes: 29 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3482,6 +3482,35 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloatOrPercent(85, true));

def = this->add("make_overhang_printable", coBool);
def->label = L("Make overhang printable");
def->category = L("Advanced");
def->tooltip = L("Modify the geometry to print overhangs without support material. Disabling modifier must include the object full horizontal dimensions.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));

def = this->add("make_overhang_printable_angle", coFloat);
def->label = L("Make overhang printable maximum angle");
def->category = L("Advanced");
def->tooltip = L("Maximum angle of overhangs to allow after making more steep overhangs printable."
"90° will not change the model at all and allow any overhang, while 0 will "
"replace all overhangs with conical material.");
def->sidetext = L("°");
def->mode = comAdvanced;
def->min = 0.;
def->max = 90.;
def->set_default_value(new ConfigOptionFloat(55.));

def = this->add("make_overhang_printable_hole_size", coFloat);
def->label = L("Make overhang printable hole area");
def->category = L("Advanced");
def->tooltip = L("Maximum area of a hole in the base of the model before it's filled by conical material."
"A value of 0 will fill all the holes in the model base.");
def->sidetext = L("mm²");
def->mode = comAdvanced;
def->min = 0.;
def->set_default_value(new ConfigOptionFloat(0.));

// Declare retract values for filament profile, overriding the printer's extruder profile.
for (const char *opt_key : {
// floats
Expand Down
5 changes: 5 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,9 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, thick_bridges))
((ConfigOptionFloat, xy_size_compensation))
((ConfigOptionBool, wipe_into_objects))
// Orca
((ConfigOptionFloat, make_overhang_printable_angle))
((ConfigOptionFloat, make_overhang_printable_hole_size))
)

PRINT_CONFIG_CLASS_DEFINE(
Expand Down Expand Up @@ -662,6 +665,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, top_solid_min_thickness))
((ConfigOptionFloatOrPercent, top_solid_infill_speed))
((ConfigOptionBool, wipe_into_infill))
// Orca
((ConfigOptionBool, make_overhang_printable))
)

PRINT_CONFIG_CLASS_DEFINE(
Expand Down
5 changes: 4 additions & 1 deletion src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,10 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "raft_layers"
|| opt_key == "raft_contact_distance"
|| opt_key == "slice_closing_radius"
|| opt_key == "slicing_mode") {
|| opt_key == "slicing_mode"
|| opt_key == "make_overhang_printable"
|| opt_key == "make_overhang_printable_angle"
|| opt_key == "make_overhang_printable_hole_size") {
steps.emplace_back(posSlice);
} else if (
opt_key == "elefant_foot_compensation"
Expand Down
105 changes: 105 additions & 0 deletions src/libslic3r/PrintObjectSlice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,9 @@ void PrintObject::slice_volumes()
apply_mm_segmentation(*this, [print]() { print->throw_if_canceled(); });
}

//Orca
this->apply_conical_overhang();
m_print->throw_if_canceled();

BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";
{
Expand Down Expand Up @@ -826,6 +829,108 @@ void PrintObject::slice_volumes()
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - end";
}

//Orca
void PrintObject::apply_conical_overhang() {
BOOST_LOG_TRIVIAL(info) << "Make overhang printable...";

if (m_layers.empty()) {
return;
}

const double conical_overhang_angle = this->config().make_overhang_printable_angle;
if (conical_overhang_angle == 90.0) {
return;
}
const double angle_radians = conical_overhang_angle * M_PI / 180.;
const double max_hole_area = this->config().make_overhang_printable_hole_size; // in MM^2
const double tan_angle = tan(angle_radians); // the XY-component of the angle
BOOST_LOG_TRIVIAL(info) << "angle " << angle_radians << " maxHoleArea " << max_hole_area << " tan_angle "
<< tan_angle;
const coordf_t layer_thickness = m_config.layer_height.value;
const coordf_t max_dist_from_lower_layer = tan_angle * layer_thickness; // max dist which can be bridged, in MM
BOOST_LOG_TRIVIAL(info) << "layer_thickness " << layer_thickness << " max_dist_from_lower_layer "
<< max_dist_from_lower_layer;

// Pre-scale config
const coordf_t scaled_max_dist_from_lower_layer = -float(scale_(max_dist_from_lower_layer));
const coordf_t scaled_max_hole_area = float(scale_(scale_(max_hole_area)));


for (auto i = m_layers.rbegin() + 1; i != m_layers.rend(); ++i) {
m_print->throw_if_canceled();
Layer *layer = *i;
Layer *upper_layer = layer->upper_layer;

if (upper_layer == nullptr || upper_layer->empty()) {
continue;
}

// Skip if entire layer has this disabled
if (std::all_of(layer->m_regions.begin(), layer->m_regions.end(),
[](const LayerRegion *r) { return r->slices().empty() || !r->region().config().make_overhang_printable; })) {
continue;
}

//layer->export_region_slices_to_svg_debug("layer_before_conical_overhang");
//upper_layer->export_region_slices_to_svg_debug("upper_layer_before_conical_overhang");


// Merge the upper layer because we want to offset the entire layer uniformly, otherwise
// the model could break at the region boundary.
auto upper_poly = upper_layer->merged(float(SCALED_EPSILON));
upper_poly = union_ex(upper_poly);

// Avoid closing up of recessed holes in the base of a model.
// Detects when a hole is completely covered by the layer above and removes the hole from the layer above before
// adding it in.
// This should have no effect any time a hole in a layer interacts with any polygon in the layer above
if (scaled_max_hole_area > 0.0) {
// Merge layer for the same reason
auto current_poly = layer->merged(float(SCALED_EPSILON));
current_poly = union_ex(current_poly);

// Now go through all the holes in the current layer and check if they intersect anything in the layer above
// If not, then they're the top of a hole and should be cut from the layer above before the union
for (auto layer_polygon : current_poly) {
for (auto hole : layer_polygon.holes) {
if (std::abs(hole.area()) < scaled_max_hole_area) {
ExPolygon hole_poly(hole);
auto hole_with_above = intersection_ex(upper_poly, hole_poly);
if (!hole_with_above.empty()) {
// The hole had some intersection with the above layer, check if it's a complete overlap
auto hole_difference = xor_ex(hole_with_above, hole_poly);
if (hole_difference.empty()) {
// The layer above completely cover it, remove it from the layer above
upper_poly = diff_ex(upper_poly, hole_poly);
}
}
}
}
}
}

// Now offset the upper layer to be added into current layer
upper_poly = offset_ex(upper_poly, scaled_max_dist_from_lower_layer);

for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
// export_to_svg(debug_out_path("Surface-obj-%d-layer-%d-region-%d.svg", id().id, layer->id(), region_id).c_str(),
// layer->m_regions[region_id]->slices.surfaces);

// Disable on given region
if (!upper_layer->m_regions[region_id]->region().config().make_overhang_printable) {
continue;
}

// Calculate the scaled upper poly that belongs to current region
auto p = intersection_ex(upper_layer->m_regions[region_id]->slices().surfaces, upper_poly);
// And now union it
ExPolygons layer_polygons = to_expolygons(layer->m_regions[region_id]->slices().surfaces);
layer->m_regions[region_id]->m_slices.set(union_ex(layer_polygons, p), stInternal);
}
//layer->export_region_slices_to_svg_debug("layer_after_conical_overhang");
}
}

std::vector<Polygons> PrintObject::slice_support_volumes(const ModelVolumeType model_volume_type) const
{
auto it_volume = this->model_object()->volumes.begin();
Expand Down
4 changes: 4 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("min_feature_size", have_arachne);
toggle_field("min_bead_width", have_arachne);
toggle_field("thin_walls", !have_arachne);
//Orca
bool have_make_overhang_printable = config->opt_bool("make_overhang_printable");
toggle_field("make_overhang_printable_angle", have_make_overhang_printable);
toggle_field("make_overhang_printable_hole_size", have_make_overhang_printable);
}

void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
Expand Down
5 changes: 5 additions & 0 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,11 @@ void TabPrint::build()
optgroup->append_single_option_line("xy_size_compensation");
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");

optgroup = page->new_optgroup(L("Overhangs"));
optgroup->append_single_option_line("make_overhang_printable");
optgroup->append_single_option_line("make_overhang_printable_angle");
optgroup->append_single_option_line("make_overhang_printable_hole_size");

optgroup = page->new_optgroup(L("Arachne perimeter generator"));
optgroup->append_single_option_line("wall_transition_angle");
optgroup->append_single_option_line("wall_transition_filter_deviation");
Expand Down