Skip to content

Commit

Permalink
SPE-2186: Add shrinkage compensation into filament settings.
Browse files Browse the repository at this point in the history
There is a limitation that on multi-tool printers, all used filaments must have the same shrinkage compression values.
  • Loading branch information
hejllukas committed May 14, 2024
1 parent e14ba9d commit 4b8fe98
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 50 deletions.
15 changes: 15 additions & 0 deletions src/libslic3r/Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,21 @@ Transform3d Transformation::get_matrix_no_scaling_factor() const
return copy.get_matrix();
}

Transform3d Transformation::get_matrix_with_applied_shrinkage_compensation(const Vec3d &shrinkage_compensation) const {
const Transform3d shrinkage_trafo = Geometry::scale_transform(shrinkage_compensation);
const Vec3d trafo_offset = this->get_offset();
const Vec3d trafo_offset_xy = Vec3d(trafo_offset.x(), trafo_offset.y(), 0.);

Transformation copy(*this);
copy.set_offset(Axis::X, 0.);
copy.set_offset(Axis::Y, 0.);

Transform3d trafo_after_shrinkage = (shrinkage_trafo * copy.get_matrix());
trafo_after_shrinkage.translation() += trafo_offset_xy;

return trafo_after_shrinkage;
}

Transformation Transformation::operator * (const Transformation& other) const
{
return Transformation(get_matrix() * other.get_matrix());
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/Geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ class Transformation
Transform3d get_matrix_no_offset() const;
Transform3d get_matrix_no_scaling_factor() const;

Transform3d get_matrix_with_applied_shrinkage_compensation(const Vec3d &shrinkage_compensation) const;

void set_matrix(const Transform3d& transform) { m_matrix = transform; }

Transformation operator * (const Transformation& other) const;
Expand Down
16 changes: 16 additions & 0 deletions src/libslic3r/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,22 @@ void ModelVolume::convert_from_meters()
this->source.is_converted_from_meters = true;
}

std::vector<size_t> ModelVolume::get_extruders_from_multi_material_painting() const {
if (!this->is_mm_painted())
return {};

assert(static_cast<size_t>(TriangleStateType::Extruder1) - 1 == 0);
const TriangleSelector::TriangleSplittingData &data = this->mm_segmentation_facets.get_data();

std::vector<size_t> extruders;
for (size_t state_idx = static_cast<size_t>(TriangleStateType::Extruder1); state_idx < data.used_states.size(); ++state_idx) {
if (data.used_states[state_idx])
extruders.emplace_back(state_idx - 1);
}

return extruders;
}

void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
{
mesh->transform(dont_translate ? get_matrix_no_offset() : get_matrix());
Expand Down
3 changes: 3 additions & 0 deletions src/libslic3r/Model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,9 @@ class ModelVolume final : public ObjectBase
bool is_seam_painted() const { return !this->seam_facets.empty(); }
bool is_mm_painted() const { return !this->mm_segmentation_facets.empty(); }

// Returns 0-based indices of extruders painted by multi-material painting gizmo.
std::vector<size_t> get_extruders_from_multi_material_painting() const;

protected:
friend class Print;
friend class SLAPrint;
Expand Down
4 changes: 3 additions & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,9 @@ static std::vector<std::string> s_Preset_filament_options {
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", "filament_retract_length_toolchange", "filament_retract_restart_extra_toolchange", "filament_travel_ramping_lift",
"filament_travel_slope", "filament_travel_max_lift", "filament_travel_lift_before_obstacle",
// Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
// Shrinkage compensation
"filament_shrinkage_compensation_xy", "filament_shrinkage_compensation_z",
};

static std::vector<std::string> s_Preset_machine_limits_options {
Expand Down
60 changes: 53 additions & 7 deletions src/libslic3r/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
// Spiral Vase forces different kind of slicing than the normal model:
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
// Therefore toggling the Spiral Vase on / off requires complete reslicing.
|| opt_key == "spiral_vase") {
|| opt_key == "spiral_vase"
|| opt_key == "filament_shrinkage_compensation_xy"
|| opt_key == "filament_shrinkage_compensation_z") {
osteps.emplace_back(posSlice);
} else if (
opt_key == "complete_objects"
Expand Down Expand Up @@ -525,6 +527,9 @@ std::string Print::validate(std::vector<std::string>* warnings) const
goto DONE;
}
DONE:;

if (!this->has_same_shrinkage_compensations())
warnings->emplace_back("_FILAMENT_SHRINKAGE_DIFFER");
}

