Supports refactoring: Split FFF supports into multiple files,
enclosed into namespaces.
This commit is contained in:
parent
cc938e7549
commit
a236351fd3
@ -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
|
||||||
|
1807
src/libslic3r/Support/SupportCommon.cpp
Normal file
1807
src/libslic3r/Support/SupportCommon.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
src/libslic3r/Support/SupportCommon.hpp
Normal file
138
src/libslic3r/Support/SupportCommon.hpp
Normal 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_ */
|
108
src/libslic3r/Support/SupportDebug.cpp
Normal file
108
src/libslic3r/Support/SupportDebug.cpp
Normal 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 */
|
18
src/libslic3r/Support/SupportDebug.hpp
Normal file
18
src/libslic3r/Support/SupportDebug.hpp
Normal 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_ */
|
@ -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
|
||||||
|
116
src/libslic3r/Support/SupportParameters.cpp
Normal file
116
src/libslic3r/Support/SupportParameters.cpp
Normal 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 ®ion = 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
|
@ -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
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user