Fix of #8472: The middle perimeter was missing for some specific configurations due to numeric rounding errors.
This commit is contained in:
parent
756eaeeb6d
commit
0161a59a93
@ -21,7 +21,7 @@ DistributedBeadingStrategy::DistributedBeadingStrategy(const coord_t optimal_wid
|
|||||||
name = "DistributedBeadingStrategy";
|
name = "DistributedBeadingStrategy";
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
|
DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(const coord_t thickness, const coord_t bead_count) const
|
||||||
{
|
{
|
||||||
Beading ret;
|
Beading ret;
|
||||||
|
|
||||||
@ -41,17 +41,23 @@ DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(coord_t
|
|||||||
weights[bead_idx] = getWeight(bead_idx);
|
weights[bead_idx] = getWeight(bead_idx);
|
||||||
|
|
||||||
const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
|
const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
|
||||||
|
coord_t accumulated_width = 0;
|
||||||
for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++) {
|
for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++) {
|
||||||
const float weight_fraction = weights[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 splitup_left_over_weight = to_be_divided * weight_fraction;
|
||||||
const coord_t width = optimal_width + splitup_left_over_weight;
|
const coord_t width = (bead_idx == bead_count - 1) ? thickness - accumulated_width : optimal_width + splitup_left_over_weight;
|
||||||
|
|
||||||
|
// Be aware that toolpath_locations is computed by dividing the width by 2, so toolpath_locations
|
||||||
|
// could be off by 1 because of rounding errors.
|
||||||
if (bead_idx == 0)
|
if (bead_idx == 0)
|
||||||
ret.toolpath_locations.emplace_back(width / 2);
|
ret.toolpath_locations.emplace_back(width / 2);
|
||||||
else
|
else
|
||||||
ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
|
ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
|
||||||
ret.bead_widths.emplace_back(width);
|
ret.bead_widths.emplace_back(width);
|
||||||
|
accumulated_width += width;
|
||||||
}
|
}
|
||||||
ret.left_over = 0;
|
ret.left_over = 0;
|
||||||
|
assert((accumulated_width + ret.left_over) == thickness);
|
||||||
} else if (bead_count == 2) {
|
} else if (bead_count == 2) {
|
||||||
const coord_t outer_width = thickness / 2;
|
const coord_t outer_width = thickness / 2;
|
||||||
ret.bead_widths.emplace_back(outer_width);
|
ret.bead_widths.emplace_back(outer_width);
|
||||||
@ -68,6 +74,13 @@ DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(coord_t
|
|||||||
ret.left_over = thickness;
|
ret.left_over = thickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(([&ret = std::as_const(ret), thickness]() -> bool {
|
||||||
|
coord_t total_bead_width = 0;
|
||||||
|
for (const coord_t &bead_width : ret.bead_widths)
|
||||||
|
total_bead_width += bead_width;
|
||||||
|
return (total_bead_width + ret.left_over) == thickness;
|
||||||
|
}()));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARACHNE_DEBUG
|
#ifdef ARACHNE_DEBUG
|
||||||
assert(is_voronoi_diagram_planar_intersection(voronoi_diagram));
|
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Try to detect cases when some Voronoi vertex is missing and when
|
// Try to detect cases when some Voronoi vertex is missing and when
|
||||||
@ -1911,7 +1911,10 @@ void SkeletalTrapezoidation::generateJunctions(ptr_vector_t<BeadingPropagation>&
|
|||||||
for (junction_idx = (std::max(size_t(1), beading->toolpath_locations.size()) - 1) / 2; junction_idx < num_junctions; junction_idx--)
|
for (junction_idx = (std::max(size_t(1), beading->toolpath_locations.size()) - 1) / 2; junction_idx < num_junctions; junction_idx--)
|
||||||
{
|
{
|
||||||
coord_t bead_R = beading->toolpath_locations[junction_idx];
|
coord_t bead_R = beading->toolpath_locations[junction_idx];
|
||||||
if (bead_R <= start_R)
|
// toolpath_locations computed inside DistributedBeadingStrategy be off by 1 because of rounding errors.
|
||||||
|
// In GH issue #8472, these roundings errors caused missing the middle extrusion.
|
||||||
|
// Adding some epsilon should help resolve those cases.
|
||||||
|
if (bead_R <= start_R + scaled<coord_t>(0.005))
|
||||||
{ // Junction coinciding with start node is used in this function call
|
{ // Junction coinciding with start node is used in this function call
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -73,3 +73,32 @@ TEST_CASE("Arachne - Closed ExtrusionLine", "[ArachneClosedExtrusionLine]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test case was distilled from GitHub issue #8472.
|
||||||
|
// Where for wall_distribution_count == 3 sometime middle perimeter was missing.
|
||||||
|
TEST_CASE("Arachne - Missing perimeter - #8472", "[ArachneMissingPerimeter8472]") {
|
||||||
|
Polygon poly = {
|
||||||
|
Point(-9000000, 8054793),
|
||||||
|
Point( 7000000, 8054793),
|
||||||
|
Point( 7000000, 10211874),
|
||||||
|
Point(-8700000, 10211874),
|
||||||
|
Point(-9000000, 9824444)
|
||||||
|
};
|
||||||
|
|
||||||
|
Polygons polygons = {poly};
|
||||||
|
coord_t spacing = 437079;
|
||||||
|
coord_t inset_count = 3;
|
||||||
|
|
||||||
|
PrintObjectConfig print_object_config = PrintObjectConfig::defaults();
|
||||||
|
print_object_config.wall_distribution_count.setInt(3);
|
||||||
|
|
||||||
|
Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, print_object_config, PrintConfig::defaults());
|
||||||
|
wallToolPaths.generate();
|
||||||
|
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
||||||
|
|
||||||
|
#ifdef ARACHNE_DEBUG_OUT
|
||||||
|
draw_extrusion(debug_out_path("arachne-missing-perimeter-8472.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
REQUIRE(perimeters.size() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user