if (m_objects.empty())
Expand Down Expand Up @@ -584,12 +589,19 @@ std::string Print::validate(std::vector<std::string>* warnings) const
//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().max_print_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().max_print_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.");

const double shrinkage_compensation_z = this->shrinkage_compensation().z();
if (shrinkage_compensation_z != 1. && layers.back() > (this->config().max_print_height / shrinkage_compensation_z + EPSILON)) {
// The object exceeds the maximum build volume height because of shrinkage compensation.
return format(_u8L("While the object %1% itself fits the build volume, it exceeds the maximum build volume height because of material shrinkage compensation."), print_object.model_object()->name);
} else if (0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().max_print_height + EPSILON) {
// The last slicing plane is below the print volume.
return format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name);
} else {
// The last slicing plane is above the print volume.
return 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.");
}
}
}

Expand Down Expand Up @@ -1618,6 +1630,40 @@ std::string Print::output_filename(const std::string &filename_base) const
return this->PrintBase::output_filename(output_filename_format, ".gcode", filename_base, &config);
}

// Returns if all used filaments have same shrinkage compensations.
bool Print::has_same_shrinkage_compensations() const {
const std::vector<unsigned int> extruders = this->extruders();
if (extruders.empty())
return false;

const double filament_shrinkage_compensation_xy = m_config.filament_shrinkage_compensation_xy.get_at(extruders.front());
const double filament_shrinkage_compensation_z = m_config.filament_shrinkage_compensation_z.get_at(extruders.front());

for (unsigned int extruder : extruders) {
if (filament_shrinkage_compensation_xy != m_config.filament_shrinkage_compensation_xy.get_at(extruder) ||
filament_shrinkage_compensation_z != m_config.filament_shrinkage_compensation_z.get_at(extruder)) {
return false;
}
}

return true;
}

// Returns scaling for each axis representing shrinkage compensations in each axis.
Vec3d Print::shrinkage_compensation() const
{
if (!this->has_same_shrinkage_compensations())
return Vec3d::Ones();

const unsigned int first_extruder = this->extruders().front();
const double xy_compensation_percent = std::clamp(m_config.filament_shrinkage_compensation_xy.get_at(first_extruder), -99., 99.);
const double z_compensation_percent = std::clamp(m_config.filament_shrinkage_compensation_z.get_at(first_extruder), -99., 99.);
const double xy_compensation = 100. / (100. - xy_compensation_percent);
const double z_compensation = 100. / (100. - z_compensation_percent);

return { xy_compensation, xy_compensation, z_compensation };
}

const std::string PrintStatistics::FilamentUsedG = "filament used [g]";
const std::string PrintStatistics::FilamentUsedGMask = "; filament used [g] =";

Expand Down
8 changes: 7 additions & 1 deletion src/libslic3r/Print.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ class PrintObject : public PrintObjectBaseWithState<Print, PrintObjectStep, posC
// The slicing parameters are dependent on various configuration values
// (layer height, first layer height, raft settings, print nozzle diameter etc).
const SlicingParameters& slicing_parameters() const { return m_slicing_params; }
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z);
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z, const Vec3d &object_shrinkage_compensation);

size_t num_printing_regions() const throw() { return m_shared_regions->all_regions.size(); }
const PrintRegion& printing_region(size_t idx) const throw() { return *m_shared_regions->all_regions[idx].get(); }
Expand Down Expand Up @@ -665,6 +665,12 @@ class Print : public PrintBaseWithState<PrintStep, psCount>
const Polygons& get_sequential_print_clearance_contours() const { return m_sequential_print_clearance_contours; }
static bool sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons = nullptr);

// Returns if all used filaments have same shrinkage compensations.
bool has_same_shrinkage_compensations() const;

// Returns scaling for each axis representing shrinkage compensations in each axis.
Vec3d shrinkage_compensation() const;

protected:
// Invalidates the step, and its depending steps in Print.
bool invalidate_step(PrintStep step);
Expand Down
7 changes: 4 additions & 3 deletions src/libslic3r/PrintApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,14 @@ struct PrintObjectTrafoAndInstances
};

