Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CURA-7979] Lock outer wall in place and width as much as possible #1405

Merged
merged 21 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a5f9acf
Possible to adjust how close to optimal-width/place outer walls are.
rburema Feb 5, 2021
869cc4d
Rethink left-over width w.r.t. redistribution.
rburema Feb 5, 2021
99f7349
Handle the 'initially only outer walls' case.
rburema Feb 5, 2021
aca8aeb
Don't handle 0-width signalling walls.
rburema Feb 5, 2021
4928723
Handle case where inner walls dissapear.
rburema Feb 5, 2021
3f28e22
Expose 'Outer Wall Lock Factor' setting to frontend.
rburema Feb 5, 2021
d13d08b
Add new setting to tests as well.
rburema Feb 7, 2021
21c93de
Rewrote outer wall lock factor usage.
jellespijker Feb 10, 2021
5582c23
Calculate weights only once
jellespijker Feb 10, 2021
2e0af51
Inner beads should also be processed
jellespijker Feb 10, 2021
c1b75ab
Make sure that all beads still adhere to minimum width
jellespijker Feb 10, 2021
8c60b9a
Take into account filtered out beads
jellespijker Feb 12, 2021
3bd13c9
Removed indention
jellespijker Feb 12, 2021
667ef4a
Reimplemented old distribution calculation.
jellespijker Feb 12, 2021
a12e989
Force symmetry from and early start.
jellespijker Feb 12, 2021
2d63dab
Made outer wall lock default behaviour.
jellespijker Feb 15, 2021
219a48c
Updated and added documentation
jellespijker Feb 15, 2021
5b7e466
Renamed parameter to minimum_width_inner for consistency
jellespijker Feb 15, 2021
82eb2b5
Merge remote-tracking branch 'origin/libArachne_rebased' into CURA-79…
jellespijker Feb 16, 2021
4404c7e
Remove dead code. Correct English spelling.
rburema Feb 16, 2021
88e793e
Merge branch 'CURA-7979_fix_outer_wall_artifacts' of https://github.c…
rburema Feb 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/BeadingStrategy/BeadingStrategyFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,21 @@ coord_t getWeightedAverage(const coord_t preferred_bead_width_outer, const coord
return preferred_bead_width_outer;
}

