Port PrusaSlicer staggered_inner_seams

This commit is contained in:
SoftFever 2023-07-06 21:08:39 +08:00
parent b47777e73e
commit c3c6bbc4e5
7 changed files with 1469 additions and 1255 deletions

File diff suppressed because it is too large Load diff

View file

@ -27,138 +27,136 @@ class Grid;
namespace SeamPlacerImpl { namespace SeamPlacerImpl {
// ************ FOR BACKPORT COMPATIBILITY ONLY ***************
// Angle from v1 to v2, returning double atan2(y, x) normalized to <-PI, PI>.
template<typename Derived, typename Derived2> inline double angle(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBase<Derived2> &v2)
{
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "angle(): first parameter is not a 2D vector");
static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "angle(): second parameter is not a 2D vector");
auto v1d = v1.template cast<double>();
auto v2d = v2.template cast<double>();
return atan2(cross2(v1d, v2d), v1d.dot(v2d));
}
// ***************************
struct GlobalModelInfo; struct GlobalModelInfo;
struct SeamComparator; struct SeamComparator;
enum class EnforcedBlockedSeamPoint { enum class EnforcedBlockedSeamPoint {
Blocked = 0, Blocked = 0,
Neutral = 1, Neutral = 1,
Enforced = 2, Enforced = 2,
}; };
// struct representing single perimeter loop // struct representing single perimeter loop
struct Perimeter struct Perimeter {
{ size_t start_index{};
size_t start_index{}; size_t end_index{}; //inclusive!
size_t end_index{}; // inclusive! size_t seam_index{};
size_t seam_index{}; float flow_width{};
float flow_width{};
// During alignment, a final position may be stored here. In that case, finalized is set to true. // During alignment, a final position may be stored here. In that case, finalized is set to true.
// Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position // Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position
// Random position also uses this flexibility to set final seam point position // Random position also uses this flexibility to set final seam point position
bool finalized = false; bool finalized = false;
Vec3f final_seam_position = Vec3f::Zero(); Vec3f final_seam_position = Vec3f::Zero();
}; };
// Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created, //Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created,
// then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam. // then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam.
// This seam position can be then further aligned // This seam position can be then further aligned
struct SeamCandidate struct SeamCandidate {
{ SeamCandidate(const Vec3f &pos, Perimeter &perimeter,
SeamCandidate(const Vec3f &pos, Perimeter &perimeter, float local_ccw_angle, EnforcedBlockedSeamPoint type) float local_ccw_angle,
: position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle(local_ccw_angle), type(type), central_enforcer(false) EnforcedBlockedSeamPoint type) :
{} position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle(
const Vec3f position; local_ccw_angle), type(type), central_enforcer(false) {
// pointer to Perimeter loop of this point. It is shared across all points of the loop }
Perimeter &perimeter; const Vec3f position;
float visibility; // pointer to Perimeter loop of this point. It is shared across all points of the loop
float overhang; Perimeter &perimeter;
// distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join) float visibility;
// Negative sign means inside the print, comes from EdgeGrid structure float overhang;
float embedded_distance; // distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join)
float local_ccw_angle; // Negative sign means inside the print, comes from EdgeGrid structure
EnforcedBlockedSeamPoint type; float embedded_distance;
bool central_enforcer; // marks this candidate as central point of enforced segment on the perimeter - important for alignment float local_ccw_angle;
EnforcedBlockedSeamPoint type;
bool central_enforcer; //marks this candidate as central point of enforced segment on the perimeter - important for alignment
}; };
struct SeamCandidateCoordinateFunctor struct SeamCandidateCoordinateFunctor {
{ SeamCandidateCoordinateFunctor(const std::vector<SeamCandidate> &seam_candidates) :
SeamCandidateCoordinateFunctor(const std::vector<SeamCandidate> &seam_candidates) : seam_candidates(seam_candidates) {} seam_candidates(seam_candidates) {
const std::vector<SeamCandidate> &seam_candidates; }
float operator()(size_t index, size_t dim) const { return seam_candidates[index].position[dim]; } const std::vector<SeamCandidate> &seam_candidates;
float operator()(size_t index, size_t dim) const {
return seam_candidates[index].position[dim];
}
}; };
} // namespace SeamPlacerImpl } // namespace SeamPlacerImpl
struct PrintObjectSeamData struct PrintObjectSeamData
{ {
using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
struct LayerSeams struct LayerSeams
{ {
Slic3r::deque<SeamPlacerImpl::Perimeter> perimeters; Slic3r::deque<SeamPlacerImpl::Perimeter> perimeters;
std::vector<SeamPlacerImpl::SeamCandidate> points; std::vector<SeamPlacerImpl::SeamCandidate> points;
std::unique_ptr<SeamCandidatesTree> points_tree; std::unique_ptr<SeamCandidatesTree> points_tree;
}; };
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter // Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter
std::vector<LayerSeams> layers; std::vector<LayerSeams> layers;
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD // Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD
// tree of all points of the given layer // tree of all points of the given layer
void clear() { layers.clear(); } void clear()
{
layers.clear();
}
}; };
class SeamPlacer class SeamPlacer {
{
public: public:
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples // Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
static constexpr size_t raycasting_visibility_samples_count = 30000; static constexpr size_t raycasting_visibility_samples_count = 30000;
// square of number of rays per sample point static constexpr size_t fast_decimation_triangle_count_target = 16000;
static constexpr size_t sqr_rays_per_sample_point = 5; //square of number of rays per sample point
static constexpr size_t sqr_rays_per_sample_point = 5;
// snapping angle - angles larger than this value will be snapped to during seam painting // snapping angle - angles larger than this value will be snapped to during seam painting
static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f; static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f;
// overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction // overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction
//BBS static constexpr float overhang_angle_threshold = 50.0f * float(PI) / 180.0f;
static constexpr float overhang_angle_threshold = 45.0f * float(PI) / 180.0f;
// determines angle importance compared to visibility ( neutral value is 1.0f. ) // determines angle importance compared to visibility ( neutral value is 1.0f. )
static constexpr float angle_importance_aligned = 0.6f; static constexpr float angle_importance_aligned = 0.6f;
static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise
// For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size // For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size
static constexpr float enforcer_oversampling_distance = 0.2f; static constexpr float enforcer_oversampling_distance = 0.2f;
// When searching for seam clusters for alignment: // When searching for seam clusters for alignment:
// following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer
static constexpr float seam_align_score_tolerance = 0.3f; static constexpr float seam_align_score_tolerance = 0.3f;
// seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width // seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width
static constexpr float seam_align_tolerable_dist_factor = 4.0f; static constexpr float seam_align_tolerable_dist_factor = 4.0f;
// minimum number of seams needed in cluster to make alignment happen // minimum number of seams needed in cluster to make alignment happen
static constexpr size_t seam_align_minimum_string_seams = 6; static constexpr size_t seam_align_minimum_string_seams = 6;
// millimeters covered by spline; determines number of splines for the given string // millimeters covered by spline; determines number of splines for the given string
static constexpr size_t seam_align_mm_per_segment = 4.0f; static constexpr size_t seam_align_mm_per_segment = 4.0f;
// The following data structures hold all perimeter points for all PrintObject. //The following data structures hold all perimeter points for all PrintObject.
std::unordered_map<const PrintObject *, PrintObjectSeamData> m_seam_per_object; std::unordered_map<const PrintObject*, PrintObjectSeamData> m_seam_per_object;
void init(const Print &print, std::function<void(void)> throw_if_canceled_func); void init(const Print &print, std::function<void(void)> throw_if_canceled_func);
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const; void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const;
private: private:
void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference); void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info);
void calculate_candidates_visibility(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info); void calculate_candidates_visibility(const PrintObject *po,
void calculate_overhangs_and_layer_embedding(const PrintObject *po); const SeamPlacerImpl::GlobalModelInfo &global_model_info);
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator); void calculate_overhangs_and_layer_embedding(const PrintObject *po);
std::vector<std::pair<size_t, size_t>> find_seam_string(const PrintObject *po, std::pair<size_t, size_t> start_seam, const SeamPlacerImpl::SeamComparator &comparator) const; void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
std::optional<std::pair<size_t, size_t>> find_next_seam_in_layer(const std::vector<PrintObjectSeamData::LayerSeams> &layers, std::vector<std::pair<size_t, size_t>> find_seam_string(const PrintObject *po,
const Vec3f & projected_position, std::pair<size_t, size_t> start_seam,
const size_t layer_idx, const SeamPlacerImpl::SeamComparator &comparator) const;
const float max_distance, std::optional<std::pair<size_t, size_t>> find_next_seam_in_layer(
const SeamPlacerImpl::SeamComparator & comparator) const; const std::vector<PrintObjectSeamData::LayerSeams> &layers,
const Vec3f& projected_position,
const size_t layer_idx, const float max_distance,
const SeamPlacerImpl::SeamComparator &comparator) const;
}; };
} // namespace Slic3r } // namespace Slic3r

