mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-26 08:07:44 +08:00
Simple implementation of spRandom
This commit is contained in:
parent
5d6bf3261e
commit
fffb79a085
@ -199,16 +199,16 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
||||
const ExtrusionLoop& loop, Point last_pos, coordf_t nozzle_dmr,
|
||||
const PrintObject* po, bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid)
|
||||
{
|
||||
if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear) {
|
||||
Polygon polygon = loop.polygon();
|
||||
const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5);
|
||||
|
||||
if (this->is_custom(layer_idx)) {
|
||||
if (this->is_custom_seam_on_layer(layer_idx)) {
|
||||
// Seam enf/blockers can begin and end in between the original vertices.
|
||||
// Let add extra points in between and update the leghths.
|
||||
polygon.densify(scale_(0.2f));
|
||||
}
|
||||
|
||||
if (seam_position != spRandom) {
|
||||
// Retrieve the last start position for this object.
|
||||
float last_pos_weight = 1.f;
|
||||
|
||||
@ -224,6 +224,8 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
||||
last_pos.x() = 0;
|
||||
last_pos.y() += coord_t(3. * po->bounding_box().radius());
|
||||
last_pos_weight = 5.f;
|
||||
} if (seam_position == spNearest) {
|
||||
// last_pos already contains current nozzle position
|
||||
}
|
||||
|
||||
// Insert a projection of last_pos into the polygon.
|
||||
@ -291,9 +293,9 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
||||
}
|
||||
}
|
||||
|
||||
// Penalty according to custom seam selection. This one is huge compared to
|
||||
// the others so that points outside enforcers/inside blockers never win.
|
||||
this->penalize_polygon(polygon, penalties, lengths, layer_idx);
|
||||
// Custom seam. Huge (negative) constant penalty is applied inside
|
||||
// blockers (enforcers) to rule out points that should not win.
|
||||
this->apply_custom_seam(polygon, penalties, lengths, layer_idx);
|
||||
|
||||
// Find a point with a minimum penalty.
|
||||
size_t idx_min = std::min_element(penalties.begin(), penalties.end()) - penalties.begin();
|
||||
@ -333,7 +335,7 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
||||
coordf_t nozzle_dmr = EXTRUDER_CONFIG(nozzle_diameter);
|
||||
coord_t delta = scale_(0.5*nozzle_dmr);
|
||||
Slic3r::offset(polylines, &polygons, delta);
|
||||
// for (size_t i = 0; i < polygons.size(); ++ i) svg.draw((Polyline)polygons[i], "blue");
|
||||
// for (size_t i = 0; i < polygons.size(); ++ i) svg.draw((Polyline)polygons[i], "blue");
|
||||
svg.draw(last_pos, "green", 3);
|
||||
svg.draw(polygon.points[idx_min], "yellow", 3);
|
||||
svg.Close();
|
||||
@ -342,25 +344,86 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
|
||||
return polygon.points[idx_min];
|
||||
|
||||
} else { // spRandom
|
||||
if (loop.loop_role() == elrContourInternalPerimeter) {
|
||||
if (loop.loop_role() == elrContourInternalPerimeter && 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
|
||||
// on the inner most contour.
|
||||
// on the innermost contour.
|
||||
//FIXME This works correctly for inner contours first only.
|
||||
//FIXME Better parametrize the loop by its length.
|
||||
Polygon polygon = loop.polygon();
|
||||
Point centroid = polygon.centroid();
|
||||
last_pos = Point(polygon.bounding_box().max(0), centroid(1));
|
||||
last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid);
|
||||
last_pos = this->get_random_seam(layer_idx, polygon);
|
||||
}
|
||||
if (loop.role() == erExternalPerimeter && is_custom_seam_on_layer(layer_idx)) {
|
||||
// There is a possibility that the loop will be influenced by custom
|
||||
// seam enforcer/blocker. In this case do not inherit the seam
|
||||
// from internal loops (which may conflict with the custom selection
|
||||
// and generate another random one.
|
||||
bool saw_custom = false;
|
||||
Point candidate = this->get_random_seam(layer_idx, polygon, &saw_custom);
|
||||
if (saw_custom)
|
||||
last_pos = candidate;
|
||||
}
|
||||
return last_pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Point SeamPlacer::get_random_seam(size_t layer_idx, const Polygon& polygon,
|
||||
bool* saw_custom) const
|
||||
{
|
||||
// Parametrize the polygon by its length.
|
||||
std::vector<float> lengths = polygon.parameter_by_length();
|
||||
|
||||
// Which of the points are inside enforcers/blockers?
|
||||
std::vector<size_t> enforcers_idxs;
|
||||
std::vector<size_t> blockers_idxs;
|
||||
this->get_enforcers_and_blockers(layer_idx, polygon, enforcers_idxs, blockers_idxs);
|
||||
|
||||
bool has_enforcers = ! enforcers_idxs.empty();
|
||||
bool has_blockers = ! blockers_idxs.empty();
|
||||
if (saw_custom)
|
||||
*saw_custom = has_enforcers || has_blockers;
|
||||
|
||||
// FIXME FIXME FIXME: This is just to test the outcome and whether it is
|
||||
// reasonable. The algorithm should really sum the length of all available
|
||||
// pieces, get a random length and find the respective point.
|
||||
float rand_len = 0.f;
|
||||
size_t pt_idx = 0;
|
||||
do {
|
||||
rand_len = lengths.back() * (rand()/float(RAND_MAX));
|
||||
auto it = std::lower_bound(lengths.begin(), lengths.end(), rand_len);
|
||||
pt_idx = it == lengths.end() ? 0 : (it-lengths.begin()-1);
|
||||
|
||||
// If there are blockers and the point is inside, repeat.
|
||||
// If there are enforcers and the point is NOT inside, repeat.
|
||||
} while ((has_blockers && std::binary_search(blockers_idxs.begin(), blockers_idxs.end(), pt_idx))
|
||||
|| (has_enforcers && ! std::binary_search(enforcers_idxs.begin(), enforcers_idxs.end(), pt_idx)));
|
||||
|
||||
if (! has_enforcers && ! has_blockers) {
|
||||
// The polygon may be too coarse, calculate the point exactly.
|
||||
bool last_seg = pt_idx == polygon.points.size()-1;
|
||||
size_t next_idx = last_seg ? 0 : pt_idx+1;
|
||||
const Point& prev = polygon.points[pt_idx];
|
||||
const Point& next = polygon.points[next_idx];
|
||||
assert(next_idx == 0 || pt_idx+1 == next_idx);
|
||||
coordf_t diff_x = next.x() - prev.x();
|
||||
coordf_t diff_y = next.y() - prev.y();
|
||||
coordf_t dist = lengths[last_seg ? pt_idx+1 : next_idx] - lengths[pt_idx];
|
||||
return Point(prev.x() + (rand_len - lengths[pt_idx]) * (diff_x/dist),
|
||||
prev.y() + (rand_len - lengths[pt_idx]) * (diff_y/dist));
|
||||
|
||||
} else {
|
||||
// The polygon should be dense enough.
|
||||
return polygon.points[pt_idx];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SeamPlacer::get_indices(size_t layer_id,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SeamPlacer::get_enforcers_and_blockers(size_t layer_id,
|
||||
const Polygon& polygon,
|
||||
std::vector<size_t>& enforcers_idxs,
|
||||
std::vector<size_t>& blockers_idxs) const
|
||||
@ -388,6 +451,8 @@ void SeamPlacer::get_indices(size_t layer_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << layer_id << ": enforcers.size() = " << enforcers_idxs.size() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@ -461,14 +526,19 @@ static std::vector<size_t> find_enforcer_centers(const Polygon& polygon,
|
||||
|
||||
|
||||
|
||||
void SeamPlacer::penalize_polygon(const Polygon& polygon,
|
||||
void SeamPlacer::apply_custom_seam(const Polygon& polygon,
|
||||
std::vector<float>& penalties,
|
||||
const std::vector<float>& lengths,
|
||||
int layer_id) const
|
||||
{
|
||||
if (! is_custom_seam_on_layer(layer_id))
|
||||
return;
|
||||
|
||||
static constexpr float ENFORCER_BLOCKER_PENALTY = 1e6;
|
||||
|
||||
std::vector<size_t> enforcers_idxs;
|
||||
std::vector<size_t> blockers_idxs;
|
||||
this->get_indices(layer_id, polygon, enforcers_idxs, blockers_idxs);
|
||||
this->get_enforcers_and_blockers(layer_id, polygon, enforcers_idxs, blockers_idxs);
|
||||
|
||||
for (size_t i : enforcers_idxs) {
|
||||
assert(i < penalties.size());
|
||||
|
@ -15,11 +15,6 @@ class SeamPlacer {
|
||||
public:
|
||||
void init(const Print& print);
|
||||
|
||||
bool is_custom(size_t layer_id) const {
|
||||
return ! ((m_enforcers.empty() || m_enforcers[layer_id].empty())
|
||||
&& (m_blockers.empty() || m_blockers[layer_id].empty()));
|
||||
}
|
||||
|
||||
Point get_seam(const size_t layer_idx, const SeamPosition seam_position,
|
||||
const ExtrusionLoop& loop, Point last_pos,
|
||||
coordf_t nozzle_diameter, const PrintObject* po,
|
||||
@ -32,17 +27,27 @@ private:
|
||||
std::map<const PrintObject*, Point> m_last_seam_position;
|
||||
|
||||
// Get indices of points inside enforcers and blockers.
|
||||
void get_indices(size_t layer_id,
|
||||
void get_enforcers_and_blockers(size_t layer_id,
|
||||
const Polygon& polygon,
|
||||
std::vector<size_t>& enforcers_idxs,
|
||||
std::vector<size_t>& blockers_idxs) const;
|
||||
|
||||
void penalize_polygon(const Polygon& polygon,
|
||||
// Apply penalties to points inside enforcers/blockers.
|
||||
void apply_custom_seam(const Polygon& polygon,
|
||||
std::vector<float>& penalties,
|
||||
const std::vector<float>& lengths,
|
||||
int layer_id) const;
|
||||
|
||||
static constexpr float ENFORCER_BLOCKER_PENALTY = 1e6;
|
||||
// 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,
|
||||
bool* saw_custom = nullptr) const;
|
||||
|
||||
// Is there any enforcer/blocker on this layer?
|
||||
bool is_custom_seam_on_layer(size_t layer_id) const {
|
||||
return ! ((m_enforcers.empty() || m_enforcers[layer_id].empty())
|
||||
&& (m_blockers.empty() || m_blockers[layer_id].empty()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user