Skip to content

Commit

Permalink
Various support improvements and bugfixes (#2202)
Browse files Browse the repository at this point in the history
* Organic supports: Added check for variable layer height, with which
Organic supports are not compatible.
Fixes prusa3d/PrusaSlicer#9528 and similar.
Check the object max Z against build volume Z in Print::validate().

Cherry-picked from prusa3d/PrusaSlicer@5b94971

* Fix crash with default tree support

* Show "support_critical_regions_only" only when using auto normal tree supports (#2195)

* Fix organic tree check

---------

Co-authored-by: Vojtech Bubnik <[email protected]>
  • Loading branch information
Noisyfox and bubnikv authored Sep 24, 2023
1 parent e93e517 commit 7ef43f6
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 27 deletions.
16 changes: 16 additions & 0 deletions src/libslic3r/Model.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral
///|/ Copyright (c) 2019 John Drake @foxox
///|/ Copyright (c) 2019 Sijmen Schoon
///|/ Copyright (c) 2017 Eyal Soha @eyal0
///|/ Copyright (c) Slic3r 2014 - 2015 Alessandro Ranellucci @alranel
///|/
///|/ ported from lib/Slic3r/Model.pm:
///|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966
///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#ifndef slic3r_Model_hpp_
#define slic3r_Model_hpp_

Expand Down Expand Up @@ -398,6 +410,10 @@ class ModelObject final : public ObjectBase
bool is_seam_painted() const;
// Checks if any of object volume is painted using the multi-material painting gizmo.
bool is_mm_painted() const;
// This object may have a varying layer height by painting or by a table.
// Even if true is returned, the layer height profile may be "flat" with no difference to default layering.
bool has_custom_layering() const
{ return ! this->layer_config_ranges.empty() || ! this->layer_height_profile.empty(); }

ModelInstance* add_instance();
ModelInstance* add_instance(const ModelInstance &instance);
Expand Down
91 changes: 76 additions & 15 deletions src/libslic3r/Print.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Matěna @lukasmatena, Tomáš Mészáros @tamasmeszaros, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Roman Beránek @zavorka, David Kocík @kocikdav
///|/ Copyright (c) BambuStudio 2023 manch1n @manch1n
///|/ Copyright (c) SuperSlicer 2023 Remi Durand @supermerill
///|/ Copyright (c) 2021 Martin Budden
///|/ Copyright (c) 2020 Paul Arden @ardenpm
///|/ Copyright (c) 2019 Thomas Moore
///|/ Copyright (c) 2019 Bryan Smith
///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2014 Petr Ledvina @ledvinap
///|/
///|/ ported from lib/Slic3r/Print.pm:
///|/ Copyright (c) Prusa Research 2016 - 2018 Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros
///|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2012 - 2013 Mark Hindess
///|/ Copyright (c) 2013 Devin Grady
///|/ Copyright (c) 2012 - 2013 Mike Sheldrake @mesheldrake
///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen
///|/ Copyright (c) 2012 Michael Moon
///|/ Copyright (c) 2011 Richard Goodwin
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "Exception.hpp"
#include "Print.hpp"
#include "BoundingBox.hpp"
Expand Down Expand Up @@ -1034,6 +1056,53 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
return {L("The spiral vase mode does not work when an object contains more than one materials."), nullptr, "spiral_mode"};
}

// Cache of layer height profiles for checking:
// 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports.
// 2) Whether layer height is constant for Organic supports.
// 3) Whether build volume Z is not violated.
std::vector<std::vector<coordf_t>> layer_height_profiles;
auto layer_height_profile = [this, &layer_height_profiles](const size_t print_object_idx) -> const std::vector<coordf_t>& {
const PrintObject &print_object = *m_objects[print_object_idx];
if (layer_height_profiles.empty())
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
std::vector<coordf_t> &profile = layer_height_profiles[print_object_idx];
if (profile.empty())
PrintObject::update_layer_height_profile(*print_object.model_object(), print_object.slicing_parameters(), profile);
return profile;
};

// Checks that the print does not exceed the max print height
for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx) {
const PrintObject &print_object = *m_objects[print_object_idx];
//FIXME It is quite expensive to generate object layers just to get the print height!
if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx));
! layers.empty() && layers.back() > this->config().printable_height + EPSILON) {
return
// Test whether the last slicing plane is below or above the print volume.
{ 0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().printable_height + EPSILON ?
format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name) :
format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) +
" " + _u8L("You might want to reduce the size of your model or change current print settings and retry.") };
}
}

// Some of the objects has variable layer height applied by painting or by a table.
bool has_custom_layering = std::find_if(m_objects.begin(), m_objects.end(),
[](const PrintObject *object) { return object->model_object()->has_custom_layering(); })
!= m_objects.end();

