mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 09:05:54 +08:00
fix seams
* fix the seam object * fix painting seam that will jump on nearest for no good reason * change hidden/near/nearer to cost with 2 boxes for setting the costs. fix preferences
This commit is contained in:
parent
3aaedd671b
commit
07be95fb69
@ -49,14 +49,15 @@ group:Overhangs
|
|||||||
setting:width$5:overhangs_reverse_threshold
|
setting:width$5:overhangs_reverse_threshold
|
||||||
end_line
|
end_line
|
||||||
group:Advanced
|
group:Advanced
|
||||||
setting:no_perimeter_unsupported_algo
|
setting:width$25:no_perimeter_unsupported_algo
|
||||||
line:Gap Fill
|
line:Gap Fill
|
||||||
setting:gap_fill
|
setting:gap_fill
|
||||||
setting:width$5:gap_fill_min_area
|
setting:width$5:gap_fill_min_area
|
||||||
end_line
|
end_line
|
||||||
line:Seam
|
line:Seam
|
||||||
setting:seam_position
|
setting:sidetext_width$2:seam_position
|
||||||
setting:seam_travel
|
setting:label_width$10:width$3:sidetext_width$2:seam_angle_cost
|
||||||
|
setting:label_width$10:width$3:sidetext_width$2:seam_travel_cost
|
||||||
end_line
|
end_line
|
||||||
line:Looping perimeter
|
line:Looping perimeter
|
||||||
setting:perimeter_loop
|
setting:perimeter_loop
|
||||||
|
@ -60,9 +60,9 @@ void AppConfig::set_defaults()
|
|||||||
set("freecad_path", ".");
|
set("freecad_path", ".");
|
||||||
|
|
||||||
if (get("version_check").empty())
|
if (get("version_check").empty())
|
||||||
set("version_check", "1");
|
set("version_check", "0");
|
||||||
if (get("preset_update").empty())
|
if (get("preset_update").empty())
|
||||||
set("preset_update", "1");
|
set("preset_update", "0");
|
||||||
|
|
||||||
if (get("export_sources_full_pathnames").empty())
|
if (get("export_sources_full_pathnames").empty())
|
||||||
set("export_sources_full_pathnames", "0");
|
set("export_sources_full_pathnames", "0");
|
||||||
|
@ -3227,7 +3227,7 @@ void GCode::split_at_seam_pos(ExtrusionLoop& loop, std::unique_ptr<EdgeGrid::Gri
|
|||||||
? lower_layer_edge_grid->get()
|
? lower_layer_edge_grid->get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
//TODO modify m_seam_placer to takers into account extra options.
|
//TODO modify m_seam_placer to takers into account extra options.
|
||||||
Point seam = m_seam_placer.get_seam(m_layer->id(), seam_position, loop,
|
Point seam = m_seam_placer.get_seam(m_layer, seam_position, loop,
|
||||||
last_pos, EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0),
|
last_pos, EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0),
|
||||||
(m_layer == NULL ? nullptr : m_layer->object()),
|
(m_layer == NULL ? nullptr : m_layer->object()),
|
||||||
was_clockwise, edge_grid_ptr);
|
was_clockwise, edge_grid_ptr);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/BoundingBox.hpp"
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
#include "libslic3r/EdgeGrid.hpp"
|
#include "libslic3r/EdgeGrid.hpp"
|
||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
@ -50,6 +51,7 @@ plot(p2.subs(r,0.2).subs(z,1.), (x, -1, 3), adaptive=False, nb_of_points=400)
|
|||||||
|
|
||||||
// Return a value in <0, 1> of a cubic B-spline kernel centered around zero.
|
// Return a value in <0, 1> of a cubic B-spline kernel centered around zero.
|
||||||
// The B-spline is re-scaled so it has value 1 at zero.
|
// The B-spline is re-scaled so it has value 1 at zero.
|
||||||
|
// 0 -> 1 ; ~0.465 -> 0.75 ; ~0.72 -> 0.5 ; 1 -> 0.25 ; ~1.23 -> 0.125 ; 2+ -> 0
|
||||||
static inline float bspline_kernel(float x)
|
static inline float bspline_kernel(float x)
|
||||||
{
|
{
|
||||||
x = std::abs(x);
|
x = std::abs(x);
|
||||||
@ -208,13 +210,16 @@ void SeamPlacer::init(const Print& print)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_position,
|
Point SeamPlacer::get_seam(const Layer *layer, SeamPosition seam_position,
|
||||||
const ExtrusionLoop& loop, Point last_pos, coordf_t nozzle_dmr,
|
const ExtrusionLoop& loop, Point last_pos, coordf_t nozzle_dmr,
|
||||||
const PrintObject* po, bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid)
|
const PrintObject* po, bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid)
|
||||||
{
|
{
|
||||||
|
const size_t layer_idx = layer->id();
|
||||||
Polygon polygon = loop.polygon();
|
Polygon polygon = loop.polygon();
|
||||||
BoundingBox polygon_bb = polygon.bounding_box();
|
BoundingBox polygon_bb = polygon.bounding_box();
|
||||||
const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5);
|
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 (this->is_custom_seam_on_layer(layer_idx)) {
|
if (this->is_custom_seam_on_layer(layer_idx)) {
|
||||||
// Seam enf/blockers can begin and end in between the original vertices.
|
// Seam enf/blockers can begin and end in between the original vertices.
|
||||||
@ -222,9 +227,53 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
|||||||
polygon.densify(MINIMAL_POLYGON_SIDE);
|
polygon.densify(MINIMAL_POLYGON_SIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_seam_custom = false;
|
||||||
|
for (ModelVolume* v : po->model_object()->volumes)
|
||||||
|
if (v->is_seam_position()) {
|
||||||
|
has_seam_custom = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (has_seam_custom) {
|
||||||
|
// Look for all lambda-seam-modifiers below current z, choose the highest one
|
||||||
|
ModelVolume* v_lambda_seam = nullptr;
|
||||||
|
Vec3d lambda_pos;
|
||||||
|
double lambda_dist;
|
||||||
|
double lambda_radius;
|
||||||
|
for (ModelVolume* v : po->model_object()->volumes)
|
||||||
|
if (v->is_seam_position()) {
|
||||||
|
//xy in object coordinates, z in plater coordinates
|
||||||
|
Vec3d test_lambda_pos = po->model_object()->instances.front()->transform_vector(v->get_offset(), true);
|
||||||
|
Vec3d test_lambda_pos_plater = po->model_object()->instances.front()->transform_vector(v->get_offset(), false);
|
||||||
|
Point xy_lambda(scale_(test_lambda_pos.x()), scale_(test_lambda_pos.y()));
|
||||||
|
Point nearest = polygon.point_projection(xy_lambda);
|
||||||
|
Vec3d polygon_3dpoint{ unscaled(nearest.x()), unscaled(nearest.y()), (double)layer->print_z };
|
||||||
|
double test_lambda_dist = (polygon_3dpoint - test_lambda_pos).norm();
|
||||||
|
double sphere_radius = po->model_object()->instances.front()->transform_bounding_box(v->mesh().bounding_box(), true).size().x() / 2;
|
||||||
|
//if (test_lambda_dist > sphere_radius)
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
//use this one if the first or nearer (in z)
|
||||||
|
if (v_lambda_seam == nullptr || lambda_dist > test_lambda_dist) {
|
||||||
|
v_lambda_seam = v;
|
||||||
|
lambda_pos = test_lambda_pos;
|
||||||
|
lambda_radius = sphere_radius;
|
||||||
|
lambda_dist = test_lambda_dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v_lambda_seam != nullptr) {
|
||||||
|
lambda_pos = po->model_object()->instances.front()->transform_vector(v_lambda_seam->get_offset(), true);
|
||||||
|
// Found, get the center point and apply rotation and scaling of Model instance. Continues to spAligned if not found or Weight set to Zero.
|
||||||
|
last_pos = Point::new_scale(lambda_pos.x(), lambda_pos.y());
|
||||||
|
// Weight is set by user and stored in the radius of the sphere
|
||||||
|
last_pos_weight = std::max(0.0, std::round(100 * (lambda_radius)));
|
||||||
|
if (last_pos_weight > 0.0)
|
||||||
|
seam_position = spCustom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (seam_position != spRandom) {
|
if (seam_position != spRandom) {
|
||||||
// Retrieve the last start position for this object.
|
// Retrieve the last start position for this object.
|
||||||
float last_pos_weight = 1.f;
|
|
||||||
|
|
||||||
if (seam_position == spAligned) {
|
if (seam_position == spAligned) {
|
||||||
// Seam is aligned to the seam at the preceding layer.
|
// Seam is aligned to the seam at the preceding layer.
|
||||||
@ -233,32 +282,51 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
|||||||
if (pos.has_value()) {
|
if (pos.has_value()) {
|
||||||
//last_pos = m_last_seam_position[po];
|
//last_pos = m_last_seam_position[po];
|
||||||
last_pos = *pos;
|
last_pos = *pos;
|
||||||
last_pos_weight = is_custom_enforcer_on_layer(layer_idx) ? 0.f : 1.f;
|
|
||||||
}
|
}
|
||||||
|
last_pos_weight = is_custom_enforcer_on_layer(layer_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.
|
// Object is centered around (0,0) in its current coordinate system.
|
||||||
last_pos.x() = 0;
|
last_pos.x() = 0;
|
||||||
last_pos.y() += coord_t(3. * po->bounding_box().radius());
|
last_pos.y() += coord_t(3. * po->bounding_box().radius());
|
||||||
last_pos_weight = 5.f;
|
last_pos_weight = 5.f;
|
||||||
} if (seam_position == spNearest) {
|
}else if (seam_position == spNearest) {
|
||||||
// last_pos already contains current nozzle position
|
// last_pos already contains current nozzle position
|
||||||
|
// set base last_pos_weight to the same value as penaltyFlatSurface
|
||||||
|
last_pos_weight = 5.f;
|
||||||
|
if (po != nullptr) {
|
||||||
|
last_pos_weight = po->config().seam_travel_cost.get_abs_value(last_pos_weight);
|
||||||
|
angle_weight = po->config().seam_angle_cost.get_abs_value(angle_weight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Insert a projection of last_pos into the polygon.
|
// Insert a projection of last_pos into the polygon.
|
||||||
size_t last_pos_proj_idx;
|
size_t last_pos_proj_idx;
|
||||||
{
|
{
|
||||||
auto 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();
|
last_pos_proj_idx = it - polygon.points.begin();
|
||||||
}
|
}
|
||||||
|
Point last_pos_proj = polygon.points[last_pos_proj_idx];
|
||||||
|
|
||||||
// Parametrize the polygon by its length.
|
// Parametrize the polygon by its length.
|
||||||
std::vector<float> lengths = polygon.parameter_by_length();
|
std::vector<float> lengths = polygon.parameter_by_length();
|
||||||
|
|
||||||
|
//find the max dist the seam can be
|
||||||
|
float dist_max = 0.1f * lengths.back();// 5.f * nozzle_dmr
|
||||||
|
if (po != nullptr && po->config().seam_travel_cost.get_abs_value(1) >= 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For each polygon point, store a penalty.
|
// 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.
|
// 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, float(nozzle_r));
|
std::vector<float> penalties = polygon_angles_at_vertices(polygon, lengths,
|
||||||
|
this->is_custom_seam_on_layer(layer_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.
|
// No penalty for reflex points, slight penalty for convex points, high penalty for flat surfaces.
|
||||||
const float penaltyConvexVertex = 1.f;
|
const float penaltyConvexVertex = 1.f;
|
||||||
const float penaltyFlatSurface = 5.f;
|
const float penaltyFlatSurface = 5.f;
|
||||||
@ -269,26 +337,33 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
|||||||
if (was_clockwise)
|
if (was_clockwise)
|
||||||
ccwAngle = - ccwAngle;
|
ccwAngle = - ccwAngle;
|
||||||
float penalty = 0;
|
float penalty = 0;
|
||||||
if (ccwAngle <- float(0.6 * PI))
|
//if (ccwAngle < -float(0.6 * PI))
|
||||||
// Sharp reflex vertex. We love that, it hides the seam perfectly.
|
// penalty = 0.f;
|
||||||
penalty = 0.f;
|
//else if (ccwAngle > float(0.6 * PI))
|
||||||
else if (ccwAngle > float(0.6 * PI))
|
//
|
||||||
// Seams on sharp convex vertices are more visible than on reflex vertices.
|
// penalty = penaltyConvexVertex;
|
||||||
penalty = penaltyConvexVertex;
|
//else
|
||||||
else if (ccwAngle < 0.f) {
|
if (ccwAngle < 0.f) {
|
||||||
|
// We love Sharp reflex vertex (high negative ccwAngle). It hides the seam perfectly.
|
||||||
// Interpolate penalty between maximum and zero.
|
// Interpolate penalty between maximum and zero.
|
||||||
penalty = penaltyFlatSurface * bspline_kernel(ccwAngle * float(PI * 2. / 3.));
|
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 {
|
} else {
|
||||||
assert(ccwAngle >= 0.f);
|
|
||||||
// Interpolate penalty between maximum and the penalty for a convex vertex.
|
// Interpolate penalty between maximum and the penalty for a convex vertex.
|
||||||
penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle * float(PI * 2. / 3.));
|
penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle);
|
||||||
|
}
|
||||||
|
penalty *= angle_weight;
|
||||||
|
if (po != nullptr && po->config().seam_travel_cost.get_abs_value(1) >= 1) {
|
||||||
|
penalty += last_pos_weight * polygon.points[i].distance_to(last_pos_proj) / dist_max;
|
||||||
|
} 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);
|
||||||
}
|
}
|
||||||
// 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]);
|
|
||||||
float dist_max = 0.1f * lengths.back(); // 5.f * nozzle_dmr
|
|
||||||
penalty -= last_pos_weight * bspline_kernel(dist_to_last_pos_proj / dist_max);
|
|
||||||
penalties[i] = std::max(0.f, penalty);
|
penalties[i] = std::max(0.f, penalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,28 +388,29 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
|||||||
|
|
||||||
// Custom seam. Huge (negative) constant penalty is applied inside
|
// Custom seam. Huge (negative) constant penalty is applied inside
|
||||||
// blockers (enforcers) to rule out points that should not win.
|
// blockers (enforcers) to rule out points that should not win.
|
||||||
this->apply_custom_seam(polygon, penalties, lengths, layer_idx, seam_position);
|
std::vector<float> penalties_with_custom_seam = penalties;
|
||||||
|
this->apply_custom_seam(polygon, penalties_with_custom_seam, lengths, layer_idx, seam_position);
|
||||||
|
|
||||||
// Find a point with a minimum penalty.
|
// Find a point with a minimum penalty.
|
||||||
size_t idx_min = std::min_element(penalties.begin(), penalties.end()) - penalties.begin();
|
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)) {
|
if (seam_position != spAligned || ! is_custom_enforcer_on_layer(layer_idx)) {
|
||||||
// Very likely the weight of idx_min is very close to the weight of last_pos_proj_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.
|
// In that case use last_pos_proj_idx instead.
|
||||||
float penalty_aligned = penalties[last_pos_proj_idx];
|
float penalty_aligned = penalties[last_pos_proj_idx];
|
||||||
float penalty_min = penalties[idx_min];
|
float penalty_min = penalties[idx_min];
|
||||||
float penalty_diff_abs = std::abs(penalty_min - penalty_aligned);
|
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(penalty_min, penalty_aligned);
|
float penalty_max = std::max(penalties[idx_min], penalties[last_pos_proj_idx]);
|
||||||
float penalty_diff_rel = (penalty_max == 0.f) ? 0.f : penalty_diff_abs / penalty_max;
|
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);
|
// 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) {
|
if (std::abs(penalty_diff_rel) < 0.05 && penalty_diff_abs < 3) {
|
||||||
// Penalty of the aligned point is very close to the minimum penalty.
|
// Penalty of the aligned point is very close to the minimum penalty.
|
||||||
// Align the seams as accurately as possible.
|
// Align the seams as accurately as possible.
|
||||||
idx_min = last_pos_proj_idx;
|
idx_min = last_pos_proj_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seam_position == spAligned && loop.role() == erExternalPerimeter)
|
if (loop.role() == erExternalPerimeter)
|
||||||
m_seam_history.add_seam(po, polygon.points[idx_min], polygon_bb);
|
m_seam_history.add_seam(po, polygon.points[idx_min], polygon_bb);
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace Slic3r {
|
|||||||
class PrintObject;
|
class PrintObject;
|
||||||
class ExtrusionLoop;
|
class ExtrusionLoop;
|
||||||
class Print;
|
class Print;
|
||||||
|
class Layer;
|
||||||
namespace EdgeGrid { class Grid; }
|
namespace EdgeGrid { class Grid; }
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ class SeamPlacer {
|
|||||||
public:
|
public:
|
||||||
void init(const Print& print);
|
void init(const Print& print);
|
||||||
|
|
||||||
Point get_seam(const size_t layer_idx, const SeamPosition seam_position,
|
Point get_seam(const Layer *layer, const SeamPosition seam_position,
|
||||||
const ExtrusionLoop& loop, Point last_pos,
|
const ExtrusionLoop& loop, Point last_pos,
|
||||||
coordf_t nozzle_diameter, const PrintObject* po,
|
coordf_t nozzle_diameter, const PrintObject* po,
|
||||||
bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid);
|
bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid);
|
||||||
|
@ -536,7 +536,8 @@ const std::vector<std::string>& Preset::print_options()
|
|||||||
"exact_last_layer_height",
|
"exact_last_layer_height",
|
||||||
"perimeter_loop",
|
"perimeter_loop",
|
||||||
"perimeter_loop_seam",
|
"perimeter_loop_seam",
|
||||||
"seam_travel",
|
"seam_angle_cost",
|
||||||
|
"seam_travel_cost",
|
||||||
"infill_connection",
|
"infill_connection",
|
||||||
"first_layer_infill_speed",
|
"first_layer_infill_speed",
|
||||||
"thin_walls_min_width",
|
"thin_walls_min_width",
|
||||||
|
@ -932,28 +932,28 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
}
|
}
|
||||||
// Copy content of the ModelObject including its ID, do not change the parent.
|
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||||
model_object.assign_copy(model_object_new);
|
model_object.assign_copy(model_object_new);
|
||||||
} else if (supports_differ || model_custom_supports_data_changed(model_object, model_object_new)) {
|
} else if (supports_differ || seam_position_differ || model_custom_supports_data_changed(model_object, model_object_new)) {
|
||||||
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||||
if (supports_differ) {
|
if (supports_differ) {
|
||||||
this->call_cancel_callback();
|
this->call_cancel_callback();
|
||||||
update_apply_status(false);
|
update_apply_status(false);
|
||||||
}
|
}
|
||||||
// Invalidate just the supports step.
|
// Invalidate just the supports step.
|
||||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
for (auto it = range.first; it != range.second; ++ it)
|
for (auto it = range.first; it != range.second; ++ it)
|
||||||
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
|
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
|
||||||
if (supports_differ) {
|
if (supports_differ) {
|
||||||
// Copy just the support volumes.
|
// Copy just the support volumes.
|
||||||
model_volume_list_update_supports_seams(model_object, model_object_new);
|
model_volume_list_update_supports_seams(model_object, model_object_new);
|
||||||
}else if (seam_position_differ) {
|
}else if (seam_position_differ) {
|
||||||
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||||
this->call_cancel_callback();
|
this->call_cancel_callback();
|
||||||
update_apply_status(false);
|
update_apply_status(false);
|
||||||
// Invalidate just the gcode step.
|
// Invalidate just the gcode step.
|
||||||
invalidate_step(psGCodeExport);
|
invalidate_step(psGCodeExport);
|
||||||
// Copy just the seam volumes.
|
// Copy just the seam volumes.
|
||||||
model_volume_list_update_supports_seams(model_object, model_object_new);
|
model_volume_list_update_supports_seams(model_object, model_object_new);
|
||||||
}
|
}
|
||||||
} else if (model_custom_seam_data_changed(model_object, model_object_new)) {
|
} else if (model_custom_seam_data_changed(model_object, model_object_new)) {
|
||||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||||
}
|
}
|
||||||
|
@ -2796,31 +2796,38 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->label = L("Seam position");
|
def->label = L("Seam position");
|
||||||
def->category = OptionCategory::perimeter;
|
def->category = OptionCategory::perimeter;
|
||||||
def->tooltip = L("Position of perimeters starting points."
|
def->tooltip = L("Position of perimeters starting points."
|
||||||
"\n --- When using Custom seam ---"
|
"\n ");
|
||||||
"\nYou have to create one or more seam sphere in the context menu of the object."
|
|
||||||
" When an object has a seam object, this setting is not taken into account nymore for the object."
|
|
||||||
" Refer to the wiki/help menu for more information.");
|
|
||||||
def->enum_keys_map = &ConfigOptionEnum<SeamPosition>::get_enum_values();
|
def->enum_keys_map = &ConfigOptionEnum<SeamPosition>::get_enum_values();
|
||||||
def->enum_values.push_back("random");
|
|
||||||
def->enum_values.push_back("near");
|
def->enum_values.push_back("near");
|
||||||
|
def->enum_values.push_back("random");
|
||||||
def->enum_values.push_back("aligned");
|
def->enum_values.push_back("aligned");
|
||||||
def->enum_values.push_back("rear");
|
def->enum_values.push_back("rear");
|
||||||
def->enum_values.push_back("hidden");
|
def->enum_labels.push_back(L("Cost-based"));
|
||||||
def->enum_labels.push_back(L("Random"));
|
def->enum_labels.push_back(L("Random"));
|
||||||
def->enum_labels.push_back(L("Nearest"));
|
|
||||||
def->enum_labels.push_back(L("Aligned"));
|
def->enum_labels.push_back(L("Aligned"));
|
||||||
def->enum_labels.push_back(L("Rear"));
|
def->enum_labels.push_back(L("Rear"));
|
||||||
def->enum_labels.push_back(L("Corners"));
|
|
||||||
def->mode = comSimple;
|
def->mode = comSimple;
|
||||||
def->set_default_value(new ConfigOptionEnum<SeamPosition>(spHidden));
|
def->set_default_value(new ConfigOptionEnum<SeamPosition>(spNearest));
|
||||||
|
|
||||||
def = this->add("seam_travel", coBool);
|
def = this->add("seam_angle_cost", coPercent);
|
||||||
def->label = L("Travel move reduced");
|
def->label = L("Angle cost");
|
||||||
|
def->full_label = L("Seam angle cost");
|
||||||
def->category = OptionCategory::perimeter;
|
def->category = OptionCategory::perimeter;
|
||||||
def->tooltip = L("Add a big cost to travel paths when possible (when going into a loop), so it will prefer a less optimal seam posistion if it's nearer.");
|
def->tooltip = L("Cost of placing the seam at a bad angle. The worst angle (max penalty) is when it's flat.");
|
||||||
def->cli = "seam-travel!";
|
def->sidetext = L("%");
|
||||||
|
def->min = 0;
|
||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionBool(false));
|
def->set_default_value(new ConfigOptionPercent(100));
|
||||||
|
|
||||||
|
def = this->add("seam_travel_cost", coPercent);
|
||||||
|
def->label = L("Travel cost");
|
||||||
|
def->full_label = L("Seam travel cost");
|
||||||
|
def->category = OptionCategory::perimeter;
|
||||||
|
def->tooltip = L("Cost of moving the extruder. The highest penalty is when the point is the farest from the position of the extruder before extruding the external periemter");
|
||||||
|
def->sidetext = L("%");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionPercent(100));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
def = this->add("seam_preferred_direction", coFloat);
|
def = this->add("seam_preferred_direction", coFloat);
|
||||||
@ -4769,8 +4776,19 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||||||
value = "notconnected";
|
value = "notconnected";
|
||||||
else
|
else
|
||||||
value = "connected";
|
value = "connected";
|
||||||
|
} else if (opt_key == "seam_travel") {
|
||||||
|
if (value == "1") {
|
||||||
|
opt_key = "seam_travel_cost";
|
||||||
|
value = "200%";
|
||||||
|
} else {
|
||||||
|
opt_key = "";
|
||||||
|
}
|
||||||
|
} else if (opt_key == "seam_position") {
|
||||||
|
if (value == "hidden") {
|
||||||
|
opt_key = "seam_travel_cost";
|
||||||
|
value = "20%";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the following obsolete configuration keys:
|
// Ignore the following obsolete configuration keys:
|
||||||
static std::set<std::string> ignore = {
|
static std::set<std::string> ignore = {
|
||||||
"duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y",
|
"duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y",
|
||||||
|
@ -100,7 +100,7 @@ enum SupportMaterialPattern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum SeamPosition {
|
enum SeamPosition {
|
||||||
spRandom, spNearest, spAligned, spRear, spHidden, spCustom
|
spRandom, spNearest, spAligned, spRear, spCustom
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SLAMaterial {
|
enum SLAMaterial {
|
||||||
@ -272,11 +272,11 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::ge
|
|||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["random"] = spRandom;
|
keys_map["random"] = spRandom;
|
||||||
keys_map["nearest"] = spHidden;
|
keys_map["nearest"] = spNearest;
|
||||||
keys_map["near"] = spNearest;
|
keys_map["near"] = spNearest;
|
||||||
keys_map["aligned"] = spAligned;
|
keys_map["aligned"] = spAligned;
|
||||||
keys_map["rear"] = spRear;
|
keys_map["rear"] = spRear;
|
||||||
keys_map["hidden"] = spHidden;
|
keys_map["hidden"] = spNearest;
|
||||||
keys_map["custom"] = spCustom;
|
keys_map["custom"] = spCustom;
|
||||||
}
|
}
|
||||||
return keys_map;
|
return keys_map;
|
||||||
@ -587,7 +587,8 @@ public:
|
|||||||
ConfigOptionPercent perimeter_bonding;
|
ConfigOptionPercent perimeter_bonding;
|
||||||
ConfigOptionInt raft_layers;
|
ConfigOptionInt raft_layers;
|
||||||
ConfigOptionEnum<SeamPosition> seam_position;
|
ConfigOptionEnum<SeamPosition> seam_position;
|
||||||
ConfigOptionBool seam_travel;
|
ConfigOptionPercent seam_angle_cost;
|
||||||
|
ConfigOptionPercent seam_travel_cost;
|
||||||
// ConfigOptionFloat seam_preferred_direction;
|
// ConfigOptionFloat seam_preferred_direction;
|
||||||
// ConfigOptionFloat seam_preferred_direction_jitter;
|
// ConfigOptionFloat seam_preferred_direction_jitter;
|
||||||
ConfigOptionFloat slice_closing_radius;
|
ConfigOptionFloat slice_closing_radius;
|
||||||
@ -650,7 +651,8 @@ protected:
|
|||||||
OPT_PTR(perimeter_bonding);
|
OPT_PTR(perimeter_bonding);
|
||||||
OPT_PTR(raft_layers);
|
OPT_PTR(raft_layers);
|
||||||
OPT_PTR(seam_position);
|
OPT_PTR(seam_position);
|
||||||
OPT_PTR(seam_travel);
|
OPT_PTR(seam_angle_cost);
|
||||||
|
OPT_PTR(seam_travel_cost);
|
||||||
OPT_PTR(slice_closing_radius);
|
OPT_PTR(slice_closing_radius);
|
||||||
// OPT_PTR(seam_preferred_direction);
|
// OPT_PTR(seam_preferred_direction);
|
||||||
// OPT_PTR(seam_preferred_direction_jitter);
|
// OPT_PTR(seam_preferred_direction_jitter);
|
||||||
|
@ -819,7 +819,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
|||||||
|| opt_key == "seam_position"
|
|| opt_key == "seam_position"
|
||||||
|| opt_key == "seam_preferred_direction"
|
|| opt_key == "seam_preferred_direction"
|
||||||
|| opt_key == "seam_preferred_direction_jitter"
|
|| opt_key == "seam_preferred_direction_jitter"
|
||||||
|| opt_key == "seam_travel"
|
|| opt_key == "seam_angle_cost"
|
||||||
|
|| opt_key == "seam_travel_cost"
|
||||||
|| opt_key == "small_perimeter_speed"
|
|| opt_key == "small_perimeter_speed"
|
||||||
|| opt_key == "solid_infill_speed"
|
|| opt_key == "solid_infill_speed"
|
||||||
|| opt_key == "support_material_interface_speed"
|
|| opt_key == "support_material_interface_speed"
|
||||||
@ -2274,7 +2275,9 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
// slicing in parallel
|
// slicing in parallel
|
||||||
std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode);
|
std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode);
|
||||||
//scale for shrinkage
|
//scale for shrinkage
|
||||||
double scale = print()->config().filament_shrink.get_abs_value(this->print()->regions()[region_id]->extruder(FlowRole::frPerimeter) - 1, 1);
|
std::cout << (&(this->print()->regions())) << " =?= " << (&(this->print()->m_regions)) << "\n";
|
||||||
|
const size_t extruder_id = this->print()->regions()[region_id]->extruder(FlowRole::frPerimeter) - 1;
|
||||||
|
double scale = print()->config().filament_shrink.get_abs_value(extruder_id, 1);
|
||||||
if (scale != 1) {
|
if (scale != 1) {
|
||||||
scale = 1 / scale;
|
scale = 1 / scale;
|
||||||
for (ExPolygons &polys : expolygons_by_layer)
|
for (ExPolygons &polys : expolygons_by_layer)
|
||||||
|
@ -81,7 +81,7 @@ void PreferencesDialog::build()
|
|||||||
def.label = L("Check for application updates");
|
def.label = L("Check for application updates");
|
||||||
def.type = coBool;
|
def.type = coBool;
|
||||||
def.tooltip = L("If enabled, SuperSlicer will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
|
def.tooltip = L("If enabled, SuperSlicer will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
|
||||||
def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "0"));
|
def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1"));
|
||||||
option = Option(def, "version_check");
|
option = Option(def, "version_check");
|
||||||
m_optgroup_general->append_single_option_line(option);
|
m_optgroup_general->append_single_option_line(option);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ void PreferencesDialog::build()
|
|||||||
def.label = L("Update built-in Presets automatically");
|
def.label = L("Update built-in Presets automatically");
|
||||||
def.type = coBool;
|
def.type = coBool;
|
||||||
def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
|
def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
|
||||||
def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "0"));
|
def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1"));
|
||||||
option = Option(def, "preset_update");
|
option = Option(def, "preset_update");
|
||||||
m_optgroup_general->append_single_option_line(option);
|
m_optgroup_general->append_single_option_line(option);
|
||||||
|
|
||||||
@ -117,25 +117,12 @@ void PreferencesDialog::build()
|
|||||||
option = Option(def, "show_incompatible_presets");
|
option = Option(def, "show_incompatible_presets");
|
||||||
m_optgroup_general->append_single_option_line(option);
|
m_optgroup_general->append_single_option_line(option);
|
||||||
|
|
||||||
def.label = L("Main GUI always in expert mode");
|
def.label = L("Main GUI always in expert mode");
|
||||||
def.type = coBool;
|
def.type = coBool;
|
||||||
def.tooltip = L("If enabled, the gui will be in expert mode even if the simple or advanced mode is selected (but not the setting tabs).");
|
def.tooltip = L("If enabled, the gui will be in expert mode even if the simple or advanced mode is selected (but not the setting tabs).");
|
||||||
def.set_default_value(new ConfigOptionBool{ app_config->get("objects_always_expert") == "1" });
|
def.set_default_value(new ConfigOptionBool{ app_config->get("objects_always_expert") == "1" });
|
||||||
option = Option(def, "objects_always_expert");
|
option = Option(def, "objects_always_expert");
|
||||||
m_optgroup_general->append_single_option_line(option);
|
m_optgroup_general->append_single_option_line(option);
|
||||||
|
|
||||||
m_optgroup_paths = std::make_shared<ConfigOptionsGroup>(this, _(L("General")));
|
|
||||||
m_optgroup_paths->title_width = 10;
|
|
||||||
m_optgroup_paths->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
|
||||||
m_values[opt_key] = boost::any_cast<std::string>(value);
|
|
||||||
};
|
|
||||||
def.label = L("FreeCAD path");
|
|
||||||
def.type = coString;
|
|
||||||
def.tooltip = L("If it point to a valid freecad instance (the bin directory or the python executable), you can use the built-in python script to quickly generate geometry.");
|
|
||||||
def.set_default_value(new ConfigOptionString{ app_config->get("freecad_path") });
|
|
||||||
option = Option(def, "freecad_path");
|
|
||||||
option.opt.full_width = true;
|
|
||||||
m_optgroup_paths->append_single_option_line(option);
|
|
||||||
|
|
||||||
def.label = L("Single Instance");
|
def.label = L("Single Instance");
|
||||||
def.type = coBool;
|
def.type = coBool;
|
||||||
@ -195,6 +182,21 @@ void PreferencesDialog::build()
|
|||||||
|
|
||||||
m_optgroup_general->activate();
|
m_optgroup_general->activate();
|
||||||
|
|
||||||
|
m_optgroup_paths = std::make_shared<ConfigOptionsGroup>(this, _(L("Paths")));
|
||||||
|
m_optgroup_paths->title_width = 10;
|
||||||
|
m_optgroup_paths->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
|
m_values[opt_key] = boost::any_cast<std::string>(value);
|
||||||
|
};
|
||||||
|
def.label = L("FreeCAD path");
|
||||||
|
def.type = coString;
|
||||||
|
def.tooltip = L("If it point to a valid freecad instance (the bin directory or the python executable), you can use the built-in python script to quickly generate geometry.");
|
||||||
|
def.set_default_value(new ConfigOptionString{ app_config->get("freecad_path") });
|
||||||
|
option = Option(def, "freecad_path");
|
||||||
|
option.opt.full_width = true;
|
||||||
|
m_optgroup_paths->append_single_option_line(option);
|
||||||
|
|
||||||
|
m_optgroup_paths->activate();
|
||||||
|
|
||||||
m_optgroup_camera = std::make_shared<ConfigOptionsGroup>(this, _L("Camera"));
|
m_optgroup_camera = std::make_shared<ConfigOptionsGroup>(this, _L("Camera"));
|
||||||
m_optgroup_camera->label_width = 40;
|
m_optgroup_camera->label_width = 40;
|
||||||
m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user