mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-05 16:51:07 -07:00
Porting curling calculations from Prusa Slier 2.6.1
This commit is contained in:
parent
f30a18d658
commit
19ca3ee715
6 changed files with 152 additions and 108 deletions
|
|
@ -46,6 +46,13 @@ public:
|
|||
~ExtrusionEntityCollection() { clear(); }
|
||||
explicit operator ExtrusionPaths() const;
|
||||
|
||||
ExtrusionEntitiesPtr::const_iterator cbegin() const { return this->entities.cbegin(); }
|
||||
ExtrusionEntitiesPtr::const_iterator cend() const { return this->entities.cend(); }
|
||||
ExtrusionEntitiesPtr::const_iterator begin() const { return this->entities.cbegin(); }
|
||||
ExtrusionEntitiesPtr::const_iterator end() const { return this->entities.cend(); }
|
||||
ExtrusionEntitiesPtr::iterator begin() { return this->entities.begin(); }
|
||||
ExtrusionEntitiesPtr::iterator end() { return this->entities.end(); }
|
||||
|
||||
bool is_collection() const override { return true; }
|
||||
ExtrusionRole role() const override {
|
||||
ExtrusionRole out = erNone;
|
||||
|
|
@ -112,6 +119,7 @@ public:
|
|||
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
|
||||
{ Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
|
||||
size_t items_count() const;
|
||||
size_t size() const { return entities.size(); }
|
||||
/// Returns a flattened copy of this ExtrusionEntityCollection. That is, all of the items in its entities vector are not collections.
|
||||
/// You should be iterating over flatten().entities if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy).
|
||||
/// \param preserve_ordering Flag to method that will flatten if and only if the underlying collection is sortable when True (default: False).
|
||||
|
|
|
|||
|
|
@ -1693,6 +1693,7 @@ void Print::process(bool use_cache)
|
|||
PrintObject* obj = m_objects[i];
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
obj->generate_support_material();
|
||||
obj->estimate_curled_extrusions();
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posSupportMaterial))
|
||||
|
|
@ -1723,6 +1724,7 @@ void Print::process(bool use_cache)
|
|||
obj->infill();
|
||||
obj->ironing();
|
||||
obj->generate_support_material();
|
||||
obj->estimate_curled_extrusions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ enum PrintStep {
|
|||
|
||||
enum PrintObjectStep {
|
||||
posSlice, posPerimeters, posPrepareInfill,
|
||||
posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifySupportPath,
|
||||
posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifySupportPath, posEstimateCurledExtrusions,
|
||||
// BBS
|
||||
posSimplifyInfill,
|
||||
posDetectOverhangsForLift,
|
||||
|
|
@ -468,6 +468,7 @@ private:
|
|||
void infill();
|
||||
void ironing();
|
||||
void generate_support_material();
|
||||
void estimate_curled_extrusions();
|
||||
void simplify_extrusion_path();
|
||||
|
||||
void slice_volumes();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "Layer.hpp"
|
||||
#include "MutablePolygon.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "SupportSpotsGenerator.hpp"
|
||||
#include "Support/TreeSupport.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include "Slicing.hpp"
|
||||
|
|
@ -498,6 +499,25 @@ void PrintObject::generate_support_material()
|
|||
}
|
||||
}
|
||||
|
||||
void PrintObject::estimate_curled_extrusions()
|
||||
{
|
||||
if (this->set_started(posEstimateCurledExtrusions)) {
|
||||
if ( std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(),
|
||||
[](const PrintRegion *region) { return region->config().enable_overhang_speed.getBool(); })) {
|
||||
|
||||
// Estimate curling of support material and add it to the malformaition lines of each layer
|
||||
float support_flow_width = support_material_flow(this, this->config().layer_height).width();
|
||||
SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values,
|
||||
float(this->print()->m_config.inner_wall_acceleration.getFloat()),
|
||||
this->config().raft_layers.getInt(), this->config().brim_type.value,
|
||||
float(this->config().brim_width.getFloat())};
|
||||
SupportSpotsGenerator::estimate_malformations(this->layers(), params);
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
this->set_done(posEstimateCurledExtrusions);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintObject::simplify_extrusion_path()
|
||||
{
|
||||
if (this->set_started(posSimplifyPath)) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "SupportSpotsGenerator.hpp"
|
||||
/*
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
#include "libslic3r/Color.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExtrusionLine
|
||||
|
|
@ -85,6 +86,112 @@ namespace SupportSpotsGenerator {
|
|||
|
||||
using LD = AABBTreeLines::LinesDistancer<ExtrusionLine>;
|
||||
|
||||
float get_flow_width(const LayerRegion *region, ExtrusionRole role)
|
||||
{
|
||||
if (role == ExtrusionRole::erBridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width();
|
||||
if (role == ExtrusionRole::erExternalPerimeter) return region->flow(FlowRole::frExternalPerimeter).width();
|
||||
if (role == ExtrusionRole::erGapFill) return region->flow(FlowRole::frInfill).width();
|
||||
if (role == ExtrusionRole::erPerimeter) return region->flow(FlowRole::frPerimeter).width();
|
||||
if (role == ExtrusionRole::erSolidInfill) return region->flow(FlowRole::frSolidInfill).width();
|
||||
if (role == ExtrusionRole::erInternalInfill) return region->flow(FlowRole::frInfill).width();
|
||||
if (role == ExtrusionRole::erTopSolidInfill) return region->flow(FlowRole::frTopSolidInfill).width();
|
||||
// default
|
||||
return region->flow(FlowRole::frPerimeter).width();
|
||||
}
|
||||
|
||||
float estimate_curled_up_height(
|
||||
float distance, float curvature, float layer_height, float flow_width, float prev_line_curled_height, Params params)
|
||||
{
|
||||
float curled_up_height = 0;
|
||||
if (fabs(distance) < 3.0 * flow_width) {
|
||||
curled_up_height = std::max(prev_line_curled_height - layer_height * 0.75f, 0.0f);
|
||||
}
|
||||
|
||||
if (distance > params.malformation_distance_factors.first * flow_width &&
|
||||
distance < params.malformation_distance_factors.second * flow_width) {
|
||||
// imagine the extrusion profile. The part that has been glued (melted) with the previous layer will be called anchored section
|
||||
// and the rest will be called curling section
|
||||
// float anchored_section = flow_width - point.distance;
|
||||
float curling_section = distance;
|
||||
|
||||
// after extruding, the curling (floating) part of the extrusion starts to shrink back to the rounded shape of the nozzle
|
||||
// The anchored part not, because the melted material holds to the previous layer well.
|
||||
// We can assume for simplicity perfect equalization of layer height and raising part width, from which:
|
||||
float swelling_radius = (layer_height + curling_section) / 2.0f;
|
||||
curled_up_height += std::max(0.f, (swelling_radius - layer_height) / 2.0f);
|
||||
|
||||
// On convex turns, there is larger tension on the floating edge of the extrusion then on the middle section.
|
||||
// The tension is caused by the shrinking tendency of the filament, and on outer edge of convex trun, the expansion is greater and
|
||||
// thus shrinking force is greater. This tension will cause the curling section to curle up
|
||||
if (curvature > 0.01) {
|
||||
float radius = (1.0 / curvature);
|
||||
float curling_t = sqrt(radius / 100);
|
||||
float b = curling_t * flow_width;
|
||||
float a = curling_section;
|
||||
float c = sqrt(std::max(0.0f, a * a - b * b));
|
||||
|
||||
curled_up_height += c;
|
||||
}
|
||||
curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height);
|
||||
}
|
||||
|
||||
return curled_up_height;
|
||||
}
|
||||
|
||||
void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
{
|
||||
LD prev_layer_lines{};
|
||||
for (Layer *l : layers) {
|
||||
l->curled_lines.clear();
|
||||
std::vector<Linef> boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector<Linef>();
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
|
||||
std::vector<ExtrusionLine> current_layer_lines;
|
||||
for (const LayerRegion *layer_region : l->regions()) {
|
||||
for (const ExtrusionEntity *extrusion : layer_region->perimeters.flatten().entities) {
|
||||
if (extrusion->role() != Slic3r::erExternalPerimeter)
|
||||
continue;
|
||||
Points extrusion_pts;
|
||||
extrusion->collect_points(extrusion_pts);
|
||||
float flow_width = get_flow_width(layer_region, extrusion->role());
|
||||
auto annotated_points = estimate_points_properties<true, true, false, false>(extrusion_pts, prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtendedPoint &b = annotated_points[i];
|
||||
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
|
||||
extrusion};
|
||||
Vec2f middle = 0.5 * (line_out.a + line_out.b);
|
||||
auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
|
||||
ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} :
|
||||
prev_layer_lines.get_line(bottom_line_idx);
|
||||
|
||||
// correctify the distance sign using slice polygons
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature),
|
||||
l->height, flow_width, bottom_line.curled_up_height, params);
|
||||
|
||||
current_layer_lines.push_back(line_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > params.curling_tolerance_limit) {
|
||||
l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height});
|
||||
}
|
||||
}
|
||||
|
||||
prev_layer_lines = LD{current_layer_lines};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
struct SupportGridFilter
|
||||
{
|
||||
private:
|
||||
|
|
@ -169,18 +276,7 @@ struct SliceConnection
|
|||
}
|
||||
};
|
||||
|
||||
float get_flow_width(const LayerRegion *region, ExtrusionRole role)
|
||||
{
|
||||
if (role == ExtrusionRole::erBridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width();
|
||||
if (role == ExtrusionRole::erExternalPerimeter) return region->flow(FlowRole::frExternalPerimeter).width();
|
||||
if (role == ExtrusionRole::erGapFill) return region->flow(FlowRole::frInfill).width();
|
||||
if (role == ExtrusionRole::erPerimeter) return region->flow(FlowRole::frPerimeter).width();
|
||||
if (role == ExtrusionRole::erSolidInfill) return region->flow(FlowRole::frSolidInfill).width();
|
||||
if (role == ExtrusionRole::erInternalInfill) return region->flow(FlowRole::frInfill).width();
|
||||
if (role == ExtrusionRole::erTopSolidInfill) return region->flow(FlowRole::frTopSolidInfill).width();
|
||||
// default
|
||||
return region->flow(FlowRole::frPerimeter).width();
|
||||
}
|
||||
|
||||
|
||||
std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length_limit)
|
||||
{
|
||||
|
|
@ -205,24 +301,7 @@ std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length
|
|||
return lines;
|
||||
}
|
||||
|
||||
float estimate_curled_up_height(
|
||||
const ExtendedPoint &point, float layer_height, float flow_width, float prev_line_curled_height, Params params)
|
||||
{
|
||||
float curled_up_height = 0.0f;
|
||||
if (fabs(point.distance) < 1.5 * flow_width) {
|
||||
curled_up_height = 0.85 * prev_line_curled_height;
|
||||
}
|
||||
if (point.distance > params.malformation_distance_factors.first * flow_width &&
|
||||
point.distance < params.malformation_distance_factors.second * flow_width && point.curvature > -0.1f) {
|
||||
float dist_factor = std::max(point.distance - params.malformation_distance_factors.first * flow_width, 0.01f) /
|
||||
((params.malformation_distance_factors.second - params.malformation_distance_factors.first) * flow_width);
|
||||
|
||||
curled_up_height = layer_height * sqrt(sqrt(dist_factor)) * std::clamp(3.0f * point.curvature, 1.0f, 3.0f);
|
||||
curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height);
|
||||
}
|
||||
|
||||
return curled_up_height;
|
||||
}
|
||||
|
||||
std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntity *entity,
|
||||
const LayerRegion *layer_region,
|
||||
|
|
@ -1104,78 +1183,7 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width,
|
|||
#endif
|
||||
}
|
||||
|
||||
void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
{
|
||||
#ifdef DEBUG_FILES
|
||||
FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w");
|
||||
FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w");
|
||||
#endif
|
||||
|
||||
LD prev_layer_lines{};
|
||||
|
||||
for (Layer *l : layers) {
|
||||
std::vector<Linef> boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector<Linef>();
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
|
||||
std::vector<ExtrusionLine> current_layer_lines;
|
||||
for (const LayerRegion *layer_region : l->regions()) {
|
||||
for (const ExtrusionEntity *extrusion : layer_region->perimeters().flatten().entities) {
|
||||
|
||||
if (!extrusion->role().is_external_perimeter()) continue;
|
||||
|
||||
Points extrusion_pts;
|
||||
extrusion->collect_points(extrusion_pts);
|
||||
float flow_width = get_flow_width(layer_region, extrusion->role());
|
||||
auto annotated_points = estimate_points_properties<true, false, false, false>(extrusion_pts, prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f;
|
||||
ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast<float>() : curr_point.position.cast<float>(),
|
||||
curr_point.position.cast<float>(), line_len, extrusion};
|
||||
|
||||
const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
|
||||
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
|
||||
ExtrusionLine{};
|
||||
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f :
|
||||
1.0f;
|
||||
curr_point.distance *= sign;
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width,
|
||||
nearest_prev_layer_line.curled_up_height, params);
|
||||
|
||||
current_layer_lines.push_back(line_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)});
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
}
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(full_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
prev_layer_lines = LD{current_layer_lines};
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
fclose(debug_file);
|
||||
fclose(full_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::pair<SupportPointCause, bool>> gather_issues(const SupportPoints &support_points, PartialObjects &partial_objects)
|
||||
{
|
||||
|
|
@ -1262,6 +1270,7 @@ std::vector<std::pair<SupportPointCause, bool>> gather_issues(const SupportPoint
|
|||
return result;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
} // namespace SupportSpotsGenerator
|
||||
} // namespace Slic3r
|
||||
*/
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||
#define SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||
/*
|
||||
|
||||
#include "Layer.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace SupportSpotsGenerator {
|
||||
|
|
@ -44,6 +45,7 @@ struct Params
|
|||
|
||||
const std::pair<float,float> malformation_distance_factors = std::pair<float, float> { 0.5, 1.1 };
|
||||
const float max_curled_height_factor = 10.0f;
|
||||
const float curling_tolerance_limit = 0.1f;
|
||||
|
||||
const float min_distance_between_support_points = 3.0f; //mm
|
||||
const float support_points_interface_radius = 1.5f; // mm
|
||||
|
|
@ -77,6 +79,9 @@ struct Params
|
|||
}
|
||||
};
|
||||
|
||||
void estimate_malformations(std::vector<Layer *> &layers, const Params ¶ms);
|
||||
|
||||
|
||||
enum class SupportPointCause {
|
||||
LongBridge, // point generated on bridge and straight perimeter extrusion longer than the allowed length
|
||||
FloatingBridgeAnchor, // point generated on unsupported bridge endpoint
|
||||
|
|
@ -97,7 +102,7 @@ enum class SupportPointCause {
|
|||
// between forces that destabilize the object (extruder conflicts with curled filament, weight if instable center of mass, bed movements etc)
|
||||
// and forces that stabilize the object (bed adhesion, other support spots adhesion, weight if stable center of mass).
|
||||
// Note that the force is only the difference - the amount needed to stabilize the object again.
|
||||
struct SupportPoint
|
||||
/*struct SupportPoint
|
||||
{
|
||||
SupportPoint(SupportPointCause cause, const Vec3f &position, float force, float spot_radius, const Vec2f &direction)
|
||||
: cause(cause), position(position), force(force), spot_radius(spot_radius), direction(direction)
|
||||
|
|
@ -147,13 +152,12 @@ using PartialObjects = std::vector<PartialObject>;
|
|||
std::tuple<SupportPoints, PartialObjects> full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms);
|
||||
|
||||
void estimate_supports_malformations(std::vector<SupportLayer *> &layers, float supports_flow_width, const Params ¶ms);
|
||||
void estimate_malformations(std::vector<Layer *> &layers, const Params ¶ms);
|
||||
|
||||
|
||||
// NOTE: the boolean marks if the issue is critical or not for now.
|
||||
std::vector<std::pair<SupportPointCause, bool>> gather_issues(const SupportPoints &support_points,
|
||||
PartialObjects &partial_objects);
|
||||
|
||||
}} // namespace Slic3r::SupportSpotsGenerator
|
||||
*/
|
||||
}} // namespace Slic3r::SupportSpotsGenerator
|
||||
|
||||
#endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue