change monotonic from monotonous

This commit is contained in:
supermerill 2020-11-06 19:05:39 +01:00
parent 21e6094530
commit e3dde4b384
9 changed files with 120 additions and 120 deletions

View File

@ -51,7 +51,7 @@ struct SurfaceFillParams : FillParams
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL(monotonous);
RETURN_COMPARE_NON_EQUAL(monotonic);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, connection);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(fill_exactly);
@ -71,7 +71,7 @@ struct SurfaceFillParams : FillParams
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->density == rhs.density &&
this->monotonous == rhs.monotonous &&
this->monotonic == rhs.monotonic &&
this->connection == rhs.connection &&
this->dont_adjust == rhs.dont_adjust &&
this->fill_exactly == rhs.fill_exactly &&
@ -570,7 +570,7 @@ void Layer::make_ironing()
fill_params.density = 1.;
// fill_params.dont_connect = true;
fill_params.connection = InfillConnection::icConnected;
fill_params.monotonous = true;
fill_params.monotonic = true;
for (size_t i = 0; i < by_extruder.size(); ++ i) {
// Find span of regions equivalent to the ironing operation.

View File

@ -31,7 +31,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear2();
case ipMonotonous: return new FillMonotonous();
case ipMonotonic: return new FillMonotonic();
case ipRectilinearWGapFill: return new FillRectilinear2WGapFill();
case ipScatteredRectilinear:return new FillScatteredRectilinear();
case ipLine: return new FillLine();

View File

@ -51,8 +51,8 @@ struct FillParams
// Don't adjust spacing to fill the space evenly.
bool dont_adjust { true };
// Monotonous infill - strictly left to right for better surface quality of top infills.
bool monotonous { false };
// Monotonic infill - strictly left to right for better surface quality of top infills.
bool monotonic { false };
// Try to extrude the exact amount of plastic to fill the volume requested
bool fill_exactly{ false };

View File

@ -1564,7 +1564,7 @@ static void traverse_graph_generate_polylines(
}
}
struct MonotonousRegion
struct MonotonicRegion
{
struct Boundary {
int vline;
@ -1589,13 +1589,13 @@ struct MonotonousRegion
#if NDEBUG
// Left regions are used to track whether all regions left to this one have already been printed.
boost::container::small_vector<MonotonousRegion*, 4> left_neighbors;
boost::container::small_vector<MonotonicRegion*, 4> left_neighbors;
// Right regions are held to pick a next region to be extruded using the "Ant colony" heuristics.
boost::container::small_vector<MonotonousRegion*, 4> right_neighbors;
boost::container::small_vector<MonotonicRegion*, 4> right_neighbors;
#else
// For debugging, use the normal vector as it is better supported by debug visualizers.
std::vector<MonotonousRegion*> left_neighbors;
std::vector<MonotonousRegion*> right_neighbors;
std::vector<MonotonicRegion*> left_neighbors;
std::vector<MonotonicRegion*> right_neighbors;
#endif
};
@ -1606,9 +1606,9 @@ struct AntPath
float pheromone{ 0 }; // <0, 1>
};
struct MonotonousRegionLink
struct MonotonicRegionLink
{
MonotonousRegion* region;
MonotonicRegion* region;
bool flipped;
// Distance of right side of this region to left side of the next region, if the "flipped" flag of this region and the next region
// is applied as defined.
@ -1624,7 +1624,7 @@ class AntPathMatrix
{
public:
AntPathMatrix(
const std::vector<MonotonousRegion>& regions,
const std::vector<MonotonicRegion>& regions,
const ExPolygonWithOffset& poly_with_offset,
const std::vector<SegmentedIntersectionLine>& segs,
const float initial_pheromone) :
@ -1640,7 +1640,7 @@ public:
ap.pheromone = initial_pheromone;
}
AntPath& operator()(const MonotonousRegion& region_from, bool flipped_from, const MonotonousRegion& region_to, bool flipped_to)
AntPath& operator()(const MonotonicRegion& region_from, bool flipped_from, const MonotonicRegion& region_to, bool flipped_to)
{
int row = 2 * int(&region_from - m_regions.data()) + flipped_from;
int col = 2 * int(&region_to - m_regions.data()) + flipped_to;
@ -1667,22 +1667,22 @@ public:
return path;
}
AntPath& operator()(const MonotonousRegionLink& region_from, const MonotonousRegion& region_to, bool flipped_to)
AntPath& operator()(const MonotonicRegionLink& region_from, const MonotonicRegion& region_to, bool flipped_to)
{
return (*this)(*region_from.region, region_from.flipped, region_to, flipped_to);
}
AntPath& operator()(const MonotonousRegion& region_from, bool flipped_from, const MonotonousRegionLink& region_to)
AntPath& operator()(const MonotonicRegion& region_from, bool flipped_from, const MonotonicRegionLink& region_to)
{
return (*this)(region_from, flipped_from, *region_to.region, region_to.flipped);
}
AntPath& operator()(const MonotonousRegionLink& region_from, const MonotonousRegionLink& region_to)
AntPath& operator()(const MonotonicRegionLink& region_from, const MonotonicRegionLink& region_to)
{
return (*this)(*region_from.region, region_from.flipped, *region_to.region, region_to.flipped);
}
private:
// Source regions, used for addressing and updating m_matrix.
const std::vector<MonotonousRegion>& m_regions;
const std::vector<MonotonicRegion>& m_regions;
// To calculate the intersection points and contour lengths.
const ExPolygonWithOffset& m_poly_with_offset;
const std::vector<SegmentedIntersectionLine>& m_segs;
@ -1837,15 +1837,15 @@ static std::pair<SegmentIntersection*, SegmentIntersection*> right_overlap(std::
return start_end.first == nullptr ? start_end : right_overlap(*start_end.first, *start_end.second, vline_this, vline_right);
}
static std::vector<MonotonousRegion> generate_montonous_regions(std::vector<SegmentedIntersectionLine> & segs)
static std::vector<MonotonicRegion> generate_montonous_regions(std::vector<SegmentedIntersectionLine> & segs)
{
std::vector<MonotonousRegion> monotonous_regions;
std::vector<MonotonicRegion> monotonic_regions;
#ifndef NDEBUG
#define SLIC3R_DEBUG_MONOTONOUS_REGIONS
#define SLIC3R_DEBUG_MONOTONIC_REGIONS
#endif
#ifdef SLIC3R_DEBUG_MONOTONOUS_REGIONS
#ifdef SLIC3R_DEBUG_MONOTONIC_REGIONS
std::vector<std::vector<std::pair<int, int>>> consumed(segs.size());
auto test_overlap = [&consumed](int segment, int low, int high) {
for (const std::pair<int, int>& interval : consumed[segment])
@ -1870,11 +1870,11 @@ static std::vector<MonotonousRegion> generate_montonous_regions(std::vector<Segm
SegmentIntersection* start = &vline_seed.intersections[i_intersection_seed];
SegmentIntersection* end = &end_of_vertical_run(vline_seed, *start);
if (!start->consumed_vertical_up) {
// Draw a new monotonous region starting with this segment.
// Draw a new monotonic region starting with this segment.
// while there is only a single right neighbor
size_t i_vline = i_vline_seed;
std::pair<SegmentIntersection*, SegmentIntersection*> left(start, end);
MonotonousRegion region;
MonotonicRegion region;
region.left.vline = int(i_vline);
region.left.low = int(left.first - vline_seed.intersections.data());
region.left.high = int(left.second - vline_seed.intersections.data());
@ -1907,19 +1907,19 @@ static std::vector<MonotonousRegion> generate_montonous_regions(std::vector<Segm
}
// Even number of lines makes the infill zig-zag to exit on the other side of the region than where it starts.
region.flips = (num_lines & 1) != 0;
monotonous_regions.emplace_back(region);
monotonic_regions.emplace_back(region);
}
i_intersection_seed = int(end - vline_seed.intersections.data()) + 1;
}
}
return monotonous_regions;
return monotonic_regions;
}
// Traverse path, calculate length of the draw for the purpose of optimization.
// This function is very similar to polylines_from_paths() in the way how it traverses the path, but
// polylines_from_paths() emits a path, while this function just calculates the path length.
static float montonous_region_path_length(const MonotonousRegion& region, bool dir, const ExPolygonWithOffset& poly_with_offset, const std::vector<SegmentedIntersectionLine>& segs)
static float montonous_region_path_length(const MonotonicRegion& region, bool dir, const ExPolygonWithOffset& poly_with_offset, const std::vector<SegmentedIntersectionLine>& segs)
{
// From the initial point (i_vline, i_intersection), follow a path.
int i_intersection = region.left_intersection_point(dir);
@ -2007,15 +2007,15 @@ static float montonous_region_path_length(const MonotonousRegion& region, bool d
return unscale<float>(total_length);
}
static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, const ExPolygonWithOffset& poly_with_offset, std::vector<SegmentedIntersectionLine>& segs)
static void connect_monotonic_regions(std::vector<MonotonicRegion>& regions, const ExPolygonWithOffset& poly_with_offset, std::vector<SegmentedIntersectionLine>& segs)
{
// Map from low intersection to left / right side of a monotonous region.
using MapType = std::pair<SegmentIntersection*, MonotonousRegion*>;
// Map from low intersection to left / right side of a monotonic region.
using MapType = std::pair<SegmentIntersection*, MonotonicRegion*>;
std::vector<MapType> map_intersection_to_region_start;
std::vector<MapType> map_intersection_to_region_end;
map_intersection_to_region_start.reserve(regions.size());
map_intersection_to_region_end.reserve(regions.size());
for (MonotonousRegion& region : regions) {
for (MonotonicRegion& region : regions) {
map_intersection_to_region_start.emplace_back(&segs[region.left.vline].intersections[region.left.low], &region);
map_intersection_to_region_end.emplace_back(&segs[region.right.vline].intersections[region.right.low], &region);
}
@ -2025,7 +2025,7 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, c
std::sort(map_intersection_to_region_end.begin(), map_intersection_to_region_end.end(), intersections_lower);
// Scatter links to neighboring regions.
for (MonotonousRegion& region : regions) {
for (MonotonicRegion& region : regions) {
if (region.left.vline > 0) {
auto& vline = segs[region.left.vline];
auto& vline_left = segs[region.left.vline - 1];
@ -2069,17 +2069,17 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, c
// Sometimes a segment may indicate that it connects to a segment on the other side while the other does not.
// This may be a valid case if one side contains runs of OUTER_LOW, INNER_LOW, {INNER_HIGH, INNER_LOW}*, INNER_HIGH, OUTER_HIGH,
// where the part in the middle does not connect to the other side, but it will be extruded through.
for (MonotonousRegion& region : regions) {
for (MonotonicRegion& region : regions) {
std::sort(region.left_neighbors.begin(), region.left_neighbors.end());
std::sort(region.right_neighbors.begin(), region.right_neighbors.end());
}
for (MonotonousRegion& region : regions) {
for (MonotonousRegion* neighbor : region.left_neighbors) {
for (MonotonicRegion& region : regions) {
for (MonotonicRegion* neighbor : region.left_neighbors) {
auto it = std::lower_bound(neighbor->right_neighbors.begin(), neighbor->right_neighbors.end(), &region);
if (it == neighbor->right_neighbors.end() || *it != &region)
neighbor->right_neighbors.insert(it, &region);
}
for (MonotonousRegion* neighbor : region.right_neighbors) {
for (MonotonicRegion* neighbor : region.right_neighbors) {
auto it = std::lower_bound(neighbor->left_neighbors.begin(), neighbor->left_neighbors.end(), &region);
if (it == neighbor->left_neighbors.end() || *it != &region)
neighbor->left_neighbors.insert(it, &region);
@ -2088,12 +2088,12 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, c
#ifndef NDEBUG
// Verify symmetry of the left_neighbors / right_neighbors.
for (MonotonousRegion& region : regions) {
for (MonotonousRegion* neighbor : region.left_neighbors) {
for (MonotonicRegion& region : regions) {
for (MonotonicRegion* neighbor : region.left_neighbors) {
assert(std::count(region.left_neighbors.begin(), region.left_neighbors.end(), neighbor) == 1);
assert(std::find(neighbor->right_neighbors.begin(), neighbor->right_neighbors.end(), &region) != neighbor->right_neighbors.end());
}
for (MonotonousRegion* neighbor : region.right_neighbors) {
for (MonotonicRegion* neighbor : region.right_neighbors) {
assert(std::count(region.right_neighbors.begin(), region.right_neighbors.end(), neighbor) == 1);
assert(std::find(neighbor->left_neighbors.begin(), neighbor->left_neighbors.end(), &region) != neighbor->left_neighbors.end());
}
@ -2101,7 +2101,7 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, c
#endif /* NDEBUG */
// Fill in sum length of connecting lines of a region. This length is used for optimizing the infill path for minimum length.
for (MonotonousRegion& region : regions) {
for (MonotonicRegion& region : regions) {
region.len1 = montonous_region_path_length(region, false, poly_with_offset, segs);
region.len2 = montonous_region_path_length(region, true, poly_with_offset, segs);
// Subtract the smaller length from the longer one, so we will optimize just with the positive difference of the two.
@ -2119,7 +2119,7 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion>& regions, c
// https://www.chalmers.se/en/departments/math/research/research-groups/optimization/OptimizationMasterTheses/MScThesis-RaadSalman-final.pdf
// Algorithm 6.1 Lexicographic Path Preserving 3-opt
// Optimize path while maintaining the ordering constraints.
void monotonous_3_opt(std::vector<MonotonousRegionLink> & path, const std::vector<SegmentedIntersectionLine> & segs)
void monotonic_3_opt(std::vector<MonotonicRegionLink> & path, const std::vector<SegmentedIntersectionLine> & segs)
{
// When doing the 3-opt path preserving flips, one has to fulfill two constraints:
//
@ -2134,7 +2134,7 @@ void monotonous_3_opt(std::vector<MonotonousRegionLink> & path, const std::vecto
// then the precedence constraint verification is amortized inside the O(n^3) loop. Now which is better for our task?
//
// It is beneficial to also try flipping of the infill zig-zags, for which a prefix sum of both flipped and non-flipped paths over
// MonotonousRegionLinks may be utilized, however updating the prefix sum has a linear complexity, the same complexity as doing the 3-opt
// MonotonicRegionLinks may be utilized, however updating the prefix sum has a linear complexity, the same complexity as doing the 3-opt
// exchange by copying the pieces.
}
@ -2147,17 +2147,17 @@ inline void print_ant(const std::string & fmt, TArgs &&... args) {
#endif
}
// Find a run through monotonous infill blocks using an 'Ant colony" optimization method.
// Find a run through monotonic infill blocks using an 'Ant colony" optimization method.
// http://www.scholarpedia.org/article/Ant_colony_optimization
static std::vector<MonotonousRegionLink> chain_monotonous_regions(
std::vector<MonotonousRegion> & regions, const ExPolygonWithOffset & poly_with_offset, const std::vector<SegmentedIntersectionLine> & segs, std::mt19937_64 & rng)
static std::vector<MonotonicRegionLink> chain_monotonic_regions(
std::vector<MonotonicRegion> & regions, const ExPolygonWithOffset & poly_with_offset, const std::vector<SegmentedIntersectionLine> & segs, std::mt19937_64 & rng)
{
// Number of left neighbors (regions that this region depends on, this region cannot be printed before the regions left of it are printed) + self.
std::vector<int32_t> left_neighbors_unprocessed(regions.size(), 1);
// Queue of regions, which have their left neighbors already printed.
std::vector<MonotonousRegion*> queue;
std::vector<MonotonicRegion*> queue;
queue.reserve(regions.size());
for (MonotonousRegion& region : regions)
for (MonotonicRegion& region : regions)
if (region.left_neighbors.empty())
queue.emplace_back(&region);
else
@ -2166,13 +2166,13 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
auto left_neighbors_unprocessed_initial = left_neighbors_unprocessed;
auto queue_initial = queue;
std::vector<MonotonousRegionLink> path, best_path;
std::vector<MonotonicRegionLink> path, best_path;
path.reserve(regions.size());
best_path.reserve(regions.size());
float best_path_length = std::numeric_limits<float>::max();
struct NextCandidate {
MonotonousRegion* region;
MonotonicRegion* region;
AntPath* link;
AntPath* link_flipped;
float probability;
@ -2187,22 +2187,22 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
[&regions, &left_neighbors_unprocessed, &path, &queue]() {
std::vector<unsigned char> regions_processed(regions.size(), false);
std::vector<unsigned char> regions_in_queue(regions.size(), false);
for (const MonotonousRegion* region : queue) {
for (const MonotonicRegion* region : queue) {
// This region is not processed yet, his predecessors are processed.
assert(left_neighbors_unprocessed[region - regions.data()] == 1);
regions_in_queue[region - regions.data()] = true;
}
for (const MonotonousRegionLink& link : path) {
for (const MonotonicRegionLink& link : path) {
assert(left_neighbors_unprocessed[link.region - regions.data()] == 0);
regions_processed[link.region - regions.data()] = true;
}
for (size_t i = 0; i < regions_processed.size(); ++i) {
assert(!regions_processed[i] || !regions_in_queue[i]);
const MonotonousRegion& region = regions[i];
const MonotonicRegion& region = regions[i];
if (regions_processed[i] || regions_in_queue[i]) {
assert(left_neighbors_unprocessed[i] == (regions_in_queue[i] ? 1 : 0));
// All left neighbors should be processed already.
for (const MonotonousRegion* left : region.left_neighbors) {
for (const MonotonicRegion* left : region.left_neighbors) {
assert(regions_processed[left - regions.data()]);
assert(left_neighbors_unprocessed[left - regions.data()] == 0);
}
@ -2211,7 +2211,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
assert(left_neighbors_unprocessed[i] > 1);
size_t num_predecessors_unprocessed = 0;
bool has_left_last_on_path = false;
for (const MonotonousRegion* left : region.left_neighbors) {
for (const MonotonicRegion* left : region.left_neighbors) {
size_t iprev = left - regions.data();
if (regions_processed[iprev]) {
assert(left_neighbors_unprocessed[iprev] == 0);
@ -2265,18 +2265,18 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
left_neighbors_unprocessed = left_neighbors_unprocessed_initial;
assert(validate_unprocessed());
// Pick the last of the queue.
MonotonousRegionLink path_end{ queue.back(), false };
MonotonicRegionLink path_end{ queue.back(), false };
queue.pop_back();
--left_neighbors_unprocessed[path_end.region - regions.data()];
float total_length = path_end.region->length(false);
while (!queue.empty() || !path_end.region->right_neighbors.empty()) {
// Chain.
MonotonousRegion& region = *path_end.region;
MonotonicRegion& region = *path_end.region;
bool dir = path_end.flipped;
NextCandidate next_candidate;
next_candidate.probability = 0;
for (MonotonousRegion* next : region.right_neighbors) {
for (MonotonicRegion* next : region.right_neighbors) {
int& unprocessed = left_neighbors_unprocessed[next - regions.data()];
assert(unprocessed > 1);
if (left_neighbors_unprocessed[next - regions.data()] == 2) {
@ -2291,7 +2291,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
}
bool from_queue = next_candidate.probability == 0;
if (from_queue) {
for (MonotonousRegion* next : queue) {
for (MonotonicRegion* next : queue) {
AntPath& path1 = path_matrix(region, dir, *next, false);
AntPath& path2 = path_matrix(region, dir, *next, true);
if (path1.visibility > next_candidate.probability)
@ -2301,7 +2301,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
}
}
// Move the other right neighbors with satisified constraints to the queue.
for (MonotonousRegion* next : region.right_neighbors)
for (MonotonicRegion* next : region.right_neighbors)
if (--left_neighbors_unprocessed[next - regions.data()] == 1 && next_candidate.region != next)
queue.emplace_back(next);
if (from_queue) {
@ -2312,7 +2312,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
queue.pop_back();
}
// Extend the path.
MonotonousRegion* next_region = next_candidate.region;
MonotonicRegion* next_region = next_candidate.region;
bool next_dir = next_candidate.dir;
total_length += next_region->length(next_dir) + path_matrix(*path_end.region, path_end.flipped, *next_region, next_dir).length;
path_end = { next_region, next_dir };
@ -2325,7 +2325,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
path_matrix.update_inital_pheromone(pheromone_initial_deposit);
}
// Probability (unnormalized) of traversing a link between two monotonous regions.
// Probability (unnormalized) of traversing a link between two monotonic regions.
auto path_probability = [pheromone_alpha, pheromone_beta](AntPath& path) {
return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta);
};
@ -2348,10 +2348,10 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
left_neighbors_unprocessed = left_neighbors_unprocessed_initial;
assert(validate_unprocessed());
// Pick randomly the first from the queue at random orientation.
//FIXME picking the 1st monotonous region should likely be done based on accumulated pheromone level as well,
// but the inefficiency caused by the random pick of the 1st monotonous region is likely insignificant.
//FIXME picking the 1st monotonic region should likely be done based on accumulated pheromone level as well,
// but the inefficiency caused by the random pick of the 1st monotonic region is likely insignificant.
int first_idx = std::uniform_int_distribution<>(0, int(queue.size()) - 1)(rng);
path.emplace_back(MonotonousRegionLink{ queue[first_idx], rng() > rng.max() / 2 });
path.emplace_back(MonotonicRegionLink{ queue[first_idx], rng() > rng.max() / 2 });
*(queue.begin() + first_idx) = std::move(queue.back());
queue.pop_back();
--left_neighbors_unprocessed[path.back().region - regions.data()];
@ -2367,12 +2367,12 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
while (!queue.empty() || !path.back().region->right_neighbors.empty()) {
// Chain.
MonotonousRegion& region = *path.back().region;
MonotonicRegion& region = *path.back().region;
bool dir = path.back().flipped;
// Sort by distance to pt.
next_candidates.clear();
next_candidates.reserve(region.right_neighbors.size() * 2);
for (MonotonousRegion* next : region.right_neighbors) {
for (MonotonicRegion* next : region.right_neighbors) {
int& unprocessed = left_neighbors_unprocessed[next - regions.data()];
assert(unprocessed > 1);
if (--unprocessed == 1) {
@ -2389,7 +2389,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
//FIXME add the queue items to the candidates? These are valid moves as well.
if (num_direct_neighbors == 0) {
// Add the queue candidates.
for (MonotonousRegion* next : queue) {
for (MonotonicRegion* next : queue) {
assert(left_neighbors_unprocessed[next - regions.data()] == 1);
AntPath& path1 = path_matrix(region, dir, *next, false);
AntPath& path1_flipped = path_matrix(region, !dir, *next, true);
@ -2432,11 +2432,11 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
queue.pop_back();
}
// Extend the path.
MonotonousRegion* next_region = take_path->region;
MonotonicRegion* next_region = take_path->region;
bool next_dir = take_path->dir;
path.back().next = take_path->link;
path.back().next_flipped = take_path->link_flipped;
path.emplace_back(MonotonousRegionLink{ next_region, next_dir });
path.emplace_back(MonotonicRegionLink{ next_region, next_dir });
assert(left_neighbors_unprocessed[next_region - regions.data()] == 1);
left_neighbors_unprocessed[next_region - regions.data()] = 0;
print_ant("\tRegion (%1%:%2%,%3%) (%4%:%5%,%6%) length to prev %7%",
@ -2464,14 +2464,14 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
}
// Perform 3-opt local optimization of the path.
monotonous_3_opt(path, segs);
monotonic_3_opt(path, segs);
// Measure path length.
assert(!path.empty());
float path_length = std::accumulate(path.begin(), path.end() - 1,
path.back().region->length(path.back().flipped),
[&path_matrix](const float l, const MonotonousRegionLink& r) {
const MonotonousRegionLink& next = *(&r + 1);
[&path_matrix](const float l, const MonotonicRegionLink& r) {
const MonotonicRegionLink& next = *(&r + 1);
return l + r.region->length(r.flipped) + path_matrix(*r.region, r.flipped, *next.region, next.flipped).length;
});
// Save the shortest path.
@ -2494,7 +2494,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
// Reinforce the path pheromones with the best path.
float total_cost = best_path_length + float(EPSILON);
for (size_t i = 0; i + 1 < path.size(); ++i) {
MonotonousRegionLink& link = path[i];
MonotonicRegionLink& link = path[i];
link.next->pheromone = (1.f - pheromone_evaporation) * link.next->pheromone + pheromone_evaporation / total_cost;
}
@ -2509,7 +2509,7 @@ end:
}
// Traverse path, produce polylines.
static void polylines_from_paths(const std::vector<MonotonousRegionLink>& path, const ExPolygonWithOffset& poly_with_offset, const std::vector<SegmentedIntersectionLine>& segs, Polylines& polylines_out)
static void polylines_from_paths(const std::vector<MonotonicRegionLink>& path, const ExPolygonWithOffset& poly_with_offset, const std::vector<SegmentedIntersectionLine>& segs, Polylines& polylines_out)
{
Polyline* polyline = nullptr;
auto finish_polyline = [&polyline, &polylines_out]() {
@ -2537,8 +2537,8 @@ static void polylines_from_paths(const std::vector<MonotonousRegionLink>& path,
polyline = nullptr;
};
for (const MonotonousRegionLink& path_segment : path) {
MonotonousRegion& region = *path_segment.region;
for (const MonotonicRegionLink& path_segment : path) {
MonotonicRegion& region = *path_segment.region;
bool dir = path_segment.flipped;
// From the initial point (i_vline, i_intersection), follow a path.
@ -2547,8 +2547,8 @@ static void polylines_from_paths(const std::vector<MonotonousRegionLink>& path,
if (polyline != nullptr && &path_segment != path.data()) {
// Connect previous path segment with the new one.
const MonotonousRegionLink& path_segment_prev = *(&path_segment - 1);
const MonotonousRegion& region_prev = *path_segment_prev.region;
const MonotonicRegionLink& path_segment_prev = *(&path_segment - 1);
const MonotonicRegion& region_prev = *path_segment_prev.region;
bool dir_prev = path_segment_prev.flipped;
int i_vline_prev = region_prev.right.vline;
const SegmentedIntersectionLine& vline_prev = segs[i_vline_prev];
@ -2653,7 +2653,7 @@ static void polylines_from_paths(const std::vector<MonotonousRegionLink>& path,
if (polyline != nullptr) {
// Finish the current vertical line,
const MonotonousRegion& region = *path.back().region;
const MonotonicRegion& region = *path.back().region;
const SegmentedIntersectionLine& vline = segs[region.right.vline];
const SegmentIntersection* ip = &vline.intersections[region.right_intersection_point(path.back().flipped)];
assert(ip->is_inner());
@ -2756,18 +2756,18 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
svg.Close();
#endif /* SLIC3R_DEBUG */
//FIXME this is a hack to get the monotonous infill rolling. We likely want a smarter switch, likely based on user decison.
bool monotonous_infill = params.monotonous; // || params.density > 0.99;
if (monotonous_infill) {
//FIXME this is a hack to get the monotonic infill rolling. We likely want a smarter switch, likely based on user decison.
bool monotonic_infill = params.monotonic; // || params.density > 0.99;
if (monotonic_infill) {
// Sometimes the outer contour pinches the inner contour from both sides along a single vertical line.
// This situation is not handled correctly by generate_montonous_regions().
// Insert phony OUTER_HIGH / OUTER_LOW pairs at the position where the contour is pinched.
pinch_contours_insert_phony_outer_intersections(segs);
std::vector<MonotonousRegion> regions = generate_montonous_regions(segs);
connect_monotonous_regions(regions, poly_with_offset, segs);
std::vector<MonotonicRegion> regions = generate_montonous_regions(segs);
connect_monotonic_regions(regions, poly_with_offset, segs);
if (!regions.empty()) {
std::mt19937_64 rng;
std::vector<MonotonousRegionLink> path = chain_monotonous_regions(regions, poly_with_offset, segs, rng);
std::vector<MonotonicRegionLink> path = chain_monotonic_regions(regions, poly_with_offset, segs, rng);
polylines_from_paths(path, poly_with_offset, segs, polylines_out);
}
} else
@ -2820,13 +2820,13 @@ Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParam
return polylines_out;
}
Polylines FillMonotonous::fill_surface(const Surface *surface, const FillParams &params) const
Polylines FillMonotonic::fill_surface(const Surface *surface, const FillParams &params) const
{
FillParams params2 = params;
params2.monotonous = true;
params2.monotonic = true;
Polylines polylines_out;
if (!fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out)) {
printf("FillMonotonous::fill_surface() failed to fill a region.\n");
printf("FillMonotonic::fill_surface() failed to fill a region.\n");
}
return polylines_out;
}
@ -3198,11 +3198,11 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
// rectilinear
Polylines polylines_rectilinear;
Surface rectilinear_surface{ *surface };
FillParams params_monotonous = params;
params_monotonous.monotonous = true;
FillParams params_monotonic = params;
params_monotonic.monotonic = true;
for (const ExPolygon &rectilinear_area : rectilinear_areas) {
rectilinear_surface.expolygon = rectilinear_area, 0 - 0.5 * params.flow.scaled_spacing();
if (!fill_surface_by_lines(&rectilinear_surface, params_monotonous, 0.f, 0.f, polylines_rectilinear)) {
if (!fill_surface_by_lines(&rectilinear_surface, params_monotonic, 0.f, 0.f, polylines_rectilinear)) {
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
}
}
@ -3250,7 +3250,7 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
//Create extrusions
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
//don't force monotonous if not top or bottom
//don't force monotonic if not top or bottom
if (surface->surface_type & (stPosTop | stPosBottom) != 0)
eec->no_sort = true;
else

View File

@ -25,11 +25,11 @@ protected:
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out) const;
};
class FillMonotonous : public FillRectilinear2
class FillMonotonic : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillMonotonous(*this); };
virtual ~FillMonotonous() = default;
virtual Fill* clone() const { return new FillMonotonic(*this); };
virtual ~FillMonotonic() = default;
virtual Polylines fill_surface(const Surface * surface, const FillParams & params) const override;
virtual bool no_sort() const { return true; }
};

View File

@ -24,7 +24,7 @@ namespace Slic3r {
// Save into layer smoothing path.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
eec->no_sort = params.monotonous;
eec->no_sort = params.monotonic;
FillParams params_modifided = params;
if (params.config != NULL && idx > 0) params_modifided.density /= (float)params.config->fill_smooth_width.get_abs_value(1);
else if (params.config != NULL && idx == 0) params_modifided.density *= 1;
@ -135,18 +135,18 @@ namespace Slic3r {
first_pass_params.role = ExtrusionRole::erSolidInfill;
perform_single_fill(0, *eecroot, *surface, first_pass_params, volumeToOccupy);
//use monotonous for ironing pass
FillParams monotonous_params = params;
monotonous_params.monotonous = true;
//use monotonic for ironing pass
FillParams monotonic_params = params;
monotonic_params.monotonic = true;
//second infill
if (nbPass > 1){
perform_single_fill(1, *eecroot, *surface, monotonous_params, volumeToOccupy);
perform_single_fill(1, *eecroot, *surface, monotonic_params, volumeToOccupy);
}
// third infill
if (nbPass > 2){
perform_single_fill(2, *eecroot, *surface, monotonous_params, volumeToOccupy);
perform_single_fill(2, *eecroot, *surface, monotonic_params, volumeToOccupy);
}
if (!eecroot->entities.empty())

View File

@ -684,7 +684,7 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("rectilineargapfill");
def->enum_values.push_back("monotonous");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("concentric");
def->enum_values.push_back("concentricgapfill");
def->enum_values.push_back("hilbertcurve");
@ -695,8 +695,8 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("smoothtriple");
def->enum_values.push_back("smoothhilbert");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonous (filled)"));
def->enum_labels.push_back(L("Monotonous"));
def->enum_labels.push_back(L("Monotonic (filled)"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Concentric (filled)"));
def->enum_labels.push_back(L("Hilbert Curve"));
@ -704,7 +704,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Octagram Spiral"));
def->enum_labels.push_back(L("Sawtooth"));
def->enum_labels.push_back(L("Ironing"));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonous));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonic));
def = this->add("bottom_fill_pattern", coEnum);
def->label = L("Bottom");
@ -716,7 +716,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("rectilineargapfill");
def->enum_values.push_back("monotonous");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("concentric");
def->enum_values.push_back("concentricgapfill");
def->enum_values.push_back("hilbertcurve");
@ -724,8 +724,8 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("octagramspiral");
def->enum_values.push_back("smooth");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonous (filled)"));
def->enum_labels.push_back(L("Monotonous"));
def->enum_labels.push_back(L("Monotonic (filled)"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Concentric (filled)"));
def->enum_labels.push_back(L("Hilbert Curve"));
@ -733,7 +733,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Octagram Spiral"));
def->enum_labels.push_back(L("Ironing"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonous));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonic));
def = this->add("solid_fill_pattern", coEnum);
def->label = L("Solid pattern");
@ -744,7 +744,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("smooth");
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("rectilineargapfill");
def->enum_values.push_back("monotonous");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("concentric");
def->enum_values.push_back("concentricgapfill");
def->enum_values.push_back("hilbertcurve");
@ -753,7 +753,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Ironing"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Rectilinear (filled)"));
def->enum_labels.push_back(L("Monotonous"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Concentric (filled)"));
def->enum_labels.push_back(L("Hilbert Curve"));
@ -1543,7 +1543,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Fill pattern for general low-density infill.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonous");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("grid");
def->enum_values.push_back("triangles");
def->enum_values.push_back("stars");
@ -1560,7 +1560,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("adaptivecubic");
def->enum_values.push_back("supportcubic");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonous"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Triangles"));
def->enum_labels.push_back(L("Stars"));
@ -3441,14 +3441,14 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Pattern for interface layer.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonous");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("concentric");
def->enum_values.push_back("concentricgapfill");
def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("sawtooth");
def->enum_values.push_back("smooth");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonous"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Concentric (filled)"));
def->enum_labels.push_back(L("Hilbert Curve"));
@ -4891,7 +4891,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
"cooling", "serial_port", "serial_speed"
};
// In PrusaSlicer 2.3.0-alpha0 the "monotonous" infill was introduced, which was later renamed to "monotonic".
// In PrusaSlicer 2.3.0-alpha0 the "monotonic" infill was introduced, which was later renamed to "monotonous".
if (value == "monotonous" && (opt_key == "top_fill_pattern" || opt_key == "bottom_fill_pattern" || opt_key == "fill_pattern"))
value = "monotonic";

View File

@ -84,7 +84,7 @@ enum InfillPattern {
ipAdaptiveCubic, ipSupportCubic,
ipSmooth, ipSmoothHilbert, ipSmoothTriple,
ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear, ipSawtooth, ipRectilinearWGapFill,
ipMonotonous,
ipMonotonic,
ipCount
};
@ -223,7 +223,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
static t_config_enum_values keys_map;
if (keys_map.empty()) {
keys_map["rectilinear"] = ipRectilinear;
keys_map["monotonous"] = ipMonotonous;
keys_map["monotonic"] = ipMonotonic;
keys_map["grid"] = ipGrid;
keys_map["triangles"] = ipTriangles;
keys_map["stars"] = ipStars;

View File

@ -3489,7 +3489,7 @@ void PrintObject::combine_infill()
// Because fill areas for rectilinear and honeycomb are grown
// later to overlap perimeters, we need to counteract that too.
((region->config().fill_pattern == ipRectilinear ||
region->config().fill_pattern == ipMonotonous ||
region->config().fill_pattern == ipMonotonic ||
region->config().fill_pattern == ipGrid ||
region->config().fill_pattern == ipLine ||
region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *