Supports refactoring: Split FFF supports into multiple files,

enclosed into namespaces.
This commit is contained in:
Vojtech Bubnik 2023-05-05 12:59:01 +02:00
parent cc938e7549
commit a236351fd3
11 changed files with 2259 additions and 2072 deletions

View File

@ -276,7 +276,12 @@ set(SLIC3R_SOURCES
SlicingAdaptive.hpp SlicingAdaptive.hpp
Subdivide.cpp Subdivide.cpp
Subdivide.hpp Subdivide.hpp
Support/SupportCommon.cpp
Support/SupportCommon.hpp
Support/SupportDebug.cpp
Support/SupportDebug.hpp
Support/SupportLayer.hpp Support/SupportLayer.hpp
Support/SupportParameters.cpp
Support/SupportParameters.hpp Support/SupportParameters.hpp
SupportMaterial.cpp SupportMaterial.cpp
SupportMaterial.hpp SupportMaterial.hpp

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
#ifndef slic3r_SupportCommon_hpp_
#define slic3r_SupportCommon_hpp_
#include "../Polygon.hpp"
#include "SupportLayer.hpp"
#include "SupportParameters.hpp"
namespace Slic3r {
class PrintObject;
class SupportLayer;
namespace FFFSupport {
// Remove bridges from support contact areas.
// To be called if PrintObjectConfig::dont_support_bridges.
void remove_bridges_from_contacts(
const PrintConfig &print_config,
const Layer &lower_layer,
const LayerRegion &layerm,
float fw,
Polygons &contact_polygons);
// Generate raft layers, also expand the 1st support layer
// in case there is no raft layer to improve support adhesion.
SupportGeneratorLayersPtr generate_raft_base(
const PrintObject &object,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers,
const SupportGeneratorLayersPtr &base_layers,
SupportGeneratorLayerStorage &layer_storage);
// returns sorted layers
SupportGeneratorLayersPtr generate_support_layers(
PrintObject &object,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
// Produce the support G-code.
// Used by both classic and tree supports.
void generate_support_toolpaths(
SupportLayerPtrs &support_layers,
const PrintObjectConfig &config,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
// FN_HIGHER_EQUAL: the provided object pointer has a Z value >= of an internal threshold.
// Find the first item with Z value >= of an internal threshold of fn_higher_equal.
// If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size()
// If the initial idx is size_t(-1), then use binary search.
// Otherwise search linearly upwards.
template<typename IteratorType, typename IndexType, typename FN_HIGHER_EQUAL>
IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
{
auto size = int(end - begin);
if (size == 0) {
idx = 0;
} else if (idx == IndexType(-1)) {
// First of the batch of layers per thread pool invocation. Use binary search.
int idx_low = 0;
int idx_high = std::max(0, size - 1);
while (idx_low + 1 < idx_high) {
int idx_mid = (idx_low + idx_high) / 2;
if (fn_higher_equal(begin[idx_mid]))
idx_high = idx_mid;
else
idx_low = idx_mid;
}
idx = fn_higher_equal(begin[idx_low]) ? idx_low :
(fn_higher_equal(begin[idx_high]) ? idx_high : size);
} else {
// For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
while (int(idx) < size && ! fn_higher_equal(begin[idx]))
++ idx;
}
return idx;
}
template<typename T, typename IndexType, typename FN_HIGHER_EQUAL>
IndexType idx_higher_or_equal(const std::vector<T>& vec, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
{
return idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal);
}
// FN_LOWER_EQUAL: the provided object pointer has a Z value <= of an internal threshold.
// Find the first item with Z value <= of an internal threshold of fn_lower_equal.
// If no vec item with Z value <= of an internal threshold of fn_lower_equal is found, return -1.
// If the initial idx is < -1, then use binary search.
// Otherwise search linearly downwards.
template<typename IT, typename FN_LOWER_EQUAL>
int idx_lower_or_equal(IT begin, IT end, int idx, FN_LOWER_EQUAL fn_lower_equal)
{
auto size = int(end - begin);
if (size == 0) {
idx = -1;
} else if (idx < -1) {
// First of the batch of layers per thread pool invocation. Use binary search.
int idx_low = 0;
int idx_high = std::max(0, size - 1);
while (idx_low + 1 < idx_high) {
int idx_mid = (idx_low + idx_high) / 2;
if (fn_lower_equal(begin[idx_mid]))
idx_low = idx_mid;
else
idx_high = idx_mid;
}
idx = fn_lower_equal(begin[idx_high]) ? idx_high :
(fn_lower_equal(begin[idx_low ]) ? idx_low : -1);
} else {
// For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
while (idx >= 0 && ! fn_lower_equal(begin[idx]))
-- idx;
}
return idx;
}
template<typename T, typename FN_LOWER_EQUAL>
int idx_lower_or_equal(const std::vector<T*> &vec, int idx, FN_LOWER_EQUAL fn_lower_equal)
{
return idx_lower_or_equal(vec.begin(), vec.end(), idx, fn_lower_equal);
}
} // namespace FFFSupport
} // namespace Slic3r
#endif /* slic3r_SupportCommon_hpp_ */

View File

@ -0,0 +1,108 @@
#if 1 //#ifdef SLIC3R_DEBUG
#include "ClipperUtils.hpp"
#include "SVG.hpp"
#include "../Layer.hpp"
#include "SupportLayer.hpp"
namespace Slic3r::FFFSupport {
const char* support_surface_type_to_color_name(const SupporLayerType surface_type)
{
switch (surface_type) {
case SupporLayerType::TopContact: return "rgb(255,0,0)"; // "red";
case SupporLayerType::TopInterface: return "rgb(0,255,0)"; // "green";
case SupporLayerType::Base: return "rgb(0,0,255)"; // "blue";
case SupporLayerType::BottomInterface:return "rgb(255,255,128)"; // yellow
case SupporLayerType::BottomContact: return "rgb(255,0,255)"; // magenta
case SupporLayerType::RaftInterface: return "rgb(0,255,255)";
case SupporLayerType::RaftBase: return "rgb(128,128,128)";
case SupporLayerType::Unknown: return "rgb(128,0,0)"; // maroon
default: return "rgb(64,64,64)";
};
}
Point export_support_surface_type_legend_to_svg_box_size()
{
return Point(scale_(1.+10.*8.), scale_(3.));
}
void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos)
{
// 1st row
coord_t pos_x0 = pos(0) + scale_(1.);
coord_t pos_x = pos_x0;
coord_t pos_y = pos(1) + scale_(1.5);
coord_t step_x = scale_(10.);
svg.draw_legend(Point(pos_x, pos_y), "top contact" , support_surface_type_to_color_name(SupporLayerType::TopContact));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "top iface" , support_surface_type_to_color_name(SupporLayerType::TopInterface));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "base" , support_surface_type_to_color_name(SupporLayerType::Base));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "bottom iface" , support_surface_type_to_color_name(SupporLayerType::BottomInterface));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "bottom contact" , support_surface_type_to_color_name(SupporLayerType::BottomContact));
// 2nd row
pos_x = pos_x0;
pos_y = pos(1)+scale_(2.8);
svg.draw_legend(Point(pos_x, pos_y), "raft interface" , support_surface_type_to_color_name(SupporLayerType::RaftInterface));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "raft base" , support_surface_type_to_color_name(SupporLayerType::RaftBase));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "unknown" , support_surface_type_to_color_name(SupporLayerType::Unknown));
pos_x += step_x;
svg.draw_legend(Point(pos_x, pos_y), "intermediate" , support_surface_type_to_color_name(SupporLayerType::Intermediate));
}
void export_print_z_polygons_to_svg(const char *path, SupportGeneratorLayer ** const layers, int n_layers)
{
BoundingBox bbox;
for (int i = 0; i < n_layers; ++ i)
bbox.merge(get_extents(layers[i]->polygons));
Point legend_size = export_support_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (int i = 0; i < n_layers; ++ i)
svg.draw(union_ex(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type), transparency);
for (int i = 0; i < n_layers; ++ i)
svg.draw(to_polylines(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type));
export_support_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
void export_print_z_polygons_and_extrusions_to_svg(
const char *path,
SupportGeneratorLayer ** const layers,
int n_layers,
SupportLayer &support_layer)
{
BoundingBox bbox;
for (int i = 0; i < n_layers; ++ i)
bbox.merge(get_extents(layers[i]->polygons));
Point legend_size = export_support_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (int i = 0; i < n_layers; ++ i)
svg.draw(union_ex(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type), transparency);
for (int i = 0; i < n_layers; ++ i)
svg.draw(to_polylines(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type));
Polygons polygons_support, polygons_interface;
support_layer.support_fills.polygons_covered_by_width(polygons_support, float(SCALED_EPSILON));
// support_layer.support_interface_fills.polygons_covered_by_width(polygons_interface, SCALED_EPSILON);
svg.draw(union_ex(polygons_support), "brown");
svg.draw(union_ex(polygons_interface), "black");
export_support_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
} // namespace Slic3r
#endif /* SLIC3R_DEBUG */

View File

@ -0,0 +1,18 @@
#ifndef slic3r_SupportCommon_hpp_
#define slic3r_SupportCommon_hpp_
namespace Slic3r {
class SupportGeneratorLayer;
class SupportLayer;
namespace FFFSupport {
void export_print_z_polygons_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers);
void export_print_z_polygons_and_extrusions_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers, SupportLayer& support_layer);
} // namespace FFFSupport
} // namespace Slic3r
#endif /* slic3r_SupportCommon_hpp_ */