BeadingStrategy* BeadingStrategyFactory::makeStrategy(const StrategyType type, const coord_t preferred_bead_width_outer, const coord_t preferred_bead_width_inner, const coord_t preferred_transition_length, const float transitioning_angle, const bool print_thin_walls, const coord_t min_bead_width, const coord_t min_feature_size, const Ratio wall_transition_threshold, const coord_t max_bead_count, const coord_t outer_wall_offset)
BeadingStrategy* BeadingStrategyFactory::makeStrategy
(
const StrategyType type,
const coord_t preferred_bead_width_outer,
const coord_t preferred_bead_width_inner,
const coord_t preferred_transition_length,
const float transitioning_angle,
const bool print_thin_walls,
const coord_t min_bead_width,
const coord_t min_feature_size,
const Ratio wall_transition_threshold,
const coord_t max_bead_count,
const coord_t outer_wall_offset,
const double minimum_variable_line_width
)
{
const coord_t bar_preferred_wall_width = getWeightedAverage(preferred_bead_width_outer, preferred_bead_width_inner, max_bead_count);
BeadingStrategy* ret = nullptr;
Expand All @@ -77,7 +91,7 @@ BeadingStrategy* BeadingStrategyFactory::makeStrategy(const StrategyType type, c
if (max_bead_count > 0)
{
logDebug("Applying the Redistribute meta-strategy with outer-wall width = %d, inner-wall width = %d", preferred_bead_width_outer, preferred_bead_width_inner);
ret = new RedistributeBeadingStrategy(preferred_bead_width_outer, preferred_bead_width_inner, ret);
ret = new RedistributeBeadingStrategy(preferred_bead_width_outer, preferred_bead_width_inner, minimum_variable_line_width, ret);
//Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch.
logDebug("Applying the Limited Beading meta-strategy with maximum bead count = %d.", max_bead_count);
ret = new LimitedBeadingStrategy(max_bead_count, ret);
Expand Down
26 changes: 15 additions & 11 deletions src/BeadingStrategy/BeadingStrategyFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,21 @@ std::string to_string(StrategyType type);
class BeadingStrategyFactory
{
public:
static BeadingStrategy* makeStrategy(const StrategyType type,
const coord_t preferred_bead_width_outer = MM2INT(0.5),
const coord_t preferred_bead_width_inner = MM2INT(0.5),
const coord_t preferred_transition_length = MM2INT(0.4),
const float transitioning_angle = M_PI_4,
const bool print_thin_walls = false,
const coord_t min_bead_width = 0,
const coord_t min_feature_size = 0,
const Ratio wall_transition_thresold = 0.5_r,
const coord_t max_bead_count = 0,
const coord_t outer_wall_offset = 0);
static BeadingStrategy* makeStrategy
(
StrategyType type,
coord_t preferred_bead_width_outer = MM2INT(0.5),
coord_t preferred_bead_width_inner = MM2INT(0.5),
coord_t preferred_transition_length = MM2INT(0.4),
float transitioning_angle = M_PI_4,
bool print_thin_walls = false,
coord_t min_bead_width = 0,
coord_t min_feature_size = 0,
Ratio wall_transition_thresold = 0.5_r,
coord_t max_bead_count = 0,
coord_t outer_wall_offset = 0,
double minimum_variable_line_width = 0.5
);
};

} // namespace cura
Expand Down
32 changes: 27 additions & 5 deletions src/BeadingStrategy/InwardDistributedBeadingStrategy.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <numeric>

#include "InwardDistributedBeadingStrategy.h"
#include "CenterDeviationBeadingStrategy.h"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this import.


namespace cura
{
Expand All @@ -11,10 +14,9 @@ namespace cura
Beading ret;

ret.total_thickness = thickness;
if (bead_count > 0)
if (bead_count > 2)
{
const coord_t to_be_divided = thickness - bead_count * optimal_width;
float total_weight = 0;
const float middle = static_cast<float>(bead_count - 1) / 2;

const auto getWeight = [middle, this](coord_t bead_idx)
Expand All @@ -23,14 +25,19 @@ namespace cura
return std::max(0.0f, 1.0f - one_over_distribution_radius_squared * dev_from_middle * dev_from_middle);
};

std::vector<float> weights;
weights.resize(bead_count);
for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
{
total_weight += getWeight(bead_idx);
weights[bead_idx] = getWeight(bead_idx);
}

const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
{
const coord_t width = optimal_width + to_be_divided * getWeight(bead_idx) / total_weight;
const float weight_fraction = weights[bead_idx] / total_weight;
const coord_t splitup_left_over_weight = to_be_divided * weight_fraction;
const coord_t width = optimal_width + splitup_left_over_weight;
if (bead_idx == 0)
{
ret.toolpath_locations.emplace_back(width / 2);
Expand All @@ -43,12 +50,27 @@ namespace cura
}
ret.left_over = 0;
}
else if (bead_count == 2)
{
const coord_t outer_width = thickness / 2;
ret.bead_widths.emplace_back(outer_width);
ret.bead_widths.emplace_back(outer_width);
ret.toolpath_locations.emplace_back(outer_width / 2);
ret.toolpath_locations.emplace_back(thickness - outer_width / 2);
ret.left_over = 0;
}
else if (bead_count == 1)
{
const coord_t outer_width = thickness;
ret.bead_widths.emplace_back(outer_width);
ret.toolpath_locations.emplace_back(outer_width / 2);
ret.left_over = 0;
}
else
{
ret.left_over = thickness;
}

return ret;
}

} // namespace cura
147 changes: 104 additions & 43 deletions src/BeadingStrategy/RedistributeBeadingStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,126 @@
#include "RedistributeBeadingStrategy.h"

#include <algorithm>
#include <numeric>

namespace cura
{
BeadingStrategy::Beading RedistributeBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
BeadingStrategy::Beading RedistributeBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
{
Beading ret;
if (bead_count > 2)
{
Beading ret = parent->compute(thickness, bead_count);
const coord_t inner_transition_width = optimal_width_inner * minimum_variable_line_width;
const coord_t outer_bead_width =
getOptimalOuterBeadWidth(thickness, optimal_width_outer, inner_transition_width);

// Actual count and thickness as represented by extant walls. Don't count any potential zero-width 'signalling' walls.
bead_count = std::count_if(ret.bead_widths.begin(), ret.bead_widths.end(), [](const coord_t width) { return width > 0; });
thickness -= ret.left_over;
// Outer wall is locked in size en position for wall regions of 3 and higher which have at least a
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'size en position' -> 'size and position'

// thickness equal to two times the optimal outer width and the minimal inner wall width.
const coord_t virtual_thickness = thickness - outer_bead_width * 2;
const coord_t virtual_bead_count = bead_count - 2;

// Early out when the only walls are outer, the parent can have been trusted to handle it.
if (bead_count < 3)
{
return ret;
}
// Calculate the beads and widths of the inner walls only
ret = parent->compute(virtual_thickness, virtual_bead_count);

// Calculate the factors with which to multiply the outer and inner walls:
const coord_t current_total_outer_walls_width = ret.bead_widths.front() + ret.bead_widths.back();
const coord_t current_total_inner_walls_width = thickness - current_total_outer_walls_width;
const coord_t optimal_total_outer_walls_width = optimal_width_outer * 2;
const coord_t optimal_total_inner_walls_width = optimal_width_inner * (bead_count - 2);
// Insert the outer beads
ret.bead_widths.insert(ret.bead_widths.begin(), outer_bead_width);
ret.bead_widths.emplace_back(outer_bead_width);
}
else
{
ret = parent->compute(thickness, bead_count);
}

const coord_t outer_factor_numerator = optimal_total_outer_walls_width * thickness;
const coord_t outer_factor_denominator = current_total_outer_walls_width * (optimal_total_outer_walls_width + optimal_total_inner_walls_width);
const coord_t inner_factor_numerator = optimal_total_inner_walls_width * thickness;
const coord_t inner_factor_denominator = current_total_inner_walls_width * (optimal_total_outer_walls_width + optimal_total_inner_walls_width);
// Filter out beads that violate the minimum inner wall widths and recompute if necessary
const coord_t outer_transition_width = optimal_width_inner * minimum_variable_line_width;
const bool removed_inner_beads = validateInnerBeadWidths(ret, outer_transition_width);
if (removed_inner_beads)
{
ret = compute(thickness, bead_count - 1);
}

// Multiply the bead-widths with the right factors:
ret.bead_widths[0] = (ret.bead_widths[0] * outer_factor_numerator) / outer_factor_denominator;
for (coord_t i_width = 1; i_width < (bead_count - 1); ++i_width)
// Ensure that the positions of the beads are distributed over the thickness
resetToolPathLocations(ret, thickness);

return ret;
}

coord_t RedistributeBeadingStrategy::getOptimalOuterBeadWidth(const coord_t thickness, const coord_t optimal_width_outer, const coord_t minimum_width_inner)
{
const coord_t total_outer_optimal_width = optimal_width_outer * 2;
coord_t outer_bead_width = thickness / 2;
if (total_outer_optimal_width < thickness)
{
if (total_outer_optimal_width + minimum_width_inner > thickness)
{
ret.bead_widths[i_width] = (ret.bead_widths[i_width] * inner_factor_numerator) / inner_factor_denominator;
outer_bead_width -= minimum_width_inner / 2;
}
ret.bead_widths[bead_count - 1] = (ret.bead_widths[bead_count - 1] * outer_factor_numerator) / outer_factor_denominator;

// Update the first half of the toolpath-locations with the updated bead-widths (starting from 0, up to half):
coord_t last_coord = 0;
coord_t last_width = 0;
for (coord_t i_location = 0; i_location < bead_count / 2; ++i_location)
else
{
ret.toolpath_locations[i_location] = last_coord + (last_width + ret.bead_widths[i_location]) / 2;
last_coord = ret.toolpath_locations[i_location];
last_width = ret.bead_widths[i_location];
outer_bead_width = optimal_width_outer;
}
}
return outer_bead_width;
}

// NOTE: Don't have to alter the middle toolpath if there's any, it'll already be at half thickness.
void RedistributeBeadingStrategy::resetToolPathLocations(BeadingStrategy::Beading& beading, const coord_t thickness)
{
const size_t bead_count = beading.bead_widths.size();
beading.toolpath_locations.resize(bead_count);

// Update the last half of the toolpath-locations with the updated bead-widths (starting from thickness, down to half):
last_coord = thickness;
last_width = 0;
for (coord_t i_location = bead_count - 1; i_location >= bead_count - (bead_count / 2); --i_location)
{
ret.toolpath_locations[i_location] = last_coord - (last_width + ret.bead_widths[i_location]) / 2;
last_coord = ret.toolpath_locations[i_location];
last_width = ret.bead_widths[i_location];
}
if (bead_count < 1)
{
beading.toolpath_locations.resize(0);
beading.total_thickness = thickness;
beading.left_over = thickness;
return;
}

// Update the first half of the toolpath-locations with the updated bead-widths (starting from 0, up to half):
coord_t last_coord = 0;
coord_t last_width = 0;
for (size_t i_location = 0; i_location < bead_count / 2; ++i_location)
{
beading.toolpath_locations[i_location] = last_coord + (last_width + beading.bead_widths[i_location]) / 2;
last_coord = beading.toolpath_locations[i_location];
last_width = beading.bead_widths[i_location];
}

return ret;
// Handle the position of any middle wall (note that the width will already have been set correctly):
if (bead_count % 2 == 1)
{
beading.toolpath_locations[bead_count / 2] = thickness / 2;
}

// Update the last half of the toolpath-locations with the updated bead-widths (starting from thickness, down to half):
last_coord = thickness;
last_width = 0;
for (size_t i_location = bead_count - 1; i_location >= bead_count - (bead_count / 2); --i_location)
{
beading.toolpath_locations[i_location] = last_coord - (last_width + beading.bead_widths[i_location]) / 2;
last_coord = beading.toolpath_locations[i_location];
last_width = beading.bead_widths[i_location];
}

// Ensure correct total and left over thickness
beading.total_thickness = thickness;
beading.left_over = thickness - std::accumulate(beading.bead_widths.cbegin(), beading.bead_widths.cend(), static_cast<coord_t>(0));
}

bool RedistributeBeadingStrategy::validateInnerBeadWidths(BeadingStrategy::Beading& beading, const coord_t minimum_width_inner)
{
// Filter out bead_widths that violate the transition width and recalculate if needed
const size_t unfiltered_beads = beading.bead_widths.size();
auto inner_begin = std::next(beading.bead_widths.begin());
auto inner_end = std::prev(beading.bead_widths.end());
beading.bead_widths.erase(
std::remove_if(inner_begin, inner_end,
[&minimum_width_inner](const coord_t width)
{
return width < minimum_width_inner;
}),
inner_end);
return unfiltered_beads != beading.bead_widths.size();
}

} // namespace cura
Loading