finalize integration into GCode.cpp export functions, remove unused
edge grids
This commit is contained in:
parent
6dbc7149be
commit
177a1fd54a
@ -118,10 +118,8 @@ set(SLIC3R_SOURCES
|
||||
GCode/PrintExtents.hpp
|
||||
GCode/SpiralVase.cpp
|
||||
GCode/SpiralVase.hpp
|
||||
GCode/SeamPlacerNG.cpp
|
||||
GCode/SeamPlacerNG.hpp
|
||||
GCode/Subdivide.hpp
|
||||
GCode/Subdivide.cpp
|
||||
GCode/SeamPlacer.cpp
|
||||
GCode/SeamPlacer.hpp
|
||||
GCode/ToolOrdering.cpp
|
||||
GCode/ToolOrdering.hpp
|
||||
GCode/WipeTower.cpp
|
||||
@ -227,6 +225,8 @@ set(SLIC3R_SOURCES
|
||||
SlicesToTriangleMesh.cpp
|
||||
SlicingAdaptive.cpp
|
||||
SlicingAdaptive.hpp
|
||||
Subdivide.cpp
|
||||
Subdivide.hpp
|
||||
SupportMaterial.cpp
|
||||
SupportMaterial.hpp
|
||||
Surface.cpp
|
||||
|
@ -2312,7 +2312,6 @@ GCode::LayerResult GCode::process_layer(
|
||||
} // for objects
|
||||
|
||||
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
||||
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
||||
for (unsigned int extruder_id : layer_tools.extruders)
|
||||
{
|
||||
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
|
||||
@ -2406,9 +2405,9 @@ GCode::LayerResult GCode::process_layer(
|
||||
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
|
||||
if (print.config().infill_first) {
|
||||
gcode += this->extrude_infill(print, by_region_specific, false);
|
||||
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
||||
gcode += this->extrude_perimeters(print, by_region_specific);
|
||||
} else {
|
||||
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
|
||||
gcode += this->extrude_perimeters(print, by_region_specific);
|
||||
gcode += this->extrude_infill(print,by_region_specific, false);
|
||||
}
|
||||
// ironing
|
||||
@ -2543,39 +2542,11 @@ std::string GCode::change_layer(coordf_t print_z)
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& layer)
|
||||
{
|
||||
auto out = make_unique<EdgeGrid::Grid>();
|
||||
|
||||
// Create the distance field for a layer below.
|
||||
const coord_t distance_field_resolution = coord_t(scale_(1.) + 0.5);
|
||||
out->create(layer.lslices, distance_field_resolution);
|
||||
out->calculate_sdf();
|
||||
#if 0
|
||||
{
|
||||
static int iRun = 0;
|
||||
BoundingBox bbox = (*lower_layer_edge_grid)->bbox();
|
||||
bbox.min(0) -= scale_(5.f);
|
||||
bbox.min(1) -= scale_(5.f);
|
||||
bbox.max(0) += scale_(5.f);
|
||||
bbox.max(1) += scale_(5.f);
|
||||
EdgeGrid::save_png(*(*lower_layer_edge_grid), bbox, scale_(0.1f), debug_out_path("GCode_extrude_loop_edge_grid-%d.png", iRun++));
|
||||
}
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid)
|
||||
std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed)
|
||||
{
|
||||
// get a copy; don't modify the orientation of the original loop object otherwise
|
||||
// next copies (if any) would not detect the correct orientation
|
||||
|
||||
if (m_layer->lower_layer && lower_layer_edge_grid != nullptr && ! *lower_layer_edge_grid)
|
||||
*lower_layer_edge_grid = calculate_layer_edge_grid(*m_layer->lower_layer);
|
||||
|
||||
// extrude all loops ccw
|
||||
bool was_clockwise = loop.make_counter_clockwise();
|
||||
|
||||
@ -2675,14 +2646,14 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid)
|
||||
std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed)
|
||||
{
|
||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
|
||||
return this->extrude_path(*path, description, speed);
|
||||
else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
|
||||
return this->extrude_multi_path(*multipath, description, speed);
|
||||
else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity))
|
||||
return this->extrude_loop(*loop, description, speed, lower_layer_edge_grid);
|
||||
return this->extrude_loop(*loop, description, speed);
|
||||
else
|
||||
throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()");
|
||||
return "";
|
||||
@ -2703,24 +2674,15 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
|
||||
}
|
||||
|
||||
// Extrude perimeters: Decide where to put seams (hide or align seams).
|
||||
std::string GCode::extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid)
|
||||
std::string GCode::extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.perimeters.empty()) {
|
||||
m_config.apply(print.get_print_region(®ion - &by_region.front()).config());
|
||||
|
||||
// plan_perimeters tries to place seams, it needs to have the lower_layer_edge_grid calculated already.
|
||||
if (m_layer->lower_layer && ! lower_layer_edge_grid)
|
||||
lower_layer_edge_grid = calculate_layer_edge_grid(*m_layer->lower_layer);
|
||||
|
||||
// m_seam_placer.plan_perimeters(std::vector<const ExtrusionEntity*>(region.perimeters.begin(), region.perimeters.end()),
|
||||
// *m_layer, m_config.seam_position, this->last_pos(), EXTRUDER_CONFIG(nozzle_diameter),
|
||||
// (m_layer == NULL ? nullptr : m_layer->object()),
|
||||
// (lower_layer_edge_grid ? lower_layer_edge_grid.get() : nullptr));
|
||||
|
||||
for (const ExtrusionEntity* ee : region.perimeters)
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1.);
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "GCode/SpiralVase.hpp"
|
||||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "GCode/SeamPlacerNG.hpp"
|
||||
#include "GCode/SeamPlacer.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
@ -274,8 +274,8 @@ private:
|
||||
void set_extruders(const std::vector<unsigned int> &extruder_ids);
|
||||
std::string preamble();
|
||||
std::string change_layer(coordf_t print_z);
|
||||
std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1., std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid = nullptr);
|
||||
std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid = nullptr);
|
||||
std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1.);
|
||||
std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1.);
|
||||
std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.);
|
||||
std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);
|
||||
|
||||
@ -342,7 +342,7 @@ private:
|
||||
// For sequential print, the instance of the object to be printing has to be defined.
|
||||
const size_t single_object_instance_idx);
|
||||
|
||||
std::string extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid);
|
||||
std::string extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region);
|
||||
std::string extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, bool ironing);
|
||||
std::string extrude_support(const ExtrusionEntityCollection &support_fills);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,12 +3,15 @@
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/AABBTreeIndirect.hpp"
|
||||
#include "libslic3r/KDTreeIndirect.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -16,119 +19,124 @@ class PrintObject;
|
||||
class ExtrusionLoop;
|
||||
class Print;
|
||||
class Layer;
|
||||
namespace EdgeGrid { class Grid; }
|
||||
|
||||
namespace EdgeGrid {
|
||||
class Grid;
|
||||
}
|
||||
|
||||
class SeamHistory {
|
||||
public:
|
||||
SeamHistory() { clear(); }
|
||||
std::optional<Point> get_last_seam(const PrintObject* po, size_t layer_id, const BoundingBox& island_bb);
|
||||
void add_seam(const PrintObject* po, const Point& pos, const BoundingBox& island_bb);
|
||||
void clear();
|
||||
namespace SeamPlacerImpl {
|
||||
|
||||
private:
|
||||
struct SeamPoint {
|
||||
Point m_pos;
|
||||
BoundingBox m_island_bb;
|
||||
};
|
||||
struct GlobalModelInfo;
|
||||
struct SeamComparator;
|
||||
|
||||
std::map<const PrintObject*, std::vector<SeamPoint>> m_data_last_layer;
|
||||
std::map<const PrintObject*, std::vector<SeamPoint>> m_data_this_layer;
|
||||
size_t m_layer_id;
|
||||
enum class EnforcedBlockedSeamPoint {
|
||||
Blocked = 0,
|
||||
Neutral = 1,
|
||||
Enforced = 2,
|
||||
};
|
||||
|
||||
// struct representing single perimeter loop
|
||||
struct Perimeter {
|
||||
size_t start_index;
|
||||
size_t end_index; //inclusive!
|
||||
size_t seam_index;
|
||||
|
||||
// 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
|
||||
// Random position also uses this flexibility to set final seam point position
|
||||
bool finalized = false;
|
||||
Vec3f final_seam_position;
|
||||
};
|
||||
|
||||
//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.
|
||||
// This seam position can be than further aligned
|
||||
struct SeamCandidate {
|
||||
SeamCandidate(const Vec3f &pos, std::shared_ptr<Perimeter> perimeter,
|
||||
float local_ccw_angle,
|
||||
EnforcedBlockedSeamPoint type) :
|
||||
position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), local_ccw_angle(
|
||||
local_ccw_angle), type(type) {
|
||||
}
|
||||
const Vec3f position;
|
||||
// pointer to Perimter loop of this point. It is shared across all points of the loop
|
||||
const std::shared_ptr<Perimeter> perimeter;
|
||||
float visibility;
|
||||
float overhang;
|
||||
float local_ccw_angle;
|
||||
EnforcedBlockedSeamPoint type;
|
||||
};
|
||||
|
||||
struct FaceVisibilityInfo {
|
||||
float visibility;
|
||||
};
|
||||
|
||||
struct SeamCandidateCoordinateFunctor {
|
||||
SeamCandidateCoordinateFunctor(std::vector<SeamCandidate> *seam_candidates) :
|
||||
seam_candidates(seam_candidates) {
|
||||
}
|
||||
std::vector<SeamCandidate> *seam_candidates;
|
||||
float operator()(size_t index, size_t dim) const {
|
||||
return seam_candidates->operator[](index).position[dim];
|
||||
}
|
||||
};
|
||||
} // namespace SeamPlacerImpl
|
||||
|
||||
class SeamPlacer {
|
||||
public:
|
||||
void init(const Print& print);
|
||||
using SeamCandidatesTree =
|
||||
KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
||||
static constexpr float raycasting_decimation_target_error = 1.0f;
|
||||
static constexpr float raycasting_subdivision_target_length = 2.0f;
|
||||
//square of number of rays per triangle
|
||||
static constexpr size_t sqr_rays_per_triangle = 7;
|
||||
|
||||
// When perimeters are printed, first call this function with the respective
|
||||
// external perimeter. SeamPlacer will find a location for its seam and remember it.
|
||||
// Subsequent calls to get_seam will return this position.
|
||||
// arm length used during angles computation
|
||||
static constexpr float polygon_local_angles_arm_distance = 0.5f;
|
||||
|
||||
// increases angle importance at the cost of deacreasing visibility info importance. must be > 0
|
||||
static constexpr float additional_angle_importance = 0.3f;
|
||||
|
||||
void plan_perimeters(const std::vector<const ExtrusionEntity*> perimeters,
|
||||
const Layer& layer, SeamPosition seam_position,
|
||||
Point last_pos, coordf_t nozzle_dmr, const PrintObject* po,
|
||||
const EdgeGrid::Grid* lower_layer_edge_grid);
|
||||
// If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer
|
||||
static constexpr float enforcer_blocker_distance_tolerance = 0.3f;
|
||||
// For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size
|
||||
static constexpr float enforcer_blocker_oversampling_distance = 0.1f;
|
||||
|
||||
void place_seam(ExtrusionLoop& loop, const Point& last_pos, bool external_first, double nozzle_diameter,
|
||||
const EdgeGrid::Grid* lower_layer_edge_grid);
|
||||
|
||||
// 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
|
||||
static constexpr float seam_align_score_tolerance = 0.5f;
|
||||
// seam_align_tolerable_dist - if next layer closes point is too far away, break string
|
||||
static constexpr float seam_align_tolerable_dist = 1.0f;
|
||||
// if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped.
|
||||
// this param limits the number of allowed skips
|
||||
static constexpr size_t seam_align_tolerable_skips = 4;
|
||||
// minimum number of seams needed in cluster to make alignemnt happen
|
||||
static constexpr size_t seam_align_minimum_string_seams = 6;
|
||||
// iterations of laplace smoothing
|
||||
static constexpr size_t seam_align_laplace_smoothing_iterations = 20;
|
||||
|
||||
using TreeType = AABBTreeIndirect::Tree<2, coord_t>;
|
||||
using AlignedBoxType = Eigen::AlignedBox<TreeType::CoordType, TreeType::NumDimensions>;
|
||||
//The following data structures hold all perimeter points for all PrintObject. The structure is as follows:
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter points of the given layer
|
||||
std::unordered_map<const PrintObject*, std::vector<std::vector<SeamPlacerImpl::SeamCandidate>>> m_perimeter_points_per_object;
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD tree of all points of the given layer
|
||||
std::unordered_map<const PrintObject*, std::vector<std::unique_ptr<SeamCandidatesTree>>> m_perimeter_points_trees_per_object;
|
||||
|
||||
void init(const Print &print);
|
||||
|
||||
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point& last_pos) const;
|
||||
|
||||
private:
|
||||
|
||||
// When given an external perimeter (!), returns the seam.
|
||||
Point calculate_seam(const Layer& layer, const SeamPosition seam_position,
|
||||
const ExtrusionLoop& loop, coordf_t nozzle_dmr, const PrintObject* po,
|
||||
const EdgeGrid::Grid* lower_layer_edge_grid, Point last_pos, bool prefer_nearest);
|
||||
|
||||
struct CustomTrianglesPerLayer {
|
||||
Polygons polys;
|
||||
TreeType tree;
|
||||
};
|
||||
|
||||
// Just a cache to save some lookups.
|
||||
const Layer* m_last_layer_po = nullptr;
|
||||
coordf_t m_last_print_z = -1.;
|
||||
const PrintObject* m_last_po = nullptr;
|
||||
|
||||
struct SeamPoint {
|
||||
Point pt;
|
||||
bool precalculated = false;
|
||||
bool external = false;
|
||||
const Layer* layer = nullptr;
|
||||
SeamPosition seam_position;
|
||||
const PrintObject* po = nullptr;
|
||||
};
|
||||
std::vector<SeamPoint> m_plan;
|
||||
size_t m_plan_idx;
|
||||
|
||||
std::vector<std::vector<CustomTrianglesPerLayer>> m_enforcers;
|
||||
std::vector<std::vector<CustomTrianglesPerLayer>> m_blockers;
|
||||
std::vector<const PrintObject*> m_po_list;
|
||||
|
||||
//std::map<const PrintObject*, Point> m_last_seam_position;
|
||||
SeamHistory m_seam_history;
|
||||
|
||||
// Get indices of points inside enforcers and blockers.
|
||||
void get_enforcers_and_blockers(size_t layer_id,
|
||||
const Polygon& polygon,
|
||||
size_t po_id,
|
||||
std::vector<size_t>& enforcers_idxs,
|
||||
std::vector<size_t>& blockers_idxs) const;
|
||||
|
||||
// Apply penalties to points inside enforcers/blockers.
|
||||
void apply_custom_seam(const Polygon& polygon, size_t po_id,
|
||||
std::vector<float>& penalties,
|
||||
const std::vector<float>& lengths,
|
||||
int layer_id, SeamPosition seam_position) const;
|
||||
|
||||
// Return random point of a polygon. The distribution will be uniform
|
||||
// along the contour and account for enforcers and blockers.
|
||||
Point get_random_seam(size_t layer_idx, const Polygon& polygon, size_t po_id,
|
||||
bool* saw_custom = nullptr) const;
|
||||
|
||||
// Is there any enforcer/blocker on this layer?
|
||||
bool is_custom_seam_on_layer(size_t layer_id, size_t po_idx) const {
|
||||
return is_custom_enforcer_on_layer(layer_id, po_idx)
|
||||
|| is_custom_blocker_on_layer(layer_id, po_idx);
|
||||
}
|
||||
|
||||
bool is_custom_enforcer_on_layer(size_t layer_id, size_t po_idx) const {
|
||||
return (! m_enforcers.at(po_idx).empty() && ! m_enforcers.at(po_idx)[layer_id].polys.empty());
|
||||
}
|
||||
|
||||
bool is_custom_blocker_on_layer(size_t layer_id, size_t po_idx) const {
|
||||
return (! m_blockers.at(po_idx).empty() && ! m_blockers.at(po_idx)[layer_id].polys.empty());
|
||||
}
|
||||
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_overhangs(const PrintObject *po);
|
||||
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
|
||||
bool find_next_seam_in_layer(const PrintObject *po,
|
||||
std::pair<size_t, size_t> &last_point_indexes,
|
||||
size_t layer_idx,const SeamPlacerImpl::SeamComparator &comparator,
|
||||
std::vector<std::pair<size_t, size_t>> &seam_string);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // libslic3r_SeamPlacer_hpp_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,142 +0,0 @@
|
||||
#ifndef libslic3r_SeamPlacerNG_hpp_
|
||||
#define libslic3r_SeamPlacerNG_hpp_
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/AABBTreeIndirect.hpp"
|
||||
#include "libslic3r/KDTreeIndirect.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class PrintObject;
|
||||
class ExtrusionLoop;
|
||||
class Print;
|
||||
class Layer;
|
||||
|
||||
namespace EdgeGrid {
|
||||
class Grid;
|
||||
}
|
||||
|
||||
namespace SeamPlacerImpl {
|
||||
|
||||
struct GlobalModelInfo;
|
||||
struct SeamComparator;
|
||||
|
||||
enum class EnforcedBlockedSeamPoint {
|
||||
Blocked = 0,
|
||||
Neutral = 1,
|
||||
Enforced = 2,
|
||||
};
|
||||
|
||||
// struct representing single perimeter loop
|
||||
struct Perimeter {
|
||||
size_t start_index;
|
||||
size_t end_index; //inclusive!
|
||||
size_t seam_index;
|
||||
|
||||
// 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
|
||||
// Random position also uses this flexibility to set final seam point position
|
||||
bool finalized = false;
|
||||
Vec3f final_seam_position;
|
||||
};
|
||||
|
||||
//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.
|
||||
// This seam position can be than further aligned
|
||||
struct SeamCandidate {
|
||||
SeamCandidate(const Vec3f &pos, std::shared_ptr<Perimeter> perimeter,
|
||||
float local_ccw_angle,
|
||||
EnforcedBlockedSeamPoint type) :
|
||||
position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), local_ccw_angle(
|
||||
local_ccw_angle), type(type) {
|
||||
}
|
||||
const Vec3f position;
|
||||
// pointer to Perimter loop of this point. It is shared across all points of the loop
|
||||
const std::shared_ptr<Perimeter> perimeter;
|
||||
float visibility;
|
||||
float overhang;
|
||||
float local_ccw_angle;
|
||||
EnforcedBlockedSeamPoint type;
|
||||
};
|
||||
|
||||
struct FaceVisibilityInfo {
|
||||
float visibility;
|
||||
};
|
||||
|
||||
struct SeamCandidateCoordinateFunctor {
|
||||
SeamCandidateCoordinateFunctor(std::vector<SeamCandidate> *seam_candidates) :
|
||||
seam_candidates(seam_candidates) {
|
||||
}
|
||||
std::vector<SeamCandidate> *seam_candidates;
|
||||
float operator()(size_t index, size_t dim) const {
|
||||
return seam_candidates->operator[](index).position[dim];
|
||||
}
|
||||
};
|
||||
} // namespace SeamPlacerImpl
|
||||
|
||||
class SeamPlacer {
|
||||
public:
|
||||
using SeamCandidatesTree =
|
||||
KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
||||
static constexpr float raycasting_decimation_target_error = 1.0f;
|
||||
static constexpr float raycasting_subdivision_target_length = 2.0f;
|
||||
//square of number of rays per triangle
|
||||
static constexpr size_t sqr_rays_per_triangle = 7;
|
||||
|
||||
// arm length used during angles computation
|
||||
static constexpr float polygon_local_angles_arm_distance = 0.5f;
|
||||
static constexpr float additional_angle_importance = 0.3f;
|
||||
|
||||
// If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer
|
||||
static constexpr float enforcer_blocker_distance_tolerance = 0.3f;
|
||||
// For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size
|
||||
static constexpr float enforcer_blocker_oversampling_distance = 0.1f;
|
||||
|
||||
// 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
|
||||
static constexpr float seam_align_score_tolerance = 0.5f;
|
||||
// seam_align_tolerable_dist - if seam is closer to the previous seam position projected to the current layer than this value,
|
||||
//it belongs automaticaly to the cluster
|
||||
static constexpr float seam_align_tolerable_dist = 0.5f;
|
||||
// if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped.
|
||||
// this param limits the number of allowed skips
|
||||
static constexpr size_t seam_align_tolerable_skips = 4;
|
||||
// minimum number of seams needed in cluster to make alignemnt happen
|
||||
static constexpr size_t seam_align_minimum_string_seams = 6;
|
||||
// iterations of laplace smoothing
|
||||
static constexpr size_t seam_align_laplace_smoothing_iterations = 20;
|
||||
|
||||
//The following data structures hold all perimeter points for all PrintObject. The structure is as follows:
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter points of the given layer
|
||||
std::unordered_map<const PrintObject*, std::vector<std::vector<SeamPlacerImpl::SeamCandidate>>> m_perimeter_points_per_object;
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD tree of all points of the given layer
|
||||
std::unordered_map<const PrintObject*, std::vector<std::unique_ptr<SeamCandidatesTree>>> m_perimeter_points_trees_per_object;
|
||||
|
||||
void init(const Print &print);
|
||||
|
||||
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point& last_pos) const;
|
||||
|
||||
private:
|
||||
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_overhangs(const PrintObject *po);
|
||||
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
|
||||
bool find_next_seam_in_layer(const PrintObject *po,
|
||||
std::pair<size_t, size_t> &last_point,
|
||||
size_t layer_idx,const SeamPlacerImpl::SeamComparator &comparator,
|
||||
std::vector<std::pair<size_t, size_t>> &seam_strings,
|
||||
std::vector<std::pair<size_t, size_t>> &outliers);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // libslic3r_SeamPlacerNG_hpp_
|
@ -3,7 +3,7 @@
|
||||
|
||||
namespace Slic3r{
|
||||
|
||||
indexed_triangle_set subdivide(
|
||||
indexed_triangle_set its_subdivide(
|
||||
const indexed_triangle_set &its, float max_length)
|
||||
{
|
||||
// same order as key order in Edge Divides
|
||||
@ -123,7 +123,7 @@ indexed_triangle_set subdivide(
|
||||
|
||||
int index_offset = count_edge_vertices/2;
|
||||
size_t i2 = (divide_index + 2) % 3;
|
||||
if (count_edge_vertices % 2 == 0 && key_swap == l[i1] < l[i2]) {
|
||||
if (count_edge_vertices % 2 == 0 && key_swap == (l[i1] < l[i2])) {
|
||||
--index_offset;
|
||||
}
|
||||
int sign = (vs.positive_order) ? 1 : -1;
|
||||
@ -161,7 +161,7 @@ indexed_triangle_set subdivide(
|
||||
}
|
||||
}
|
||||
|
||||
if (index_offset < count_edge_vertices-1) {
|
||||
if (index_offset < int(count_edge_vertices)-1) {
|
||||
std::pair<size_t, size_t> new_key(new_index, key.second);
|
||||
bool new_key_swap = false;
|
||||
if (new_key.first > new_key.second) {
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
indexed_triangle_set subdivide(const indexed_triangle_set &its, float max_length);
|
||||
indexed_triangle_set its_subdivide(const indexed_triangle_set &its, float max_length);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user