View File

@ -3,8 +3,10 @@
#include <oneapi/tbb/scalable_allocator.h> #include <oneapi/tbb/scalable_allocator.h>
#include <oneapi/tbb/spin_mutex.h> #include <oneapi/tbb/spin_mutex.h>
// for Slic3r::deque
#include "../libslic3r.h"
namespace Slic3r { namespace Slic3r::FFFSupport {
// Support layer type to be used by SupportGeneratorLayer. This type carries a much more detailed information // Support layer type to be used by SupportGeneratorLayer. This type carries a much more detailed information
// about the support layer type than the final support layers stored in a PrintObject. // about the support layer type than the final support layers stored in a PrintObject.
@ -111,18 +113,30 @@ public:
// Layers are allocated and owned by a deque. Once a layer is allocated, it is maintained // Layers are allocated and owned by a deque. Once a layer is allocated, it is maintained
// up to the end of a generate() method. The layer storage may be replaced by an allocator class in the future, // up to the end of a generate() method. The layer storage may be replaced by an allocator class in the future,
// which would allocate layers by multiple chunks. // which would allocate layers by multiple chunks.
#if 0
class SupportGeneratorLayerStorage { class SupportGeneratorLayerStorage {
public: public:
SupportGeneratorLayer& allocate_unguarded(SupporLayerType layer_type) {
m_storage.emplace_back();
m_storage.back().layer_type = layer_type;
return m_storage.back();
}
SupportGeneratorLayer& allocate(SupporLayerType layer_type)
{
m_mutex.lock();
m_storage.emplace_back();
SupportGeneratorLayer *layer_new = &m_storage.back();
m_mutex.unlock();
layer_new->layer_type = layer_type;
return *layer_new;
}
private: private:
template<typename BaseType> template<typename BaseType>
using Allocator = tbb::scalable_allocator<BaseType>; using Allocator = tbb::scalable_allocator<BaseType>;
Slic3r::deque<SupportGeneratorLayer, Allocator<SupportGeneratorLayer>> m_data; Slic3r::deque<SupportGeneratorLayer, Allocator<SupportGeneratorLayer>> m_storage;
tbb::spin_mutex m_mutex; tbb::spin_mutex m_mutex;
}; };
#else
#endif
using SupportGeneratorLayerStorage = std::deque<SupportGeneratorLayer>;
using SupportGeneratorLayersPtr = std::vector<SupportGeneratorLayer*>; using SupportGeneratorLayersPtr = std::vector<SupportGeneratorLayer*>;
} // namespace Slic3r } // namespace Slic3r

View File

@ -0,0 +1,116 @@
#include "../Print.hpp"
#include "../PrintConfig.hpp"
#include "../Slicing.hpp"
#include "SupportParameters.hpp"
namespace Slic3r::FFFSupport {
SupportParameters::SupportParameters(const PrintObject &object)
{
const PrintConfig &print_config = object.print()->config();
const PrintObjectConfig &object_config = object.config();
const SlicingParameters &slicing_params = object.slicing_parameters();
this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height));
this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height));
this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height));
this->raft_interface_flow = support_material_interface_flow;
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
this->support_layer_height_min = scaled<coord_t>(0.01);
for (auto lh : print_config.min_layer_height.values)
this->support_layer_height_min = std::min(this->support_layer_height_min, std::max(0.01, lh));
for (auto layer : object.layers())
this->support_layer_height_min = std::min(this->support_layer_height_min, std::max(0.01, layer->height));
if (object_config.support_material_interface_layers.value == 0) {
// No interface layers allowed, print everything with the base support pattern.
this->support_material_interface_flow = this->support_material_flow;
}
// Evaluate the XY gap between the object outer perimeters and the support structures.
// Evaluate the XY gap between the object outer perimeters and the support structures.
coordf_t external_perimeter_width = 0.;
coordf_t bridge_flow_ratio = 0;
for (size_t region_id = 0; region_id < object.num_printing_regions(); ++ region_id) {
const PrintRegion &region = object.printing_region(region_id);
external_perimeter_width = std::max(external_perimeter_width, coordf_t(region.flow(object, frExternalPerimeter, slicing_params.layer_height).width()));
bridge_flow_ratio += region.config().bridge_flow_ratio;
}
this->gap_xy = object_config.support_material_xy_spacing.get_abs_value(external_perimeter_width);
bridge_flow_ratio /= object.num_printing_regions();
this->support_material_bottom_interface_flow = slicing_params.soluble_interface || ! object_config.thick_bridges ?
this->support_material_interface_flow.with_flow_ratio(bridge_flow_ratio) :
Flow::bridging_flow(bridge_flow_ratio * this->support_material_interface_flow.nozzle_diameter(), this->support_material_interface_flow.nozzle_diameter());
this->can_merge_support_regions = object_config.support_material_extruder.value == object_config.support_material_interface_extruder.value;
if (!this->can_merge_support_regions && (object_config.support_material_extruder.value == 0 || object_config.support_material_interface_extruder.value == 0)) {
// One of the support extruders is of "don't care" type.
auto object_extruders = object.object_extruders();
if (object_extruders.size() == 1 &&
*object_extruders.begin() == std::max<unsigned int>(object_config.support_material_extruder.value, object_config.support_material_interface_extruder.value))
// Object is printed with the same extruder as the support.
this->can_merge_support_regions = true;
}
double interface_spacing = object_config.support_material_interface_spacing.value + this->support_material_interface_flow.spacing();
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / interface_spacing);
double raft_interface_spacing = object_config.support_material_interface_spacing.value + this->raft_interface_flow.spacing();
this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing);
double support_spacing = object_config.support_material_spacing.value + this->support_material_flow.spacing();
this->support_density = std::min(1., this->support_material_flow.spacing() / support_spacing);
if (object_config.support_material_interface_layers.value == 0) {
// No interface layers allowed, print everything with the base support pattern.
this->interface_density = this->support_density;
}
SupportMaterialPattern support_pattern = object_config.support_material_pattern;
this->with_sheath = object_config.support_material_with_sheath;
this->base_fill_pattern =
support_pattern == smpHoneycomb ? ipHoneycomb :
this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase;
this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase;
this->contact_fill_pattern =
(object_config.support_material_interface_pattern == smipAuto && slicing_params.soluble_interface) ||
object_config.support_material_interface_pattern == smipConcentric ?
ipConcentric :
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
this->base_angle = Geometry::deg2rad(float(object_config.support_material_angle.value));
this->interface_angle = Geometry::deg2rad(float(object_config.support_material_angle.value + 90.));
this->raft_angle_1st_layer = 0.f;
this->raft_angle_base = 0.f;
this->raft_angle_interface = 0.f;
if (slicing_params.base_raft_layers > 1) {
assert(slicing_params.raft_layers() >= 4);
// There are all raft layer types (1st layer, base, interface & contact layers) available.
this->raft_angle_1st_layer = this->interface_angle;
this->raft_angle_base = this->base_angle;
this->raft_angle_interface = this->interface_angle;
if ((slicing_params.interface_raft_layers & 1) == 0)
// Allign the 1st raft interface layer so that the object 1st layer is hatched perpendicularly to the raft contact interface.
this->raft_angle_interface += float(0.5 * M_PI);
} else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) {
assert(slicing_params.raft_layers() == 2 || slicing_params.raft_layers() == 3);
// 1st layer, interface & contact layers available.
this->raft_angle_1st_layer = this->base_angle;
this->raft_angle_interface = this->interface_angle + 0.5 * M_PI;
} else if (slicing_params.interface_raft_layers == 1) {
// Only the contact raft layer is non-empty, which will be printed as the 1st layer.
assert(slicing_params.base_raft_layers == 0);
assert(slicing_params.interface_raft_layers == 1);
assert(slicing_params.raft_layers() == 1);
this->raft_angle_1st_layer = float(0.5 * M_PI);
this->raft_angle_interface = this->raft_angle_1st_layer;
} else {
// No raft.
assert(slicing_params.base_raft_layers == 0);
assert(slicing_params.interface_raft_layers == 0);
assert(slicing_params.raft_layers() == 0);
}
}
} // namespace Slic3r

