Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce the interleaved prime tower wasted filament #2094

Merged
merged 58 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
0017f57
Remove dead code
wawanbreton Apr 17, 2024
ec0567e
Code simplification
wawanbreton Apr 18, 2024
c65d92b
Fixed missing interleaved prime tower raft layer
wawanbreton Apr 18, 2024
7812a0e
Fixed missing prime tower layers when using raft
wawanbreton Apr 19, 2024
dbc1c55
Merge remote-tracking branch 'origin/CURA-9830_consolidate_polygon_cl…
wawanbreton May 9, 2024
e58b257
Fix possibly wrong generated circle
wawanbreton May 9, 2024
c063eb4
Fix crash due to previous merge
wawanbreton May 9, 2024
6ca20e4
Clean code
wawanbreton May 9, 2024
bca6edd
Fix crash when using support_z_seam_away_from_model and raft
wawanbreton May 9, 2024
14fca54
Use a pointer for the primer tower handler object
wawanbreton May 9, 2024
0012716
Remove unused file
wawanbreton May 9, 2024
ec67b52
Remove some headers inclusions
wawanbreton May 9, 2024
3e52bc1
Split PrimeTower class in (placeholder) subclasses
wawanbreton May 9, 2024
6eaa915
Move extruder prime logic calculation to PrimeTower* classes
wawanbreton May 9, 2024
7dc995e
Add a utility vector to store items by layers
wawanbreton May 11, 2024
41efc4c
Use LayerVector when possible in PrimeTower
wawanbreton May 11, 2024
d882198
Fix some (mostly type-related) warnings
wawanbreton May 11, 2024
34d38a2
Split normal/interleaved behaviors into dedicated classes
wawanbreton May 13, 2024
cd32170
Merge remote-tracking branch 'origin/main' into smaller-prime-tower
wawanbreton May 29, 2024
1e29c82
Finalized seperation of prime tower implementations
wawanbreton May 29, 2024
4a753f2
Remove some now useless variables
wawanbreton May 29, 2024
7b81059
Implement basically working version of smaller PT
wawanbreton May 29, 2024
4efe481
Applied clang-format.
wawanbreton May 29, 2024
f5fa05d
Fix inset and base printing
wawanbreton May 30, 2024
fdc169b
Applied clang-format.
wawanbreton May 30, 2024
1f72f19
Simplify generateGroundpoly code
wawanbreton May 30, 2024
893a7d9
Fix interaction between prime tower base and support/adhesion
wawanbreton May 31, 2024
dab68df
Restored normal prime tower
wawanbreton May 31, 2024
3dfa6d0
Polish iteration loops
wawanbreton May 31, 2024
8819cc7
Fix the normal prime tower base
wawanbreton May 31, 2024
358d12e
Remove useless code/variables
wawanbreton May 31, 2024
eb926d7
Fix missing segment on prime tower circles
wawanbreton Jun 1, 2024
4776b31
Fix missing inset on first layer
wawanbreton Jun 1, 2024
ab91476
Fix interleaved generation
wawanbreton Jun 1, 2024
80cffb6
Fix possibly missing support layer with normal prime tower
wawanbreton Jun 1, 2024
c9c45dc
Fix remaining warning in prime tower classes
wawanbreton Jun 2, 2024
a6aa840
Merge remote-tracking branch 'origin/main' into smaller-prime-tower
wawanbreton Jun 12, 2024
a4b6c5a
Remove unentionnally added empty lines
wawanbreton Jun 12, 2024
ac2408a
Fix missing function call
wawanbreton Jun 12, 2024
9939da9
Clean code and add documentation
wawanbreton Jun 12, 2024
ea20a56
Restore previous behavior for prime tower start position
wawanbreton Jun 12, 2024
453fd31
Add code documentation and reword some code
wawanbreton Jun 13, 2024
d135948
Generate only circular patterns for base and initial inset
wawanbreton Jun 13, 2024
6c5dca6
Fix double base print and optimize execution
wawanbreton Jun 14, 2024
06e3169
Change constants as define to class member
wawanbreton Jun 14, 2024
992d187
Fix wipe out start positions with base
wawanbreton Jun 14, 2024
eced18e
Use the most explicit geometric types in PrimeTower
wawanbreton Jun 17, 2024
5325ce0
Remove obsolete unit test
wawanbreton Jun 18, 2024
2b817f7
Add documentation
wawanbreton Jun 18, 2024
8badc29
Handle prime_tower_min_shell_thickness settings
wawanbreton Jun 18, 2024
bb25501
Merge branch 'main' into smaller-prime-tower
wawanbreton Jun 18, 2024
8108a08
Merge remote-tracking branch 'origin/main' into smaller-prime-tower
wawanbreton Jun 19, 2024
d6813bc
Merge remote-tracking branch 'origin/CURA-9399_sharp_points' into sma…
wawanbreton Jun 19, 2024
d1bae90
Merge remote-tracking branch 'origin/main' into smaller-prime-tower
wawanbreton Jun 25, 2024
15d4e12
Add/fix documentation
wawanbreton Jun 28, 2024
f0341eb
Apply suggested code consistency
wawanbreton Jun 28, 2024
32cf43b
Merge remote-tracking branch 'origin/main' into smaller-prime-tower
wawanbreton Jun 28, 2024
1d170b4
Merge branch 'main' into smaller-prime-tower
HellAholic Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ set(engine_SRCS # Except main.cpp.
src/multiVolumes.cpp
src/path_ordering.cpp
src/Preheat.cpp
src/PrimeTower.cpp
src/PrimeTower/PrimeTower.cpp
src/PrimeTower/PrimeTowerNormal.cpp
src/PrimeTower/PrimeTowerInterleaved.cpp
src/raft.cpp
src/Scene.cpp
src/SkeletalTrapezoidation.cpp
Expand Down
2 changes: 1 addition & 1 deletion include/ExtruderPrime.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace cura
enum class ExtruderPrime
{
None, // Do not prime at all for this extruder on this layer
Sparse, // Just extrude a sparse priming which purpose is to make the tower stronger
Support, // Just extrude a sparse pattern which purpose is to support the upper parts of the prime tower
Prime, // Do an actual prime
};

Expand Down
18 changes: 3 additions & 15 deletions include/FffGcodeWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "GCodePathConfig.h"
#include "LayerPlanBuffer.h"
#include "gcodeExport.h"
#include "utils/LayerVector.h"
#include "utils/NoCopy.h"
#include "utils/gettime.h"

Expand Down Expand Up @@ -60,13 +61,8 @@ class FffGcodeWriter : public NoCopy
*/
std::ofstream output_file;

/*!
* For each raft/filler layer, the extruders to be used in that layer in the order in which they are going to be used.
* The first number is the first raft layer. Indexing is shifted compared to normal negative layer numbers for raft/filler layers.
*/
std::vector<std::vector<ExtruderUse>> extruder_order_per_layer_negative_layers;

std::vector<std::vector<ExtruderUse>> extruder_order_per_layer; //!< For each layer, the extruders to be used in that layer in the order in which they are going to be used
//!< For each layer, the extruders to be used in that layer in the order in which they are going to be used
LayerVector<std::vector<ExtruderUse>> extruder_order_per_layer;

std::vector<std::vector<size_t>> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed)

