Skip to content

Commit

Permalink
Implement basically working version of smaller PT
Browse files Browse the repository at this point in the history
  • Loading branch information
wawanbreton committed May 29, 2024
1 parent 4a753f2 commit 7b81059
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 19 deletions.
21 changes: 18 additions & 3 deletions include/PrimeTower/PrimeTower.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class PrimeTower
*/
std::map<size_t, std::map<size_t, Shape>> sparse_pattern_per_extruders_;

/*
* The first index is the layer number
* The second index is the extruder number
* The shape represents what should be printed for the given extruder at the given layer
*/
std::map<LayerIndex, std::map<size_t, Shape>> moves_;

MovesByLayer base_extra_moves_; //!< For each layer and each extruder, the extra moves to be processed for better adhesion/strength
MovesByExtruder inset_extra_moves_; //!< For each extruder, the extra inset moves to be processed for better adhesion on initial layer

Expand Down Expand Up @@ -112,9 +119,7 @@ class PrimeTower
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const = 0;

virtual void polishExtrudersUse(LayerVector<std::vector<ExtruderUse>>& /*extruders_use*/, const SliceDataStorage& /*storage*/) const
{
}
void processExtrudersUse(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder);

static PrimeTower* createPrimeTower(SliceDataStorage& storage);

Expand Down Expand Up @@ -158,6 +163,16 @@ class PrimeTower

virtual void processExtruderNoPrime(const size_t extruder_nr, LayerPlan& gcode_layer) const = 0;

virtual void polishExtrudersUses(LayerVector<std::vector<ExtruderUse>>& /*extruders_use*/, const SliceDataStorage& /*storage*/, const size_t /*start_extruder*/)
{
}

virtual std::map<LayerIndex, std::map<size_t, Shape>> generateExtrusionsMoves(const LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage) = 0;

std::tuple<Shape, coord_t> generatePrimeMoves(const size_t extruder_nr, const coord_t outer_radius);

Shape generateSupportMoves(const size_t extruder_nr, const coord_t outer_radius, const coord_t inner_radius);

static bool extruderRequiresPrime(const std::vector<bool>& extruder_is_used_on_this_layer, size_t extruder_nr, size_t last_extruder);

private:
Expand Down
7 changes: 5 additions & 2 deletions include/PrimeTower/PrimeTowerInterleaved.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ class PrimeTowerInterleaved : public PrimeTower
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const override;

virtual void polishExtrudersUse(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage) const override;

protected:
virtual bool requiresBaseExtraPrint(size_t extruder_nr) const override;

Expand All @@ -36,6 +34,11 @@ class PrimeTowerInterleaved : public PrimeTower
const std::vector<size_t>& initial_list_idx = {}) const override;

virtual void processExtruderNoPrime(const size_t extruder_nr, LayerPlan& gcode_layer) const override;

virtual void polishExtrudersUses(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder) override;

virtual std::map<LayerIndex, std::map<size_t, Shape>>
generateExtrusionsMoves(const LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage) override;
};

} // namespace cura
Expand Down
3 changes: 3 additions & 0 deletions include/PrimeTower/PrimeTowerNormal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class PrimeTowerNormal : public PrimeTower
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const override;

virtual std::map<LayerIndex, std::map<size_t, Shape>>
generateExtrusionsMoves(const LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage) override;

protected:
virtual bool requiresBaseExtraPrint(size_t extruder_nr) const override;

Expand Down
8 changes: 5 additions & 3 deletions src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1509,14 +1509,16 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor
size_t last_extruder;
// set the initial extruder of this meshgroup
Scene& scene = Application::getInstance().current_slice_->scene;
size_t start_extruder;
if (scene.current_mesh_group == scene.mesh_groups.begin())
{ // first meshgroup
last_extruder = getStartExtruder(storage);
start_extruder = getStartExtruder(storage);
}
else
{
last_extruder = gcode.getExtruderNr();
start_extruder = gcode.getExtruderNr();
}
last_extruder = start_extruder;

extruder_order_per_layer.init(true, storage.print_layer_count);

Expand All @@ -1534,7 +1536,7 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor

if (storage.prime_tower_)
{
storage.prime_tower_->polishExtrudersUse(extruder_order_per_layer, storage);
storage.prime_tower_->processExtrudersUse(extruder_order_per_layer, storage, start_extruder);
}
}

Expand Down
96 changes: 91 additions & 5 deletions src/PrimeTower/PrimeTower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ void PrimeTower::generatePaths()
{
generateGroundpoly();

generateStartLocations();

std::vector<coord_t> cumulative_insets;
generateDenseInfill(cumulative_insets);

generateStartLocations();

generateSparseInfill(cumulative_insets);
}

Expand Down Expand Up @@ -214,6 +214,69 @@ Shape PrimeTower::generatePath_sparseInfill(
return pattern;
}