// Generate a list of trafos and XY offsets for instances of a ModelObject
static std::vector<PrintObjectTrafoAndInstances> print_objects_from_model_object(const ModelObject &model_object)
static std::vector<PrintObjectTrafoAndInstances> print_objects_from_model_object(const ModelObject &model_object, const Vec3d &shrinkage_compensation)
{
std::set<PrintObjectTrafoAndInstances> trafos;
PrintObjectTrafoAndInstances trafo;
for (ModelInstance *model_instance : model_object.instances)
if (model_instance->is_printable()) {
trafo.trafo = model_instance->get_matrix();
Geometry::Transformation model_instance_transformation = model_instance->get_transformation();
trafo.trafo = model_instance_transformation.get_matrix_with_applied_shrinkage_compensation(shrinkage_compensation);
auto shift = Point::new_scale(trafo.trafo.data()[12], trafo.trafo.data()[13]);
// Reset the XY axes of the transformation.
trafo.trafo.data()[12] = 0;
Expand Down Expand Up @@ -1281,7 +1282,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// Walk over all new model objects and check, whether there are matching PrintObjects.
for (ModelObject *model_object : m_model.objects) {
ModelObjectStatus &model_object_status = const_cast<ModelObjectStatus&>(model_object_status_db.reuse(*model_object));
model_object_status.print_instances = print_objects_from_model_object(*model_object);
model_object_status.print_instances = print_objects_from_model_object(*model_object, this->shrinkage_compensation());
std::vector<const PrintObjectStatus*> old;
old.reserve(print_object_status_db.count(*model_object));
for (const PrintObjectStatus &print_object_status : print_object_status_db.get_range(*model_object))
Expand Down
22 changes: 22 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,28 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionString(L("(Unknown)")));
def->cli = ConfigOptionDef::nocli;

def = this->add("filament_shrinkage_compensation_xy", coPercents);
def->label = L("Shrinkage XY");
def->tooltip = L("Enter your filament shrinkage percentages for the X and Y axes here to apply scaling of the object to "
"compensate for shrinkage in the X and Y axes. For example, if you measured 99mm instead of 100mm, "
"then you should put here 1%.");
def->sidetext = L("%");
def->mode = comAdvanced;
def->min = -10.;
def->max = 10.;
def->set_default_value(new ConfigOptionPercents { 0 });

def = this->add("filament_shrinkage_compensation_z", coPercents);
def->label = L("Shrinkage Z");
def->tooltip = L("Enter your filament shrinkage percentages for the Z axis here to apply scaling of the object to "
"compensate for shrinkage in the Z axis. For example, if you measured 99mm instead of 100mm, "
"then you should put here 1%.");
def->sidetext = L("%");
def->mode = comAdvanced;
def->min = -10.;
def->max = 10.;
def->set_default_value(new ConfigOptionPercents { 0. });

def = this->add("fill_angle", coFloat);
def->label = L("Fill angle");
def->category = L("Infill");
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, filament_multitool_ramming_flow))
((ConfigOptionFloats, filament_stamping_loading_speed))
((ConfigOptionFloats, filament_stamping_distance))
((ConfigOptionPercents, filament_shrinkage_compensation_xy))
((ConfigOptionPercents, filament_shrinkage_compensation_z))
((ConfigOptionBool, gcode_comments))
((ConfigOptionEnum<GCodeFlavor>, gcode_flavor))
((ConfigOptionEnum<LabelObjectsStyle>, gcode_label_objects))
Expand Down
20 changes: 10 additions & 10 deletions src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2620,15 +2620,14 @@ PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &defau
return config;
}

void PrintObject::update_slicing_parameters()
{
if (!m_slicing_params.valid)
m_slicing_params = SlicingParameters::create_from_config(
this->print()->config(), m_config, this->model_object()->max_z(), this->object_extruders());
void PrintObject::update_slicing_parameters() {
if (!m_slicing_params.valid) {
m_slicing_params = SlicingParameters::create_from_config(this->print()->config(), m_config, this->model_object()->max_z(),
this->object_extruders(), this->print()->shrinkage_compensation());
}
}

SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
{
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z, const Vec3d &object_shrinkage_compensation) {
PrintConfig print_config;
PrintObjectConfig object_config;
PrintRegionConfig default_region_config;
Expand Down Expand Up @@ -2661,7 +2660,8 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full

if (object_max_z <= 0.f)
object_max_z = (float)model_object.raw_bounding_box().size().z();
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);

return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders, object_shrinkage_compensation);
}

// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
Expand All @@ -2682,7 +2682,6 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
if (layer_height_profile.empty()) {
// use the constructor because the assignement is crashing on ASAN OsX
layer_height_profile = 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 @@ -2693,8 +2692,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
// Must not be of even length.
((layer_height_profile.size() & 1) != 0 ||
// Last entry must be at the top of the object.
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max + slicing_parameters.object_print_z_min) > 1e-3))
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_uncompensated_max + slicing_parameters.object_print_z_min) > 1e-3)) {
layer_height_profile.clear();
}

if (layer_height_profile.empty()) {
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
Expand Down
Loading

0 comments on commit 4b8fe98

Please sign in to comment.