Expand Down Expand Up @@ -735,14 +731,6 @@ class FffGcodeWriter : public NoCopy
* \return The first or last exruder used at the given index
*/
size_t findUsedExtruderIndex(const SliceDataStorage& storage, const LayerIndex& layer_nr, bool last) const;

/*!
* Get the extruders use at the given layer
*
* \param layer_nr The index of the layer at which we want the extruders uses
* \return The extruders use at the given layer, which may be empty in some cases
*/
std::vector<ExtruderUse> getExtruderUse(const LayerIndex& layer_nr) const;
};

} // namespace cura
Expand Down
6 changes: 2 additions & 4 deletions include/LayerPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ class LayerPlan : public NoCopy

std::vector<Point2LL> layer_start_pos_per_extruder_; //!< The starting position of a layer for each extruder
std::vector<bool> has_prime_tower_planned_per_extruder_; //!< For each extruder, whether the prime tower is planned yet or not.
bool has_prime_tower_base_planned_; //!< Whether the prime tower base is planned yet or not.
bool has_prime_tower_inset_planned_; //!< Whether the prime tower inset is planned yet or not.
std::optional<Point2LL> last_planned_position_; //!< The last planned XY position of the print head (if known)

std::shared_ptr<const SliceMeshStorage> current_mesh_; //!< The mesh of the last planned move.
Expand Down Expand Up @@ -202,14 +200,14 @@ class LayerPlan : public NoCopy
* Whether the prime tower is already planned for the specified extruder.
* \param extruder_nr The extruder to check.
*/
bool getPrimeTowerIsPlanned(unsigned int extruder_nr) const;
bool getPrimeTowerIsPlanned(size_t extruder_nr) const;