std::tuple<Shape, coord_t> PrimeTower::generatePrimeMoves(const size_t extruder_nr, const coord_t outer_radius)
{
const Scene& scene = Application::getInstance().current_slice_->scene;
const Settings& mesh_group_settings = scene.current_mesh_group->settings;
const coord_t layer_height = mesh_group_settings.get<coord_t>("layer_height");
const coord_t tower_radius = mesh_group_settings.get<coord_t>("prime_tower_size") / 2;
const coord_t line_width = scene.extruders[extruder_nr].settings_.get<coord_t>("prime_tower_line_width");
const double required_volume = scene.extruders[extruder_nr].settings_.get<double>("prime_tower_min_volume") * 1000000000;
const Ratio flow = scene.extruders[extruder_nr].settings_.get<Ratio>("prime_tower_flow");

double current_volume = 0;
coord_t current_outer_diameter = outer_radius;
Shape moves;
do
{
Shape shape = outer_poly_.offset(-(tower_radius - current_outer_diameter + line_width / 2));

if (! shape.empty())
{
moves.push_back(shape);
current_volume += static_cast<double>(shape.length() * line_width * layer_height) * flow;
current_outer_diameter -= line_width;
}
else
{
// Don't continue. We won't ever reach the required volume because it doesn't fit.
break;
}
} while (current_volume < required_volume);

return std::make_tuple(moves, current_outer_diameter);
}

Shape PrimeTower::generateSupportMoves(const size_t extruder_nr, const coord_t outer_radius, const coord_t inner_radius)
{
const Scene& scene = Application::getInstance().current_slice_->scene;
const double max_bridging_distance = static_cast<double>(scene.extruders[extruder_nr].settings_.get<coord_t>("prime_tower_max_bridging_distance"));
const coord_t line_width = scene.extruders[extruder_nr].settings_.get<coord_t>("prime_tower_line_width");
const coord_t radius_delta = outer_radius - inner_radius;
const coord_t semi_line_width = line_width / 2;

Shape moves;

// Split ring according to max bridging distance
const coord_t nb_rings = static_cast<coord_t>(std::ceil(static_cast<double>(radius_delta) / max_bridging_distance));
if (nb_rings > 0)
{
const coord_t actual_radius_step = radius_delta / nb_rings;

for (coord_t i = 0; i < nb_rings; ++i)
{
const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width;
const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width;

const size_t semi_nb_spokes = static_cast<size_t>(std::ceil((std::numbers::pi * static_cast<double>(ring_outer_radius)) / max_bridging_distance));

moves.push_back(PolygonUtils::makeWheel(middle_, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION));
}
}

return moves;
}

void PrimeTower::generateStartLocations()
{
// Evenly spread out a number of dots along the prime tower's outline. This is done for the complete outline,
Expand Down Expand Up @@ -276,7 +339,7 @@ void PrimeTower::addToGcode(
return;
}

std::vector<size_t> extra_primed_extruders_idx;
/*std::vector<size_t> extra_primed_extruders_idx;
switch (extruder_iterator->prime)
{
Expand Down Expand Up @@ -306,6 +369,23 @@ void PrimeTower::addToGcode(
}
}
break;
}*/

const Shape* moves = nullptr;
auto iterator_layer = moves_.find(layer_nr);
if (iterator_layer != moves_.end())
{
auto iterator_extruder = iterator_layer->second.find(new_extruder_nr);
if (iterator_extruder != iterator_layer->second.end())
{
moves = &iterator_extruder->second;
}
}

if (moves && ! moves->empty())
{
const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[new_extruder_nr];
gcode_layer.addPolygonsByOptimizer(*moves, config);
}

if (! gcode_layer.getPrimeTowerBaseIsPlanned() && addToGcode_base(gcode_layer, new_extruder_nr))
Expand All @@ -318,10 +398,10 @@ void PrimeTower::addToGcode(
gcode_layer.setPrimeTowerInsetIsPlanned();
}

for (const size_t& primed_extruder_idx : extra_primed_extruders_idx)
/*for (const size_t& primed_extruder_idx : extra_primed_extruders_idx)
{
gcode_layer.setPrimeTowerIsPlanned(extruder_order_.at(primed_extruder_idx));
}
}*/

// post-wipe:
if (post_wipe)
Expand Down Expand Up @@ -479,6 +559,12 @@ const Shape& PrimeTower::getGroundPoly() const
return getOuterPoly(-Raft::getTotalExtraLayers());
}

void PrimeTower::processExtrudersUse(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder)
{
polishExtrudersUses(extruders_use, storage, start_extruder);
moves_ = generateExtrusionsMoves(extruders_use, storage);
}