// Custom layering is not allowed for tree supports as of now.
for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx)
if (const PrintObject &print_object = *m_objects[print_object_idx];
print_object.has_support_material() && is_tree(print_object.config().support_type.value) && (print_object.config().support_style.value == smsOrganic ||
// Orca: use organic as default
print_object.config().support_style.value == smsDefault) &&
print_object.model_object()->has_custom_layering()) {
if (const std::vector<coordf_t> &layers = layer_height_profile(print_object_idx); ! layers.empty())
if (! check_object_layers_fixed(print_object.slicing_parameters(), layers))
return {_u8L("Variable layer height is not supported with Organic supports.") };
}

if (this->has_wipe_tower() && ! m_objects.empty()) {
// Make sure all extruders use same diameter filament and have the same nozzle diameter
// EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments
Expand Down Expand Up @@ -1081,19 +1150,8 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
#endif

if (m_objects.size() > 1) {
bool has_custom_layering = false;
std::vector<std::vector<coordf_t>> layer_height_profiles;
for (const PrintObject *object : m_objects) {
has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
if (has_custom_layering) {
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
break;
}
}
const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters();
size_t tallest_object_idx = 0;
if (has_custom_layering)
PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front());
size_t tallest_object_idx = 0;
for (size_t i = 1; i < m_objects.size(); ++ i) {
const PrintObject *object = m_objects[i];
const SlicingParameters &slicing_params = object->slicing_parameters();
Expand All @@ -1111,8 +1169,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
if (!equal_layering(slicing_params, slicing_params0))
return { L("The prime tower requires that all objects are sliced with the same layer heights."), object };
if (has_custom_layering) {
PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]);
if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2))
auto &lh = layer_height_profile(i);
auto &lh_tallest = layer_height_profile(tallest_object_idx);
if (*(lh.end() - 2) > *(lh_tallest.end() - 2))
tallest_object_idx = i;
}
}
Expand Down Expand Up @@ -1198,7 +1257,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*