/*!
* Mark the prime tower as planned for the specified extruder.
* \param extruder_nr The extruder to mark as having its prime tower
* planned.
*/
void setPrimeTowerIsPlanned(unsigned int extruder_nr);
void setPrimeTowerIsPlanned(size_t extruder_nr);

/*!
* Whether the prime tower extra base is already planned.
Expand Down
234 changes: 234 additions & 0 deletions include/PrimeTower/PrimeTower.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// Copyright (c) 2022 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef PRIME_TOWER_H
#define PRIME_TOWER_H

#include <map>
#include <vector>

#include "ExtruderUse.h"
#include "geometry/ClosedLinesSet.h"
#include "geometry/Polygon.h"
#include "settings/EnumSettings.h"
#include "settings/types/LayerIndex.h"
#include "utils/LayerVector.h"
#include "utils/polygonUtils.h"

namespace cura
{

class SliceDataStorage;
class LayerPlan;

/*!
* Abstract class for everything to do with the prime tower:
* - Generating the occupation areas.
* - Checking up untill which height the prime tower has to be printed.
* - Inserting priming commands in extruders uses
* - Generating priming paths and adding them to the layer plan.
*
* We may adopt different strategies to generate the prime tower, thus this class is abstract and different
* implementations may co-exist. The common behavior implemented in the main class is:
* - Generate occupation areas as a cylinder with a flared base
* - Generate the base extra extrusion discs around the base cylinder
* - Generate the first layer extra inset inside the base cylinder
* Then it is the job of the specific implementation to handle the generation of extrusion paths for the base cylinder
*/
class PrimeTower
{
protected:
struct OccupiedOutline
{
Polygon outline;
coord_t outer_radius;
};

struct ExtruderToolPaths
{
size_t extruder_nr;
ClosedLinesSet toolpaths;
coord_t outer_radius;
coord_t inner_radius;
};

private:
bool wipe_from_middle_; //!< Whether to wipe on the inside of the hollow prime tower
Point2LL middle_; //!< The middle of the prime tower

Point2LL post_wipe_point_; //!< Location to post-wipe the unused nozzle off on

static constexpr size_t number_of_prime_tower_start_locations_ = 21; //!< The required size of \ref PrimeTower::wipe_locations
static constexpr AngleRadians start_locations_step_ = (std::numbers::pi * 2.0) / number_of_prime_tower_start_locations_;

/*
* The map index is the layer number
* For each layer, the list contains the extruders moves to be processed. This list is sorted from outer annuli to inner
* annuli, which is not the printing chronological order, but the physical arrangement.
*/
std::map<LayerIndex, std::vector<ExtruderToolPaths>> toolpaths_;

OccupiedOutline outer_poly_; //!< The outline of the prime tower, not including the base

//!< This is the exact outline of the extrusions lines of each layer, for layers having extra width for the base
LayerVector<Polygon> base_extrusion_outline_;
//!< This is the approximate outline of the area filled at each layer, for layers having extra width for the base
LayerVector<OccupiedOutline> base_occupied_outline_;

static constexpr size_t circle_definition_{ 32 }; // The number of vertices in each circle.
static constexpr size_t arc_definition_{ 4 }; // The number of segments in each arc of a wheel

public:
/*! \brief Creates a prime tower instance that will determine where and how the prime tower gets printed. */
PrimeTower();

virtual ~PrimeTower() = default;

/*!
* Add path plans for the prime tower to the \p gcode_layer
*
* \param storage where to get settings from; where to get the maximum height of the prime tower from
* \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths
* \param required_extruder_prime the extruders which actually required to be primed at this layer
* \param prev_extruder_nr The previous extruder with which paths were planned; from which extruder a switch was made
* \param new_extruder_nr The switched to extruder with which the prime tower paths should be generated.
*/
void addToGcode(
const SliceDataStorage& storage,
LayerPlan& gcode_layer,
const std::vector<ExtruderUse>& required_extruder_prime,
const size_t prev_extruder_nr,
const size_t new_extruder_nr) const;

/*!
* Get the occupied outline of the prime tower at the given layer
*
* \param[in] layer_nr The index of the layer
* \return The outer polygon for the prime tower at the given layer
* \note The returned outline is a close approximation of the actual toolpaths. The actual extrusion area may be slightly smaller.
* Use this method only if you need to get the exclusion area of the prime tower. Otherwise use getExtrusionOutline().
* This method exists because this approximate area can be calculated as soon as the prime tower is initialized.
*/
const Polygon& getOccupiedOutline(const LayerIndex& layer_nr) const;

/*!
* Get the occupied outline of the prime tower at the first layer
*
* \note @sa getOccupiedOutline()
*/
const Polygon& getOccupiedGroundOutline() const;

/*!
* Get the extrusion outline of the prime tower at the given layer
*
* \param[in] layer_nr The index of the layer
* \return The extrusion outline for the prime tower at the given layer
* \note The returned outline is the exact outline of the extrusion path, which is useful if you need to generate a toolpath
* touching the prime tower. Otherwise use getExtrusionOutline(). This method will return the valid result only after
* processExtrudersUse() has been called, which is "late" is the global slicing operation.
*/
const Polygon& getExtrusionOutline(const LayerIndex& layer_nr) const;

/*!
* \brief Get the required priming for the given extruder at the given layer
* \param extruder_is_used_on_this_layer A list indicating which extruders are used at this layer
* \param extruder_nr The extruder for which we want the priming information
* \param last_extruder The extruder that was in use just before using the new one
* \param storage The storage containing all the slice data
* \param layer_nr The layer at which we want to use the extruder
* \return An enumeration indication how the extruder will be used by the prime tower at this layer
*/
virtual ExtruderPrime getExtruderPrime(
const std::vector<bool>& extruder_is_used_on_this_layer,
size_t extruder_nr,
size_t last_extruder,
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const = 0;

/*!
* \brief This method has to be called once the extruders use for each layer have been calculated. From this point,
* we can start generating the prime tower, and also polish the given extruders uses.
* \param extruders_use The calculated extruders uses at each layer. This may be slightly changed to make sure that
* the prime tower can be properly printed.
* \param start_extruder The very first used extruder
*/
void processExtrudersUse(LayerVector<std::vector<ExtruderUse>>& extruders_use, const size_t start_extruder);

/*!
* \brief Create the proper prime tower object according to the current settings
* \param storage The storage containing all the slice data
* \return The proper prime tower object, which may be null if prime tower is actually disabled or not required
*/
static PrimeTower* createPrimeTower(SliceDataStorage& storage);

protected:
/*!
* \brief Once all the extruders uses have been calculated for each layer, this method makes a global pass to make
* sure that the prime tower can be properly printed. This is required because we sometimes need to know what
* a layer above is made of to fix a layer below.
* \param extruders_use The calculated extruders uses at each layer
* \param start_extruder The very first used extruder
*/
virtual void polishExtrudersUses(LayerVector<std::vector<ExtruderUse>>& /*extruders_use*/, const size_t /*start_extruder*/)
{
// Default behavior is to keep the extruders uses as they were calculated
}

/*!
* \brief Generated the extruders toolpaths for each layer of the prime tower
* \param extruders_use The calculated extruders uses at each layer
* \return A map of extruders toolpaths per layer. The inner list is sorted from outer annuli to inner
* annuli, which is not the printing chronological order, but the physical arrangement. @sa toolpaths_
*/
virtual std::map<LayerIndex, std::vector<ExtruderToolPaths>> generateToolPaths(const LayerVector<std::vector<ExtruderUse>>& extruders_use) = 0;

/*!
* \brief Generate the actual priming toolpaths for the given extruder, starting at the given outer circle radius
* \param extruder_nr The extruder for which we want the priming toolpath
* \param outer_radius The radius of the starting outer circle
* \return A tuple containing the newly generated toolpaths, and the inner radius of the newly generated annulus
*/
std::tuple<ClosedLinesSet, coord_t> generatePrimeToolpaths(const size_t extruder_nr, const coord_t outer_radius);

/*!
* \brief Generate support toolpaths using the wheel pattern applied on an annulus
* \param extruder_nr The extruder for which we want the support toolpath
* \param outer_radius The annulus outer radius
* \param inner_radius The annulis inner radius
* \return
*/
ClosedLinesSet generateSupportToolpaths(const size_t extruder_nr, const coord_t outer_radius, const coord_t inner_radius);

/*!
* \brief Calculates whether an extruder requires priming at a specific layer
* \param extruder_is_used_on_this_layer The list of used extruders at this layer
* \param extruder_nr The extruder we now want to use
* \param last_extruder The extruder that was in use before switching to the new one
* \return True if the extruder needs to be primed, false otherwise
*/
static bool extruderRequiresPrime(const std::vector<bool>& extruder_is_used_on_this_layer, size_t extruder_nr, size_t last_extruder);

private:
/*! \brief Generates the extra inset used for better adhesion at the first layer */
void generateFirtLayerInset();

/*! \brief Generates the extra annuli around the first layers of the prime tower which help make it stronger */
void generateBase();

/*!
* For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower.
* This function picks a start location for this extruder on the prime tower's perimeter and travels there to avoid
* starting at the location everytime which can result in z-seam blobs.
*/
void gotoStartLocation(LayerPlan& gcode_layer, const size_t extruder) const;

/*!
* \brief Subtract the prime tower from the support areas in storage.
* \param storage The storage where to find the support from which to subtract a prime tower.
*/
void subtractFromSupport(SliceDataStorage& storage);
};

} // namespace cura

