Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsupermerill <merill@free.fr>2022-08-09 17:17:33 +0300
committersupermerill <merill@free.fr>2022-08-11 00:56:04 +0300
commitae6165c8f9b571d073a833a37fe14677309fe71b (patch)
tree9bec3354cd99e3c798a418b8c4c477f7d62bd86f
parentf2041cab5670c429a2586a90c9b22fdaf609bdc7 (diff)
Fix aligned seam & add some others:
- contiguous: even more aligned - scattered: old random: random per island per layer - random : new random: every loop has its own random seam.
-rw-r--r--resources/ui_layout/default/print.as27
-rw-r--r--resources/ui_layout/default/print.ui2
-rw-r--r--src/libslic3r/GCode.cpp5
-rw-r--r--src/libslic3r/GCode/SeamPlacer.cpp297
-rw-r--r--src/libslic3r/GCode/SeamPlacer.hpp11
-rw-r--r--src/libslic3r/PerimeterGenerator.cpp2
-rw-r--r--src/libslic3r/PrintConfig.cpp6
-rw-r--r--src/libslic3r/PrintConfig.hpp2
8 files changed, 208 insertions, 144 deletions
diff --git a/resources/ui_layout/default/print.as b/resources/ui_layout/default/print.as
index 85656054c..3c830bfd1 100644
--- a/resources/ui_layout/default/print.as
+++ b/resources/ui_layout/default/print.as
@@ -156,6 +156,10 @@ void s_not_thick_bridge_set(bool set)
// spRandom [spNearest] spAligned spRear [spCustom] spCost
// ("Cost-based") ("Random") ("Aligned") ("Rear")
// -> Corners Nearest Random Aligned Rear Custom
+
+// spRandom spAllRandom [spNearest] spAligned spExtrAligned spRear [spCustom] spCost
+// ("Cost-based") ("Scattered") ("Random") ("Aligned") ("Contiguous") ("Rear")
+// -> Corners Nearest Scattered Random Aligned Contiguous Rear Custom
float user_angle = 0;
float user_travel = 0;
@@ -164,8 +168,9 @@ int s_seam_position_get(string &out get_val)
int pos = get_int("seam_position");
string seam_pos;
get_string("seam_position", seam_pos);
- if(pos < 5){
- if (pos == 0) return 2;
+ if(pos < 7){
+ if (pos == 0) return 2;// Scattered
+ if (pos == 1) return 3;// Random
return pos + 1;
} else {
float angle = get_float("seam_angle_cost");
@@ -175,15 +180,23 @@ int s_seam_position_get(string &out get_val)
user_angle = angle;
user_travel = travel;
}
- return 5;
+ return 7;
}
void s_seam_position_set(string &in set_val, int idx)
{
if (idx == 2 ) {
- set_int("seam_position", 0);
+ set_int("seam_position", 0); // Scattered
+ } else if (idx == 3) {
+ set_int("seam_position", 1); // Random
+ } else if (idx == 4) {
+ set_int("seam_position", 3); // Aligned
+ } else if (idx == 5) {
+ set_int("seam_position", 4); // Contiguous
+ } else if (idx == 6) {
+ set_int("seam_position", 5); // Rear
} else if (idx <= 1) {
- set_int("seam_position", 5);
+ set_int("seam_position", 7);
if (idx == 0) {
set_percent("seam_angle_cost", 80);
set_percent("seam_travel_cost", 20);
@@ -191,10 +204,8 @@ void s_seam_position_set(string &in set_val, int idx)
set_percent("seam_angle_cost", 30);
set_percent("seam_travel_cost", 60);
}
- } else if (idx < 5) {
- set_int("seam_position", idx - 1);
} else {
- set_int("seam_position", 5);
+ set_int("seam_position", 7);
if(user_angle > 0 || user_travel > 0){
set_percent("seam_angle_cost", user_angle);
set_percent("seam_travel_cost", user_travel);
diff --git a/resources/ui_layout/default/print.ui b/resources/ui_layout/default/print.ui
index d8e3cd442..b3f959aae 100644
--- a/resources/ui_layout/default/print.ui
+++ b/resources/ui_layout/default/print.ui
@@ -70,7 +70,7 @@ group:Advanced
setting:width$5:gap_fill_last
end_line
line:Seam
- setting:tags$Simple$Advanced$Expert$Prusa$SuSi:script:enum$corners$Corners$nearest$Nearest$random$Random$aligned$Aligned$rear$Rear$custom$Custom:depends$seam_position$seam_angle_cost$seam_travel_cost:label$Seam position:label_width$12:sidetext_width$0:tooltip$Position of perimeters' starting points.\nCustom can be defined in Advanced or Expert mode. Cost-based settings let you choose the angle and travel cost. A high angle cost will place the seam where it can be hidden by a corner, the travel cost place the seam near the last position (often at the end of the previous infill).:s_seam_position
+ setting:tags$Simple$Advanced$Expert$Prusa$SuSi:script:enum$corners$Corners$nearest$Nearest$random$Scattered$allrandom$Random$aligned$Aligned$contiguous$Contiguous$rear$Rear$custom$Custom:depends$seam_position$seam_angle_cost$seam_travel_cost:label$Seam position:label_width$12:sidetext_width$0:tooltip$Position of perimeters' starting points.\nCustom can be defined in Advanced or Expert mode. Cost-based settings let you choose the angle and travel cost. A high angle cost will place the seam where it can be hidden by a corner, the travel cost place the seam near the last position (often at the end of the previous infill).:s_seam_position
# setting:tags$Expert:label_width$12:sidetext_width$0:seam_position
setting:tags$Advanced$Expert$SuSi:width$3:sidetext_width$0:seam_angle_cost
setting:tags$Advanced$Expert$SuSi:width$3:sidetext_width$0:seam_travel_cost
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 0ee540981..1468ce55e 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -3683,12 +3683,13 @@ void GCode::split_at_seam_pos(ExtrusionLoop& loop, std::unique_ptr<EdgeGrid::Gri
if (!loop.split_at_vertex(seam))
// The point is not in the original loop. Insert it.
loop.split_at(seam, true);*/
- } else
- m_seam_placer.place_seam(loop,
+ } else {
+ m_seam_placer.place_seam(loop, *this->layer(),
this->last_pos(), m_config.external_perimeters_first,
EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4),
m_print_object_instance_id,
lower_layer_edge_grid ? lower_layer_edge_grid->get() : nullptr);
+ }
}
namespace check_wipe {
diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp
index 83751a3c2..ed7cefc65 100644
--- a/src/libslic3r/GCode/SeamPlacer.cpp
+++ b/src/libslic3r/GCode/SeamPlacer.cpp
@@ -322,7 +322,7 @@ void SeamPlacer::plan_perimeters(const std::vector<const ExtrusionEntity*> perim
m_plan.resize(perimeters.size());
for (int i = 0; i < int(perimeters.size()); ++i) {
- if ((perimeters[i]->role() == erExternalPerimeter || seam_position == SeamPosition::spRandom) && perimeters[i]->is_loop()) {
+ if ((perimeters[i]->role() == erExternalPerimeter || seam_position == SeamPosition::spRandom || seam_position == SeamPosition::spAllRandom) && perimeters[i]->is_loop()) {
last_pos = this->calculate_seam(
layer,
seam_position,
@@ -353,7 +353,7 @@ void SeamPlacer::plan_perimeters(const std::vector<const ExtrusionEntity*> perim
}
-void SeamPlacer::place_seam(ExtrusionLoop& loop, const Point& last_pos, bool external_first, double nozzle_diameter,
+void SeamPlacer::place_seam(ExtrusionLoop& loop, const Layer& layer, const Point& last_pos, bool external_first, double nozzle_diameter,
const uint16_t print_object_instance_idx, const EdgeGrid::Grid* lower_layer_edge_grid)
{
// const double seam_offset = nozzle_diameter;
@@ -371,7 +371,8 @@ void SeamPlacer::place_seam(ExtrusionLoop& loop, const Point& last_pos, bool ext
m_plan[m_plan_idx].po, print_object_instance_idx, lower_layer_edge_grid, last_pos, false);
if (loop.role() == erExternalPerimeter /*m_plan[m_plan_idx].seam_position == spAligned*/)
- m_seam_history.add_seam(m_plan[m_plan_idx].po, m_plan[m_plan_idx].pt, loop.polygon().bounding_box()); }
+ m_seam_history.add_seam(m_plan[m_plan_idx].po, m_plan[m_plan_idx].pt, layer.print_z, loop.polygon().bounding_box());
+ }
else {
if (!external_first) {
// Internal perimeter printed before the external.
@@ -510,6 +511,10 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position,
const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5);
float last_pos_weight = 1.f;
float angle_weight = 1.f;
+ if (seam_position == spCustom)
+ seam_position = spCost;
+ if(seam_position == spNearest)
+ seam_position = spCost;
size_t po_idx = std::find(m_po_list.begin(), m_po_list.end(), po) - m_po_list.begin();
@@ -596,11 +601,11 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position,
}
}
- if (seam_position != spRandom) {
+ if (seam_position != spRandom && seam_position != spAllRandom) {
// Retrieve the last start position for this object.
double travel_cost = 1;
- if (seam_position == spAligned) {
+ if (seam_position == spAligned || seam_position == spExtremlyAligned) {
// Seam is aligned to the seam at the preceding layer.
if (po != nullptr) {
std::optional<Point> pos = m_seam_history.get_last_seam(m_po_list[po_idx], layer_po->print_z, loop.polygon().bounding_box());
@@ -610,17 +615,17 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position,
// TODO: check why i put it out of the if
last_pos_weight = is_custom_enforcer_on_layer(layer_idx, po_idx) ? 0.f : 1.f;
}
- }else if (seam_position == spRear) {
+ } else if (seam_position == spRear) {
// Object is centered around (0,0) in its current coordinate system.
last_pos.x() = 0;
last_pos.y() = coord_t(3. * po->bounding_box().radius());
last_pos_weight = 5.f;
travel_cost = 0;
- }else if (seam_position == spNearest) {
+ } else if (seam_position == spNearest) {
last_pos_weight = 25.f;
travel_cost = 0;
angle_weight = 0;
- }else if (seam_position == spCost) {
+ } else if (seam_position == spCost) {
// last_pos already contains current nozzle position
// set base last_pos_weight to the same value as penaltyFlatSurface
last_pos_weight = 5.f;
@@ -636,122 +641,124 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position,
// Insert a projection of last_pos into the polygon.
size_t last_pos_proj_idx;
{
- Points::const_iterator it = project_point_to_polygon_and_insert(polygon, last_pos, 0.1 * nozzle_r );
+ Points::const_iterator it = project_point_to_polygon_and_insert(polygon, last_pos, 0.1 * nozzle_r);
last_pos_proj_idx = it - polygon.points.begin();
}
Point last_pos_proj = polygon.points[last_pos_proj_idx];
- // Parametrize the polygon by its length.
- std::vector<float> lengths = polygon.parameter_by_length();
+ if (seam_position != spExtremlyAligned) {
- //find the max dist the seam can be
- float dist_max = 0.1f * lengths.back();// 5.f * nozzle_dmr
- if (po != nullptr && travel_cost >= 1) {
- last_pos_weight *= 2;
- dist_max = 0;
- for (size_t i = 0; i < polygon.points.size(); ++i) {
- dist_max = std::max(dist_max, (float)polygon.points[i].distance_to(last_pos_proj));
- }
- }
+ // Parametrize the polygon by its length.
+ std::vector<float> lengths = polygon.parameter_by_length();
- // For each polygon point, store a penalty.
- // First calculate the angles, store them as penalties. The angles are caluculated over a minimum arm length of nozzle_r.
- std::vector<float> penalties = polygon_angles_at_vertices(polygon, lengths,
- this->is_custom_seam_on_layer(layer_idx, po_idx) ? std::min(MINIMAL_POLYGON_SIDE / 2.f, float(nozzle_r)) : float(nozzle_r));
- // No penalty for reflex points, slight penalty for convex points, high penalty for flat surfaces.
- const float penaltyConvexVertex = 1.f;
- const float penaltyFlatSurface = 3.f;
- const float penaltyOverhangHalf = 10.f;
- // Penalty for visible seams.
- for (size_t i = 0; i < polygon.points.size(); ++ i) {
- float ccwAngle = penalties[i];
- if (was_clockwise)
- ccwAngle = - ccwAngle;
- float penalty = 0;
- //if (ccwAngle < -float(0.6 * PI))
- // penalty = 0.f;
- //else if (ccwAngle > float(0.6 * PI))
- //
- // penalty = penaltyConvexVertex;
- //else
- if (ccwAngle < 0.f) {
- // We love Sharp reflex vertex (high negative ccwAngle). It hides the seam perfectly.
- // Interpolate penalty between maximum and zero.
- penalty = penaltyFlatSurface * bspline_kernel(ccwAngle);
- } else if (ccwAngle > float(0.67 * PI)) {
- //penalize too sharp convex angle, it's best to be nearer to ~100°
- penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel( (PI - ccwAngle) * 1.5);
- } else {
- // Interpolate penalty between maximum and the penalty for a convex vertex.
- penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle);
- }
- penalty *= angle_weight;
+ //find the max dist the seam can be
+ float dist_max = 0.1f * lengths.back();// 5.f * nozzle_dmr
if (po != nullptr && travel_cost >= 1) {
- //TODO maybe delete this code path, it's not used in prusa and may not be optimal. At least, document why it's here.
- penalty += last_pos_weight * polygon.points[i].distance_to(last_pos_proj) / dist_max;
- penalties[i] = std::max(0.f, penalty);
- } else {
- // Give a negative penalty for points close to the last point or the prefered seam location.
- float dist_to_last_pos_proj = (i < last_pos_proj_idx) ?
- std::min(lengths[last_pos_proj_idx] - lengths[i], lengths.back() - lengths[last_pos_proj_idx] + lengths[i]) :
- std::min(lengths[i] - lengths[last_pos_proj_idx], lengths.back() - lengths[i] + lengths[last_pos_proj_idx]);
- penalty -= last_pos_weight * bspline_kernel(dist_to_last_pos_proj / dist_max);
- penalties[i] = std::max(0.f, penalty);
- if (prefer_nearest) {
- // This hack limits the search around the nearest position projection.
- penalties[i] += dist_to_last_pos_proj > 6.f * nozzle_r ? 100.f : 0.f;
+ last_pos_weight *= 2;
+ dist_max = 0;
+ for (size_t i = 0; i < polygon.points.size(); ++i) {
+ dist_max = std::max(dist_max, (float)polygon.points[i].distance_to(last_pos_proj));
}
}
- }
-
- // Penalty for overhangs.
- if (lower_layer_edge_grid) {
- // Use the edge grid distance field structure over the lower layer to calculate overhangs.
- coord_t nozzle_r = coord_t(std::floor(scale_(0.5 * nozzle_dmr) + 0.5));
- coord_t search_r = coord_t(std::floor(scale_(0.8 * nozzle_dmr) + 0.5));
- for (size_t i = 0; i < polygon.points.size(); ++ i) {
- const Point &p = polygon.points[i];
- coordf_t dist;
- // Signed distance is positive outside the object, negative inside the object.
- // The point is considered at an overhang, if it is more than nozzle radius
- // outside of the lower layer contour.
- [[maybe_unused]] bool found = lower_layer_edge_grid->signed_distance(p, search_r, dist);
- // If the approximate Signed Distance Field was initialized over lower_layer_edge_grid,
- // then the signed distnace shall always be known.
- assert(found);
- penalties[i] += extrudate_overlap_penalty(float(nozzle_r), penaltyOverhangHalf, float(dist));
+
+ // For each polygon point, store a penalty.
+ // First calculate the angles, store them as penalties. The angles are caluculated over a minimum arm length of nozzle_r.
+ std::vector<float> penalties = polygon_angles_at_vertices(polygon, lengths,
+ this->is_custom_seam_on_layer(layer_idx, po_idx) ? std::min(MINIMAL_POLYGON_SIDE / 2.f, float(nozzle_r)) : float(nozzle_r));
+ // No penalty for reflex points, slight penalty for convex points, high penalty for flat surfaces.
+ const float penaltyConvexVertex = 1.f;
+ const float penaltyFlatSurface = 3.f;
+ const float penaltyOverhangHalf = 10.f;
+ // Penalty for visible seams.
+ for (size_t i = 0; i < polygon.points.size(); ++i) {
+ float ccwAngle = penalties[i];
+ if (was_clockwise)
+ ccwAngle = -ccwAngle;
+ float penalty = 0;
+ //if (ccwAngle < -float(0.6 * PI))
+ // penalty = 0.f;
+ //else if (ccwAngle > float(0.6 * PI))
+ //
+ // penalty = penaltyConvexVertex;
+ //else
+ if (ccwAngle < 0.f) {
+ // We love Sharp reflex vertex (high negative ccwAngle). It hides the seam perfectly.
+ // Interpolate penalty between maximum and zero.
+ penalty = penaltyFlatSurface * bspline_kernel(ccwAngle);
+ } else if (ccwAngle > float(0.67 * PI)) {
+ //penalize too sharp convex angle, it's best to be nearer to ~100°
+ penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel((PI - ccwAngle) * 1.5);
+ } else {
+ // Interpolate penalty between maximum and the penalty for a convex vertex.
+ penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle);
+ }
+ penalty *= angle_weight;
+ if (po != nullptr && travel_cost >= 1) {
+ //TODO maybe delete this code path, it's not used in prusa and may not be optimal. At least, document why it's here.
+ penalty += last_pos_weight * polygon.points[i].distance_to(last_pos_proj) / dist_max;
+ penalties[i] = std::max(0.f, penalty);
+ } else {
+ // Give a negative penalty for points close to the last point or the prefered seam location.
+ float dist_to_last_pos_proj = (i < last_pos_proj_idx) ?
+ std::min(lengths[last_pos_proj_idx] - lengths[i], lengths.back() - lengths[last_pos_proj_idx] + lengths[i]) :
+ std::min(lengths[i] - lengths[last_pos_proj_idx], lengths.back() - lengths[i] + lengths[last_pos_proj_idx]);
+ penalty -= last_pos_weight * bspline_kernel(dist_to_last_pos_proj / dist_max);
+ penalties[i] = std::max(0.f, penalty);
+ if (prefer_nearest) {
+ // This hack limits the search around the nearest position projection.
+ penalties[i] += dist_to_last_pos_proj > 6.f * nozzle_r ? 100.f : 0.f;
+ }
+ }
}
- }
-
- // Custom seam. Huge (negative) constant penalty is applied inside
- // blockers (enforcers) to rule out points that should not win.
- std::vector<float> penalties_with_custom_seam = penalties;
- this->apply_custom_seam(polygon, po_idx, penalties_with_custom_seam, lengths, layer_idx, seam_position);
-
- // Find a point with a minimum penalty.
- size_t idx_min = std::min_element(penalties_with_custom_seam.begin(), penalties_with_custom_seam.end()) - penalties_with_custom_seam.begin();
-
- if (seam_position != spAligned || ! is_custom_enforcer_on_layer(layer_idx, po_idx)) {
- // Very likely the weight of idx_min is very close to the weight of last_pos_proj_idx.
- // In that case use last_pos_proj_idx instead.
- float penalty_aligned = penalties[last_pos_proj_idx];
- float penalty_min = penalties[idx_min];
- float penalty_diff_abs = std::abs(penalties_with_custom_seam[idx_min] - penalties_with_custom_seam[last_pos_proj_idx]);
- float penalty_max = std::max(std::abs(penalties[idx_min]), std::abs(penalties[last_pos_proj_idx]));
- float penalty_diff_rel = (penalty_max == 0.f) ? 0.f : penalty_diff_abs / penalty_max;
- // printf("Align seams, penalty aligned: %f, min: %f, diff abs: %f, diff rel: %f\n", penalty_aligned, penalty_min, penalty_diff_abs, penalty_diff_rel);
- if (std::abs(penalty_diff_rel) < 0.05 && penalty_diff_abs < 3) {
- // Penalty of the aligned point is very close to the minimum penalty.
- // Align the seams as accurately as possible.
- idx_min = last_pos_proj_idx;
+
+ // Penalty for overhangs.
+ if (lower_layer_edge_grid) {
+ // Use the edge grid distance field structure over the lower layer to calculate overhangs.
+ coord_t nozzle_r = coord_t(std::floor(scale_(0.5 * nozzle_dmr) + 0.5));
+ coord_t search_r = coord_t(std::floor(scale_(0.8 * nozzle_dmr) + 0.5));
+ for (size_t i = 0; i < polygon.points.size(); ++i) {
+ const Point& p = polygon.points[i];
+ coordf_t dist;
+ // Signed distance is positive outside the object, negative inside the object.
+ // The point is considered at an overhang, if it is more than nozzle radius
+ // outside of the lower layer contour.
+ [[maybe_unused]] bool found = lower_layer_edge_grid->signed_distance(p, search_r, dist);
+ // If the approximate Signed Distance Field was initialized over lower_layer_edge_grid,
+ // then the signed distnace shall always be known.
+ assert(found);
+ penalties[i] += extrudate_overlap_penalty(float(nozzle_r), penaltyOverhangHalf, float(dist));
+ }
}
- }
- // moved up //TODO verify it's all good
- //if (loop.role() == erExternalPerimeter)
- // m_seam_history.add_seam(po, polygon.points[idx_min], polygon_bb);
+ // Custom seam. Huge (negative) constant penalty is applied inside
+ // blockers (enforcers) to rule out points that should not win.
+ std::vector<float> penalties_with_custom_seam = penalties;
+ this->apply_custom_seam(polygon, po_idx, penalties_with_custom_seam, lengths, layer_idx, seam_position);
+
+ // Find a point with a minimum penalty.
+ size_t idx_min = std::min_element(penalties_with_custom_seam.begin(), penalties_with_custom_seam.end()) - penalties_with_custom_seam.begin();
+
+ if ((seam_position != spAligned && seam_position != spExtremlyAligned) || !is_custom_enforcer_on_layer(layer_idx, po_idx)) {
+ // Very likely the weight of idx_min is very close to the weight of last_pos_proj_idx.
+ // In that case use last_pos_proj_idx instead.
+ float penalty_aligned = penalties[last_pos_proj_idx];
+ float penalty_min = penalties[idx_min];
+ float penalty_diff_abs = std::abs(penalties_with_custom_seam[idx_min] - penalties_with_custom_seam[last_pos_proj_idx]);
+ float penalty_max = std::max(std::abs(penalties[idx_min]), std::abs(penalties[last_pos_proj_idx]));
+ float penalty_diff_rel = (penalty_max == 0.f) ? 0.f : penalty_diff_abs / penalty_max;
+ // printf("Align seams, penalty aligned: %f, min: %f, diff abs: %f, diff rel: %f\n", penalty_aligned, penalty_min, penalty_diff_abs, penalty_diff_rel);
+ if (std::abs(penalty_diff_rel) < 0.05 && penalty_diff_abs < 3) {
+ // Penalty of the aligned point is very close to the minimum penalty.
+ // Align the seams as accurately as possible.
+ idx_min = last_pos_proj_idx;
+ }
+ }
- // Export the contour into a SVG file.
+ // moved up //TODO verify it's all good
+ //if (loop.role() == erExternalPerimeter)
+ // m_seam_history.add_seam(po, polygon.points[idx_min], polygon_bb);
+
+ // Export the contour into a SVG file.
#if 0
{
static int iRun = 0;
@@ -773,9 +780,14 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position,
svg.Close();
}
#endif
- return polygon.points[idx_min];
-
+ return polygon.points[idx_min];
+ } else { // spExtremlyAligned
+ return last_pos_proj;
+ }
} else { // spRandom
+ if (seam_position == spAllRandom) {
+ return this->get_random_seam(layer_idx, polygon, po_idx);
+ }
if ( (loop.loop_role() & ExtrusionLoopRole::elrInternal) != 0 && loop.role() != erExternalPerimeter) {
// This loop does not contain any other loop. Set a random position.
// The other loops will get a seam close to the random point chosen
@@ -1050,7 +1062,7 @@ void SeamPlacer::apply_custom_seam(const Polygon& polygon, size_t po_idx,
assert(i < penalties.size());
penalties[i] += float(ENFORCER_BLOCKER_PENALTY);
}
- if (seam_position == spAligned) {
+ if (seam_position == spAligned || seam_position == spExtremlyAligned) {
std::vector<size_t> enf_centers = find_enforcer_centers(polygon, lengths, enforcers_idxs);
for (size_t idx : enf_centers) {
assert(idx < penalties.size());
@@ -1093,20 +1105,35 @@ void SeamPlacer::apply_custom_seam(const Polygon& polygon, size_t po_idx,
-std::optional<Point> SeamHistory::get_last_seam(const PrintObject* po, coord_t layer_z, const BoundingBox& island_bb)
+std::optional<Point> SeamHistory::get_last_seam(const PrintObject* po, double layer_z, const BoundingBox& island_bb)
{
+
+ std::optional<Point> out;
+
+ if (m_data.empty())
+ return out;
+
+ // Get seam was called for different layer than last time.
+ std::map<const PrintObject*, std::vector<SeamPoint>>* data_last_layer = nullptr;
+ for (auto it = m_data.begin() + 1; it != m_data.end(); ++it) {
+ if (it->first == layer_z) {
+ data_last_layer = &std::prev(it)->second;
+ break;
+ }
+ }
+ if (data_last_layer == nullptr && m_data.back().first < layer_z) {
+ data_last_layer = &m_data.back().second;
+ }
+ if (data_last_layer == nullptr)
+ return out;
+
assert(layer_z >= m_layer_z);
if (layer_z > m_layer_z) {
- // Get seam was called for different layer than last time.
- m_data_last_layer = m_data_this_layer;
- m_data_this_layer.clear();
m_layer_z = layer_z;
}
- std::optional<Point> out;
-
- auto seams_it = m_data_last_layer.find(po);
- if (seams_it == m_data_last_layer.end())
+ auto seams_it = data_last_layer->find(po);
+ if (seams_it == data_last_layer->end())
return out;
const std::vector<SeamPoint>& seam_data_po = seams_it->second;
@@ -1137,9 +1164,28 @@ std::optional<Point> SeamHistory::get_last_seam(const PrintObject* po, coord_t l
-void SeamHistory::add_seam(const PrintObject* po, const Point& pos, const BoundingBox& island_bb)
+void SeamHistory::add_seam(const PrintObject* po, const Point& pos, double layer_z, const BoundingBox& island_bb)
{
- m_data_this_layer[po].push_back({pos, island_bb});;
+ std::map<const PrintObject*, std::vector<SeamPoint>>* data_this_layer = nullptr;
+ for (auto it = m_data.begin(); it != m_data.end(); ++it) {
+ if (it->first == layer_z) {
+ data_this_layer = &it->second;
+ break;
+ }
+ if (it->first >= layer_z) {
+ //add it before
+ m_data.emplace(it);
+ it->first = layer_z;
+ data_this_layer = &it->second;
+ }
+ }
+ if (data_this_layer == nullptr) {
+ //push to end
+ m_data.emplace_back();
+ m_data.back().first = layer_z;
+ data_this_layer = &m_data.back().second;
+ }
+ (*data_this_layer)[po].push_back({pos, island_bb});
}
@@ -1147,8 +1193,7 @@ void SeamHistory::add_seam(const PrintObject* po, const Point& pos, const Boundi
void SeamHistory::clear()
{
m_layer_z = 0;
- m_data_last_layer.clear();
- m_data_this_layer.clear();
+ m_data.clear();
}
diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp
index 061c35b21..089557b5b 100644
--- a/src/libslic3r/GCode/SeamPlacer.hpp
+++ b/src/libslic3r/GCode/SeamPlacer.hpp
@@ -21,9 +21,9 @@ namespace EdgeGrid { class Grid; }
class SeamHistory {
public:
- SeamHistory() { clear(); }
- std::optional<Point> get_last_seam(const PrintObject* po, coord_t layer_z, const BoundingBox& island_bb);
- void add_seam(const PrintObject* po, const Point& pos, const BoundingBox& island_bb);
+ SeamHistory() {}
+ std::optional<Point> get_last_seam(const PrintObject* po, double layer_z, const BoundingBox& island_bb);
+ void add_seam(const PrintObject* po, const Point& pos, double layer_z, const BoundingBox& island_bb);
void clear();
private:
@@ -32,8 +32,7 @@ private:
BoundingBox m_island_bb;
};
- std::map<const PrintObject*, std::vector<SeamPoint>> m_data_last_layer;
- std::map<const PrintObject*, std::vector<SeamPoint>> m_data_this_layer;
+ std::vector<std::pair<double, std::map<const PrintObject*, std::vector<SeamPoint>>>> m_data;
coord_t m_layer_z;
};
@@ -54,7 +53,7 @@ public:
const uint16_t print_object_instance_idx,
const EdgeGrid::Grid* lower_layer_edge_grid);
- void place_seam(ExtrusionLoop& loop, const Point& last_pos, bool external_first, double nozzle_diameter,
+ void place_seam(ExtrusionLoop& loop, const Layer& layer, const Point& last_pos, bool external_first, double nozzle_diameter,
const uint16_t print_object_instance_idx, const EdgeGrid::Grid* lower_layer_edge_grid);
diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp
index 2500136c1..1248b8890 100644
--- a/src/libslic3r/PerimeterGenerator.cpp
+++ b/src/libslic3r/PerimeterGenerator.cpp
@@ -1954,7 +1954,7 @@ PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children,
if (myPolylines.paths[idx_poly].length() < dist_cut + perimeter_flow.scaled_width()/20) continue;
if ((myPolylines.paths[idx_poly].role() == erExternalPerimeter || child.is_external() )
- && this->object_config->seam_position.value != SeamPosition::spRandom) {
+ && (this->object_config->seam_position.value != SeamPosition::spRandom && this->object_config->seam_position.value != SeamPosition::spAllRandom)) {
//first, try to find 2 point near enough
for (size_t idx_point = 0; idx_point < myPolylines.paths[idx_poly].polyline.points.size(); idx_point++) {
const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point];
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index fb4f3dc2a..739651ecf 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -201,9 +201,11 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialInterfacePattern)
static const t_config_enum_values s_keys_map_SeamPosition{
{"random", spRandom},
+ {"allrandom", spAllRandom},
{"nearest", spNearest}, // unused, replaced by cost
{"cost", spCost},
{"aligned", spAligned},
+ {"contiguous", spExtremlyAligned},
{"rear", spRear},
{"custom", spCustom}, // for seam object
};
@@ -4286,11 +4288,15 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<SeamPosition>::get_enum_values();
def->enum_values.push_back("cost");
def->enum_values.push_back("random");
+ def->enum_values.push_back("allrandom");
def->enum_values.push_back("aligned");
+ def->enum_values.push_back("contiguous");
def->enum_values.push_back("rear");
def->enum_labels.push_back(L("Cost-based"));
+ def->enum_labels.push_back(L("Scattered"));
def->enum_labels.push_back(L("Random"));
def->enum_labels.push_back(L("Aligned"));
+ def->enum_labels.push_back(L("Contiguous"));
def->enum_labels.push_back(L("Rear"));
def->mode = comSimpleAE | comPrusa;
def->set_default_value(new ConfigOptionEnum<SeamPosition>(spCost));
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index e233d309d..c894d0b70 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -165,8 +165,10 @@ enum SupportMaterialInterfacePattern {
enum SeamPosition {
spRandom,
+ spAllRandom,
spNearest, //not used anymore
spAligned,
+ spExtremlyAligned,
spRear,
spCustom, // or seam object
spCost,