Merge branch 'main' into dev/ams-heat

This commit is contained in:
SoftFever
2026-07-15 19:45:27 +08:00
committed by GitHub
95 changed files with 18718 additions and 6505 deletions
+75
View File
@@ -1,3 +1,7 @@
#include <limits>
#include <numeric>
#include <unordered_map>
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "ShortestPath.hpp"
@@ -930,6 +934,77 @@ Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_closed(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
// Orca: Sort and orient open polyline fragments produced by clipping `source` with
// intersection_pl(), so that they run in the same order and direction as the source
// polyline. Clipping creates new endpoints at the clip boundary, but it keeps the
// interior source vertices intact, so a fragment's position on the source path is
// recovered exactly by looking its vertices up in the source. Fragments without any
// surviving source vertex lie on a single source segment, found by a nearest-segment
// search.
void restore_source_path_order(const Slic3r::Polyline &source, Slic3r::Polylines &fragments)
{
const Points &src = source.points;
if (src.size() < 2 || fragments.empty())
return;
std::unordered_map<Point, size_t, PointHash> source_index;
source_index.reserve(src.size());
for (size_t i = 0; i < src.size(); ++ i)
source_index.emplace(src[i], i);
// Sort key: index of the source vertex where the fragment starts, then the signed
// offset of the fragment's start from that vertex, to order multiple fragments cut
// from one long source segment.
std::vector<std::pair<size_t, double>> keys(fragments.size());
for (size_t n = 0; n < fragments.size(); ++ n) {
Polyline &pl = fragments[n];
const size_t npos = size_t(-1);
size_t front = npos;
size_t back = npos;
for (const Point &pt : pl.points)
if (auto it = source_index.find(pt); it != source_index.end()) {
front = it->second;
break;
}
for (auto i = pl.points.rbegin(); i != pl.points.rend(); ++ i)
if (auto it = source_index.find(*i); it != source_index.end()) {
back = it->second;
break;
}
Vec2crd source_dir;
if (front == npos) {
// All vertices were created by clipping, thus the whole fragment lies on a
// single source segment. Find that segment.
double best = std::numeric_limits<double>::max();
for (size_t i = 0; i + 1 < src.size(); ++ i)
if (double d = Line::distance_to_squared(pl.first_point(), src[i], src[i + 1]); d < best) {
best = d;
front = i;
}
back = front;
source_dir = src[front + 1] - src[front];
} else
source_dir = src[std::min(back + 1, src.size() - 1)] - src[front > 0 ? front - 1 : 0];
if (front > back) {
pl.reverse();
std::swap(front, back);
} else if (front == back &&
(pl.last_point() - pl.first_point()).cast<double>().dot(source_dir.cast<double>()) < 0.)
pl.reverse();
const Vec2crd seg = src[std::min(front + 1, src.size() - 1)] - src[front];
keys[n] = { front, (pl.first_point() - src[front]).cast<double>().dot(seg.cast<double>()) };
}
std::vector<size_t> order(fragments.size());
std::iota(order.begin(), order.end(), size_t(0));
std::sort(order.begin(), order.end(), [&keys](size_t a, size_t b) { return keys[a] < keys[b]; });
Polylines sorted;
sorted.reserve(fragments.size());
for (size_t n : order)
sorted.emplace_back(std::move(fragments[n]));
fragments = std::move(sorted);
}
Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip)
{
// convert Lines to Polylines
+4
View File
@@ -528,6 +528,10 @@ Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r
Slic3r::Polylines3 intersection_pl(const Slic3r::Polylines3 &subject, const Slic3r::Polygon &clip);
Slic3r::Polylines3 intersection_pl(const Slic3r::Polylines3 &subject, const Slic3r::ExPolygon &clip);
// Orca: Sort and orient open polyline fragments produced by clipping `source` with
// intersection_pl(), so that they run in the same order and direction as the source polyline.
void restore_source_path_order(const Slic3r::Polyline &source, Slic3r::Polylines &fragments);
inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip)
{
return _clipper_ln(ClipperLib::ctIntersection, subject, clip);
+8 -1
View File
@@ -177,7 +177,14 @@ double Extruder::filament_flow_ratio() const
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
double Extruder::retract_before_wipe() const
{
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_config_index) * 0.01));
return std::clamp(m_config->retract_before_wipe.get_at(m_config_index) * 0.01, 0., 1.);
}
// Orca:
// Return a "retract_after_wipe" percentage as a factor clamped to <0, 1>
double Extruder::retract_after_wipe() const
{
return std::min(std::clamp(m_config->retract_after_wipe.get_at(m_config_index) * 0.01, 0., 1.), 1. - retract_before_wipe());
}
double Extruder::retraction_length() const
+2
View File
@@ -74,6 +74,8 @@ public:
double filament_cost() const;
double filament_flow_ratio() const;
double retract_before_wipe() const;
// Orca:
double retract_after_wipe() const;
double retraction_length() const;
double retract_lift() const;
int retract_speed() const;
+10 -7
View File
@@ -352,8 +352,7 @@ namespace Slic3r
int k,
const std::vector<unsigned int>& used_filaments,
const std::unordered_map<int, std::vector<int>>& unplaceable_limits,
int* cost,
int timeout_ms)
int* cost)
{
auto distance_evaluator = std::make_shared<FlushDistanceEvaluator>(ctx.model_info.flush_matrix, used_filaments, ctx.model_info.layer_filaments);
KMediods PAM(k, (int)used_filaments.size(), distance_evaluator, ctx.machine_info.master_extruder_id);
@@ -369,7 +368,7 @@ namespace Slic3r
}
PAM.set_cluster_group_size(cluster_size_limit);
PAM.do_clustering(ctx, timeout_ms, 30);
PAM.do_clustering(ctx, m_clustering_budget);
m_memoryed_heap = PAM.get_memoryed_groups();
@@ -793,7 +792,7 @@ namespace Slic3r
2.1 In each cluster, make the point that minimizes the sum of distances within the cluster the medoid
2.2 Reassign each point to the cluster defined by the closest medoid determined in the previous step
*/
void KMediods::do_clustering(const FilamentGroupContext &context, int timeout_ms, int retry)
void KMediods::do_clustering(const FilamentGroupContext& context, const ClusteringBudget& budget)
{
FlushTimeMachine T;
T.time_machine_start();
@@ -817,7 +816,11 @@ namespace Slic3r
double best_cluster_cost = std::numeric_limits<double>::max();
int retry_count = 0;
while (retry_count < retry && T.time_machine_end() < timeout_ms) {
// Run at least one restart; otherwise every filament would stay in the default group.
const int retry = std::max(1, budget.max_restarts);
auto within_budget = [&]() { return budget.timeout_ms <= 0 || T.time_machine_end() < budget.timeout_ms; };
while (retry_count < retry && within_budget()) {
std::vector<int> curr_cluster_centers = init_cluster_center(m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size, retry_count);
std::vector<int> curr_cluster_labels = assign_cluster_label(curr_cluster_centers, m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size);
double curr_cluster_cost = evaluate_labels(curr_cluster_labels);
@@ -826,7 +829,7 @@ namespace Slic3r
update_memoryed_groups(g, memory_threshold, memoryed_groups);
bool mediods_changed = true;
while (mediods_changed && T.time_machine_end() < timeout_ms) {
while (mediods_changed && within_budget()) {
mediods_changed = false;
double best_swap_cost = curr_cluster_cost;
int best_swap_cluster = -1;
@@ -889,7 +892,7 @@ namespace Slic3r
if (estimated < ENUM_THRESHOLD)
result = calc_group_by_enum(k, used_filaments, unplaceable_limits, cost);
else
result = calc_group_by_kmedoids(k, used_filaments, unplaceable_limits, cost, 3000);
result = calc_group_by_kmedoids(k, used_filaments, unplaceable_limits, cost);
change_memoryed_heaps_to_arrays(m_memoryed_heap, ctx.group_info.total_filament_num, used_filaments, m_memoryed_groups);
+15 -2
View File
@@ -142,6 +142,16 @@ namespace Slic3r
FilamentGroupContext::SpeedInfo m_speed_info;
};
// Search budget for the k-medoids clustering, an anytime search. Each restart is seeded from its
// own index, so what it returns depends on how many restarts complete before the clock expires,
// and therefore on the speed of the machine. A timeout_ms <= 0 removes the clock and bounds the
// search by max_restarts alone.
struct ClusteringBudget
{
int timeout_ms = 3000;
int max_restarts = 30;
};
class FilamentGroup
{
using MemoryedGroup = FilamentGroupUtils::MemoryedGroup;
@@ -149,6 +159,8 @@ namespace Slic3r
public:
explicit FilamentGroup(const FilamentGroupContext& ctx_) :ctx(ctx_) {}
public:
void set_clustering_budget(const ClusteringBudget& budget) { m_clustering_budget = budget; }
std::vector<int> calc_filament_group(int * cost = nullptr);
std::vector<std::vector<int>> get_memoryed_groups()const { return m_memoryed_groups; }
@@ -162,7 +174,7 @@ namespace Slic3r
std::vector<int> calc_group_by_enum(int k, const std::vector<unsigned int>& used_filaments,
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr);
std::vector<int> calc_group_by_kmedoids(int k, const std::vector<unsigned int>& used_filaments,
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr, int timeout_ms = 500);
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr);
std::map<int, int> rebuild_unprintables(const std::vector<unsigned int>& used_filaments, const std::map<int,int>& extruder_unprintables);
std::unordered_map<int, std::vector<int>> rebuild_nozzle_unprintables(const std::vector<unsigned int>& used_filaments, const std::unordered_map<int, std::vector<int>>& extruder_unprintables, const std::vector<int>& filament_volume_map);
@@ -175,6 +187,7 @@ namespace Slic3r
FilamentGroupContext ctx;
MemoryedGroupHeap m_memoryed_heap;
std::vector<std::vector<int>> m_memoryed_groups;
ClusteringBudget m_clustering_budget;
public:
std::optional<std::function<bool(int, std::vector<int>&)>> get_custom_seq;
};
@@ -220,7 +233,7 @@ namespace Slic3r
void set_memory_threshold(double threshold) { memory_threshold = threshold; }
MemoryedGroupHeap get_memoryed_groups()const { return memoryed_groups; }
void do_clustering(const FilamentGroupContext& context, int timeout_ms = 100, int retry = 10);
void do_clustering(const FilamentGroupContext& context, const ClusteringBudget& budget);
std::vector<int> get_cluster_labels()const { return m_cluster_labels; }
protected:
+15 -6
View File
@@ -272,10 +272,12 @@ struct SurfaceFillParams
// For Gyroid: when true, use the parameterized "optimized" wave.
bool gyroid_optimized = false;
bool anisotropic_surfaces{false};
CenterOfSurfacePattern center_of_surface_pattern{CenterOfSurfacePattern::Each_Surface};
bool separated_infills{false};
// Orca: forced print order of surface fill loops/fragments for center-based patterns.
SurfaceFillOrder fill_order = SurfaceFillOrder::Default;
bool operator<(const SurfaceFillParams &rhs) const {
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
@@ -308,9 +310,9 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(skin_infill_depth);
RETURN_COMPARE_NON_EQUAL(infill_overhang_angle);
RETURN_COMPARE_NON_EQUAL(gyroid_optimized);
RETURN_COMPARE_NON_EQUAL(anisotropic_surfaces);
RETURN_COMPARE_NON_EQUAL(center_of_surface_pattern);
RETURN_COMPARE_NON_EQUAL(separated_infills);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, fill_order);
return false;
}
@@ -337,10 +339,10 @@ struct SurfaceFillParams
this->infill_lock_depth == rhs.infill_lock_depth &&
this->skin_infill_depth == rhs.skin_infill_depth &&
this->infill_overhang_angle == rhs.infill_overhang_angle &&
this->anisotropic_surfaces == rhs.anisotropic_surfaces &&
this->center_of_surface_pattern == rhs.center_of_surface_pattern &&
this->separated_infills == rhs.separated_infills &&
this->gyroid_optimized == rhs.gyroid_optimized;
this->gyroid_optimized == rhs.gyroid_optimized &&
this->fill_order == rhs.fill_order;
}
};
@@ -879,7 +881,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.lateral_lattice_angle_1 = region_config.lateral_lattice_angle_1;
params.lateral_lattice_angle_2 = region_config.lateral_lattice_angle_2;
params.infill_overhang_angle = region_config.infill_overhang_angle;
params.anisotropic_surfaces = region_config.anisotropic_surfaces;
params.center_of_surface_pattern = region_config.center_of_surface_pattern;
params.separated_infills = region_config.separated_infills;
if (params.pattern == ipLockedZag) {
@@ -936,6 +937,14 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.extruder = region_config.bottom_surface_filament_id;
else if (params.extrusion_role == erSolidInfill)
params.extruder = region_config.internal_solid_filament_id;
// Orca: forced fill order applies only to top/bottom surfaces filled with a
// center-based pattern; everything else stays at Default to keep batching together.
if (params.pattern == ipConcentric || params.pattern == ipArchimedeanChords || params.pattern == ipOctagramSpiral) {
if (params.extrusion_role == erTopSolidInfill)
params.fill_order = region_config.top_surface_fill_order.value;
else if (params.extrusion_role == erBottomSurface)
params.fill_order = region_config.bottom_surface_fill_order.value;
}
// Orca: apply fill multiline only for sparse infill
params.multiline = params.extrusion_role == erInternalInfill ? int(region_config.fill_multiline) : 1;
@@ -1322,12 +1331,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
auto &region_config = layerm->region().config();
params.config = &region_config;
params.pattern = surface_fill.params.pattern;
params.fill_order = surface_fill.params.fill_order;
// Orca: Checking the filling of a centered surface by drawing for each model parts
bool is_top_or_bottom = params.extrusion_role == erTopSolidInfill || params.extrusion_role == erBottomSurface;
bool is_centered_infill = surface_fill.params.pattern == ipArchimedeanChords || surface_fill.params.pattern == ipOctagramSpiral;
if (is_top_or_bottom) {
params.is_anisotropic = surface_fill.params.anisotropic_surfaces; // Orca: anisotropic surfaces
params.center_of_surface_pattern = surface_fill.params.center_of_surface_pattern; // Orca: center of surface pattern
}
// Orca: Each_Model centers the pattern on each model part's bbox; Each_Surface / Each_Assembly
+7 -7
View File
@@ -162,10 +162,11 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
out.push_back(eec = new ExtrusionEntityCollection());
// Only concentric fills are not sorted.
eec->no_sort = this->no_sort();
// ORCA: special flag for flow rate calibration
auto is_flow_calib = params.extrusion_role == erTopSolidInfill && this->print_object_config->has("calib_flowrate_topinfill_special_order") &&
this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool();
if (is_flow_calib || params.is_anisotropic) { // Orca: disable sorting while anisotropic surfaces
// Orca: a forced surface fill order must survive the G-code path planner, which would
// otherwise re-chain and possibly reverse the paths. This also covers the flow rate
// calibration, which forces an outward fill order on its top surfaces.
const bool keep_fill_order = params.fill_order != SurfaceFillOrder::Default;
if (keep_fill_order) {
eec->no_sort = true;
}
size_t idx = eec->entities.size();
@@ -180,14 +181,13 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
params.extrusion_role,
flow_mm3_per_mm, float(flow_width), params.flow.height());
}
if (!params.can_reverse || is_flow_calib) {
if (!params.can_reverse || keep_fill_order) {
for (size_t i = idx; i < eec->entities.size(); i++)
eec->entities[i]->set_reverse();
}
// Orca: run gap fill
if (!(params.is_anisotropic)) // Orca: Disable gap filling while anisotropic
this->_create_gap_fill(surface, params, eec);
this->_create_gap_fill(surface, params, eec);
}
}
+4 -1
View File
@@ -100,13 +100,16 @@ struct FillParams
bool dont_sort{ false }; // do not sort the lines, just simply connect them
bool can_reverse{true};
// Orca: forced print order of surface fill loops/fragments for center-based patterns
// (Concentric, Archimedean Chords, Octagram Spiral). Default keeps shortest-path ordering.
SurfaceFillOrder fill_order { SurfaceFillOrder::Default };
float horiz_move{0.0}; //move infill to get cross zag pattern
bool symmetric_infill_y_axis{false};
coord_t symmetric_y_axis{0};
bool locked_zag{false};
float infill_lock_depth{0.0};
float skin_infill_depth{0.0};
bool is_anisotropic{false};
CenterOfSurfacePattern center_of_surface_pattern{CenterOfSurfacePattern::Each_Surface};
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
+17 -1
View File
@@ -41,6 +41,10 @@ void FillConcentric::_fill_surface_single(
// generate paths from the outermost to the innermost, to avoid
// adhesion problems of the first central tiny loops
loops = union_pt_chained_outside_in(loops);
// Orca: an outward fill order prints the innermost loops first instead.
if (params.fill_order == SurfaceFillOrder::Outward)
std::reverse(loops.begin(), loops.end());
// split paths using a nearest neighbor search
size_t iPathFirst = polylines_out.size();
@@ -108,6 +112,17 @@ void FillConcentric::_fill_surface_single(const FillParams& params,
all_extrusions.emplace_back(&wall);
}
// Orca: a forced fill order prints the loops in strictly monotonic depth order so
// that surfaces broken up by holes or slots cannot hop outward and back inward.
const bool forced_fill_order = params.fill_order != SurfaceFillOrder::Default;
if (forced_fill_order) {
const bool outward = params.fill_order == SurfaceFillOrder::Outward;
std::stable_sort(all_extrusions.begin(), all_extrusions.end(),
[outward](const Arachne::ExtrusionLine *a, const Arachne::ExtrusionLine *b) {
return outward ? a->inset_idx > b->inset_idx : a->inset_idx < b->inset_idx;
});
}
// Split paths using a nearest neighbor search.
size_t firts_poly_idx = thick_polylines_out.size();
Point last_pos(0, 0);
@@ -136,7 +151,8 @@ void FillConcentric::_fill_surface_single(const FillParams& params,
if (j < thick_polylines_out.size())
thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end());
reorder_by_shortest_traverse(thick_polylines_out);
if (!forced_fill_order)
reorder_by_shortest_traverse(thick_polylines_out);
}
else {
Polylines polylines;
+18 -41
View File
@@ -133,49 +133,26 @@ void FillPlanePath::_fill_surface_single(
polylines = intersection_pl(std::move(polylines), expolygon);
if (!polylines.empty()) {
Polylines chained;
if (!params.is_anisotropic) { // Orca: not anisotropic surface
if ((params.dont_connect() || params.density > 0.5)) {
// ORCA: special flag for flow rate calibration
auto is_flow_calib = params.extrusion_role == erTopSolidInfill &&
this->print_object_config->has("calib_flowrate_topinfill_special_order") &&
this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool() &&
dynamic_cast<FillArchimedeanChords*>(this);
if (is_flow_calib) {
// We want the spiral part to be printed inside-out
// Find the center spiral line first, by looking for the longest one
auto it = std::max_element(polylines.begin(), polylines.end(),
[](const Polyline& a, const Polyline& b) { return a.length() < b.length(); });
Polyline center_spiral = std::move(*it);
// Ensure the spiral is printed from inside to out
if ((center_spiral.first_point().squaredNorm() > center_spiral.last_point().squaredNorm())) {
center_spiral.reverse();
}
// Chain the other polylines
polylines.erase(it);
chained = chain_polylines(std::move(polylines), nullptr);
// Then add the center spiral back
chained.push_back(std::move(center_spiral));
} else {
chained = chain_polylines(std::move(polylines), nullptr);
if (params.dont_connect() || params.density > 0.5) {
if (params.fill_order != SurfaceFillOrder::Default) {
// Orca: print the fragments in the order they appear along the generated
// path, which runs from the center outwards. The Euclidean distance from
// the center cannot be used for this: along the Octagram Spiral the radius
// oscillates by far more than the ring spacing, so fragments of different
// rings would interleave.
restore_source_path_order(polyline, polylines);
chained = std::move(polylines);
if (params.fill_order == SurfaceFillOrder::Inward) {
// The source path runs from the center outwards; flip everything for inward.
std::reverse(chained.begin(), chained.end());
for (Polyline &pl : chained)
pl.reverse();
}
} else
connect_infill(std::move(polylines), expolygon, chained, this->spacing, params);
} else { // Orca: anisotropic surface
const Point _center(0., 0.);
for (Polyline& segment : polylines) { // sort paths by its direction
if (segment.size() > 1) { // need at least two points to evaluate direction
if (segment.first_point().ccw(segment.points[1], _center) < 0)
segment.reverse();
}
chained.emplace_back(std::move(segment));
} else {
chained = chain_polylines(std::move(polylines), nullptr);
}
std::sort(chained.begin(), chained.end(), [&_center](const Polyline& a, const Polyline& b) { // just sort polylines from center to outside
return a.distance_to(_center) < b.distance_to(_center);
});
}
} else
connect_infill(std::move(polylines), expolygon, chained, this->spacing, params);
// paths must be repositioned and rotated back
for (Polyline& pl : chained) {
pl.translate(shift.x(), shift.y());
+40 -21
View File
@@ -441,22 +441,30 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
// Declare & initialize retraction lengths
double retraction_length_remaining = 0,
retractionBeforeWipe = 0,
retractionDuringWipe = 0;
retraction_length_before_wipe = 0,
retraction_length_during_wipe = 0,
retraction_length_after_wipe = 0;
// initialise the remaining retraction amount with the full retraction amount.
retraction_length_remaining = toolchange ? extruder->retract_length_toolchange() : extruder->retraction_length();
// Initialise the remaining retraction amount with the full retraction amount.
retraction_length_remaining = toolchange ?
extruder->retract_length_toolchange() : extruder->retraction_length();
// nothing to retract - return early
if(retraction_length_remaining <=EPSILON) return {0.f,0.f};
// Nothing to retract - return early
if (retraction_length_remaining <= EPSILON)
return { 0.f, 0.f, 0.f };
// calculate retraction before wipe distance from the user setting. Keep adding to this variable any excess retraction needed
// to be performed before the wipe.
retractionBeforeWipe = retraction_length_remaining * extruder->retract_before_wipe();
retraction_length_remaining -= retractionBeforeWipe; // subtract it from the remaining retraction length
// all of the retraction is to be done before the wipe
if(retraction_length_remaining <=EPSILON) return {retractionBeforeWipe,0.f};
// Calculate retraction before and after wipe distances from the user setting.
// Keep adding to the for retraction before wipe variable any excess retraction
// needed to be performed before the wipe.
retraction_length_before_wipe = retraction_length_remaining * extruder->retract_before_wipe();
retraction_length_after_wipe = retraction_length_remaining * extruder->retract_after_wipe();
// Subtract it from the remaining retraction length
retraction_length_remaining -= retraction_length_before_wipe + retraction_length_after_wipe;
// All of the retraction is to be done before the wipe
if (retraction_length_remaining <= EPSILON)
return { retraction_length_before_wipe, 0., retraction_length_after_wipe };
// Calculate wipe speed
// Orca: resolve the travel_speed slot via the Print-side per-layer resolver; the writer's
@@ -471,18 +479,25 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
double wipe_path_length = std::min(wipe_path.length(), wipe_dist);
// Calculate the maximum retraction amount during wipe
retractionDuringWipe = config.retraction_speed.get_at(extruder_id) * unscale_(wipe_path_length) / wipe_speed;
// If the maximum retraction amount during wipe is too small, return 0 and retract everything prior to the wipe.
if(retractionDuringWipe <= EPSILON) return {retractionBeforeWipe,0.f};
retraction_length_during_wipe = config.retraction_speed.get_at(extruder_id) *
unscale_(wipe_path_length) / wipe_speed;
// If the maximum retraction amount during wipe is too small,
// disable wipe-time retraction and leave any remaining retract amount
// to the subsequent standard retract flow.
if (retraction_length_during_wipe <= EPSILON)
return { retraction_length_before_wipe, 0., retraction_length_after_wipe };
// If the maximum retraction amount during wipe is greater than any remaining retraction length
// return the remaining retraction length to be retracted during the wipe
if (retractionDuringWipe - retraction_length_remaining > EPSILON) return {retractionBeforeWipe,retraction_length_remaining};
if (retraction_length_during_wipe - retraction_length_remaining > EPSILON)
return { retraction_length_before_wipe, retraction_length_remaining, retraction_length_after_wipe };
// We will always proceed with incrementing the retraction amount before wiping with the difference
// and return the maximum allowed wipe amount to be retracted during the wipe move
retractionBeforeWipe += retraction_length_remaining - retractionDuringWipe;
return {retractionBeforeWipe, retractionDuringWipe};
retraction_length_before_wipe += retraction_length_remaining - retraction_length_during_wipe;
return { retraction_length_before_wipe, retraction_length_during_wipe, retraction_length_after_wipe };
}
std::string transform_gcode(const std::string &gcode, Vec2f pos, const Vec2f &translation, float angle)
@@ -8507,8 +8522,12 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
// wipe (if it's enabled for this extruder and we have a stored wipe path and no-zero wipe distance)
if (FILAMENT_CONFIG(wipe) && m_wipe.has_path() && scale_(FILAMENT_CONFIG(wipe_distance)) > SCALED_EPSILON) {
Wipe::RetractionValues wipeRetractions = m_wipe.calculateWipeRetractionLengths(*this, toolchange);
gcode += toolchange ? m_writer.retract_for_toolchange(true,wipeRetractions.retractLengthBeforeWipe) : m_writer.retract(true, wipeRetractions.retractLengthBeforeWipe);
gcode += m_wipe.wipe(*this,wipeRetractions.retractLengthDuringWipe, toolchange, is_last_retraction);
gcode += toolchange ? m_writer.retract_for_toolchange(true, wipeRetractions.retraction_length_before_wipe) :
m_writer.retract(true, wipeRetractions.retraction_length_before_wipe);
gcode += m_wipe.wipe(*this, wipeRetractions.retraction_length_during_wipe, toolchange, is_last_retraction);
// Orca: wipeRetractions.retraction_length_after_wipe is not being used explicitly,
// the remaining retraction after wipe is handled by the subsequent m_writer.retract() call
}
/* The parent class will decide whether we need to perform an actual retraction
+7 -2
View File
@@ -60,15 +60,20 @@ class Wipe {
public:
bool enable;
Polyline path;
// Orca:
struct RetractionValues{
double retractLengthBeforeWipe;
double retractLengthDuringWipe;
double retraction_length_before_wipe = 0.;
double retraction_length_during_wipe = 0.;
double retraction_length_after_wipe = 0.;
};
Wipe() : enable(false) {}
bool has_path() const { return !this->path.points.empty(); }
void reset_path() { this->path = Polyline(); }
std::string wipe(GCode &gcodegen, double length, bool toolchange = false, bool is_last = false);
// Orca:
RetractionValues calculateWipeRetractionLengths(GCode& gcodegen, bool toolchange);
};
+4 -1
View File
@@ -6551,8 +6551,11 @@ void GCodeProcessor::process_T(const std::string_view command, int nozzle_id)
if (command.length() > 1) {
if (eid < 0 || eid > 254) {
//BBS: T255, T1000 and T1100 is used as special command for BBL machine and does not cost time. return directly
// Orca: T1001 (hotend-type detection) and T65535/T65279 (AMS unload virtual-tool selects, paired with
// M620/M621 S65535/S65279) are firmware opcodes emitted verbatim by BBL machine start/end g-code, not
// real tool changes - whitelist them so the time estimator stops flagging these valid lines.
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && (command == "Tx" || command == "Tc" || command == "T?" ||
eid == 1000 || eid == 1100 || eid == 255))
eid == 1000 || eid == 1100 || eid == 255 || eid == 1001 || eid == 65279 || eid == 65535))
return;
// T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools)
+16 -4
View File
@@ -1048,6 +1048,8 @@ static std::vector<std::string> s_Preset_print_options{
"top_surface_expansion_margin",
"top_surface_expansion_direction",
"bottom_surface_pattern",
"top_surface_fill_order",
"bottom_surface_fill_order",
"infill_direction",
"solid_infill_direction",
"top_layer_direction",
@@ -1063,7 +1065,6 @@ static std::vector<std::string> s_Preset_print_options{
"skin_infill_density",
"align_infill_direction_to_model",
"extra_solid_infills",
"anisotropic_surfaces",
"center_of_surface_pattern",
"separated_infills",
"minimum_sparse_infill_area",
@@ -1309,7 +1310,6 @@ static std::vector<std::string> s_Preset_print_options{
"interlocking_depth",
"interlocking_boundary_avoidance",
"interlocking_beam_width",
"calib_flowrate_topinfill_special_order",
// Z Anti-Aliasing (ZAA)
"zaa_enabled",
"zaa_minimize_perimeter_height",
@@ -1335,8 +1335,20 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
//exhaust fan control
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
// Retract overrides
"filament_retraction_length", "filament_z_hop", "filament_z_hop_types", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_lift_enforce", "filament_retraction_speed", "filament_deretraction_speed", "filament_retract_restart_extra", "filament_retraction_minimum_travel",
"filament_retract_when_changing_layer", "filament_wipe", "filament_retract_before_wipe",
"filament_deretraction_speed",
"filament_retract_after_wipe", // Orca
"filament_retract_before_wipe",
"filament_retract_lift_above",
"filament_retract_lift_below",
"filament_retract_lift_enforce",
"filament_retract_restart_extra",
"filament_retract_when_changing_layer",
"filament_retraction_length",
"filament_retraction_minimum_travel",
"filament_retraction_speed",
"filament_wipe",
"filament_z_hop",
"filament_z_hop_types",
// Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
//BBS
+16 -7
View File
@@ -177,6 +177,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"filename_format",
"retraction_minimum_travel",
"retract_before_wipe",
// Orca:
"retract_after_wipe",
"retract_when_changing_layer",
"retraction_length",
"retract_length_toolchange",
@@ -210,7 +212,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"chamber_minimal_temperature",
"thumbnails",
"thumbnails_format",
"anisotropic_surfaces",
"center_of_surface_pattern",
"separated_infills",
"seam_gap",
@@ -3676,6 +3677,8 @@ int Print::get_filament_config_indx(int filament_id, int layer_id)
void Print::update_filament_self_index_cache()
{
m_missing_nozzle_group_logged.clear(); // reset the per-slice get_config_index log dedupe
std::vector<int> values;
if (m_full_print_config.has("filament_self_index")) {
values = m_full_print_config.option<ConfigOptionInts>("filament_self_index")->values;
@@ -3721,9 +3724,12 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
return filament_id;
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
if (!nozzle_info.has_value()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
layer_id;
// Orca: this fallback runs per-filament/per-layer in the g-code hot path — log once per filament
// (reset each slice) instead of flooding thousands of identical lines that bury the real error.
if (m_missing_nozzle_group_logged.insert(filament_id).second)
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3% (further occurrences for this filament suppressed)") % __LINE__ % filament_id %
layer_id;
return 0;
}
@@ -3750,9 +3756,12 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
return (int)get_extruder_id(filament_id);
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
if (!nozzle_info.has_value()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
layer_id;
// Orca: this fallback runs per-filament/per-layer in the g-code hot path — log once per filament
// (reset each slice) instead of flooding thousands of identical lines that bury the real error.
if (m_missing_nozzle_group_logged.insert(filament_id).second)
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3% (further occurrences for this filament suppressed)") % __LINE__ % filament_id %
layer_id;
return 0;
}
+4
View File
@@ -1303,6 +1303,10 @@ private:
FilamentIndexMap m_filament_index_map;
// Used to cache printer and process parameter information
PrintIndexMap m_nozzle_index_map;
// Orca: filament ids already reported as missing a nozzle-group entry this slice. get_config_index()
// falls back per-filament/per-layer in the g-code hot path, so this dedupes its log to once per
// filament instead of flooding thousands of identical error lines. Cleared with the caches each slice.
std::set<int> m_missing_nozzle_group_logged;
// save the config value of "filament_self_index"
std::vector<int> m_filament_self_index;
+122 -27
View File
@@ -79,6 +79,9 @@ const std::vector<std::string> filament_extruder_override_keys = {
"filament_wipe",
// percents
"filament_retract_before_wipe",
// Orca
"filament_retract_after_wipe",
// BBS
"filament_long_retractions_when_cut",
"filament_retraction_distances_when_cut"
};
@@ -310,6 +313,14 @@ static t_config_enum_values s_keys_map_WallDirection{
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WallDirection)
//Orca
static t_config_enum_values s_keys_map_SurfaceFillOrder{
{ "default", int(SurfaceFillOrder::Default) },
{ "outward", int(SurfaceFillOrder::Outward) },
{ "inward", int(SurfaceFillOrder::Inward) },
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SurfaceFillOrder)
//BBS
static t_config_enum_values s_keys_map_PrintSequence {
{ "by layer", int(PrintSequence::ByLayer) },
@@ -2319,6 +2330,40 @@ void PrintConfigDef::init_fff_params()
def->max = 100;
def->set_default_value(new ConfigOptionPercent(100));
auto def_top_fill_order = def = this->add("top_surface_fill_order", coEnum);
def->label = L("Top surface fill order");
def->category = L("Strength");
def->tooltip = L("Direction in which top surfaces are filled when using a center-based pattern "
"(Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed "
"towards the edge where it is least visible. Inward starts at the edge and ends "
"with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction.");
def->enum_keys_map = &ConfigOptionEnum<SurfaceFillOrder>::get_enum_values();
def->enum_values.push_back("default");
def->enum_values.push_back("outward");
def->enum_values.push_back("inward");
def->enum_labels.push_back(L("Default"));
def->enum_labels.push_back(L("Outward"));
def->enum_labels.push_back(L("Inward"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Default));
def = this->add("bottom_surface_fill_order", coEnum);
def->label = L("Bottom surface fill order");
def->category = L("Strength");
def->tooltip = L("Direction in which bottom surfaces are filled when using a center-based pattern "
"(Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer "
"adhesion on build plates where the tight curves at the center may not stick. "
"Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction.");
def->enum_keys_map = &ConfigOptionEnum<SurfaceFillOrder>::get_enum_values();
def->enum_values = def_top_fill_order->enum_values;
def->enum_labels = def_top_fill_order->enum_labels;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Default));
def = this->add("internal_solid_infill_pattern", coEnum);
def->label = L("Internal solid infill pattern");
def->category = L("Strength");
@@ -4602,11 +4647,6 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(2));
// ORCA: special flag for flow rate calibration
def = this->add("calib_flowrate_topinfill_special_order", coBool);
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("ironing_type", coEnum);
def->label = L("Ironing type");
def->category = L("Quality");
@@ -5546,6 +5586,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPercents { 100 });
// Orca:
def = this->add("retract_after_wipe", coPercents);
def->label = L("Retract amount after wipe");
def->tooltip = L("The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value.");
def->sidetext = "%";
def->mode = comExpert;
def->set_default_value(new ConfigOptionPercents { 0 });
def = this->add("retract_when_changing_layer", coBools);
def->label = L("Retract on layer change");
def->tooltip = L("This forces a retraction on layer changes.");
@@ -7186,17 +7235,6 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloat(0.6));
def = this->add("anisotropic_surfaces", coBool);
def->label = L("Anisotropic surfaces");
def->category = L("Strength");
def->tooltip = L("Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color "
"dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("separated_infills", coBool);
def->label = L("Separated infills");
def->category = L("Strength");
@@ -7987,17 +8025,44 @@ void PrintConfigDef::init_extruder_option_keys()
{
// ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings
m_extruder_option_keys = {
"extruder_type", "nozzle_diameter", "default_nozzle_volume_type", "min_layer_height", "max_layer_height", "extruder_offset",
"extruder_printable_height", "nozzle_volume", "nozzle_type", "nozzle_flush_dataset",
"retraction_length", "z_hop", "z_hop_types", "travel_slope", "retract_lift_above", "retract_lift_below", "retract_lift_enforce", "retraction_speed", "deretraction_speed",
"retract_before_wipe", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance",
"retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
"default_filament_profile","retraction_distances_when_cut","long_retractions_when_cut"
"default_filament_profile",
"default_nozzle_volume_type",
"deretraction_speed",
"extruder_colour",
"extruder_offset",
"extruder_printable_height",
"extruder_type",
"long_retractions_when_cut",
"max_layer_height",
"min_layer_height",
"nozzle_diameter",
"nozzle_flush_dataset",
"nozzle_type",
"nozzle_volume",
"retract_after_wipe",
"retract_before_wipe",
"retract_length_toolchange",
"retract_lift_above",
"retract_lift_below",
"retract_lift_enforce",
"retract_restart_extra",
"retract_restart_extra_toolchange",
"retract_when_changing_layer",
"retraction_distances_when_cut",
"retraction_length",
"retraction_minimum_travel",
"retraction_speed",
"travel_slope",
"wipe",
"wipe_distance",
"z_hop",
"z_hop_types"
};
m_extruder_retract_keys = {
"deretraction_speed",
"long_retractions_when_cut",
"retract_after_wipe",
"retract_before_wipe",
"retract_lift_above",
"retract_lift_below",
@@ -8020,17 +8085,40 @@ void PrintConfigDef::init_extruder_option_keys()
void PrintConfigDef::init_filament_option_keys()
{
m_filament_option_keys = {
"filament_diameter", "min_layer_height", "max_layer_height","volumetric_speed_coefficients",
"retraction_length", "z_hop", "z_hop_types", "retract_lift_above", "retract_lift_below", "retract_lift_enforce", "retraction_speed", "deretraction_speed",
"retract_before_wipe", "filament_retract_length_nc", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance",
"retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", "filament_colour",
"default_filament_profile","retraction_distances_when_cut","long_retractions_when_cut"/*,"filament_seam_gap"*/
"default_filament_profile",
"deretraction_speed",
"filament_colour",
"filament_diameter",
"filament_retract_length_nc",
// "filament_seam_gap",
"long_retractions_when_cut",
"max_layer_height",
"min_layer_height",
"retract_after_wipe",
"retract_before_wipe",
"retract_length_toolchange",
"retract_lift_above",
"retract_lift_below",
"retract_lift_enforce",
"retract_restart_extra",
"retract_restart_extra_toolchange",
"retract_when_changing_layer",
"retraction_distances_when_cut",
"retraction_length",
"retraction_minimum_travel",
"retraction_speed",
"volumetric_speed_coefficients",
"wipe",
"wipe_distance",
"z_hop",
"z_hop_types",
};
m_filament_retract_keys = {
"deretraction_speed",
"filament_retract_length_nc",
"long_retractions_when_cut",
"retract_after_wipe",
"retract_before_wipe",
"retract_lift_above",
"retract_lift_below",
@@ -8928,6 +9016,8 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
"internal_bridge_support_thickness", "top_area_threshold", "reduce_wall_solid_infill","filament_load_time","filament_unload_time",
"smooth_coefficient", "overhang_totally_speed", "silent_mode",
"overhang_speed_classic", "filament_prime_volume",
"calib_flowrate_topinfill_special_order",
"anisotropic_surfaces", // superseded by top_surface_fill_order / bottom_surface_fill_order
};
if (ignore.find(opt_key) != ignore.end()) {
@@ -9074,6 +9164,9 @@ std::set<std::string> filament_options_with_variant = {
//BBS
"filament_wipe_distance",
"filament_retract_before_wipe",
// Orca
"filament_retract_after_wipe",
//BBS
"filament_long_retractions_when_cut",
"filament_retraction_distances_when_cut",
"long_retractions_when_ec",
@@ -9124,6 +9217,8 @@ std::set<std::string> printer_options_with_variant_1 = {
"wipe",
"wipe_distance",
"retract_before_wipe",
// Orca:
"retract_after_wipe",
"retract_length_toolchange",
"retract_restart_extra",
"retract_restart_extra_toolchange",
+15 -4
View File
@@ -193,6 +193,15 @@ enum class WallDirection
Count,
};
// Orca: print order of surface fill loops/fragments for center-based fill patterns
// (Concentric, Archimedean Chords, Octagram Spiral).
enum class SurfaceFillOrder {
Default,
Outward,
Inward,
Count,
};
//BBS
enum class PrintSequence {
ByLayer,
@@ -660,6 +669,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(WipeTowerWallType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ToolChangeOrderingType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PowerLossRecoveryMode)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SurfaceFillOrder)
#undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS
@@ -1211,9 +1221,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionInt, interlocking_beam_layer_count))
((ConfigOptionInt, interlocking_depth))
((ConfigOptionInt, interlocking_boundary_avoidance))
// Orca: internal use only
((ConfigOptionBool, calib_flowrate_topinfill_special_order)) // ORCA: special flag for flow rate calibration
)
// This object is mapped to Perl as Slic3r::Config::PrintRegion.
@@ -1237,6 +1244,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionPercent, bottom_surface_density))
((ConfigOptionEnum<InfillPattern>, top_surface_pattern))
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionEnum<SurfaceFillOrder>, top_surface_fill_order))
((ConfigOptionEnum<SurfaceFillOrder>, bottom_surface_fill_order))
((ConfigOptionEnum<InfillPattern>, internal_solid_infill_pattern))
((ConfigOptionFloatOrPercent, outer_wall_line_width))
((ConfigOptionFloatsNullable, outer_wall_speed))
@@ -1257,7 +1266,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, lightning_prune_angle))
((ConfigOptionFloat, lightning_straightening_angle))
((ConfigOptionBool, align_infill_direction_to_model))
((ConfigOptionBool, anisotropic_surfaces))
((ConfigOptionEnum<CenterOfSurfacePattern>, center_of_surface_pattern))
((ConfigOptionBool, separated_infills))
((ConfigOptionString, extra_solid_infills))
@@ -1544,6 +1552,9 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionPercents, retract_before_wipe))
// Orca
((ConfigOptionPercents, retract_after_wipe))
((ConfigOptionFloats, retraction_length))
((ConfigOptionFloats, retract_length_toolchange))
((ConfigOptionInt, enable_long_retraction_when_cut))
+2 -1
View File
@@ -1393,6 +1393,8 @@ bool PrintObject::invalidate_state_by_config_options(
} else if (
opt_key == "top_surface_pattern"
|| opt_key == "bottom_surface_pattern"
|| opt_key == "top_surface_fill_order"
|| opt_key == "bottom_surface_fill_order"
|| opt_key == "internal_solid_infill_pattern"
|| opt_key == "external_fill_link_max_length"
|| opt_key == "infill_anchor"
@@ -1400,7 +1402,6 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "top_surface_line_width"
|| opt_key == "top_surface_density"
|| opt_key == "bottom_surface_density"
|| opt_key == "anisotropic_surfaces"
|| opt_key == "center_of_surface_pattern"
|| opt_key == "separated_infills"
|| opt_key == "initial_layer_line_width"
@@ -22,7 +22,7 @@ struct Params
: /*max_acceleration(max_acceleration), */raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width)
{
if (filament_types.size() > 1) {
BOOST_LOG_TRIVIAL(warning)
BOOST_LOG_TRIVIAL(debug)
<< "SupportSpotsGenerator does not currently handle different materials properly, only first will be used";
}
if (filament_types.empty() || filament_types[0].empty()) {