// Prusa: Fixing crashes with invalid tip diameter or branch diameter
// https://github.com/prusa3d/PrusaSlicer/commit/96b3ae85013ac363cd1c3e98ec6b7938aeacf46d
if (object->config().support_style == smsOrganic) {
if (is_tree(object->config().support_type.value) && (object->config().support_style == smsOrganic ||
// Orca: use organic as default
object->config().support_style == smsDefault)) {
float extrusion_width = std::min(
support_material_flow(object).width(),
support_material_interface_flow(object).width());
Expand Down
16 changes: 15 additions & 1 deletion src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Hejl @hejllukas, Pavel Mikuš @Godrak, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Roman Beránek @zavorka
///|/ Copyright (c) 2021 Justin Schuh @jschuh
///|/ Copyright (c) 2021 Ilya @xorza
///|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens
///|/ Copyright (c) Slic3r 2014 - 2016 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "Exception.hpp"
#include "Print.hpp"
#include "BoundingBox.hpp"
Expand Down Expand Up @@ -2086,6 +2095,8 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
// use the constructor because the assignement is crashing on ASAN OsX
layer_height_profile = std::vector<coordf_t>(model_object.layer_height_profile.get());
// layer_height_profile = model_object.layer_height_profile;
// The layer height returned is sampled with high density for the UI layer height painting
// and smoothing tool to work.
updated = true;
}

Expand All @@ -2100,6 +2111,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
if (layer_height_profile.empty() || layer_height_profile[1] != slicing_parameters.first_object_layer_height) {
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
// The layer height profile is already compressed.
updated = true;
}

Expand Down Expand Up @@ -2539,7 +2551,9 @@ void PrintObject::_generate_support_material()
support_material.generate(*this);

if (this->config().enable_support.value && is_tree(this->config().support_type.value)) {
if (this->config().support_style.value == smsOrganic || this->config().support_style.value == smsDefault) {
if (this->config().support_style.value == smsOrganic ||
// Orca: use organic as default
this->config().support_style.value == smsDefault) {
fff_tree_support_generate(*this, std::function<void()>([this]() { this->throw_if_canceled(); }));
} else {
TreeSupport tree_support(*this, m_slicing_params);
Expand Down
40 changes: 39 additions & 1 deletion src/libslic3r/Slicing.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include <limits>

#include "libslic3r.h"
Expand Down Expand Up @@ -321,7 +325,7 @@ std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slici
print_z += height;
}

double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2];
double z_gap = slicing_params.object_print_z_height() - *(layer_height_profile.end() - 2);
if (z_gap > 0.0)
{
layer_height_profile.push_back(slicing_params.object_print_z_height());
Expand Down Expand Up @@ -685,6 +689,40 @@ std::vector<coordf_t> generate_object_layers(
return out;
}

// Check whether the layer height profile describes a fixed layer height profile.
bool check_object_layers_fixed(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layer_height_profile)
{
assert(layer_height_profile.size() >= 4);
assert(layer_height_profile.size() % 2 == 0);
assert(layer_height_profile[0] == 0);

if (layer_height_profile.size() != 4 && layer_height_profile.size() != 8)
return false;

bool fixed_step1 = is_approx(layer_height_profile[1], layer_height_profile[3]);
bool fixed_step2 = layer_height_profile.size() == 4 ||
(layer_height_profile[2] == layer_height_profile[4] && is_approx(layer_height_profile[5], layer_height_profile[7]));

if (! fixed_step1 || ! fixed_step2)
return false;

if (layer_height_profile[2] < 0.5 * slicing_params.first_object_layer_height + EPSILON ||
! is_approx(layer_height_profile[3], slicing_params.first_object_layer_height))
return false;

double z_max = layer_height_profile[layer_height_profile.size() - 2];
double z_2nd = slicing_params.first_object_layer_height + 0.5 * slicing_params.layer_height;
if (z_2nd > z_max)
return true;
if (z_2nd < *(layer_height_profile.end() - 4) + EPSILON ||
! is_approx(layer_height_profile.back(), slicing_params.layer_height))
return false;

return true;
}

int generate_layer_height_texture(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layers,
Expand Down
21 changes: 15 additions & 6 deletions src/libslic3r/Slicing.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Vojtěch Král @vojtechkral
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
// Based on implementation by @platsch

#ifndef slic3r_Slicing_hpp_
Expand Down Expand Up @@ -133,11 +137,11 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;

extern std::vector<coordf_t> layer_height_profile_from_ranges(
std::vector<coordf_t> layer_height_profile_from_ranges(
const SlicingParameters &slicing_params,
const t_layer_config_ranges &layer_config_ranges);

extern std::vector<double> layer_height_profile_adaptive(
std::vector<double> layer_height_profile_adaptive(
const SlicingParameters& slicing_params,
const ModelObject& object, float quality_factor);

Expand All @@ -150,7 +154,7 @@ struct HeightProfileSmoothingParams
HeightProfileSmoothingParams(unsigned int radius, bool keep_min) : radius(radius), keep_min(keep_min) {}
};

extern std::vector<double> smooth_height_profile(
std::vector<double> smooth_height_profile(
const std::vector<double>& profile, const SlicingParameters& slicing_params,
const HeightProfileSmoothingParams& smoothing_params);

Expand All @@ -161,7 +165,7 @@ enum LayerHeightEditActionType : unsigned int {
LAYER_HEIGHT_EDIT_ACTION_SMOOTH = 3
};

extern void adjust_layer_height_profile(
void adjust_layer_height_profile(
const SlicingParameters &slicing_params,
std::vector<coordf_t> &layer_height_profile,
coordf_t z,
Expand All @@ -171,14 +175,19 @@ extern void adjust_layer_height_profile(

// Produce object layers as pairs of low / high layer boundaries, stored into a linear vector.
// The object layers are based at z=0, ignoring the raft layers.
extern std::vector<coordf_t> generate_object_layers(
std::vector<coordf_t> generate_object_layers(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layer_height_profile);

// Check whether the layer height profile describes a fixed layer height profile.
bool check_object_layers_fixed(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layer_height_profile);

// Produce a 1D texture packed into a 2D texture describing in the RGBA format
// the planned object layers.
// Returns number of cells used by the texture of the 0th LOD level.
extern int generate_layer_height_texture(
int generate_layer_height_texture(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layers,
void *data, int rows, int cols, bool level_of_detail_2nd_level);
Expand Down
4 changes: 3 additions & 1 deletion src/libslic3r/Support/SupportCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,9 @@ void generate_support_toolpaths(
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
sheath = true;
no_sort = true;
} else if (config.support_style == SupportMaterialStyle::smsOrganic) {
} else if (config.support_style == SupportMaterialStyle::smsOrganic ||
// Orca: use organic as default
config.support_style == smsDefault) {
tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params);
done = true;
}
Expand Down
3 changes: 3 additions & 0 deletions src/libslic3r/Support/SupportMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,9 @@ class SupportGridPattern
case smsTreeSlim:
case smsTreeStrong:
case smsTreeHybrid:

// Orca: use organic as default
case smsDefault:
case smsOrganic:
// assert(false);
[[fallthrough]];
Expand Down
6 changes: 4 additions & 2 deletions src/libslic3r/Support/TreeSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3530,8 +3530,10 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
auto t_place = std::chrono::high_resolution_clock::now();

// ### draw these points as circles

if (print_object.config().support_style.value != smsOrganic)

if (print_object.config().support_style.value != smsOrganic &&
// Orca: use organic as default
print_object.config().support_style.value != smsDefault)
draw_areas(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds,
bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel);
else {
Expand Down
Loading

0 comments on commit 7ef43f6

Please sign in to comment.