Adaptive infill:
Fixing compilation on Linux, WIP: Better chainining of infill lines.
This commit is contained in:
parent
5432784ed4
commit
348c654c26
2 changed files with 72 additions and 26 deletions
|
@ -434,6 +434,64 @@ static void generate_infill_lines_recursive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Collect the line segments.
|
||||||
|
static Polylines chain_lines(const std::vector<Line> &lines, const double point_distance_epsilon)
|
||||||
|
{
|
||||||
|
// Create line end point lookup.
|
||||||
|
struct LineEnd {
|
||||||
|
LineEnd(Line *line, bool start) : line(line), start(start) {}
|
||||||
|
Line *line;
|
||||||
|
// Is it the start or end point?
|
||||||
|
bool start;
|
||||||
|
const Point& point() const { return start ? line->a : line->b; }
|
||||||
|
const Point& other_point() const { return start ? line->b : line->a; }
|
||||||
|
LineEnd other_end() const { return LineEnd(line, ! start); }
|
||||||
|
bool operator==(const LineEnd &rhs) const { return this->line == rhs.line && this->start == rhs.start; }
|
||||||
|
};
|
||||||
|
struct LineEndAccessor {
|
||||||
|
const Point* operator()(const LineEnd &pt) const { return &pt.point(); }
|
||||||
|
};
|
||||||
|
typedef ClosestPointInRadiusLookup<LineEnd, LineEndAccessor> ClosestPointLookupType;
|
||||||
|
ClosestPointLookupType closest_end_point_lookup(point_distance_epsilon);
|
||||||
|
for (const Line &line : lines) {
|
||||||
|
closest_end_point_lookup.insert(LineEnd(&line, true));
|
||||||
|
closest_end_point_lookup.insert(LineEnd(&line, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain the lines.
|
||||||
|
std::vector<char> line_consumed(lines.size(), false);
|
||||||
|
static const double point_distance_epsilon2 = point_distance_epsilon * point_distance_epsilon;
|
||||||
|
Polylines out;
|
||||||
|
for (const Line &seed : lines)
|
||||||
|
if (! line_consumed[&seed - lines.data()]) {
|
||||||
|
line_consumed[&seed - lines.data()] = true;
|
||||||
|
closest_end_point_lookup.erase(LineEnd(&seed, false));
|
||||||
|
closest_end_point_lookup.erase(LineEnd(&seed, true));
|
||||||
|
Polyline pl { seed.a, seed.b };
|
||||||
|
for (size_t round = 0; round < 2; ++ round) {
|
||||||
|
for (;;) {
|
||||||
|
auto [line_end, dist2] = closest_end_point_lookup.find(pl.last_point());
|
||||||
|
if (line_end == nullptr || dist2 >= point_distance_epsilon2)
|
||||||
|
// Cannot extent in this direction.
|
||||||
|
break;
|
||||||
|
// Average the last point.
|
||||||
|
pl.points.back() = 0.5 * (pl.points.back() + line_end->point());
|
||||||
|
// and extend with the new line segment.
|
||||||
|
pl.points.emplace_back(line_end->other_point());
|
||||||
|
closest_end_point_lookup.erase(line_end);
|
||||||
|
closest_end_point_lookup.erase(line_end->other_end());
|
||||||
|
line_consumed[line_end->line - lines.data()] = true;
|
||||||
|
}
|
||||||
|
// reverse and try the oter direction.
|
||||||
|
pl.reverse();
|
||||||
|
}
|
||||||
|
out.emplace_back(std::move(pl));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// #define ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
// #define ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
||||||
#endif
|
#endif
|
||||||
|
@ -517,6 +575,7 @@ void Filler::_fill_surface_single(
|
||||||
lines.emplace_back(line);
|
lines.emplace_back(line);
|
||||||
}
|
}
|
||||||
// Convert lines to polylines.
|
// Convert lines to polylines.
|
||||||
|
//FIXME chain the lines
|
||||||
all_polylines.reserve(lines.size());
|
all_polylines.reserve(lines.size());
|
||||||
std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; });
|
std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; });
|
||||||
}
|
}
|
||||||
|
@ -533,23 +592,8 @@ void Filler::_fill_surface_single(
|
||||||
|
|
||||||
if (params.dont_connect)
|
if (params.dont_connect)
|
||||||
append(polylines_out, std::move(all_polylines));
|
append(polylines_out, std::move(all_polylines));
|
||||||
else {
|
else
|
||||||
Polylines boundary_polylines;
|
connect_infill(chain_polylines(std::move(all_polylines)), expolygon, polylines_out, this->spacing, params);
|
||||||
Polylines non_boundary_polylines;
|
|
||||||
for (const Polyline &polyline : all_polylines)
|
|
||||||
// connect_infill required all polylines to touch the boundary.
|
|
||||||
if (polyline.lines().size() == 1 && expolygon.has_boundary_point(polyline.lines().front().a) && expolygon.has_boundary_point(polyline.lines().front().b))
|
|
||||||
boundary_polylines.push_back(polyline);
|
|
||||||
else
|
|
||||||
non_boundary_polylines.push_back(polyline);
|
|
||||||
|
|
||||||
if (!boundary_polylines.empty()) {
|
|
||||||
boundary_polylines = chain_polylines(boundary_polylines);
|
|
||||||
connect_infill(std::move(boundary_polylines), expolygon, polylines_out, this->spacing, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
append(polylines_out, std::move(non_boundary_polylines));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
|
||||||
{
|
{
|
||||||
|
@ -618,7 +662,7 @@ OctreePtr build_octree(const indexed_triangle_set &triangle_mesh, coordf_t line_
|
||||||
auto octree = OctreePtr(new Octree(cube_center, cubes_properties));
|
auto octree = OctreePtr(new Octree(cube_center, cubes_properties));
|
||||||
|
|
||||||
if (cubes_properties.size() > 1) {
|
if (cubes_properties.size() > 1) {
|
||||||
auto up_vector = support_overhangs_only ? transform_to_octree() * Vec3d(0., 0., 1.) : Vec3d();
|
auto up_vector = support_overhangs_only ? Vec3d(transform_to_octree() * Vec3d(0., 0., 1.)) : Vec3d();
|
||||||
for (auto &tri : triangle_mesh.indices) {
|
for (auto &tri : triangle_mesh.indices) {
|
||||||
auto a = triangle_mesh.vertices[tri[0]].cast<double>();
|
auto a = triangle_mesh.vertices[tri[0]].cast<double>();
|
||||||
auto b = triangle_mesh.vertices[tri[1]].cast<double>();
|
auto b = triangle_mesh.vertices[tri[1]].cast<double>();
|
||||||
|
|
|
@ -847,8 +847,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
|
||||||
boundary.assign(boundary_src.holes.size() + 1, Points());
|
boundary.assign(boundary_src.holes.size() + 1, Points());
|
||||||
boundary_data.assign(boundary_src.holes.size() + 1, std::vector<ContourPointData>());
|
boundary_data.assign(boundary_src.holes.size() + 1, std::vector<ContourPointData>());
|
||||||
// Mapping the infill_ordered end point to a (contour, point) of boundary.
|
// Mapping the infill_ordered end point to a (contour, point) of boundary.
|
||||||
std::vector<std::pair<size_t, size_t>> map_infill_end_point_to_boundary;
|
std::vector<std::pair<size_t, size_t>> map_infill_end_point_to_boundary;
|
||||||
map_infill_end_point_to_boundary.assign(infill_ordered.size() * 2, std::pair<size_t, size_t>(std::numeric_limits<size_t>::max(), std::numeric_limits<size_t>::max()));
|
static constexpr auto boundary_idx_unconnected = std::numeric_limits<size_t>::max();
|
||||||
|
map_infill_end_point_to_boundary.assign(infill_ordered.size() * 2, std::pair<size_t, size_t>(boundary_idx_unconnected, boundary_idx_unconnected));
|
||||||
{
|
{
|
||||||
// Project the infill_ordered end points onto boundary_src.
|
// Project the infill_ordered end points onto boundary_src.
|
||||||
std::vector<std::pair<EdgeGrid::Grid::ClosestPointResult, size_t>> intersection_points;
|
std::vector<std::pair<EdgeGrid::Grid::ClosestPointResult, size_t>> intersection_points;
|
||||||
|
@ -898,13 +899,14 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
|
||||||
contour_data.front().param = contour_data.back().param + (contour_dst.back().cast<float>() - contour_dst.front().cast<float>()).norm();
|
contour_data.front().param = contour_data.back().param + (contour_dst.back().cast<float>() - contour_dst.front().cast<float>()).norm();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
assert(boundary.size() == boundary_src.num_contours());
|
assert(boundary.size() == boundary_src.num_contours());
|
||||||
assert(std::all_of(map_infill_end_point_to_boundary.begin(), map_infill_end_point_to_boundary.end(),
|
#if 0
|
||||||
|
// Adaptive Cubic Infill produces infill lines, which not always end at the outer boundary.
|
||||||
|
assert(std::all_of(map_infill_end_point_to_boundary.begin(), map_infill_end_point_to_boundary.end(),
|
||||||
[&boundary](const std::pair<size_t, size_t> &contour_point) {
|
[&boundary](const std::pair<size_t, size_t> &contour_point) {
|
||||||
return contour_point.first < boundary.size() && contour_point.second < boundary[contour_point.first].size();
|
return contour_point.first < boundary.size() && contour_point.second < boundary[contour_point.first].size();
|
||||||
}));
|
}));
|
||||||
#endif /* NDEBUG */
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the points and segments of split boundary as consumed if they are very close to some of the infill line.
|
// Mark the points and segments of split boundary as consumed if they are very close to some of the infill line.
|
||||||
|
@ -935,9 +937,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
|
||||||
const Polyline &pl2 = infill_ordered[idx_chain];
|
const Polyline &pl2 = infill_ordered[idx_chain];
|
||||||
const std::pair<size_t, size_t> *cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1];
|
const std::pair<size_t, size_t> *cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1];
|
||||||
const std::pair<size_t, size_t> *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
|
const std::pair<size_t, size_t> *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
|
||||||
const std::vector<ContourPointData> &contour_data = boundary_data[cp1->first];
|
if (cp1->first != boundary_idx_unconnected && cp1->first == cp2->first) {
|
||||||
if (cp1->first == cp2->first) {
|
|
||||||
// End points on the same contour. Try to connect them.
|
// End points on the same contour. Try to connect them.
|
||||||
|
const std::vector<ContourPointData> &contour_data = boundary_data[cp1->first];
|
||||||
float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param;
|
float param_lo = (cp1->second == 0) ? 0.f : contour_data[cp1->second].param;
|
||||||
float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param;
|
float param_hi = (cp2->second == 0) ? 0.f : contour_data[cp2->second].param;
|
||||||
float param_end = contour_data.front().param;
|
float param_end = contour_data.front().param;
|
||||||
|
@ -964,7 +966,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_
|
||||||
const std::pair<size_t, size_t> *cp1prev = cp1 - 1;
|
const std::pair<size_t, size_t> *cp1prev = cp1 - 1;
|
||||||
const std::pair<size_t, size_t> *cp2 = &map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2];
|
const std::pair<size_t, size_t> *cp2 = &map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2];
|
||||||
const std::pair<size_t, size_t> *cp2next = cp2 + 1;
|
const std::pair<size_t, size_t> *cp2next = cp2 + 1;
|
||||||
assert(cp1->first == cp2->first);
|
assert(cp1->first == cp2->first && cp1->first != boundary_idx_unconnected);
|
||||||
std::vector<ContourPointData> &contour_data = boundary_data[cp1->first];
|
std::vector<ContourPointData> &contour_data = boundary_data[cp1->first];
|
||||||
if (connection_cost.reversed)
|
if (connection_cost.reversed)
|
||||||
std::swap(cp1, cp2);
|
std::swap(cp1, cp2);
|
||||||
|
|
Loading…
Add table
Reference in a new issue