From 7b8105995cf6ccd83d806b3d236b96acb004253b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 29 May 2024 22:25:29 +0200 Subject: [PATCH] Implement basically working version of smaller PT --- include/PrimeTower/PrimeTower.h | 21 ++++- include/PrimeTower/PrimeTowerInterleaved.h | 7 +- include/PrimeTower/PrimeTowerNormal.h | 3 + src/FffGcodeWriter.cpp | 8 +- src/PrimeTower/PrimeTower.cpp | 96 ++++++++++++++++++++-- src/PrimeTower/PrimeTowerInterleaved.cpp | 70 ++++++++++++++-- src/PrimeTower/PrimeTowerNormal.cpp | 5 ++ src/sliceDataStorage.cpp | 1 - 8 files changed, 192 insertions(+), 19 deletions(-) diff --git a/include/PrimeTower/PrimeTower.h b/include/PrimeTower/PrimeTower.h index 78f1cd340f..c804961bd5 100644 --- a/include/PrimeTower/PrimeTower.h +++ b/include/PrimeTower/PrimeTower.h @@ -50,6 +50,13 @@ class PrimeTower */ std::map> 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> 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 @@ -112,9 +119,7 @@ class PrimeTower const SliceDataStorage& storage, const LayerIndex& layer_nr) const = 0; - virtual void polishExtrudersUse(LayerVector>& /*extruders_use*/, const SliceDataStorage& /*storage*/) const - { - } + void processExtrudersUse(LayerVector>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder); static PrimeTower* createPrimeTower(SliceDataStorage& storage); @@ -158,6 +163,16 @@ class PrimeTower virtual void processExtruderNoPrime(const size_t extruder_nr, LayerPlan& gcode_layer) const = 0; + virtual void polishExtrudersUses(LayerVector>& /*extruders_use*/, const SliceDataStorage& /*storage*/, const size_t /*start_extruder*/) + { + } + + virtual std::map> generateExtrusionsMoves(const LayerVector>& extruders_use, const SliceDataStorage& storage) = 0; + + std::tuple 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& extruder_is_used_on_this_layer, size_t extruder_nr, size_t last_extruder); private: diff --git a/include/PrimeTower/PrimeTowerInterleaved.h b/include/PrimeTower/PrimeTowerInterleaved.h index 442b82a512..454cf51f41 100644 --- a/include/PrimeTower/PrimeTowerInterleaved.h +++ b/include/PrimeTower/PrimeTowerInterleaved.h @@ -21,8 +21,6 @@ class PrimeTowerInterleaved : public PrimeTower const SliceDataStorage& storage, const LayerIndex& layer_nr) const override; - virtual void polishExtrudersUse(LayerVector>& extruders_use, const SliceDataStorage& storage) const override; - protected: virtual bool requiresBaseExtraPrint(size_t extruder_nr) const override; @@ -36,6 +34,11 @@ class PrimeTowerInterleaved : public PrimeTower const std::vector& initial_list_idx = {}) const override; virtual void processExtruderNoPrime(const size_t extruder_nr, LayerPlan& gcode_layer) const override; + + virtual void polishExtrudersUses(LayerVector>& extruders_use, const SliceDataStorage& storage, const size_t start_extruder) override; + + virtual std::map> + generateExtrusionsMoves(const LayerVector>& extruders_use, const SliceDataStorage& storage) override; }; } // namespace cura diff --git a/include/PrimeTower/PrimeTowerNormal.h b/include/PrimeTower/PrimeTowerNormal.h index 6dec7b51bc..9a986332ed 100644 --- a/include/PrimeTower/PrimeTowerNormal.h +++ b/include/PrimeTower/PrimeTowerNormal.h @@ -21,6 +21,9 @@ class PrimeTowerNormal : public PrimeTower const SliceDataStorage& storage, const LayerIndex& layer_nr) const override; + virtual std::map> + generateExtrusionsMoves(const LayerVector>& extruders_use, const SliceDataStorage& storage) override; + protected: virtual bool requiresBaseExtraPrint(size_t extruder_nr) const override; diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 75ca167644..1187db0f08 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -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); @@ -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); } } diff --git a/src/PrimeTower/PrimeTower.cpp b/src/PrimeTower/PrimeTower.cpp index 42f75a87b6..20d40538f6 100644 --- a/src/PrimeTower/PrimeTower.cpp +++ b/src/PrimeTower/PrimeTower.cpp @@ -71,11 +71,11 @@ void PrimeTower::generatePaths() { generateGroundpoly(); + generateStartLocations(); + std::vector cumulative_insets; generateDenseInfill(cumulative_insets); - generateStartLocations(); - generateSparseInfill(cumulative_insets); } @@ -214,6 +214,69 @@ Shape PrimeTower::generatePath_sparseInfill( return pattern; } +std::tuple 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("layer_height"); + const coord_t tower_radius = mesh_group_settings.get("prime_tower_size") / 2; + const coord_t line_width = scene.extruders[extruder_nr].settings_.get("prime_tower_line_width"); + const double required_volume = scene.extruders[extruder_nr].settings_.get("prime_tower_min_volume") * 1000000000; + const Ratio flow = scene.extruders[extruder_nr].settings_.get("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(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(scene.extruders[extruder_nr].settings_.get("prime_tower_max_bridging_distance")); + const coord_t line_width = scene.extruders[extruder_nr].settings_.get("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(std::ceil(static_cast(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(std::ceil((std::numbers::pi * static_cast(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, @@ -276,7 +339,7 @@ void PrimeTower::addToGcode( return; } - std::vector extra_primed_extruders_idx; + /*std::vector extra_primed_extruders_idx; switch (extruder_iterator->prime) { @@ -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)) @@ -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) @@ -479,6 +559,12 @@ const Shape& PrimeTower::getGroundPoly() const return getOuterPoly(-Raft::getTotalExtraLayers()); } +void PrimeTower::processExtrudersUse(LayerVector>& 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; diff --git a/src/PrimeTower/PrimeTowerInterleaved.cpp b/src/PrimeTower/PrimeTowerInterleaved.cpp index 29a8f55eaa..2d730cac9b 100644 --- a/src/PrimeTower/PrimeTowerInterleaved.cpp +++ b/src/PrimeTower/PrimeTowerInterleaved.cpp @@ -34,16 +34,47 @@ ExtruderPrime PrimeTowerInterleaved::getExtruderPrime( } } -void PrimeTowerInterleaved::polishExtrudersUse(LayerVector>& extruders_use, const SliceDataStorage& storage) const +std::map> + PrimeTowerInterleaved::generateExtrusionsMoves(const LayerVector>& 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("prime_tower_size") / 2; + coord_t support_radius = tower_radius; + std::map> 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& 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& extruders_use_at_layer = extruders_use[layer_nr]; + std::map 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 @@ -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>& 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& 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 diff --git a/src/PrimeTower/PrimeTowerNormal.cpp b/src/PrimeTower/PrimeTowerNormal.cpp index 9bd0ed33ef..83ae82769f 100644 --- a/src/PrimeTower/PrimeTowerNormal.cpp +++ b/src/PrimeTower/PrimeTowerNormal.cpp @@ -38,6 +38,11 @@ ExtruderPrime PrimeTowerNormal::getExtruderPrime( } } +std::map > PrimeTowerNormal::generateExtrusionsMoves(const LayerVector>& extruders_use, const SliceDataStorage& storage) +{ + return {}; +} + bool PrimeTowerNormal::requiresBaseExtraPrint(size_t extruder_nr) const { // Generate base extra rings only for the outermost printed extruder diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index bfd63e388b..e1a6c1cc3a 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -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