View file

@ -708,7 +708,7 @@ static std::vector<std::string> s_Preset_print_options {
"layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", "slicing_mode", "layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", "slicing_mode",
"top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness", "top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness",
"ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall",
"seam_position", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "seam_position", "staggered_inner_seams", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern",
"infill_direction", "infill_direction",
"minimum_sparse_infill_area", "reduce_infill_retraction", "minimum_sparse_infill_area", "reduce_infill_retraction",
"ironing_type", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_type", "ironing_flow", "ironing_speed", "ironing_spacing",

View file

@ -2613,6 +2613,12 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Random")); def->enum_labels.push_back(L("Random"));
def->mode = comSimple; def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum<SeamPosition>(spAligned)); def->set_default_value(new ConfigOptionEnum<SeamPosition>(spAligned));
def = this->add("staggered_inner_seams", coBool);
def->label = L("Staggered inner seams");
def->tooltip = L("This option causes the inner seams to be shifted backwards based on their depth, forming a zigzag pattern.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("seam_gap", coFloatOrPercent); def = this->add("seam_gap", coFloatOrPercent);
def->label = L("Seam gap"); def->label = L("Seam gap");

View file

@ -646,6 +646,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, raft_first_layer_expansion)) ((ConfigOptionFloat, raft_first_layer_expansion))
((ConfigOptionInt, raft_layers)) ((ConfigOptionInt, raft_layers))
((ConfigOptionEnum<SeamPosition>, seam_position)) ((ConfigOptionEnum<SeamPosition>, seam_position))
((ConfigOptionBool, staggered_inner_seams))
((ConfigOptionFloat, slice_closing_radius)) ((ConfigOptionFloat, slice_closing_radius))
((ConfigOptionEnum<SlicingMode>, slicing_mode)) ((ConfigOptionEnum<SlicingMode>, slicing_mode))
((ConfigOptionBool, enable_support)) ((ConfigOptionBool, enable_support))

View file

@ -540,7 +540,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
bool have_perimeters = config->opt_int("wall_loops") > 0; bool have_perimeters = config->opt_int("wall_loops") > 0;
for (auto el : { "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", for (auto el : { "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall",
"seam_position", "wall_infill_order", "outer_wall_line_width", "seam_position", "staggered_inner_seams", "wall_infill_order", "outer_wall_line_width",
"inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" })
toggle_field(el, have_perimeters); toggle_field(el, have_perimeters);

View file

@ -1845,6 +1845,7 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Seam"), L"param_seam"); optgroup = page->new_optgroup(L("Seam"), L"param_seam");
optgroup->append_single_option_line("seam_position", "Seam"); optgroup->append_single_option_line("seam_position", "Seam");
optgroup->append_single_option_line("staggered_inner_seams", "Seam");
optgroup->append_single_option_line("seam_gap","Seam"); optgroup->append_single_option_line("seam_gap","Seam");
optgroup->append_single_option_line("role_based_wipe_speed","Seam"); optgroup->append_single_option_line("role_based_wipe_speed","Seam");
optgroup->append_single_option_line("wipe_speed", "Seam"); optgroup->append_single_option_line("wipe_speed", "Seam");