ENH: generate outer wall contour paths in arachne
1. Add OuterWallContourStrategy class to generate outer wall contour paths. 2. Fix top one wall issue in arachne jira:NONE Signed-off-by: xun.zhang <xun.zhang@bambulab.com> Change-Id: I44574df765cdd0d0d3fc4f6c3f7b846dfb4fa21f
This commit is contained in:
parent
032b34eded
commit
6018d326f4
|
@ -13,6 +13,8 @@ namespace Slic3r::Arachne
|
||||||
|
|
||||||
template<typename T> constexpr T pi_div(const T div) { return static_cast<T>(M_PI) / div; }
|
template<typename T> constexpr T pi_div(const T div) { return static_cast<T>(M_PI) / div; }
|
||||||
|
|
||||||
|
constexpr int WallContourMarkedWidth = 0;
|
||||||
|
constexpr int FirstWallContourMarkedWidth = 1;
|
||||||
/*!
|
/*!
|
||||||
* Mostly virtual base class template.
|
* Mostly virtual base class template.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "DistributedBeadingStrategy.hpp"
|
#include "DistributedBeadingStrategy.hpp"
|
||||||
#include "RedistributeBeadingStrategy.hpp"
|
#include "RedistributeBeadingStrategy.hpp"
|
||||||
#include "OuterWallInsetBeadingStrategy.hpp"
|
#include "OuterWallInsetBeadingStrategy.hpp"
|
||||||
|
#include "OuterWallContourStrategy.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
@ -44,9 +45,16 @@ BeadingStrategyPtr BeadingStrategyFactory::makeStrategy(
|
||||||
ret = std::make_unique<OuterWallInsetBeadingStrategy>(outer_wall_offset, std::move(ret));
|
ret = std::make_unique<OuterWallInsetBeadingStrategy>(outer_wall_offset, std::move(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Apply the OuterWallContourStrategy last, since that adds a 1-width marker wall to mark the boundary of first beading.
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Applying the First Beading Contour Strategy.";
|
||||||
|
ret = std::make_unique<OuterWallContourStrategy>(std::move(ret));
|
||||||
|
|
||||||
//Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch.
|
//Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch.
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Applying the Limited Beading meta-strategy with maximum bead count = " << max_bead_count << ".";
|
BOOST_LOG_TRIVIAL(debug) << "Applying the Limited Beading meta-strategy with maximum bead count = " << max_bead_count << ".";
|
||||||
ret = std::make_unique<LimitedBeadingStrategy>(max_bead_count, std::move(ret));
|
ret = std::make_unique<LimitedBeadingStrategy>(max_bead_count + 2, std::move(ret));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} // namespace Slic3r::Arachne
|
} // namespace Slic3r::Arachne
|
||||||
|
|
|
@ -48,7 +48,7 @@ LimitedBeadingStrategy::Beading LimitedBeadingStrategy::compute(coord_t thicknes
|
||||||
const coord_t innermost_toolpath_location = ret.toolpath_locations[max_bead_count / 2 - 1];
|
const coord_t innermost_toolpath_location = ret.toolpath_locations[max_bead_count / 2 - 1];
|
||||||
const coord_t innermost_toolpath_width = ret.bead_widths[max_bead_count / 2 - 1];
|
const coord_t innermost_toolpath_width = ret.bead_widths[max_bead_count / 2 - 1];
|
||||||
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + max_bead_count / 2, innermost_toolpath_location + innermost_toolpath_width / 2);
|
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + max_bead_count / 2, innermost_toolpath_location + innermost_toolpath_width / 2);
|
||||||
ret.bead_widths.insert(ret.bead_widths.begin() + max_bead_count / 2, 0);
|
ret.bead_widths.insert(ret.bead_widths.begin() + max_bead_count / 2, WallContourMarkedWidth);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -77,14 +77,14 @@ LimitedBeadingStrategy::Beading LimitedBeadingStrategy::compute(coord_t thicknes
|
||||||
coord_t innermost_toolpath_location = ret.toolpath_locations[max_bead_count / 2 - 1];
|
coord_t innermost_toolpath_location = ret.toolpath_locations[max_bead_count / 2 - 1];
|
||||||
coord_t innermost_toolpath_width = ret.bead_widths[max_bead_count / 2 - 1];
|
coord_t innermost_toolpath_width = ret.bead_widths[max_bead_count / 2 - 1];
|
||||||
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + max_bead_count / 2, innermost_toolpath_location + innermost_toolpath_width / 2);
|
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + max_bead_count / 2, innermost_toolpath_location + innermost_toolpath_width / 2);
|
||||||
ret.bead_widths.insert(ret.bead_widths.begin() + max_bead_count / 2, 0);
|
ret.bead_widths.insert(ret.bead_widths.begin() + max_bead_count / 2, WallContourMarkedWidth);
|
||||||
|
|
||||||
//Symmetry on both sides. Symmetry is guaranteed since this code is stopped early if the bead_count <= max_bead_count, and never reaches this point then.
|
//Symmetry on both sides. Symmetry is guaranteed since this code is stopped early if the bead_count <= max_bead_count, and never reaches this point then.
|
||||||
const size_t opposite_bead = bead_count - (max_bead_count / 2 - 1);
|
const size_t opposite_bead = bead_count - (max_bead_count / 2 - 1);
|
||||||
innermost_toolpath_location = ret.toolpath_locations[opposite_bead];
|
innermost_toolpath_location = ret.toolpath_locations[opposite_bead];
|
||||||
innermost_toolpath_width = ret.bead_widths[opposite_bead];
|
innermost_toolpath_width = ret.bead_widths[opposite_bead];
|
||||||
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + opposite_bead, innermost_toolpath_location - innermost_toolpath_width / 2);
|
ret.toolpath_locations.insert(ret.toolpath_locations.begin() + opposite_bead, innermost_toolpath_location - innermost_toolpath_width / 2);
|
||||||
ret.bead_widths.insert(ret.bead_widths.begin() + opposite_bead, 0);
|
ret.bead_widths.insert(ret.bead_widths.begin() + opposite_bead, WallContourMarkedWidth);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
#include "OuterWallContourStrategy.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::Arachne
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
OuterWallContourStrategy::OuterWallContourStrategy(BeadingStrategyPtr parent)
|
||||||
|
: BeadingStrategy(*parent)
|
||||||
|
, parent(std::move(parent))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OuterWallContourStrategy::toString() const
|
||||||
|
{
|
||||||
|
return std::string("OuterWallContourStrategy+") + parent->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
coord_t OuterWallContourStrategy::getTransitioningLength(coord_t lower_bead_count) const
|
||||||
|
{
|
||||||
|
return parent->getTransitioningLength(lower_bead_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
float OuterWallContourStrategy::getTransitionAnchorPos(coord_t lower_bead_count) const
|
||||||
|
{
|
||||||
|
return parent->getTransitionAnchorPos(lower_bead_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<coord_t> OuterWallContourStrategy::getNonlinearThicknesses(coord_t lower_bead_count) const
|
||||||
|
{
|
||||||
|
return parent->getNonlinearThicknesses(lower_bead_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
coord_t OuterWallContourStrategy::getTransitionThickness(coord_t lower_bead_count) const
|
||||||
|
{
|
||||||
|
if(lower_bead_count <= 1)
|
||||||
|
return parent->getTransitionThickness(lower_bead_count);
|
||||||
|
else if(lower_bead_count == 2 || lower_bead_count ==3)
|
||||||
|
return parent->getTransitionThickness(1);
|
||||||
|
return parent->getTransitionThickness(lower_bead_count-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
coord_t OuterWallContourStrategy::getOptimalBeadCount(coord_t thickness) const
|
||||||
|
{
|
||||||
|
coord_t parent_bead_count = parent->getOptimalBeadCount(thickness);
|
||||||
|
if(parent_bead_count <= 1)
|
||||||
|
return parent_bead_count;
|
||||||
|
return parent_bead_count + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
coord_t OuterWallContourStrategy::getOptimalThickness(coord_t bead_count) const
|
||||||
|
{
|
||||||
|
if (bead_count <= 1)
|
||||||
|
return parent->getOptimalThickness(bead_count);
|
||||||
|
return parent->getOptimalThickness(bead_count - 2) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeadingStrategy::Beading OuterWallContourStrategy::compute(coord_t thickness, coord_t bead_count) const
|
||||||
|
{
|
||||||
|
if (bead_count <= 1)
|
||||||
|
return parent->compute(thickness, bead_count);
|
||||||
|
|
||||||
|
assert(bead_count >= 3);
|
||||||
|
Beading ret = parent->compute(thickness, bead_count - 2);
|
||||||
|
if(ret.toolpath_locations.size() == 1){
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if(ret.toolpath_locations.size() > 0 ){
|
||||||
|
assert(ret.bead_widths.size()>0);
|
||||||
|
double location = ret.toolpath_locations.front() + ret.bead_widths.front() / 2;
|
||||||
|
double location_reverse = ret.toolpath_locations.back() - ret.bead_widths.back() / 2;
|
||||||
|
ret.toolpath_locations.insert(ret.toolpath_locations.begin()+1, location);
|
||||||
|
ret.bead_widths.insert(ret.bead_widths.begin()+1, FirstWallContourMarkedWidth);
|
||||||
|
ret.toolpath_locations.insert((ret.toolpath_locations.rbegin()+1).base(), location_reverse);
|
||||||
|
ret.bead_widths.insert((ret.bead_widths.rbegin()).base(), FirstWallContourMarkedWidth);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} // namespace Slic3r::Arachne
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef OUTER_WALL_CONTOUR_STRATEGY_H
|
||||||
|
#define OUTER_WALL_CONTOUR_STRATEGY_H
|
||||||
|
|
||||||
|
#include "BeadingStrategy.hpp"
|
||||||
|
namespace Slic3r::Arachne
|
||||||
|
{
|
||||||
|
|
||||||
|
class OuterWallContourStrategy : public BeadingStrategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OuterWallContourStrategy(BeadingStrategyPtr parent);
|
||||||
|
~OuterWallContourStrategy() override = default;
|
||||||
|
|
||||||
|
Beading compute(coord_t thickness, coord_t bead_count) const override;
|
||||||
|
coord_t getOptimalThickness(coord_t bead_count) const override;
|
||||||
|
coord_t getTransitionThickness(coord_t lower_bead_count) const override;
|
||||||
|
coord_t getOptimalBeadCount(coord_t thickness) const override;
|
||||||
|
std::string toString() const override;
|
||||||
|
|
||||||
|
coord_t getTransitioningLength(coord_t lower_bead_count) const override;
|
||||||
|
float getTransitionAnchorPos(coord_t lower_bead_count) const override;
|
||||||
|
std::vector<coord_t> getNonlinearThicknesses(coord_t lower_bead_count) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const BeadingStrategyPtr parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -700,27 +700,37 @@ const std::vector<VariableWidthLines> &WallToolPaths::getToolPaths()
|
||||||
|
|
||||||
void WallToolPaths::separateOutInnerContour()
|
void WallToolPaths::separateOutInnerContour()
|
||||||
{
|
{
|
||||||
|
enum PathType{
|
||||||
|
ActualPath,
|
||||||
|
WallContour,
|
||||||
|
FirstWallContour
|
||||||
|
};
|
||||||
|
|
||||||
//We'll remove all 0-width paths from the original toolpaths and store them separately as polygons.
|
//We'll remove all 0-width paths from the original toolpaths and store them separately as polygons.
|
||||||
std::vector<VariableWidthLines> actual_toolpaths;
|
std::vector<VariableWidthLines> actual_toolpaths;
|
||||||
actual_toolpaths.reserve(toolpaths.size()); //A bit too much, but the correct order of magnitude.
|
actual_toolpaths.reserve(toolpaths.size()); //A bit too much, but the correct order of magnitude.
|
||||||
std::vector<VariableWidthLines> contour_paths;
|
std::vector<VariableWidthLines> wall_contour_paths;
|
||||||
contour_paths.reserve(toolpaths.size() / inset_count);
|
wall_contour_paths.reserve(toolpaths.size() / inset_count);
|
||||||
|
std::vector<VariableWidthLines> first_wall_contour_paths;
|
||||||
inner_contour.clear();
|
inner_contour.clear();
|
||||||
|
first_wall_contour.clear();
|
||||||
for (const VariableWidthLines &inset : toolpaths) {
|
for (const VariableWidthLines &inset : toolpaths) {
|
||||||
if (inset.empty())
|
if (inset.empty())
|
||||||
continue;
|
continue;
|
||||||
bool is_contour = false;
|
PathType type;
|
||||||
for (const ExtrusionLine &line : inset) {
|
for (const ExtrusionLine &line : inset) {
|
||||||
for (const ExtrusionJunction &j : line) {
|
for (const ExtrusionJunction &j : line) {
|
||||||
if (j.w == 0)
|
if (j.w == Arachne::WallContourMarkedWidth)
|
||||||
is_contour = true;
|
type = WallContour;
|
||||||
|
else if(j.w == Arachne::FirstWallContourMarkedWidth)
|
||||||
|
type = FirstWallContour;
|
||||||
else
|
else
|
||||||
is_contour = false;
|
type = ActualPath;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_contour) {
|
if (type==WallContour) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (const ExtrusionLine &line : inset)
|
for (const ExtrusionLine &line : inset)
|
||||||
for (const ExtrusionJunction &j : line)
|
for (const ExtrusionJunction &j : line)
|
||||||
|
@ -732,7 +742,16 @@ void WallToolPaths::separateOutInnerContour()
|
||||||
else if (line.is_closed) // sometimes an very small even polygonal wall is not stitched into a polygon
|
else if (line.is_closed) // sometimes an very small even polygonal wall is not stitched into a polygon
|
||||||
inner_contour.emplace_back(line.toPolygon());
|
inner_contour.emplace_back(line.toPolygon());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else if (type == FirstWallContour){
|
||||||
|
for (const ExtrusionLine &line : inset) {
|
||||||
|
if (line.is_odd)
|
||||||
|
continue;
|
||||||
|
else if (line.is_closed)
|
||||||
|
first_wall_contour.emplace_back(line.toPolygon());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
actual_toolpaths.emplace_back(inset);
|
actual_toolpaths.emplace_back(inset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,6 +766,15 @@ void WallToolPaths::separateOutInnerContour()
|
||||||
//This can be done by applying the even-odd rule to the shape. This rule is not sensitive to the winding order of the polygon.
|
//This can be done by applying the even-odd rule to the shape. This rule is not sensitive to the winding order of the polygon.
|
||||||
//The even-odd rule would be incorrect if the polygon self-intersects, but that should never be generated by the skeletal trapezoidation.
|
//The even-odd rule would be incorrect if the polygon self-intersects, but that should never be generated by the skeletal trapezoidation.
|
||||||
inner_contour = union_(inner_contour, ClipperLib::PolyFillType::pftEvenOdd);
|
inner_contour = union_(inner_contour, ClipperLib::PolyFillType::pftEvenOdd);
|
||||||
|
first_wall_contour = union_(first_wall_contour, ClipperLib::PolyFillType::pftEvenOdd);
|
||||||
|
|
||||||
|
// restore the idx of non first wall paths
|
||||||
|
for (auto& paths : toolpaths) {
|
||||||
|
for (auto& path : paths) {
|
||||||
|
if (path.inset_idx > 1)
|
||||||
|
path.inset_idx -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Polygons& WallToolPaths::getInnerContour()
|
const Polygons& WallToolPaths::getInnerContour()
|
||||||
|
@ -762,6 +790,20 @@ const Polygons& WallToolPaths::getInnerContour()
|
||||||
return inner_contour;
|
return inner_contour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Polygons& WallToolPaths::getFirstWallContour()
|
||||||
|
{
|
||||||
|
if (!toolpaths_generated && inset_count > 0)
|
||||||
|
{
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
else if(inset_count == 0)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return first_wall_contour;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WallToolPaths::removeEmptyToolPaths(std::vector<VariableWidthLines> &toolpaths)
|
bool WallToolPaths::removeEmptyToolPaths(std::vector<VariableWidthLines> &toolpaths)
|
||||||
{
|
{
|
||||||
toolpaths.erase(std::remove_if(toolpaths.begin(), toolpaths.end(), [](const VariableWidthLines& lines)
|
toolpaths.erase(std::remove_if(toolpaths.begin(), toolpaths.end(), [](const VariableWidthLines& lines)
|
||||||
|
|
|
@ -78,6 +78,8 @@ public:
|
||||||
*/
|
*/
|
||||||
const Polygons& getInnerContour();
|
const Polygons& getInnerContour();
|
||||||
|
|
||||||
|
const Polygons& getFirstWallContour();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Removes empty paths from the toolpaths
|
* Removes empty paths from the toolpaths
|
||||||
* \param toolpaths the VariableWidthPaths generated with \p generate()
|
* \param toolpaths the VariableWidthPaths generated with \p generate()
|
||||||
|
@ -131,6 +133,7 @@ private:
|
||||||
bool toolpaths_generated; //<! Are the toolpaths generated
|
bool toolpaths_generated; //<! Are the toolpaths generated
|
||||||
std::vector<VariableWidthLines> toolpaths; //<! The generated toolpaths
|
std::vector<VariableWidthLines> toolpaths; //<! The generated toolpaths
|
||||||
Polygons inner_contour; //<! The inner contour of the generated toolpaths
|
Polygons inner_contour; //<! The inner contour of the generated toolpaths
|
||||||
|
Polygons first_wall_contour; //<! The contour of the first wall
|
||||||
const WallToolPathsParams m_params;
|
const WallToolPathsParams m_params;
|
||||||
private:
|
private:
|
||||||
bool enable_hole_compensation{ false };
|
bool enable_hole_compensation{ false };
|
||||||
|
|
|
@ -401,6 +401,8 @@ set(lisbslic3r_sources
|
||||||
Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp
|
Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp
|
||||||
Arachne/BeadingStrategy/WideningBeadingStrategy.hpp
|
Arachne/BeadingStrategy/WideningBeadingStrategy.hpp
|
||||||
Arachne/BeadingStrategy/WideningBeadingStrategy.cpp
|
Arachne/BeadingStrategy/WideningBeadingStrategy.cpp
|
||||||
|
Arachne/BeadingStrategy/OuterWallContourStrategy.hpp
|
||||||
|
Arachne/BeadingStrategy/OuterWallContourStrategy.cpp
|
||||||
Arachne/utils/ExtrusionJunction.hpp
|
Arachne/utils/ExtrusionJunction.hpp
|
||||||
Arachne/utils/ExtrusionJunction.cpp
|
Arachne/utils/ExtrusionJunction.cpp
|
||||||
Arachne/utils/ExtrusionLine.hpp
|
Arachne/utils/ExtrusionLine.hpp
|
||||||
|
|
|
@ -1797,14 +1797,11 @@ void PerimeterGenerator::process_arachne()
|
||||||
// we need to process each island separately because we might have different
|
// we need to process each island separately because we might have different
|
||||||
// extra perimeters for each one
|
// extra perimeters for each one
|
||||||
|
|
||||||
|
|
||||||
for (const Surface& surface : this->slices->surfaces) {
|
for (const Surface& surface : this->slices->surfaces) {
|
||||||
bool generate_one_wall = false;
|
|
||||||
bool generate_one_wall_by_first_layer = this->object_config->only_one_wall_first_layer && layer_id == 0;
|
bool generate_one_wall_by_first_layer = this->object_config->only_one_wall_first_layer && layer_id == 0;
|
||||||
bool generate_one_wall_by_top_one_wall = this->object_config->top_one_wall_type == TopOneWallType::Topmost && this->upper_slices == nullptr ||
|
bool generate_one_wall_by_top_one_wall = this->object_config->top_one_wall_type == TopOneWallType::Topmost && this->upper_slices == nullptr ||
|
||||||
this->object_config->top_one_wall_type == TopOneWallType::Alltop;
|
this->object_config->top_one_wall_type == TopOneWallType::Alltop;
|
||||||
|
bool generate_one_wall = generate_one_wall_by_first_layer || generate_one_wall_by_top_one_wall;
|
||||||
generate_one_wall = generate_one_wall_by_first_layer || generate_one_wall_by_top_one_wall;
|
|
||||||
// detect how many perimeters must be generated for this island
|
// detect how many perimeters must be generated for this island
|
||||||
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
||||||
|
|
||||||
|
@ -1815,35 +1812,6 @@ void PerimeterGenerator::process_arachne()
|
||||||
if (last.size() != 1 || new_size != surface.expolygon.num_contours())
|
if (last.size() != 1 || new_size != surface.expolygon.num_contours())
|
||||||
apply_circle_compensation = false;
|
apply_circle_compensation = false;
|
||||||
|
|
||||||
std::vector<int> circle_poly_indices;
|
|
||||||
Polygons last_p;
|
|
||||||
if (apply_circle_compensation)
|
|
||||||
last_p = to_polygons_with_flag(last.front(), surface.counter_circle_compensation, surface.holes_circle_compensation, circle_poly_indices);
|
|
||||||
else
|
|
||||||
last_p = to_polygons(last);
|
|
||||||
|
|
||||||
// check whether to activate one wall mode
|
|
||||||
if (generate_one_wall && !generate_one_wall_by_first_layer)
|
|
||||||
{
|
|
||||||
ExPolygons top_expolys;
|
|
||||||
ExPolygons infill_contour_by_one_wall = offset_ex(last, -(ext_perimeter_width + perimeter_spacing) / 2.f);
|
|
||||||
|
|
||||||
BoundingBox infill_bbox = get_extents(infill_contour_by_one_wall);
|
|
||||||
infill_bbox.offset(EPSILON);
|
|
||||||
|
|
||||||
Polygons upper_polygons_clipped;
|
|
||||||
if (this->upper_slices)
|
|
||||||
upper_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->upper_slices, infill_bbox);
|
|
||||||
top_expolys = diff_ex(infill_contour_by_one_wall, upper_polygons_clipped);
|
|
||||||
|
|
||||||
Polygons lower_polygons_clipped;
|
|
||||||
if (this->lower_slices)
|
|
||||||
lower_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, infill_bbox);
|
|
||||||
ExPolygons bottom_expolys = offset_ex(diff_ex(top_expolys, lower_polygons_clipped), std::max(ext_perimeter_spacing, perimeter_width));
|
|
||||||
|
|
||||||
top_expolys = diff_ex(top_expolys, bottom_expolys);
|
|
||||||
generate_one_wall = should_enable_top_one_wall(last, top_expolys);
|
|
||||||
}
|
|
||||||
|
|
||||||
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
|
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
|
||||||
Arachne::WallToolPathsParams input_params;
|
Arachne::WallToolPathsParams input_params;
|
||||||
|
@ -1864,15 +1832,77 @@ void PerimeterGenerator::process_arachne()
|
||||||
input_params.wall_distribution_count = this->object_config->wall_distribution_count.value;
|
input_params.wall_distribution_count = this->object_config->wall_distribution_count.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
coord_t real_loop_number = generate_one_wall ? 1 : loop_number + 1;
|
std::vector<int> circle_poly_indices;
|
||||||
|
Polygons last_p;
|
||||||
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, real_loop_number, 0, layer_height, input_params);
|
if (apply_circle_compensation)
|
||||||
|
last_p = to_polygons_with_flag(last.front(), surface.counter_circle_compensation, surface.holes_circle_compensation, circle_poly_indices);
|
||||||
|
else
|
||||||
|
last_p = to_polygons(last);
|
||||||
|
|
||||||
|
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, loop_number + 1, 0, layer_height, input_params);
|
||||||
if (apply_circle_compensation)
|
if (apply_circle_compensation)
|
||||||
wallToolPaths.EnableHoleCompensation(true, circle_poly_indices);
|
wallToolPaths.EnableHoleCompensation(true, circle_poly_indices);
|
||||||
|
|
||||||
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
ExPolygons top_expolys_by_one_wall;
|
||||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
ExPolygons infill_contour_by_one_wall = union_ex(wallToolPaths.getFirstWallContour());
|
||||||
|
|
||||||
|
// do detail check whether to enable one wall
|
||||||
|
if (generate_one_wall && !generate_one_wall_by_first_layer)
|
||||||
|
{
|
||||||
|
BoundingBox infill_bbox = get_extents(infill_contour_by_one_wall);
|
||||||
|
infill_bbox.offset(EPSILON);
|
||||||
|
|
||||||
|
Polygons upper_polygons_clipped;
|
||||||
|
if (this->upper_slices)
|
||||||
|
upper_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->upper_slices, infill_bbox);
|
||||||
|
top_expolys_by_one_wall = diff_ex(infill_contour_by_one_wall, upper_polygons_clipped);
|
||||||
|
|
||||||
|
Polygons lower_polygons_clipped;
|
||||||
|
if (this->lower_slices)
|
||||||
|
lower_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, infill_bbox);
|
||||||
|
ExPolygons bottom_expolys = diff_ex(top_expolys_by_one_wall, lower_polygons_clipped);
|
||||||
|
|
||||||
|
top_expolys_by_one_wall = diff_ex(top_expolys_by_one_wall, bottom_expolys);
|
||||||
|
generate_one_wall = should_enable_top_one_wall(last, top_expolys_by_one_wall);
|
||||||
|
if (generate_one_wall)
|
||||||
|
top_expolys_by_one_wall = offset_ex(top_expolys_by_one_wall, perimeter_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Arachne::VariableWidthLines> total_perimeters;
|
||||||
|
ExPolygons infill_contour;
|
||||||
|
if (!generate_one_wall) {
|
||||||
|
total_perimeters = wallToolPaths.getToolPaths();
|
||||||
|
infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||||
|
}
|
||||||
|
else if(loop_number >0) {
|
||||||
|
last = diff_ex(infill_contour_by_one_wall, top_expolys_by_one_wall);
|
||||||
|
last_p = to_polygons(last);
|
||||||
|
Arachne::WallToolPaths paths_new(last_p, perimeter_spacing, perimeter_spacing, loop_number, 0, layer_height, input_params);
|
||||||
|
|
||||||
|
auto old_perimeters = wallToolPaths.getToolPaths();
|
||||||
|
auto new_perimeters = paths_new.getToolPaths();
|
||||||
|
for (auto& perimeters : old_perimeters) {
|
||||||
|
if (std::find_if(perimeters.begin(), perimeters.end(), [](auto& item) {return item.inset_idx == 0; }) != perimeters.end()) {
|
||||||
|
total_perimeters.emplace_back();
|
||||||
|
for (auto& p : perimeters) {
|
||||||
|
if (p.inset_idx == 0)
|
||||||
|
total_perimeters.back().emplace_back(std::move(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& perimeters : new_perimeters) {
|
||||||
|
if (!perimeters.empty()) {
|
||||||
|
for (auto& p : perimeters){
|
||||||
|
p.inset_idx += 1;
|
||||||
|
}
|
||||||
|
total_perimeters.emplace_back(std::move(perimeters));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infill_contour = union_ex(union_ex(paths_new.getInnerContour()), top_expolys_by_one_wall);
|
||||||
|
infill_contour = intersection_ex(infill_contour, infill_contour_by_one_wall);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ARACHNE_DEBUG
|
#ifdef ARACHNE_DEBUG
|
||||||
{
|
{
|
||||||
static int iRun = 0;
|
static int iRun = 0;
|
||||||
|
@ -1883,15 +1913,15 @@ void PerimeterGenerator::process_arachne()
|
||||||
// All closed ExtrusionLine should have the same the first and the last point.
|
// All closed ExtrusionLine should have the same the first and the last point.
|
||||||
// But in rare cases, Arachne produce ExtrusionLine marked as closed but without
|
// But in rare cases, Arachne produce ExtrusionLine marked as closed but without
|
||||||
// equal the first and the last point.
|
// equal the first and the last point.
|
||||||
assert([&perimeters = std::as_const(perimeters)]() -> bool {
|
assert([&total_perimeters = std::as_const(total_perimeters)]() -> bool {
|
||||||
for (const Arachne::VariableWidthLines& perimeter : perimeters)
|
for (const Arachne::VariableWidthLines& perimeter : total_perimeters)
|
||||||
for (const Arachne::ExtrusionLine& el : perimeter)
|
for (const Arachne::ExtrusionLine& el : perimeter)
|
||||||
if (el.is_closed && el.junctions.front().p != el.junctions.back().p)
|
if (el.is_closed && el.junctions.front().p != el.junctions.back().p)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
|
|
||||||
int start_perimeter = int(perimeters.size()) - 1;
|
int start_perimeter = int(total_perimeters.size()) - 1;
|
||||||
int end_perimeter = -1;
|
int end_perimeter = -1;
|
||||||
int direction = -1;
|
int direction = -1;
|
||||||
|
|
||||||
|
@ -1899,15 +1929,15 @@ void PerimeterGenerator::process_arachne()
|
||||||
this->object_config->wall_sequence == WallSequence::OuterInner || this->object_config->wall_sequence == WallSequence::InnerOuterInner;
|
this->object_config->wall_sequence == WallSequence::OuterInner || this->object_config->wall_sequence == WallSequence::InnerOuterInner;
|
||||||
if (is_outer_wall_first) {
|
if (is_outer_wall_first) {
|
||||||
start_perimeter = 0;
|
start_perimeter = 0;
|
||||||
end_perimeter = int(perimeters.size());
|
end_perimeter = int(total_perimeters.size());
|
||||||
direction = 1;
|
direction = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Arachne::ExtrusionLine*> all_extrusions;
|
std::vector<Arachne::ExtrusionLine*> all_extrusions;
|
||||||
for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) {
|
for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) {
|
||||||
if (perimeters[perimeter_idx].empty())
|
if (total_perimeters[perimeter_idx].empty())
|
||||||
continue;
|
continue;
|
||||||
for (Arachne::ExtrusionLine& wall : perimeters[perimeter_idx])
|
for (Arachne::ExtrusionLine& wall : total_perimeters[perimeter_idx])
|
||||||
all_extrusions.emplace_back(&wall);
|
all_extrusions.emplace_back(&wall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2069,7 +2099,7 @@ void PerimeterGenerator::process_arachne()
|
||||||
if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty())
|
if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty())
|
||||||
this->loops->append(extrusion_coll);
|
this->loops->append(extrusion_coll);
|
||||||
|
|
||||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
const coord_t spacing = (total_perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||||
|
|
||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
|
|
Loading…
Reference in New Issue