Skip to content

CURA-12474 set fixed 0 gap for brim support #2213

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 20 additions & 8 deletions include/SkirtBrim.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,47 @@ constexpr coord_t min_brim_line_length = 3000u; //!< open polyline brim lines sm
class SkirtBrim
{
private:
/*!
* Store the various outlines that we want to create a brim around
*/
struct Outline
{
Shape gapped; //!< Outlines for which we want to start a brim by applying the gap for easy detaching
Shape touching; //!< Outlines for which we want the brim to touch, so that it has better adhesion
};

/*!
* A helper class to store an offset yet to be performed on either an outline polygon, or based on an earlier generated brim line.
*/
struct Offset
{
Offset(
const std::variant<Shape*, int>& reference_outline_or_index,
const std::variant<Outline*, int>& reference_outline_or_index,
const bool outside,
const bool inside,
const coord_t offset_value,
const coord_t offset_value_gapped,
const coord_t offset_value_touching,
const coord_t total_offset,
const size_t inset_idx,
const size_t extruder_nr,
const bool is_last)
: reference_outline_or_index_(reference_outline_or_index)
, outside_(outside)
, inside_(inside)
, offset_value_(offset_value)
, offset_value_gapped_(offset_value_gapped)
, offset_value_touching_(offset_value_touching)
, total_offset_(total_offset)
, inset_idx_(inset_idx)
, extruder_nr_(extruder_nr)
, is_last_(is_last)
{
}

std::variant<Shape*, int> reference_outline_or_index_;
std::variant<Outline*, int> reference_outline_or_index_;
bool outside_; //!< Wether to offset outward from the reference polygons
bool inside_; //!< Wether to offset inward from the reference polygons
coord_t offset_value_; //!< Distance by which to offset from the reference
coord_t offset_value_gapped_; //!< Distance by which to offset from the reference, for outlines with gap applied
coord_t offset_value_touching_; //!< Distance by which to offset from the reference, for outlines with no gap applied
coord_t total_offset_; //!< Total distance from the model
int inset_idx_; //!< The outset index of this brimline
size_t extruder_nr_; //!< The extruder by which to print this brim line
Expand Down Expand Up @@ -124,7 +136,7 @@ class SkirtBrim
* \param[out] starting_outlines The first layer outlines from which to compute the offsets. Returned as output parameter because pointers need to stay valid.
* \return An ordered list of offsets to perform in the order in which they are to be performed.
*/
std::vector<Offset> generateBrimOffsetPlan(std::vector<Shape>& starting_outlines);
std::vector<Offset> generateBrimOffsetPlan(std::vector<Outline>& starting_outlines);

/*!
* Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously.
Expand Down Expand Up @@ -158,7 +170,7 @@ class SkirtBrim
* \param extruder_nr The extruder for which to get the outlines. -1 to include outliens for all extruders
* \return The resulting reference polygons
*/
Shape getFirstLayerOutline(const int extruder_nr = -1);
Outline getFirstLayerOutline(const int extruder_nr = -1);

/*!
* The disallowed area around the internal holes of parts with other parts inside which would get an external brim.
Expand Down Expand Up @@ -206,7 +218,7 @@ class SkirtBrim
* \param[in] starting_outlines The previously generated starting outlines for each extruder
* \return The list of allowed areas for each extruder
*/
std::vector<Shape> generateAllowedAreas(const std::vector<Shape>& starting_outlines) const;
std::vector<Shape> generateAllowedAreas(const std::vector<Outline>& starting_outlines) const;

public:
/*!
Expand Down
114 changes: 70 additions & 44 deletions src/SkirtBrim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage)
}
}

std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Shape>& starting_outlines)
std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Outline>& starting_outlines)
{
std::vector<Offset> all_brim_offsets;

Expand All @@ -96,24 +96,42 @@ std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Sha
const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr];
const coord_t semi_line_width = extruder_config.line_width_ / 2;

if (! extruder_config.extruder_is_used_ || (skirt_brim_extruder_nr_ >= 0 && extruder_nr != skirt_brim_extruder_nr_) || starting_outlines[extruder_nr].empty())
if (! extruder_config.extruder_is_used_ || (skirt_brim_extruder_nr_ >= 0 && extruder_nr != skirt_brim_extruder_nr_)
|| (starting_outlines[extruder_nr].gapped.empty() && starting_outlines[extruder_nr].touching.empty()))
{
continue; // only include offsets for brim extruder
}

for (int line_idx = 0; line_idx < extruder_config.line_count_; line_idx++)
{
const bool is_last = line_idx == extruder_config.line_count_ - 1;
coord_t offset = extruder_config.gap_ + semi_line_width + extruder_config.line_width_ * line_idx;
const coord_t offset_touching = semi_line_width + extruder_config.line_width_ * line_idx;
const coord_t offset_gapped = offset_touching + extruder_config.gap_;
if (line_idx == 0)
{
all_brim_offsets
.emplace_back(&starting_outlines[extruder_nr], extruder_config.outside_polys_, extruder_config.inside_polys_, offset, offset, line_idx, extruder_nr, is_last);
all_brim_offsets.emplace_back(
&starting_outlines[extruder_nr],
extruder_config.outside_polys_,
extruder_config.inside_polys_,
offset_gapped,
offset_touching,
offset_gapped,
line_idx,
extruder_nr,
is_last);
}
else
{
all_brim_offsets
.emplace_back(line_idx - 1, extruder_config.outside_polys_, extruder_config.inside_polys_, extruder_config.line_width_, offset, line_idx, extruder_nr, is_last);
all_brim_offsets.emplace_back(
line_idx - 1,
extruder_config.outside_polys_,
extruder_config.inside_polys_,
extruder_config.line_width_,
extruder_config.line_width_,
offset_gapped,
line_idx,
extruder_nr,
is_last);
}
}
}
Expand All @@ -124,7 +142,7 @@ std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Sha

void SkirtBrim::generate()
{
std::vector<Shape> starting_outlines(extruder_count_);
std::vector<Outline> starting_outlines(extruder_count_);
std::vector<Offset> all_brim_offsets = generateBrimOffsetPlan(starting_outlines);
std::vector<Shape> allowed_areas_per_extruder = generateAllowedAreas(starting_outlines);

Expand Down Expand Up @@ -205,6 +223,7 @@ std::vector<coord_t> SkirtBrim::generatePrimaryBrim(std::vector<Offset>& all_bri
extruder_config.inside_polys_,
extruder_config.line_width_,
offset.total_offset_ + extruder_config.line_width_,
offset.total_offset_ + extruder_config.line_width_,
offset.inset_idx_ + 1,
offset.extruder_nr_,
is_last);
Expand All @@ -220,20 +239,23 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std
Shape brim;
const ExtruderConfig& extruder_config = extruders_configs_[offset.extruder_nr_];

if (std::holds_alternative<Shape*>(offset.reference_outline_or_index_))
if (std::holds_alternative<Outline*>(offset.reference_outline_or_index_))
{
Shape* reference_outline = std::get<Shape*>(offset.reference_outline_or_index_);
const coord_t offset_value = offset.offset_value_;
for (const Polygon& polygon : *reference_outline)
Outline* reference_outline = std::get<Outline*>(offset.reference_outline_or_index_);
for (const auto& [shape, offset_value] :
{ std::make_tuple(reference_outline->gapped, offset.offset_value_gapped_), std::make_tuple(reference_outline->touching, offset.offset_value_touching_) })
{
const double area = polygon.area();
if (area > 0 && offset.outside_)
{
brim.push_back(polygon.offset(offset_value, ClipperLib::jtRound));
}
else if (area < 0 && offset.inside_)
for (const Polygon& polygon : shape)
{
brim.push_back(polygon.offset(-offset_value, ClipperLib::jtRound));
const double area = polygon.area();
if (area > 0 && offset.outside_)
{
brim.push_back(polygon.offset(offset_value, ClipperLib::jtRound));
}
else if (area < 0 && offset.inside_)
{
brim.push_back(polygon.offset(-offset_value, ClipperLib::jtRound));
}
}
}
}
Expand Down Expand Up @@ -284,9 +306,9 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std
return length_added;
}

Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
SkirtBrim::Outline SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
{
Shape first_layer_outline;
Outline first_layer_outline;
Settings& global_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings;
int reference_extruder_nr = skirt_brim_extruder_nr_;
assert(! (reference_extruder_nr == -1 && extruder_nr == -1) && "We should only request the outlines of all layers when the brim is being generated for only one material");
Expand All @@ -299,7 +321,6 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
const LayerIndex layer_nr = 0;
if (adhesion_type_ == EPlatformAdhesion::SKIRT)
{
first_layer_outline = Shape();
int skirt_height = 0;
for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders)
{
Expand All @@ -314,7 +335,7 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
{
constexpr bool include_support = true;
constexpr bool include_prime_tower = true;
first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, true));
first_layer_outline.gapped = first_layer_outline.gapped.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, true));
}

Shape shields;
Expand All @@ -326,22 +347,25 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
{
shields = shields.unionPolygons(storage_.draft_protection_shield);
}
first_layer_outline = first_layer_outline.unionPolygons(shields.offset(
first_layer_outline.gapped = first_layer_outline.gapped.unionPolygons(shields.offset(
reference_extruder_config.line_width_ / 2 // because the shield is printed *on* the stored polygons; not inside hteir area
- reference_extruder_config.gap_)); // so that when we apply the gap we will end up right next to the shield
// NOTE: offsetting by -gap here and by +gap in the main brim algorithm effectively performs a morphological close,
// so in some cases with a large skirt gap and small models and small shield distance
// the skirt lines can cross the shield lines.
// This shouldn't be a big problem, since the skirt lines are far away from the model.
first_layer_outline = first_layer_outline.approxConvexHull();
first_layer_outline.gapped = first_layer_outline.gapped.approxConvexHull();
}
else
{ // add brim underneath support by removing support where there's brim around the model
constexpr bool include_support = false; // Don't include the supports yet because we need to reduce them before
constexpr bool include_prime_tower = false; // Not included, has its own brim
constexpr bool external_polys_only = false; // Gather all polygons and treat them separately.
first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr);
first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule.
{
constexpr bool include_support = false; // Don't include the supports yet because we need to reduce them before
constexpr bool include_prime_tower = false; // Not included, has its own brim
constexpr bool external_polys_only = false; // Gather all polygons and treat them separately.
first_layer_outline.gapped = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr);
first_layer_outline.gapped
= first_layer_outline.gapped.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule.
}

if (storage_.support.generated && primary_line_count > 0 && ! storage_.support.supportLayers.empty()
&& (extruder_nr == -1 || extruder_nr == global_settings.get<int>("support_infill_extruder_nr")))
Expand All @@ -363,7 +387,7 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
// always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides
const coord_t offset = primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2);

for (const Polygon& polygon : first_layer_outline)
for (const Polygon& polygon : first_layer_outline.gapped)
{
// Compute the fringe that the brim is going to cover around the model
Shape outset;
Expand Down Expand Up @@ -394,20 +418,20 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)

for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts)
{
first_layer_outline.push_back(support_infill_part.outline_);
first_layer_outline.touching.push_back(support_infill_part.outline_);
}
first_layer_outline.push_back(support_layer.support_bottom);
first_layer_outline.push_back(support_layer.support_roof);
first_layer_outline.touching.push_back(support_layer.support_bottom);
first_layer_outline.touching.push_back(support_layer.support_roof);
}
}
constexpr coord_t join_distance = 20;
first_layer_outline = first_layer_outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon
constexpr coord_t smallest_line_length = 200;
constexpr coord_t largest_error_of_removed_point = 50;
first_layer_outline = Simplify(smallest_line_length, largest_error_of_removed_point, 0).polygon(first_layer_outline);
if (first_layer_outline.empty())

for (Shape& outline : std::array{ first_layer_outline.gapped, first_layer_outline.touching })
{
spdlog::warn("Couldn't generate skirt / brim! No polygons on first layer for extruder {}.", extruder_nr);
constexpr coord_t join_distance = 20;
outline = outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon
constexpr coord_t smallest_line_length = 200;
constexpr coord_t largest_error_of_removed_point = 50;
outline = Simplify(smallest_line_length, largest_error_of_removed_point, 0).polygon(outline);
}
return first_layer_outline;
}
Expand Down Expand Up @@ -492,7 +516,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++)
{
bool first = true;
Shape reference_outline = covered_area;
Outline reference_outline{ .touching = covered_area };
const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr];
while (total_length[extruder_nr] < extruder_config.skirt_brim_minimal_length_)
{
Expand All @@ -515,6 +539,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
outside_polys,
inside_polys,
offset_from_reference,
offset_from_reference,
bogus_total_offset,
storage_.skirt_brim[extruder_nr].size(),
extruder_nr,
Expand All @@ -537,7 +562,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
}
}

std::vector<Shape> SkirtBrim::generateAllowedAreas(const std::vector<Shape>& starting_outlines) const
std::vector<Shape> SkirtBrim::generateAllowedAreas(const std::vector<Outline>& starting_outlines) const
{
constexpr LayerIndex layer_nr = 0;

Expand Down Expand Up @@ -635,7 +660,8 @@ std::vector<Shape> SkirtBrim::generateAllowedAreas(const std::vector<Shape>& sta
}

// Anyway, don't allow a brim/skirt to grow inside itself, which may happen e.g. with ooze shield+skirt
allowed_areas = allowed_areas.difference(starting_outlines[extruder_nr].offset(extruder_config.gap_ - 50, ClipperLib::jtRound));
allowed_areas = allowed_areas.difference(starting_outlines[extruder_nr].gapped.offset(extruder_config.gap_ - 50, ClipperLib::jtRound));
allowed_areas = allowed_areas.difference(starting_outlines[extruder_nr].touching.offset(-50, ClipperLib::jtRound));
}

return allowed_areas_per_extruder;
Expand Down
Loading