View File

@ -9,6 +9,8 @@ namespace Slic3r {
class PrintObject; class PrintObject;
enum InfillPattern : int; enum InfillPattern : int;
namespace FFFSupport {
struct SupportParameters { struct SupportParameters {
SupportParameters(const PrintObject &object); SupportParameters(const PrintObject &object);
@ -61,6 +63,8 @@ struct SupportParameters {
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); } { return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
}; };
} // namespace FFFSupport
} // namespace Slic3r } // namespace Slic3r
#endif /* slic3r_SupportParameters_hpp_ */ #endif /* slic3r_SupportParameters_hpp_ */

File diff suppressed because it is too large Load Diff

View File

@ -12,54 +12,6 @@ namespace Slic3r {
class PrintObject; class PrintObject;
// Remove bridges from support contact areas.
// To be called if PrintObjectConfig::dont_support_bridges.
void remove_bridges_from_contacts(
const PrintConfig &print_config,
const Layer &lower_layer,
const LayerRegion &layerm,
float fw,
Polygons &contact_polygons);
// Generate raft layers, also expand the 1st support layer
// in case there is no raft layer to improve support adhesion.
SupportGeneratorLayersPtr generate_raft_base(
const PrintObject &object,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers,
const SupportGeneratorLayersPtr &base_layers,
SupportGeneratorLayerStorage &layer_storage);
// returns sorted layers
SupportGeneratorLayersPtr generate_support_layers(
PrintObject &object,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
// Produce the support G-code.
// Used by both classic and tree supports.
void generate_support_toolpaths(
SupportLayerPtrs &support_layers,
const PrintObjectConfig &config,
const SupportParameters &support_params,
const SlicingParameters &slicing_params,
const SupportGeneratorLayersPtr &raft_layers,
const SupportGeneratorLayersPtr &bottom_contacts,
const SupportGeneratorLayersPtr &top_contacts,
const SupportGeneratorLayersPtr &intermediate_layers,
const SupportGeneratorLayersPtr &interface_layers,
const SupportGeneratorLayersPtr &base_interface_layers);
void export_print_z_polygons_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers);
void export_print_z_polygons_and_extrusions_to_svg(const char *path, SupportGeneratorLayer ** const layers, size_t n_layers, SupportLayer& support_layer);
// This class manages raft and supports for a single PrintObject. // This class manages raft and supports for a single PrintObject.
// Instantiated by Slic3r::Print::Object->_support_material() // Instantiated by Slic3r::Print::Object->_support_material()
// This class is instantiated before the slicing starts as Object.pm will query // This class is instantiated before the slicing starts as Object.pm will query
@ -84,6 +36,10 @@ public:
void generate(PrintObject &object); void generate(PrintObject &object);
private: private:
using SupportGeneratorLayersPtr = FFFSupport::SupportGeneratorLayersPtr;
using SupportGeneratorLayerStorage = FFFSupport::SupportGeneratorLayerStorage;
using SupportParameters = FFFSupport::SupportParameters;
std::vector<Polygons> buildplate_covered(const PrintObject &object) const; std::vector<Polygons> buildplate_covered(const PrintObject &object) const;
// Generate top contact layers supporting overhangs. // Generate top contact layers supporting overhangs.

View File

@ -19,9 +19,10 @@
#include "Polygon.hpp" #include "Polygon.hpp"
#include "Polyline.hpp" #include "Polyline.hpp"
#include "MutablePolygon.hpp" #include "MutablePolygon.hpp"
#include "SupportMaterial.hpp"
#include "TriangleMeshSlicer.hpp" #include "TriangleMeshSlicer.hpp"
#include "Support/SupportCommon.hpp"
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
@ -37,7 +38,6 @@
#include <tbb/global_control.h> #include <tbb/global_control.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
#if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32) #if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32)
#define TREE_SUPPORT_SHOW_ERRORS_WIN32 #define TREE_SUPPORT_SHOW_ERRORS_WIN32
@ -53,6 +53,8 @@
// #define TREESUPPORT_DEBUG_SVG // #define TREESUPPORT_DEBUG_SVG
using namespace Slic3r::FFFSupport;
namespace Slic3r namespace Slic3r
{ {
@ -963,12 +965,10 @@ static LayerIndex layer_idx_floor(const SlicingParameters &slicing_params, const
static inline SupportGeneratorLayer& layer_initialize( static inline SupportGeneratorLayer& layer_initialize(
SupportGeneratorLayer &layer_new, SupportGeneratorLayer &layer_new,
const SupporLayerType layer_type,
const SlicingParameters &slicing_params, const SlicingParameters &slicing_params,
const TreeSupportSettings &config, const TreeSupportSettings &config,
const size_t layer_idx) const size_t layer_idx)
{ {
layer_new.layer_type = layer_type;
layer_new.print_z = layer_z(slicing_params, config, layer_idx); layer_new.print_z = layer_z(slicing_params, config, layer_idx);
layer_new.bottom_z = layer_idx > 0 ? layer_z(slicing_params, config, layer_idx - 1) : 0; layer_new.bottom_z = layer_idx > 0 ? layer_z(slicing_params, config, layer_idx - 1) : 0;
layer_new.height = layer_new.print_z - layer_new.bottom_z; layer_new.height = layer_new.print_z - layer_new.bottom_z;
@ -976,29 +976,26 @@ static inline SupportGeneratorLayer& layer_initialize(
} }
// Using the std::deque as an allocator. // Using the std::deque as an allocator.
inline SupportGeneratorLayer& layer_allocate( inline SupportGeneratorLayer& layer_allocate_unguarded(
std::deque<SupportGeneratorLayer> &layer_storage, SupportGeneratorLayerStorage &layer_storage,
SupporLayerType layer_type, SupporLayerType layer_type,
const SlicingParameters &slicing_params, const SlicingParameters &slicing_params,
const TreeSupportSettings &config, const TreeSupportSettings &config,
size_t layer_idx) size_t layer_idx)
{ {
//FIXME take raft into account. SupportGeneratorLayer &layer = layer_storage.allocate_unguarded(layer_type);
layer_storage.push_back(SupportGeneratorLayer()); return layer_initialize(layer, slicing_params, config, layer_idx);
return layer_initialize(layer_storage.back(), layer_type, slicing_params, config, layer_idx);
} }
inline SupportGeneratorLayer& layer_allocate( inline SupportGeneratorLayer& layer_allocate(
std::deque<SupportGeneratorLayer> &layer_storage, SupportGeneratorLayerStorage &layer_storage,
tbb::spin_mutex& layer_storage_mutex,
SupporLayerType layer_type, SupporLayerType layer_type,
const SlicingParameters &slicing_params, const SlicingParameters &slicing_params,
const TreeSupportSettings &config, const TreeSupportSettings &config,
size_t layer_idx) size_t layer_idx)
{ {
tbb::spin_mutex::scoped_lock lock(layer_storage_mutex); SupportGeneratorLayer &layer = layer_storage.allocate(layer_type);
layer_storage.push_back(SupportGeneratorLayer()); return layer_initialize(layer, slicing_params, config, layer_idx);
return layer_initialize(layer_storage.back(), layer_type, slicing_params, config, layer_idx);
} }
int generate_raft_contact( int generate_raft_contact(
@ -1016,7 +1013,7 @@ int generate_raft_contact(
while (raft_contact_layer_idx > 0 && config.raft_layers[raft_contact_layer_idx] > print_object.slicing_parameters().raft_contact_top_z + EPSILON) while (raft_contact_layer_idx > 0 && config.raft_layers[raft_contact_layer_idx] > print_object.slicing_parameters().raft_contact_top_z + EPSILON)
-- raft_contact_layer_idx; -- raft_contact_layer_idx;
// Create the raft contact layer. // Create the raft contact layer.
SupportGeneratorLayer &raft_contact_layer = layer_allocate(layer_storage, SupporLayerType::TopContact, print_object.slicing_parameters(), config, raft_contact_layer_idx); SupportGeneratorLayer &raft_contact_layer = layer_allocate_unguarded(layer_storage, SupporLayerType::TopContact, print_object.slicing_parameters(), config, raft_contact_layer_idx);
top_contacts[raft_contact_layer_idx] = &raft_contact_layer; top_contacts[raft_contact_layer_idx] = &raft_contact_layer;
const ExPolygons &lslices = print_object.get_layer(0)->lslices; const ExPolygons &lslices = print_object.get_layer(0)->lslices;
double expansion = print_object.config().raft_expansion.value; double expansion = print_object.config().raft_expansion.value;
@ -1115,7 +1112,7 @@ public:
{ {
SupportGeneratorLayer*& l = top_contacts[insert_layer_idx]; SupportGeneratorLayer*& l = top_contacts[insert_layer_idx];
if (l == nullptr) if (l == nullptr)
l = &layer_allocate(layer_storage, SupporLayerType::TopContact, slicing_parameters, config, insert_layer_idx); l = &layer_allocate_unguarded(layer_storage, SupporLayerType::TopContact, slicing_parameters, config, insert_layer_idx);
// will be unioned in finalize_interface_and_support_areas() // will be unioned in finalize_interface_and_support_areas()
append(l->polygons, std::move(new_roofs)); append(l->polygons, std::move(new_roofs));
} }
@ -1141,7 +1138,7 @@ public:
std::lock_guard<std::mutex> lock(m_mutex_layer_storage); std::lock_guard<std::mutex> lock(m_mutex_layer_storage);
SupportGeneratorLayer*& l = top_contacts[0]; SupportGeneratorLayer*& l = top_contacts[0];
if (l == nullptr) if (l == nullptr)
l = &layer_allocate(layer_storage, SupporLayerType::TopContact, slicing_parameters, config, 0); l = &layer_allocate_unguarded(layer_storage, SupporLayerType::TopContact, slicing_parameters, config, 0);
append(l->polygons, std::move(overhang_areas)); append(l->polygons, std::move(overhang_areas));
} }
@ -3309,7 +3306,6 @@ static void finalize_interface_and_support_areas(
#endif // SLIC3R_TREESUPPORTS_PROGRESS #endif // SLIC3R_TREESUPPORTS_PROGRESS
// Iterate over the generated circles in parallel and clean them up. Also add support floor. // Iterate over the generated circles in parallel and clean them up. Also add support floor.
tbb::spin_mutex layer_storage_mutex;
tbb::parallel_for(tbb::blocked_range<size_t>(0, support_layer_storage.size()), tbb::parallel_for(tbb::blocked_range<size_t>(0, support_layer_storage.size()),
[&](const tbb::blocked_range<size_t> &range) { [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
@ -3402,7 +3398,7 @@ static void finalize_interface_and_support_areas(
} }
if (! floor_layer.empty()) { if (! floor_layer.empty()) {
if (support_bottom == nullptr) if (support_bottom == nullptr)
support_bottom = &layer_allocate(layer_storage, layer_storage_mutex, SupporLayerType::BottomContact, print_object.slicing_parameters(), config, layer_idx); support_bottom = &layer_allocate(layer_storage, SupporLayerType::BottomContact, print_object.slicing_parameters(), config, layer_idx);
support_bottom->polygons = union_(floor_layer, support_bottom->polygons); support_bottom->polygons = union_(floor_layer, support_bottom->polygons);
base_layer_polygons = diff_clipped(base_layer_polygons, offset(support_bottom->polygons, scaled<float>(0.01), jtMiter, 1.2)); // Subtract the support floor from the normal support. base_layer_polygons = diff_clipped(base_layer_polygons, offset(support_bottom->polygons, scaled<float>(0.01), jtMiter, 1.2)); // Subtract the support floor from the normal support.
} }
@ -3410,11 +3406,11 @@ static void finalize_interface_and_support_areas(
if (! support_roof_polygons.empty()) { if (! support_roof_polygons.empty()) {
if (support_roof == nullptr) if (support_roof == nullptr)
support_roof = top_contacts[layer_idx] = &layer_allocate(layer_storage, layer_storage_mutex, SupporLayerType::TopContact, print_object.slicing_parameters(), config, layer_idx); support_roof = top_contacts[layer_idx] = &layer_allocate(layer_storage, SupporLayerType::TopContact, print_object.slicing_parameters(), config, layer_idx);
support_roof->polygons = union_(support_roof_polygons); support_roof->polygons = union_(support_roof_polygons);
} }
if (! base_layer_polygons.empty()) { if (! base_layer_polygons.empty()) {
SupportGeneratorLayer *base_layer = intermediate_layers[layer_idx] = &layer_allocate(layer_storage, layer_storage_mutex, SupporLayerType::Base, print_object.slicing_parameters(), config, layer_idx); SupportGeneratorLayer *base_layer = intermediate_layers[layer_idx] = &layer_allocate(layer_storage, SupporLayerType::Base, print_object.slicing_parameters(), config, layer_idx);
base_layer->polygons = union_(base_layer_polygons); base_layer->polygons = union_(base_layer_polygons);
} }