WIP Tree Supports: Major changes, it does not compile yet.

This commit is contained in:
Vojtech Bubnik 2022-07-27 08:54:26 +02:00
parent 8a1e8f97a9
commit 665d1a94b4
7 changed files with 1861 additions and 2112 deletions

View File

@ -2770,8 +2770,10 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<SupportMaterialStyle>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<SupportMaterialStyle>::get_enum_values();
def->enum_values.push_back("grid"); def->enum_values.push_back("grid");
def->enum_values.push_back("snug"); def->enum_values.push_back("snug");
def->enum_values.push_back("tree");
def->enum_labels.push_back(L("Grid")); def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Snug")); def->enum_labels.push_back(L("Snug"));
def->enum_labels.push_back(L("Tree"));
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SupportMaterialStyle>(smsGrid)); def->set_default_value(new ConfigOptionEnum<SupportMaterialStyle>(smsGrid));

View File

@ -85,7 +85,7 @@ enum SupportMaterialPattern {
}; };
enum SupportMaterialStyle { enum SupportMaterialStyle {
smsGrid, smsSnug, smsGrid, smsSnug, smsTree,
}; };
enum SupportMaterialInterfacePattern { enum SupportMaterialInterfacePattern {

View File

@ -8,6 +8,7 @@
#include "Layer.hpp" #include "Layer.hpp"
#include "MutablePolygon.hpp" #include "MutablePolygon.hpp"
#include "SupportMaterial.hpp" #include "SupportMaterial.hpp"
#include "TreeSupport.hpp"
#include "Surface.hpp" #include "Surface.hpp"
#include "Slicing.hpp" #include "Slicing.hpp"
#include "Tesselate.hpp" #include "Tesselate.hpp"
@ -2127,9 +2128,14 @@ void PrintObject::combine_infill()
void PrintObject::_generate_support_material() void PrintObject::_generate_support_material()
{ {
if (m_config.support_material_style == smsTree) {
TreeSupport tree_support;
tree_support.generateSupportAreas();
} else {
PrintObjectSupportMaterial support_material(this, m_slicing_params); PrintObjectSupportMaterial support_material(this, m_slicing_params);
support_material.generate(*this); support_material.generate(*this);
} }
}
static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const indexed_triangle_set &custom_facets, const Transform3f &tr, bool seam, std::vector<Polygons> &out) static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const indexed_triangle_set &custom_facets, const Transform3f &tr, bool seam, std::vector<Polygons> &out)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,9 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <boost/functional/hash.hpp>
#include "Point.hpp"
#include "Polygon.hpp" #include "Polygon.hpp"
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
@ -22,42 +25,174 @@ namespace Slic3r
using LayerIndex = size_t; using LayerIndex = size_t;
using AngleRadians = double; using AngleRadians = double;
//FIXME class BuildVolume;
class SliceDataStorage; class PrintObject;
class SliceMeshStorage;
struct TreeSupportMeshGroupSettings { struct TreeSupportMeshGroupSettings {
AngleRadians support_tree_angle; TreeSupportMeshGroupSettings() = default;
AngleRadians support_tree_angle_slow; TreeSupportMeshGroupSettings(const PrintObject &print_object);
AngleRadians support_tree_branch_diameter_angle;
coord_t support_tree_bp_diameter; /*********************************************************************/
coord_t support_tree_max_diameter_increase_by_merges_when_support_to_model; /* Print parameters, not support specific: */
coord_t support_tree_min_height_to_model; /*********************************************************************/
coord_t support_line_width; coord_t layer_height { scaled<coord_t>(0.15) };
coord_t layer_height; // Maximum Deviation (meshfix_maximum_deviation)
coord_t support_tree_branch_diameter; // The maximum deviation allowed when reducing the resolution for the Maximum Resolution setting. If you increase this,
coord_t support_tree_tip_diameter; // the print will be less accurate, but the g-code will be smaller. Maximum Deviation is a limit for Maximum Resolution,
bool support_bottom_enable; // so if the two conflict the Maximum Deviation will always be held true.
coord_t support_bottom_height; coord_t resolution { scaled<coord_t>(0.025) };
bool support_material_buildplate_only; // Minimum Feature Size (aka minimum line width)
bool support_xy_overrides_z; // Minimum thickness of thin features. Model features that are thinner than this value will not be printed, while features thicker
coord_t support_xy_distance; // than the Minimum Feature Size will be widened to the Minimum Wall Line Width.
coord_t support_xy_distance_overhang; coord_t min_feature_size { scaled<coord_t>(0.1) };
coord_t support_top_distance;
coord_t support_bottom_distance; /*********************************************************************/
coord_t support_interface_skip_height; /* General support parameters: */
std::vector<AngleRadians> support_infill_angles; /*********************************************************************/
std::vector<AngleRadians> support_roof_angles;
SupportMaterialInterfacePattern support_roof_pattern; // Support Overhang Angle
SupportMaterialPattern support_pattern; // The minimum angle of overhangs for which support is added. At a value of 0° all overhangs are supported, 90° will not provide any support.
coord_t support_roof_line_width; AngleRadians support_angle { 50. * M_PI / 180. };
coord_t support_line_distance; // Support Line Width
coord_t support_bottom_offset; // Width of a single support structure line.
int support_wall_count; coord_t support_line_width { scaled<coord_t>(0.4) };
coord_t meshfix_maximum_deviation; // Support Roof Line Width: Width of a single support roof line.
coord_t meshfix_maximum_resolution; coord_t support_roof_line_width { scaled<coord_t>(0.4) };
coord_t support_roof_line_distance; // Enable Support Floor (aka bottom interfaces)
coord_t min_feature_size; // Generate a dense slab of material between the bottom of the support and the model. This will create a skin between the model and support.
bool support_bottom_enable { false };
// Support Floor Thickness
// The thickness of the support floors. This controls the number of dense layers that are printed on top of places of a model on which support rests.
coord_t support_bottom_height { scaled<coord_t>(1.) };
bool support_material_buildplate_only { false };
// Support Distance Priority
// Whether the Support X/Y Distance overrides the Support Z Distance or vice versa. When X/Y overrides Z the X/Y distance can push away
// the support from the model, influencing the actual Z distance to the overhang. We can disable this by not applying the X/Y distance around overhangs.
bool support_xy_overrides_z { false };
// Support X/Y Distance
// Distance of the support structure from the print in the X/Y directions.
// minimum: 0, maximum warning: 1.5 * machine_nozzle_tip_outer_diameter
coord_t support_xy_distance { scaled<coord_t>(0.7) };
// Minimum Support X/Y Distance
// Distance of the support structure from the overhang in the X/Y directions.
// minimum_value: 0, minimum warning": support_xy_distance - support_line_width * 2, maximum warning: support_xy_distance
// Used if ! support_xy_overrides_z.
coord_t support_xy_distance_overhang { scaled<coord_t>(0.2) };
// Support Top Distance
// Distance from the top of the support to the print.
coord_t support_top_distance { scaled<coord_t>(0.1) };
// Support Bottom Distance
// Distance from the print to the bottom of the support.
coord_t support_bottom_distance { scaled<coord_t>(0.1) };
//FIXME likely not needed, optimization for clipping of interface layers
// When checking where there's model above and below the support, take steps of the given height. Lower values will slice slower, while higher values
// may cause normal support to be printed in some places where there should have been support interface.
coord_t support_interface_skip_height { scaled<coord_t>(0.3) };
// Support Infill Line Directions
// A list of integer line directions to use. Elements from the list are used sequentially as the layers progress and when the end
// of the list is reached, it starts at the beginning again. The list items are separated by commas and the whole list is contained
// in square brackets. Default is an empty list which means use the default angle 0 degrees.
std::vector<AngleRadians> support_infill_angles {};
// Enable Support Roof
// Generate a dense slab of material between the top of support and the model. This will create a skin between the model and support.
bool support_roof_enable { false };
// Support Roof Thickness
// The thickness of the support roofs. This controls the amount of dense layers at the top of the support on which the model rests.
coord_t support_roof_height { scaled<coord_t>(1.) };
// Minimum Support Roof Area
// Minimum area size for the roofs of the support. Polygons which have an area smaller than this value will be printed as normal support.
double minimum_roof_area { scaled<double>(scaled<double>(1.)) };
// A list of integer line directions to use. Elements from the list are used sequentially as the layers progress
// and when the end of the list is reached, it starts at the beginning again. The list items are separated
// by commas and the whole list is contained in square brackets. Default is an empty list which means
// use the default angles (alternates between 45 and 135 degrees if interfaces are quite thick or 90 degrees).
std::vector<AngleRadians> support_roof_angles {};
// Support Roof Pattern (aka top interface)
// The pattern with which the roofs of the support are printed.
SupportMaterialInterfacePattern support_roof_pattern { smipAuto };
// Support Pattern
// The pattern of the support structures of the print. The different options available result in sturdy or easy to remove support.
SupportMaterialPattern support_pattern { smpRectilinear };
// Support Line Distance
// Distance between the printed support structure lines. This setting is calculated by the support density.
coord_t support_line_spacing { scaled<coord_t>(2.66 - 0.4) };
// Support Floor Horizontal Expansion
// Amount of offset applied to the floors of the support.
coord_t support_bottom_offset { scaled<coord_t>(0.) };
// Support Wall Line Count
// The number of walls with which to surround support infill. Adding a wall can make support print more reliably
// and can support overhangs better, but increases print time and material used.
// tree: 1, zig-zag: 0, concentric: 1
int support_wall_count { 1 };
// Support Roof Line Distance
// Distance between the printed support roof lines. This setting is calculated by the Support Roof Density, but can be adjusted separately.
coord_t support_roof_line_distance { scaled<coord_t>(0.4) };
// Minimum Support Area
// Minimum area size for support polygons. Polygons which have an area smaller than this value will not be generated.
coord_t minimum_support_area { scaled<coord_t>(0.) };
// Minimum Support Floor Area
// Minimum area size for the floors of the support. Polygons which have an area smaller than this value will be printed as normal support.
coord_t minimum_bottom_area { scaled<coord_t>(1.0) };
// Support Horizontal Expansion
// Amount of offset applied to all support polygons in each layer. Positive values can smooth out the support areas and result in more sturdy support.
coord_t support_offset { scaled<coord_t>(0.) };
/*********************************************************************/
/* Parameters for the Cura tree supports implementation: */
/*********************************************************************/
// Tree Support Maximum Branch Angle
// The maximum angle of the branches, when the branches have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach.
// minimum: 0, minimum warning: 20, maximum: 89, maximum warning": 85
AngleRadians support_tree_angle { 60. * M_PI / 180. };
// Tree Support Branch Diameter Angle
// The angle of the branches' diameter as they gradually become thicker towards the bottom. An angle of 0 will cause the branches to have uniform thickness over their length.
// A bit of an angle can increase stability of the tree support.
// minimum: 0, maximum: 89.9999, maximum warning: 15
AngleRadians support_tree_branch_diameter_angle { 5. * M_PI / 180. };
// Tree Support Branch Distance
// How far apart the branches need to be when they touch the model. Making this distance small will cause
// the tree support to touch the model at more points, causing better overhang but making support harder to remove.
coord_t support_tree_branch_distance { scaled<coord_t>(50.) };
// Tree Support Branch Diameter
// The diameter of the thinnest branches of tree support. Thicker branches are more sturdy. Branches towards the base will be thicker than this.
// minimum: 0.001, minimum warning: support_line_width * 2
coord_t support_tree_branch_diameter { scaled<coord_t>(2.) };
/*********************************************************************/
/* Parameters new to the Thomas Rahm's tree supports implementation: */
/*********************************************************************/
// Tree Support Preferred Branch Angle
// The preferred angle of the branches, when they do not have to avoid the model. Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster.
// minimum: 0, minimum warning: 10, maximum: support_tree_angle, maximum warning: support_tree_angle-1
AngleRadians support_tree_angle_slow { 50. * M_PI / 180. };
// Tree Support Diameter Increase To Model
// The most the diameter of a branch that has to connect to the model may increase by merging with branches that could reach the buildplate.
// Increasing this reduces print time, but increases the area of support that rests on model
// minimum: 0
coord_t support_tree_max_diameter_increase_by_merges_when_support_to_model { scaled<coord_t>(1.0) };
// Tree Support Minimum Height To Model
// How tall a branch has to be if it is placed on the model. Prevents small blobs of support. This setting is ignored when a branch is supporting a support roof.
// minimum: 0, maximum warning: 5
coord_t support_tree_min_height_to_model { scaled<coord_t>(1.0) };
// Tree Support Inital Layer Diameter
// Diameter every branch tries to achieve when reaching the buildplate. Improves bed adhesion.
// minimum: 0, maximum warning: 20
coord_t support_tree_bp_diameter { scaled<coord_t>(7.5) };
// Tree Support Branch Density
// Adjusts the density of the support structure used to generate the tips of the branches. A higher value results in better overhangs,
// but the supports are harder to remove. Use Support Roof for very high values or ensure support density is similarly high at the top.
// 5%-35%
double support_tree_top_rate { 15. };
// Tree Support Tip Diameter
// The diameter of the top of the tip of the branches of tree support."
// minimum: min_wall_line_width, minimum warning: min_wall_line_width+0.05, maximum_value: support_tree_branch_diameter, value: support_line_width
coord_t support_tree_tip_diameter { scaled<coord_t>(0.4) };
// Support Interface Priority
// How support interface and support will interact when they overlap. Currently only implemented for support roof.
//enum support_interface_priority { support_lines_overwrite_interface_area };
}; };
inline coord_t round_up_divide(const coord_t dividend, const coord_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer inline coord_t round_up_divide(const coord_t dividend, const coord_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer
@ -69,7 +204,8 @@ class TreeModelVolumes
{ {
public: public:
TreeModelVolumes() = default; TreeModelVolumes() = default;
TreeModelVolumes(const SliceDataStorage& storage, coord_t max_move, coord_t max_move_slow, size_t current_mesh_idx, double progress_multiplier, double progress_offset, const std::vector<Polygons>& additional_excluded_areas = std::vector<Polygons>()); TreeModelVolumes(const PrintObject &print_object, const BuildVolume &build_volume,
coord_t max_move, coord_t max_move_slow, size_t current_mesh_idx, double progress_multiplier, double progress_offset, const std::vector<Polygons> &additional_excluded_areas = {});
TreeModelVolumes(TreeModelVolumes&&) = default; TreeModelVolumes(TreeModelVolumes&&) = default;
TreeModelVolumes& operator=(TreeModelVolumes&&) = default; TreeModelVolumes& operator=(TreeModelVolumes&&) = default;
@ -103,22 +239,20 @@ class TreeModelVolumes
* \param min_xy_dist Is the minimum xy distance used. * \param min_xy_dist Is the minimum xy distance used.
* \return Polygons object * \return Polygons object
*/ */
const Polygons& getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false) const;
const Polygons& getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false);
/*! /*!
* \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed. * \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed.
* *
* The result is a 2D area that would cause nodes of given radius to * The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole. * collide with the model or be inside a hole.
* A Hole is defined as an area, in which a branch with increase_until_radius radius would collide with the wall. * A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* \param radius The radius of the node of interest * \param radius The radius of the node of interest
* \param layer_idx The layer of interest * \param layer_idx The layer of interest
* \param min_xy_dist Is the minimum xy distance used. * \param min_xy_dist Is the minimum xy distance used.
* \return Polygons object * \return Polygons object
*/ */
const Polygons& getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false); const Polygons& getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false) const;
/*! /*!
* \brief Provides the areas that have to be avoided by the tree's branches * \brief Provides the areas that have to be avoided by the tree's branches
@ -137,14 +271,14 @@ class TreeModelVolumes
* \param min_xy_dist is the minimum xy distance used. * \param min_xy_dist is the minimum xy distance used.
* \return Polygons object * \return Polygons object
*/ */
const Polygons& getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model = false, bool min_xy_dist = false); const Polygons& getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model = false, bool min_xy_dist = false) const;
/*! /*!
* \brief Provides the area represents all areas on the model where the branch does completely fit on the given layer. * \brief Provides the area represents all areas on the model where the branch does completely fit on the given layer.
* \param radius The radius of the node of interest * \param radius The radius of the node of interest
* \param layer_idx The layer of interest * \param layer_idx The layer of interest
* \return Polygons object * \return Polygons object
*/ */
const Polygons& getPlaceableAreas(coord_t radius, LayerIndex layer_idx); const Polygons& getPlaceableAreas(coord_t radius, LayerIndex layer_idx) const;
/*! /*!
* \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See calculateWallRestrictions for better description. * \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See calculateWallRestrictions for better description.
* \param radius The radius of the node of interest. * \param radius The radius of the node of interest.
@ -152,9 +286,9 @@ class TreeModelVolumes
* \param min_xy_dist is the minimum xy distance used. * \param min_xy_dist is the minimum xy distance used.
* \return Polygons object * \return Polygons object
*/ */
const Polygons& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist); const Polygons& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) const;
/*! /*!
* \brief Round \p radius upwards to either a multiple of radius_sample_resolution_ or a exponentially increasing value * \brief Round \p radius upwards to either a multiple of m_radius_sample_resolution or a exponentially increasing value
* *
* It also adds the difference between the minimum xy distance and the regular one. * It also adds the difference between the minimum xy distance and the regular one.
* *
@ -172,16 +306,17 @@ class TreeModelVolumes
*/ */
coord_t getRadiusNextCeil(coord_t radius, bool min_xy_dist) const; coord_t getRadiusNextCeil(coord_t radius, bool min_xy_dist) const;
private: private:
/*! /*!
* \brief Convenience typedef for the keys to the caches * \brief Convenience typedef for the keys to the caches
*/ */
using RadiusLayerPair = std::pair<coord_t, LayerIndex>; using RadiusLayerPair = std::pair<coord_t, LayerIndex>;
using RadiusLayerPolygonCache = std::unordered_map<RadiusLayerPair, Polygons, boost::hash<RadiusLayerPair>>;
friend std::optional<std::reference_wrapper<const Polygons>> getArea(const TreeModelVolumes::RadiusLayerPolygonCache &cache, const TreeModelVolumes::RadiusLayerPair &key);
/*! /*!
* \brief Round \p radius upwards to either a multiple of radius_sample_resolution_ or a exponentially increasing value * \brief Round \p radius upwards to either a multiple of m_radius_sample_resolution or a exponentially increasing value
* *
* \param radius The radius of the node of interest * \param radius The radius of the node of interest
*/ */
@ -193,7 +328,7 @@ class TreeModelVolumes
* \param layer_idx The layer which should be extracted from the mesh * \param layer_idx The layer which should be extracted from the mesh
* \return Polygons object representing the outline * \return Polygons object representing the outline
*/ */
Polygons extractOutlineFromMesh(const SliceMeshStorage& mesh, LayerIndex layer_idx) const; // Polygons extractOutlineFromMesh(const PrintObject &print_object, LayerIndex layer_idx) const;
/*! /*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer.
@ -219,7 +354,7 @@ class TreeModelVolumes
* *
* The result is a 2D area that would cause nodes of given radius to * The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole. Result is saved in the cache. * collide with the model or be inside a hole. Result is saved in the cache.
* A Hole is defined as an area, in which a branch with increase_until_radius radius would collide with the wall. * A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer. * \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*/ */
void calculateCollisionHolefree(std::deque<RadiusLayerPair> keys); void calculateCollisionHolefree(std::deque<RadiusLayerPair> keys);
@ -229,7 +364,7 @@ class TreeModelVolumes
* *
* The result is a 2D area that would cause nodes of given radius to * The result is a 2D area that would cause nodes of given radius to
* collide with the model or be inside a hole. Result is saved in the cache. * collide with the model or be inside a hole. Result is saved in the cache.
* A Hole is defined as an area, in which a branch with increase_until_radius radius would collide with the wall. * A Hole is defined as an area, in which a branch with m_increase_until_radius radius would collide with the wall.
* \param key RadiusLayerPairs the requested areas. The radius will be calculated up to the provided layer. * \param key RadiusLayerPairs the requested areas. The radius will be calculated up to the provided layer.
*/ */
void calculateCollisionHolefree(RadiusLayerPair key) void calculateCollisionHolefree(RadiusLayerPair key)
@ -237,7 +372,7 @@ class TreeModelVolumes
calculateCollisionHolefree(std::deque<RadiusLayerPair>{ RadiusLayerPair(key) }); calculateCollisionHolefree(std::deque<RadiusLayerPair>{ RadiusLayerPair(key) });
} }
Polygons safeOffset(const Polygons& me, coord_t distance, ClipperLib::JoinType jt, coord_t max_safe_step_distance, const Polygons& collision) const; static Polygons safeOffset(const Polygons& me, coord_t distance, ClipperLib::JoinType jt, coord_t max_safe_step_distance, const Polygons& collision);
/*! /*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model. * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model.
@ -316,14 +451,6 @@ class TreeModelVolumes
calculateWallRestrictions(std::deque<RadiusLayerPair>{ RadiusLayerPair(key) }); calculateWallRestrictions(std::deque<RadiusLayerPair>{ RadiusLayerPair(key) });
} }
/*!
* \brief Checks a cache for a given RadiusLayerPair and returns it if it is found
* \param key RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer.
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
*/
template <typename KEY>
const std::optional<std::reference_wrapper<const Polygons>> getArea(const std::unordered_map<KEY, Polygons>& cache, const KEY key) const;
bool checkSettingsEquality(const TreeSupportMeshGroupSettings& me, const TreeSupportMeshGroupSettings& other) const;
/*! /*!
* \brief Get the highest already calculated layer in the cache. * \brief Get the highest already calculated layer in the cache.
* \param radius The radius for which the highest already calculated layer has to be found. * \param radius The radius for which the highest already calculated layer has to be found.
@ -331,139 +458,130 @@ class TreeModelVolumes
* *
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found) * \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
*/ */
LayerIndex getMaxCalculatedLayer(coord_t radius, const std::unordered_map<RadiusLayerPair, Polygons>& map) const; LayerIndex getMaxCalculatedLayer(coord_t radius, const RadiusLayerPolygonCache& map) const;
Polygons calculateMachineBorderCollision(Polygon machine_border);
/*! /*!
* \brief The maximum distance that the center point of a tree branch may move in consecutive layers if it has to avoid the model. * \brief The maximum distance that the center point of a tree branch may move in consecutive layers if it has to avoid the model.
*/ */
coord_t max_move_; coord_t m_max_move;
/*! /*!
* \brief The maximum distance that the centre-point of a tree branch may * \brief The maximum distance that the centre-point of a tree branch may
* move in consecutive layers if it does not have to avoid the model * move in consecutive layers if it does not have to avoid the model
*/ */
coord_t max_move_slow_; coord_t m_max_move_slow;
/*! /*!
* \brief The smallest maximum resolution for simplify * \brief The smallest maximum resolution for simplify
*/ */
coord_t min_maximum_resolution_; coord_t m_min_resolution;
/*!
* \brief The smallest maximum deviation for simplify bool m_precalculated = false;
*/
coord_t min_maximum_deviation_;
/*!
* \brief Whether the precalculate was called, meaning every required value should be cached.
*/
bool precalculated = false;
/*! /*!
* \brief The index to access the outline corresponding with the currently processing mesh * \brief The index to access the outline corresponding with the currently processing mesh
*/ */
size_t current_outline_idx; size_t m_current_outline_idx;
/*! /*!
* \brief The minimum required clearance between the model and the tree branches * \brief The minimum required clearance between the model and the tree branches
*/ */
coord_t current_min_xy_dist; coord_t m_current_min_xy_dist;
/*! /*!
* \brief The difference between the minimum required clearance between the model and the tree branches and the regular one. * \brief The difference between the minimum required clearance between the model and the tree branches and the regular one.
*/ */
coord_t current_min_xy_dist_delta; coord_t m_current_min_xy_dist_delta;
/*! /*!
* \brief Does at least one mesh allow support to rest on a model. * \brief Does at least one mesh allow support to rest on a model.
*/ */
bool support_rests_on_model; bool m_support_rests_on_model;
/*! /*!
* \brief The progress of the precalculate function for communicating it to the progress bar. * \brief The progress of the precalculate function for communicating it to the progress bar.
*/ */
coord_t precalculation_progress = 0; coord_t m_precalculation_progress = 0;
/*! /*!
* \brief The progress multiplier of all values added progress bar. * \brief The progress multiplier of all values added progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times * Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/ */
double progress_multiplier; double m_progress_multiplier;
/*! /*!
* \brief The progress offset added to all values communicated to the progress bar. * \brief The progress offset added to all values communicated to the progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times * Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/ */
double progress_offset; double m_progress_offset;
/*! /*!
* \brief Increase radius in the resulting drawn branches, even if the avoidance does not allow it. Will be cut later to still fit. * \brief Increase radius in the resulting drawn branches, even if the avoidance does not allow it. Will be cut later to still fit.
*/ */
coord_t increase_until_radius; coord_t m_increase_until_radius;
/*! /*!
* \brief Polygons representing the limits of the printable area of the * \brief Polygons representing the limits of the printable area of the
* machine * machine
*/ */
Polygons machine_border_; Polygons m_machine_border;
/*! /*!
* \brief Storage for layer outlines and the corresponding settings of the meshes grouped by meshes with identical setting. * \brief Storage for layer outlines and the corresponding settings of the meshes grouped by meshes with identical setting.
*/ */
std::vector<std::pair<TreeSupportMeshGroupSettings, std::vector<Polygons>>> layer_outlines_; std::vector<std::pair<TreeSupportMeshGroupSettings, std::vector<Polygons>>> m_layer_outlines;
/*! /*!
* \brief Storage for areas that should be avoided, like support blocker or previous generated trees. * \brief Storage for areas that should be avoided, like support blocker or previous generated trees.
*/ */
std::vector<Polygons> anti_overhang_; std::vector<Polygons> m_anti_overhang;
/*! /*!
* \brief Radii that can be ignored by ceilRadius as they will never be requested. * \brief Radii that can be ignored by ceilRadius as they will never be requested.
*/ */
std::unordered_set<coord_t> ignorable_radii_; std::unordered_set<coord_t> m_ignorable_radii;
/*! /*!
* \brief Smallest radius a branch can have. This is the radius of a SupportElement with DTT=0. * \brief Smallest radius a branch can have. This is the radius of a SupportElement with DTT=0.
*/ */
coord_t radius_0; coord_t m_radius_0;
/*! /*!
* \brief Caches for the collision, avoidance and areas on the model where support can be placed safely * \brief Caches for the collision, avoidance and areas on the model where support can be placed safely
* at given radius and layer indices. * at given radius and layer indices.
*
* These are mutable to allow modification from const function. This is
* generally considered OK as the functions are still logically const
* (ie there is no difference in behaviour for the user between
* calculating the values each time vs caching the results).
*/ */
mutable std::unordered_map<RadiusLayerPair, Polygons> collision_cache_; RadiusLayerPolygonCache m_collision_cache;
std::unique_ptr<std::mutex> critical_collision_cache_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_collision_cache { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> collision_cache_holefree_; RadiusLayerPolygonCache m_collision_cache_holefree;
std::unique_ptr<std::mutex> critical_collision_cache_holefree_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_collision_cache_holefree { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_; RadiusLayerPolygonCache m_avoidance_cache;
std::unique_ptr<std::mutex> critical_avoidance_cache_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_slow_; RadiusLayerPolygonCache m_avoidance_cache_slow;
std::unique_ptr<std::mutex> critical_avoidance_cache_slow_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache_slow { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_to_model_; RadiusLayerPolygonCache m_avoidance_cache_to_model;
std::unique_ptr<std::mutex> critical_avoidance_cache_to_model_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache_to_model { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_to_model_slow_; RadiusLayerPolygonCache m_avoidance_cache_to_model_slow;
std::unique_ptr<std::mutex> critical_avoidance_cache_to_model_slow_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache_to_model_slow { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> placeable_areas_cache_;
std::unique_ptr<std::mutex> critical_placeable_areas_cache_ = std::make_unique<std::mutex>();
RadiusLayerPolygonCache m_placeable_areas_cache;
std::unique_ptr<std::mutex> m_critical_placeable_areas_cache { std::make_unique<std::mutex>() };
/*! /*!
* \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes. Also called safe avoidances, as they are safe regarding not running into holes. * \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes.
* Also called safe avoidances, as they are safe regarding not running into holes.
*/ */
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_hole_; RadiusLayerPolygonCache m_avoidance_cache_hole;
std::unique_ptr<std::mutex> critical_avoidance_cache_holefree_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache_holefree { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> avoidance_cache_hole_to_model_; RadiusLayerPolygonCache m_avoidance_cache_hole_to_model;
std::unique_ptr<std::mutex> critical_avoidance_cache_holefree_to_model_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_avoidance_cache_holefree_to_model { std::make_unique<std::mutex>() };
/*! /*!
* \brief Caches to represent walls not allowed to be passed over. * \brief Caches to represent walls not allowed to be passed over.
*/ */
mutable std::unordered_map<RadiusLayerPair, Polygons> wall_restrictions_cache_; RadiusLayerPolygonCache m_wall_restrictions_cache;
std::unique_ptr<std::mutex> critical_wall_restrictions_cache_ = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_wall_restrictions_cache { std::make_unique<std::mutex>() };
mutable std::unordered_map<RadiusLayerPair, Polygons> wall_restrictions_cache_min_; // A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer) is much smaller when min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall restriction would be slower. // A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer)
std::unique_ptr<std::mutex> critical_wall_restrictions_cache_min_ = std::make_unique<std::mutex>(); // is much smaller when min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall
// restriction would be slower.
RadiusLayerPolygonCache m_wall_restrictions_cache_min;
std::unique_ptr<std::mutex> m_critical_wall_restrictions_cache_min = std::make_unique<std::mutex>();
std::unique_ptr<std::mutex> critical_progress = std::make_unique<std::mutex>(); std::unique_ptr<std::mutex> m_critical_progress { std::make_unique<std::mutex>() };
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#define slic3r_TreeSupport_hpp #define slic3r_TreeSupport_hpp
#include "TreeModelVolumes.hpp" #include "TreeModelVolumes.hpp"
#include "Point.hpp"
#include <boost/functional/hash.hpp> // For combining hashes #include <boost/functional/hash.hpp> // For combining hashes
@ -17,6 +18,7 @@
#define SUPPORT_TREE_CIRCLE_RESOLUTION 25 // The number of vertices in each circle. #define SUPPORT_TREE_CIRCLE_RESOLUTION 25 // The number of vertices in each circle.
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
// The various stages of the process can be weighted differently in the progress bar. // The various stages of the process can be weighted differently in the progress bar.
// These weights are obtained experimentally using a small sample size. Sensible weights can differ drastically based on the assumed default settings and model. // These weights are obtained experimentally using a small sample size. Sensible weights can differ drastically based on the assumed default settings and model.
#define TREE_PROGRESS_TOTAL 10000 #define TREE_PROGRESS_TOTAL 10000
@ -25,10 +27,10 @@
#define TREE_PROGRESS_GENERATE_NODES TREE_PROGRESS_TOTAL * 0.1 #define TREE_PROGRESS_GENERATE_NODES TREE_PROGRESS_TOTAL * 0.1
#define TREE_PROGRESS_AREA_CALC TREE_PROGRESS_TOTAL * 0.3 #define TREE_PROGRESS_AREA_CALC TREE_PROGRESS_TOTAL * 0.3
#define TREE_PROGRESS_DRAW_AREAS TREE_PROGRESS_TOTAL * 0.1 #define TREE_PROGRESS_DRAW_AREAS TREE_PROGRESS_TOTAL * 0.1
#define TREE_PROGRESS_GENERATE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 #define TREE_PROGRESS_GENERATE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
#define TREE_PROGRESS_SMOOTH_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 #define TREE_PROGRESS_SMOOTH_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
#define TREE_PROGRESS_FINALIZE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 #define TREE_PROGRESS_FINALIZE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
#endif // SLIC3R_TREESUPPORTS_PROGRESS
#define SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL false #define SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL false
#define SUPPORT_TREE_AVOID_SUPPORT_BLOCKER true #define SUPPORT_TREE_AVOID_SUPPORT_BLOCKER true
@ -38,16 +40,15 @@
#define SUPPORT_TREE_PRE_EXPONENTIAL_STEPS 1 #define SUPPORT_TREE_PRE_EXPONENTIAL_STEPS 1
#define SUPPORT_TREE_COLLISION_RESOLUTION 500 // Only has an effect if SUPPORT_TREE_USE_EXPONENTIAL_COLLISION_RESOLUTION is false #define SUPPORT_TREE_COLLISION_RESOLUTION 500 // Only has an effect if SUPPORT_TREE_USE_EXPONENTIAL_COLLISION_RESOLUTION is false
#define SUPPORT_TREE_MAX_DEVIATION 0
namespace Slic3r namespace Slic3r
{ {
using LayerIndex = size_t; using LayerIndex = size_t;
//FIXME //FIXME
class SierpinskiFillProvider; class Print;
class PrintObject;
class SliceDataStorage;
/*! /*!
* \brief Generates a tree structure to support your models. * \brief Generates a tree structure to support your models.
@ -68,10 +69,8 @@ class TreeSupport
/*! /*!
* \brief Creates an instance of the tree support generator. * \brief Creates an instance of the tree support generator.
*
* \param storage The data storage to get global settings from.
*/ */
TreeSupport(const SliceDataStorage& storage); TreeSupport();
/*! /*!
* \brief Create the areas that need support. * \brief Create the areas that need support.
@ -80,7 +79,7 @@ class TreeSupport
* \param storage The data storage where the mesh data is gotten from and * \param storage The data storage where the mesh data is gotten from and
* where the resulting support areas are stored. * where the resulting support areas are stored.
*/ */
void generateSupportAreas(SliceDataStorage& storage); void generateSupportAreas(Print &print, const BuildVolume &build_volume, std::vector<size_t>& print_object_ids);
//todo Remove! Only relevant for public BETA! //todo Remove! Only relevant for public BETA!
@ -92,29 +91,28 @@ class TreeSupport
struct AreaIncreaseSettings struct AreaIncreaseSettings
{ {
AreaIncreaseSettings() : type(AvoidanceType::FAST), increase_speed(0), increase_radius(false), no_error(false), use_min_distance(false), move(false) AvoidanceType type { AvoidanceType::FAST };
{ coord_t increase_speed { 0 };
} bool increase_radius { false };
bool no_error { false };
AreaIncreaseSettings(AvoidanceType type, coord_t increase_speed, bool increase_radius, bool simplify, bool use_min_distance, bool move) : type(type), increase_speed(increase_speed), increase_radius(increase_radius), no_error(simplify), use_min_distance(use_min_distance), move(move) bool use_min_distance { false };
{ bool move { false };
}
AvoidanceType type;
coord_t increase_speed;
bool increase_radius;
bool no_error;
bool use_min_distance;
bool move;
bool operator==(const AreaIncreaseSettings& other) const bool operator==(const AreaIncreaseSettings& other) const
{ {
return increase_radius == other.increase_radius && increase_speed == other.increase_speed && type == other.type && no_error == other.no_error && use_min_distance == other.use_min_distance && move == other.move; return increase_radius == other.increase_radius && increase_speed == other.increase_speed && type == other.type &&
no_error == other.no_error && use_min_distance == other.use_min_distance && move == other.move;
} }
}; };
struct SupportElement struct SupportElement
{ {
SupportElement(coord_t distance_to_top, size_t target_height, Point target_position, bool to_buildplate, bool to_model_gracious, bool use_min_xy_dist, size_t dont_move_until, bool supports_roof, bool can_use_safe_radius, bool force_tips_to_roof, bool skip_ovalisation) : target_height(target_height), target_position(target_position), next_position(target_position), next_height(target_height), effective_radius_height(distance_to_top), to_buildplate(to_buildplate), distance_to_top(distance_to_top), area(nullptr), result_on_layer(target_position), increased_to_model_radius(0), to_model_gracious(to_model_gracious), elephant_foot_increases(0), use_min_xy_dist(use_min_xy_dist), supports_roof(supports_roof), dont_move_until(dont_move_until), can_use_safe_radius(can_use_safe_radius), last_area_increase(AreaIncreaseSettings(AvoidanceType::FAST, 0, false, false, false, false)), missing_roof_layers(force_tips_to_roof ? dont_move_until : 0), skip_ovalisation(skip_ovalisation) SupportElement(
coord_t distance_to_top, size_t target_height, Point target_position, bool to_buildplate, bool to_model_gracious, bool use_min_xy_dist, size_t dont_move_until,
bool supports_roof, bool can_use_safe_radius, bool force_tips_to_roof, bool skip_ovalisation) :
target_height(target_height), target_position(target_position), next_position(target_position), next_height(target_height), effective_radius_height(distance_to_top),
to_buildplate(to_buildplate), distance_to_top(distance_to_top), area(nullptr), result_on_layer(target_position), increased_to_model_radius(0), to_model_gracious(to_model_gracious),
elephant_foot_increases(0), use_min_xy_dist(use_min_xy_dist), supports_roof(supports_roof), dont_move_until(dont_move_until), can_use_safe_radius(can_use_safe_radius),
last_area_increase(AreaIncreaseSettings{ AvoidanceType::FAST, 0, false, false, false, false }), missing_roof_layers(force_tips_to_roof ? dont_move_until : 0), skip_ovalisation(skip_ovalisation)
{ {
} }
@ -205,7 +203,13 @@ class TreeSupport
// set last settings to the best out of both parents. If this is wrong, it will only cause a small performance penalty instead of weird behavior. // set last settings to the best out of both parents. If this is wrong, it will only cause a small performance penalty instead of weird behavior.
last_area_increase = AreaIncreaseSettings(std::min(first.last_area_increase.type, second.last_area_increase.type), std::min(first.last_area_increase.increase_speed, second.last_area_increase.increase_speed), first.last_area_increase.increase_radius || second.last_area_increase.increase_radius, first.last_area_increase.no_error || second.last_area_increase.no_error, first.last_area_increase.use_min_distance && second.last_area_increase.use_min_distance, first.last_area_increase.move || second.last_area_increase.move); last_area_increase = {
std::min(first.last_area_increase.type, second.last_area_increase.type),
std::min(first.last_area_increase.increase_speed, second.last_area_increase.increase_speed),
first.last_area_increase.increase_radius || second.last_area_increase.increase_radius,
first.last_area_increase.no_error || second.last_area_increase.no_error,
first.last_area_increase.use_min_distance && second.last_area_increase.use_min_distance,
first.last_area_increase.move || second.last_area_increase.move };
} }
/*! /*!
@ -326,10 +330,7 @@ class TreeSupport
if (*this == other) if (*this == other)
return false; return false;
if (other.target_height != target_height) if (other.target_height != target_height)
{
return other.target_height < target_height; return other.target_height < target_height;
}
return other.target_position.x() == target_position.x() ? other.target_position.y() < target_position.y() : other.target_position.x() < target_position.x(); return other.target_position.x() == target_position.x() ? other.target_position.y() < target_position.y() : other.target_position.x() < target_position.x();
} }
@ -379,11 +380,10 @@ class TreeSupport
roof_pattern(mesh_group_settings.support_roof_pattern), roof_pattern(mesh_group_settings.support_roof_pattern),
support_pattern(mesh_group_settings.support_pattern), support_pattern(mesh_group_settings.support_pattern),
support_roof_line_width(mesh_group_settings.support_roof_line_width), support_roof_line_width(mesh_group_settings.support_roof_line_width),
support_line_distance(mesh_group_settings.support_line_distance), support_line_spacing(mesh_group_settings.support_line_spacing),
support_bottom_offset(mesh_group_settings.support_bottom_offset), support_bottom_offset(mesh_group_settings.support_bottom_offset),
support_wall_count(mesh_group_settings.support_wall_count), support_wall_count(mesh_group_settings.support_wall_count),
maximum_deviation(mesh_group_settings.meshfix_maximum_deviation), resolution(mesh_group_settings.resolution),
maximum_resolution(mesh_group_settings.meshfix_maximum_resolution),
support_roof_line_distance(mesh_group_settings.support_roof_line_distance), // in the end the actual infill has to be calculated to subtract interface from support areas according to interface_preference. support_roof_line_distance(mesh_group_settings.support_roof_line_distance), // in the end the actual infill has to be calculated to subtract interface from support areas according to interface_preference.
settings(mesh_group_settings), settings(mesh_group_settings),
min_feature_size(mesh_group_settings.min_feature_size) min_feature_size(mesh_group_settings.min_feature_size)
@ -406,30 +406,22 @@ class TreeSupport
if (angles.empty()) if (angles.empty())
{ {
if (pattern == SupportMaterialInterfacePattern::smipConcentric) if (pattern == SupportMaterialInterfacePattern::smipConcentric)
{
angles.push_back(0); // Concentric has no rotation. angles.push_back(0); // Concentric has no rotation.
}
/* /*
else if (pattern == SupportMaterialInterfacePattern::TRIANGLES) else if (pattern == SupportMaterialInterfacePattern::TRIANGLES)
{
angles.push_back(90); // Triangular support interface shouldn't alternate every layer. angles.push_back(90); // Triangular support interface shouldn't alternate every layer.
}
*/ */
else else {
{ if (TreeSupportSettings::some_model_contains_thick_roof) {
if (TreeSupportSettings::some_model_contains_thick_roof)
{
// Some roofs are quite thick. // Some roofs are quite thick.
// Alternate between the two kinds of diagonal: / and \ . // Alternate between the two kinds of diagonal: / and \ .
angles.push_back(M_PI / 4.); angles.push_back(M_PI / 4.);
angles.push_back(3. * M_PI / 4.); angles.push_back(3. * M_PI / 4.);
} }
if (angles.empty()) if (angles.empty())
{
angles.push_back(M_PI / 2.); // Perpendicular to support lines. angles.push_back(M_PI / 2.); // Perpendicular to support lines.
} }
} }
}
}; };
//getInterfaceAngles(support_infill_angles, support_pattern); //getInterfaceAngles(support_infill_angles, support_pattern);
@ -437,7 +429,9 @@ class TreeSupport
getInterfaceAngles(support_roof_angles, roof_pattern); getInterfaceAngles(support_roof_angles, roof_pattern);
// const std::unordered_map<std::string, InterfacePreference> interface_map = { { "support_area_overwrite_interface_area", InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE }, { "interface_area_overwrite_support_area", InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT }, { "support_lines_overwrite_interface_area", InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE }, { "interface_lines_overwrite_support_area", InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT }, { "nothing", InterfacePreference::NOTHING } }; // const std::unordered_map<std::string, InterfacePreference> interface_map = { { "support_area_overwrite_interface_area", InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE }, { "interface_area_overwrite_support_area", InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT }, { "support_lines_overwrite_interface_area", InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE }, { "interface_lines_overwrite_support_area", InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT }, { "nothing", InterfacePreference::NOTHING } };
// interface_preference = interface_map.at(mesh_group_settings.get<std::string>("support_interface_priority")); // interface_preference = interface_map.at(mesh_group_settings.get<std::string>("support_interface_priority"));
interface_preference = InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE; //FIXME this was the default
// interface_preference = InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE;
interface_preference = InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE;
} }
private: private:
@ -565,7 +559,7 @@ class TreeSupport
/*! /*!
* \brief Distance between support infill lines. * \brief Distance between support infill lines.
*/ */
coord_t support_line_distance; coord_t support_line_spacing;
/*! /*!
* \brief Offset applied to the support floor area. * \brief Offset applied to the support floor area.
*/ */
@ -577,11 +571,7 @@ class TreeSupport
/* /*
* \brief Maximum allowed deviation when simplifying. * \brief Maximum allowed deviation when simplifying.
*/ */
coord_t maximum_deviation; coord_t resolution;
/*
* \brief Maximum allowed resolution (length of a line segment) when simplifying. The resolution is higher when this variable is smaller => Minimum size a line segment may have.
*/
coord_t maximum_resolution;
/* /*
* \brief Distance between the lines of the roof. * \brief Distance between the lines of the roof.
*/ */
@ -607,10 +597,10 @@ class TreeSupport
return branch_radius == other.branch_radius && tip_layers == other.tip_layers && diameter_angle_scale_factor == other.diameter_angle_scale_factor && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius && diameter_scale_bp_radius == other.diameter_scale_bp_radius && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius. return branch_radius == other.branch_radius && tip_layers == other.tip_layers && diameter_angle_scale_factor == other.diameter_angle_scale_factor && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius && diameter_scale_bp_radius == other.diameter_scale_bp_radius && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius.
xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated. xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated.
support_rests_on_model == other.support_rests_on_model && increase_radius_until_layer == other.increase_radius_until_layer && min_dtt_to_model == other.min_dtt_to_model && max_to_model_radius_increase == other.max_to_model_radius_increase && maximum_move_distance == other.maximum_move_distance && maximum_move_distance_slow == other.maximum_move_distance_slow && z_distance_bottom_layers == other.z_distance_bottom_layers && support_line_width == other.support_line_width && support_rests_on_model == other.support_rests_on_model && increase_radius_until_layer == other.increase_radius_until_layer && min_dtt_to_model == other.min_dtt_to_model && max_to_model_radius_increase == other.max_to_model_radius_increase && maximum_move_distance == other.maximum_move_distance && maximum_move_distance_slow == other.maximum_move_distance_slow && z_distance_bottom_layers == other.z_distance_bottom_layers && support_line_width == other.support_line_width &&
support_xy_overrides_z == other.support_xy_overrides_z && support_line_distance == other.support_line_distance && support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless. support_xy_overrides_z == other.support_xy_overrides_z && support_line_spacing == other.support_line_spacing && support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless.
support_bottom_offset == other.support_bottom_offset && support_wall_count == other.support_wall_count && support_pattern == other.support_pattern && roof_pattern == other.roof_pattern && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless. support_bottom_offset == other.support_bottom_offset && support_wall_count == other.support_wall_count && support_pattern == other.support_pattern && roof_pattern == other.roof_pattern && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless.
support_roof_angles == other.support_roof_angles && support_infill_angles == other.support_infill_angles && increase_radius_until_radius == other.increase_radius_until_radius && support_bottom_layers == other.support_bottom_layers && layer_height == other.layer_height && z_distance_top_layers == other.z_distance_top_layers && maximum_deviation == other.maximum_deviation && // Infill generation depends on deviation and resolution. support_roof_angles == other.support_roof_angles && support_infill_angles == other.support_infill_angles && increase_radius_until_radius == other.increase_radius_until_radius && support_bottom_layers == other.support_bottom_layers && layer_height == other.layer_height && z_distance_top_layers == other.z_distance_top_layers && resolution == other.resolution && // Infill generation depends on deviation and resolution.
maximum_resolution == other.maximum_resolution && support_roof_line_distance == other.support_roof_line_distance && interface_preference == other.interface_preference support_roof_line_distance == other.support_roof_line_distance && interface_preference == other.interface_preference
&& min_feature_size == other.min_feature_size // interface_preference should be identical to ensure the tree will correctly interact with the roof. && min_feature_size == other.min_feature_size // interface_preference should be identical to ensure the tree will correctly interact with the roof.
// The infill class now wants the settings object and reads a lot of settings, and as the infill class is used to calculate support roof lines for interface-preference. Not all of these may be required to be identical, but as I am not sure, better safe than sorry // The infill class now wants the settings object and reads a lot of settings, and as the infill class is used to calculate support roof lines for interface-preference. Not all of these may be required to be identical, but as I am not sure, better safe than sorry
#if 0 #if 0
@ -712,108 +702,6 @@ class TreeSupport
}; };
private: private:
enum class LineStatus
{
INVALID,
TO_MODEL,
TO_MODEL_GRACIOUS,
TO_MODEL_GRACIOUS_SAFE,
TO_BP,
TO_BP_SAFE
};
using LineInformation = std::vector<std::pair<Point, TreeSupport::LineStatus>>;
/*!
* \brief Precalculates all avoidances, that could be required.
*
* \param storage[in] Background storage to access meshes.
* \param currently_processing_meshes[in] Indexes of all meshes that are processed in this iteration
*/
void precalculate(const SliceDataStorage& storage, std::vector<size_t> currently_processing_meshes);
/*!
* \brief Converts a Polygons object representing a line into the internal format.
*
* \param polylines[in] The Polyline that will be converted.
* \param layer_idx[in] The current layer.
* \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in.
*/
std::vector<LineInformation> convertLinesToInternal(Polygons polylines, LayerIndex layer_idx);
/*!
* \brief Converts lines in internal format into a Polygons object representing these lines.
*
* \param lines[in] The lines that will be converted.
* \return All lines of the \p lines object as a Polygons object.
*/
Polygons convertInternalToLines(std::vector<TreeSupport::LineInformation> lines);
/*!
* \brief Returns a function, evaluating if a point has to be added now. Required for a splitLines call in generateInitialAreas.
*
* \param current_layer[in] The layer on which the point lies
* \return A function that can be called to evaluate a point.
*/
std::function<bool(std::pair<Point, TreeSupport::LineStatus>)> getEvaluatePointForNextLayerFunction(size_t current_layer);
/*!
* \brief Evaluates which points of some lines are not valid one layer below and which are. Assumes all points are valid on the current layer. Validity is evaluated using supplied lambda.
*
* \param lines[in] The lines that have to be evaluated.
* \param evaluatePoint[in] The function used to evaluate the points.
* \return A pair with which points are still valid in the first slot and which are not in the second slot.
*/
std::pair<std::vector<LineInformation>, std::vector<LineInformation>> splitLines(std::vector<LineInformation> lines, std::function<bool(std::pair<Point, TreeSupport::LineStatus>)> evaluatePoint); // assumes all Points on the current line are valid
/*!
* \brief Eensures that every line segment is about distance in length. The resulting lines may differ from the original but all points are on the original
*
* \param input[in] The lines on which evenly spaced points should be placed.
* \param distance[in] The distance the points should be from each other.
* \param min_points[in] The amount of points that have to be placed. If not enough can be placed the distance will be reduced to place this many points.
* \return A Polygons object containing the evenly spaced points. Does not represent an area, more a collection of points on lines.
*/
Polygons ensureMaximumDistancePolyline(const Polygons& input, coord_t distance, size_t min_points) const;
/*!
* \brief Adds the implicit line from the last vertex of a Polygon to the first one.
*
* \param poly[in] The Polygons object, of which its lines should be extended.
* \return A Polygons object with implicit line from the last vertex of a Polygon to the first one added.
*/
Polygons toPolylines(const Polygons& poly) const;
/*!
* \brief Returns Polylines representing the (infill) lines that will result in slicing the given area
*
* \param area[in] The area that has to be filled with infill.
* \param roof[in] Whether the roofing or regular support settings should be used.
* \param layer_idx[in] The current layer index.
* \param support_infill_distance[in] The distance that should be between the infill lines.
* \param cross_fill_provider[in] A SierpinskiFillProvider required for cross infill.
*
* \return A Polygons object that represents the resulting infill lines.
*/
Polygons generateSupportInfillLines(const Polygons& area, bool roof, LayerIndex layer_idx, coord_t support_infill_distance, SierpinskiFillProvider* cross_fill_provider = nullptr, bool include_walls = false);
/*!
* \brief Unions two Polygons. Ensures that if the input is non empty that the output also will be non empty.
* \param first[in] The first Polygon.
* \param second[in] The second Polygon.
* \return The union of both Polygons
*/
[[nodiscard]] Polygons safeUnion(const Polygons first, const Polygons second = Polygons()) const;
/*!
* \brief Creates a valid CrossInfillProvider
* Based on AreaSupport::precomputeCrossInfillTree, but calculates for each mesh separately
* \param mesh[in] The mesh that is currently processed.
* \param line_distance[in] The distance between the infill lines of the resulting infill
* \param line_width[in] What is the width of a line used in the infill.
* \return A valid CrossInfillProvider. Has to be freed manually to avoid a memory leak.
*/
SierpinskiFillProvider* generateCrossFillProvider(const SliceMeshStorage& mesh, coord_t line_distance, coord_t line_width);
/*! /*!
* \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang. * \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang.
* *
@ -823,53 +711,7 @@ class TreeSupport
* \param move_bounds[out] Storage for the influence areas. * \param move_bounds[out] Storage for the influence areas.
* \param storage[in] Background storage, required for adding roofs. * \param storage[in] Background storage, required for adding roofs.
*/ */
void generateInitialAreas(const SliceMeshStorage& mesh, std::vector<std::set<SupportElement*>>& move_bounds, SliceDataStorage& storage); void generateInitialAreas(const PrintObject &print_object, std::vector<std::set<SupportElement*>> &move_bounds);
/*!
* \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle.
* \param me[in] Polygons object that has to be offset.
* \param distance[in] The distance by which me should be offset. Expects values >=0.
* \param collision[in] The area representing obstacles.
* \param last_step_offset_without_check[in] The most it is allowed to offset in one step.
* \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get very small. Required as arcTolerance is not exposed in offset, which should result with a similar result.
* \return The resulting Polygons object.
*/
[[nodiscard]] Polygons safeOffsetInc(const Polygons& me, coord_t distance, const Polygons& collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset) const;
/*!
* \brief Merges Influence Areas if possible.
*
* Branches which do overlap have to be merged. This helper merges all elements in input with the elements into reduced_new_layer.
* Elements in input_aabb are merged together if possible, while elements reduced_new_layer_aabb are not checked against each other.
*
* \param reduced_aabb[in,out] The already processed elements.
* \param input_aabb[in] Not yet processed elements
* \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate. Value is the influence area where the center of a circle of support may be placed.
* \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to.
* Value is the influence area where the center of a circle of support may be placed.
* \param influence_areas[in] The influence areas without avoidance removed.
* \param insert_bp_areas[out] Elements to be inserted into the main dictionary after the Helper terminates.
* \param insert_model_areas[out] Elements to be inserted into the secondary dictionary after the Helper terminates.
* \param insert_influence[out] Elements to be inserted into the dictionary containing the largest possibly valid influence area (ignoring if the area may not be there because of avoidance)
* \param erase[out] Elements that should be deleted from the above dictionaries.
* \param layer_idx[in] The Index of the current Layer.
*/
void mergeHelper(std::map<SupportElement, BoundingBox>& reduced_aabb, std::map<SupportElement, BoundingBox>& input_aabb, const std::unordered_map<SupportElement, Polygons>& to_bp_areas, const std::unordered_map<SupportElement, Polygons>& to_model_areas, const std::map<SupportElement, Polygons>& influence_areas, std::unordered_map<SupportElement, Polygons>& insert_bp_areas, std::unordered_map<SupportElement, Polygons>& insert_model_areas, std::unordered_map<SupportElement, Polygons>& insert_influence, std::vector<SupportElement>& erase, const LayerIndex layer_idx);
/*!
* \brief Merges Influence Areas if possible.
*
* Branches which do overlap have to be merged. This manages the helper and uses a divide and conquer approach to parallelize this problem. This parallelization can at most accelerate the merging by a factor of 2.
*
* \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate.
* Value is the influence area where the center of a circle of support may be placed.
* \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to.
* Value is the influence area where the center of a circle of support may be placed.
* \param influence_areas[in] The Elements of the current Layer without avoidances removed. This is the largest possible influence area for this layer.
* Value is the influence area where the center of a circle of support may be placed.
* \param layer_idx[in] The current layer.
*/
void mergeInfluenceAreas(std::unordered_map<SupportElement, Polygons>& to_bp_areas, std::unordered_map<SupportElement, Polygons>& to_model_areas, std::map<SupportElement, Polygons>& influence_areas, LayerIndex layer_idx);
/*! /*!
* \brief Checks if an influence area contains a valid subsection and returns the corresponding metadata and the new Influence area. * \brief Checks if an influence area contains a valid subsection and returns the corresponding metadata and the new Influence area.
@ -969,7 +811,6 @@ class TreeSupport
*/ */
void dropNonGraciousAreas(std::vector<std::unordered_map<SupportElement*, Polygons>>& layer_tree_polygons, const std::vector<std::pair<LayerIndex, SupportElement*>>& linear_data, std::vector<std::vector<std::pair<LayerIndex, Polygons>>>& dropped_down_areas, const std::map<SupportElement*, SupportElement*>& inverse_tree_order); void dropNonGraciousAreas(std::vector<std::unordered_map<SupportElement*, Polygons>>& layer_tree_polygons, const std::vector<std::pair<LayerIndex, SupportElement*>>& linear_data, std::vector<std::vector<std::pair<LayerIndex, Polygons>>>& dropped_down_areas, const std::map<SupportElement*, SupportElement*>& inverse_tree_order);
/*! /*!
* \brief Generates Support Floor, ensures Support Roof can not cut of branches, and saves the branches as support to storage * \brief Generates Support Floor, ensures Support Roof can not cut of branches, and saves the branches as support to storage
* *
@ -977,7 +818,7 @@ class TreeSupport
* \param support_roof_storage[in] Areas where support was replaced with roof. * \param support_roof_storage[in] Areas where support was replaced with roof.
* \param storage[in,out] The storage where the support should be stored. * \param storage[in,out] The storage where the support should be stored.
*/ */
void finalizeInterfaceAndSupportAreas(std::vector<Polygons>& support_layer_storage, std::vector<Polygons>& support_roof_storage, SliceDataStorage& storage); void finalizeInterfaceAndSupportAreas(const PrintObject &print_object, std::vector<Polygons>& support_layer_storage, std::vector<Polygons>& support_roof_storage);
/*! /*!
* \brief Draws circles around result_on_layer points of the influence areas and applies some post processing. * \brief Draws circles around result_on_layer points of the influence areas and applies some post processing.
@ -985,36 +826,36 @@ class TreeSupport
* \param move_bounds[in] All currently existing influence areas * \param move_bounds[in] All currently existing influence areas
* \param storage[in,out] The storage where the support should be stored. * \param storage[in,out] The storage where the support should be stored.
*/ */
void drawAreas(std::vector<std::set<SupportElement*>>& move_bounds, SliceDataStorage& storage); void drawAreas(PrintObject &print_object, std::vector<std::set<SupportElement*>>& move_bounds);
/*! /*!
* \brief Settings with the indexes of meshes that use these settings. * \brief Settings with the indexes of meshes that use these settings.
* *
*/ */
std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> grouped_meshes; std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> m_grouped_meshes;
/*! /*!
* \brief Generator for model collision, avoidance and internal guide volumes. * \brief Generator for model collision, avoidance and internal guide volumes.
* *
*/ */
TreeModelVolumes volumes_; TreeModelVolumes m_volumes;
/*! /*!
* \brief Contains config settings to avoid loading them in every function. This was done to improve readability of the code. * \brief Contains config settings to avoid loading them in every function. This was done to improve readability of the code.
*/ */
TreeSupportSettings config; TreeSupportSettings m_config;
/*! /*!
* \brief The progress multiplier of all values added progress bar. * \brief The progress multiplier of all values added progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times * Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/ */
double progress_multiplier = 1; double m_progress_multiplier = 1;
/*! /*!
* \brief The progress offset added to all values communicated to the progress bar. * \brief The progress offset added to all values communicated to the progress bar.
* Required for the progress bar the behave as expected when areas have to be calculated multiple times * Required for the progress bar the behave as expected when areas have to be calculated multiple times
*/ */
double progress_offset = 0; double m_progress_offset = 0;
}; };
@ -1027,7 +868,7 @@ struct hash<Slic3r::TreeSupport::SupportElement>
{ {
size_t operator()(const Slic3r::TreeSupport::SupportElement& node) const size_t operator()(const Slic3r::TreeSupport::SupportElement& node) const
{ {
size_t hash_node = hash<Slic3r::Point>()(node.target_position); size_t hash_node = Slic3r::PointHash{}(node.target_position);
boost::hash_combine(hash_node, size_t(node.target_height)); boost::hash_combine(hash_node, size_t(node.target_height));
return hash_node; return hash_node;
} }