#endif // PRIME_TOWER_H
40 changes: 40 additions & 0 deletions include/PrimeTower/PrimeTowerInterleaved.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2024 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef PRIME_TOWER_INTERLEAVED_H
#define PRIME_TOWER_INTERLEAVED_H

#include "PrimeTower/PrimeTower.h"

namespace cura
{

/*!
* Specific prime tower implementation that generates interleaved priming paths. It is optimized to waste as few
* filament as possible, while ensuring that the prime tower is still robust even if it gets very high.
* When there is no actual priming required for extruders, it will create a kind of circular zigzag pattern that acts as
* a sparse support. Otherwise it will create priming annuli, stacked on top of each other.
* This is very effective when doing multi-color printing, however it can be used only if all the filaments properly
* adhere to each other. Otherwise there is a high risk that the tower will collapse during the print.
*/
class PrimeTowerInterleaved : public PrimeTower
wawanbreton marked this conversation as resolved.
Show resolved Hide resolved
{
public:
PrimeTowerInterleaved();

virtual ExtruderPrime getExtruderPrime(
const std::vector<bool>& extruder_is_used_on_this_layer,
size_t extruder_nr,
size_t last_extruder,
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const override;

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

virtual std::map<LayerIndex, std::vector<ExtruderToolPaths>> generateToolPaths(const LayerVector<std::vector<ExtruderUse>>& extruders_use) override;
};

} // namespace cura

#endif // PRIME_TOWER_INTERLEAVED_H
37 changes: 37 additions & 0 deletions include/PrimeTower/PrimeTowerNormal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2024 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef PRIME_TOWER_NORMAL_H
#define PRIME_TOWER_NORMAL_H

#include "PrimeTower/PrimeTower.h"

namespace cura
{

/*!
* Specific prime tower implementation that generates nested cylinders. Each layer, all the extruders will be used to
* contribute to the prime tower, even if they don't actually need priming. In this case, a circular zigzag pattern will
* be used to act as support for upper priming extrusions.
* Although this method is not very efficient, it is required when using different materials that don't properly adhere
* to each other. By nesting the cylinders, you make sure that the tower remains consistent and strong along the print.
*/
class PrimeTowerNormal : public PrimeTower
wawanbreton marked this conversation as resolved.
Show resolved Hide resolved
{
public:
PrimeTowerNormal();

virtual ExtruderPrime getExtruderPrime(
const std::vector<bool>& extruder_is_used_on_this_layer,
size_t extruder_nr,
size_t last_extruder,
const SliceDataStorage& storage,
const LayerIndex& layer_nr) const override;

protected:
virtual std::map<LayerIndex, std::vector<ExtruderToolPaths>> generateToolPaths(const LayerVector<std::vector<ExtruderUse>>& extruders_use) override;
};

} // namespace cura

#endif // PRIME_TOWER_NORMAL_H
Loading
Loading