PrimeTower* PrimeTower::createPrimeTower(SliceDataStorage& storage)
{
PrimeTower* prime_tower = nullptr;
Expand Down
70 changes: 65 additions & 5 deletions src/PrimeTower/PrimeTowerInterleaved.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,47 @@ ExtruderPrime PrimeTowerInterleaved::getExtruderPrime(
}
}

void PrimeTowerInterleaved::polishExtrudersUse(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage) const
std::map<LayerIndex, std::map<size_t, Shape>>
PrimeTowerInterleaved::generateExtrusionsMoves(const LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage)
{
for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < storage.print_layer_count; ++layer_nr)
const Scene& scene = Application::getInstance().current_slice_->scene;
const Settings& mesh_group_settings = scene.current_mesh_group->settings;
const coord_t tower_radius = mesh_group_settings.get<coord_t>("prime_tower_size") / 2;
coord_t support_radius = tower_radius;
std::map<LayerIndex, std::map<size_t, Shape>> moves;

// Now loop again, but from top bo bottom, so that the required support increases with what is actually required
for (LayerIndex layer_nr = storage.max_print_height_second_to_last_extruder; layer_nr >= -Raft::getTotalExtraLayers(); --layer_nr)
{
std::vector<ExtruderUse>& extruders_use_at_layer = extruders_use[layer_nr];
if (extruders_use_at_layer.size() == 1 && extruders_use_at_layer.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder)
const std::vector<ExtruderUse>& extruders_use_at_layer = extruders_use[layer_nr];
std::map<size_t, Shape> moves_at_layer;

// Now generate actual priming patterns
coord_t outer_radius = tower_radius;
for (const ExtruderUse& extruder_use : extruders_use_at_layer)
{
extruders_use_at_layer.front().prime = ExtruderPrime::Sparse;
if (extruder_use.prime == ExtruderPrime::Prime)
{
Shape extruder_moves;
std::tie(extruder_moves, outer_radius) = generatePrimeMoves(extruder_use.extruder_nr, outer_radius);
moves_at_layer[extruder_use.extruder_nr] = extruder_moves;
}
}

// Generate extra "support" sparse pattern if required
if (support_radius < outer_radius)
{
Shape support_moves = generateSupportMoves(extruders_use_at_layer.back().extruder_nr, outer_radius, support_radius);
moves_at_layer[extruders_use_at_layer.back().extruder_nr].push_back(support_moves);
}

// Now decrease support radius if required
support_radius = std::min(support_radius, outer_radius);

moves[layer_nr] = moves_at_layer;
}

return moves;
}

bool PrimeTowerInterleaved::requiresBaseExtraPrint(size_t /*extruder_nr*/) const
Expand Down Expand Up @@ -153,4 +184,33 @@ void PrimeTowerInterleaved::processExtruderNoPrime(const size_t /*extruder_nr*/,
// Do nothing because we want to know which extruder has been additionally processed
}

void PrimeTowerInterleaved::polishExtrudersUses(LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder)
{
size_t last_used_extruder = start_extruder;

// Loop through the extruders uses from bottom to top to find the last used extruder at each layer, and make sure we always have some support to print
for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr <= storage.max_print_height_second_to_last_extruder; ++layer_nr)
{
std::vector<ExtruderUse>& extruders_use_at_layer = extruders_use[layer_nr];

// Make sure we always have something to print
if (extruders_use_at_layer.empty())
{
extruders_use_at_layer.emplace_back(last_used_extruder, ExtruderPrime::Sparse);
}
else if (std::all_of(
extruders_use_at_layer.begin(),
extruders_use_at_layer.end(),
[](const ExtruderUse& extruder_use)
{
return extruder_use.prime == ExtruderPrime::None;
}))
{
extruders_use_at_layer.back().prime = ExtruderPrime::Sparse;
}

last_used_extruder = extruders_use_at_layer.back().extruder_nr;
}
}

} // namespace cura
5 changes: 5 additions & 0 deletions src/PrimeTower/PrimeTowerNormal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ ExtruderPrime PrimeTowerNormal::getExtruderPrime(
}
}

std::map<LayerIndex, std::map<size_t, Shape> > PrimeTowerNormal::generateExtrusionsMoves(const LayerVector<std::vector<ExtruderUse>>& extruders_use, const SliceDataStorage& storage)
{
return {};
}

bool PrimeTowerNormal::requiresBaseExtraPrint(size_t extruder_nr) const
{
// Generate base extra rings only for the outermost printed extruder
Expand Down
1 change: 0 additions & 1 deletion src/sliceDataStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,6 @@ void SliceDataStorage::initializePrimeTower()
prime_tower_ = PrimeTower::createPrimeTower(*this);
}


void SupportLayer::excludeAreasFromSupportInfillAreas(const Shape& exclude_polygons, const AABB& exclude_polygons_boundary_box)
{
// record the indexes that need to be removed and do that after
Expand Down

0 comments on commit 7b81059

Please sign in to comment.