ENH: add rectilinear interface pattern for organic support
1. add rectilinear interface pattern for organic support jira: STUDIO-7181 2. add tree support optgroup Change-Id: I94882bc34a61c6adc06b8ecbc9f2323f9b039aac (cherry picked from commit a8142ab3f37e0bd140a31a7e635b8475f471d7e3)
This commit is contained in:
parent
c80a3fc5d1
commit
69cf816b94
|
@ -281,6 +281,8 @@ set(lisbslic3r_sources
|
|||
SlicesToTriangleMesh.cpp
|
||||
SlicingAdaptive.cpp
|
||||
SlicingAdaptive.hpp
|
||||
Support/SupportCommon.cpp
|
||||
Support/SupportCommon.hpp
|
||||
Support/SupportMaterial.cpp
|
||||
Support/SupportMaterial.hpp
|
||||
Support/TreeSupport.hpp
|
||||
|
@ -290,6 +292,7 @@ set(lisbslic3r_sources
|
|||
Support/TreeModelVolumes.hpp
|
||||
Support/TreeModelVolumes.cpp
|
||||
Support/TreeSupportCommon.hpp
|
||||
Support/SupportParameters.hpp
|
||||
MinimumSpanningTree.hpp
|
||||
MinimumSpanningTree.cpp
|
||||
Surface.cpp
|
||||
|
|
|
@ -269,8 +269,8 @@ bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
|
|||
|
||||
// Offset CCW contours outside, CW contours (holes) inside.
|
||||
// Don't calculate union of the output paths.
|
||||
template<typename PathsProvider, ClipperLib::EndType endType = ClipperLib::etClosedPolygon>
|
||||
static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
||||
template<typename PathsProvider>
|
||||
static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType endType = ClipperLib::etClosedPolygon)
|
||||
{
|
||||
ClipperLib::ClipperOffset co;
|
||||
ClipperLib::Paths out;
|
||||
|
@ -280,7 +280,7 @@ static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, Clipper
|
|||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(offset * ClipperOffsetShortestEdgeFactor));
|
||||
co.ShortestEdgeLength = std::abs(offset * ClipperOffsetShortestEdgeFactor);
|
||||
for (const ClipperLib::Path &path : paths) {
|
||||
co.Clear();
|
||||
// Execute reorients the contours so that the outer most contour has a positive area. Thus the output
|
||||
|
@ -356,11 +356,11 @@ ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool
|
|||
return PolyTreeToExPolygons(clipper_union<ClipperLib::PolyTree>(input, do_union ? ClipperLib::pftNonZero : ClipperLib::pftEvenOdd));
|
||||
}
|
||||
|
||||
template<typename PathsProvider, ClipperLib::EndType endType = ClipperLib::etClosedPolygon>
|
||||
static ClipperLib::Paths raw_offset_polyline(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
||||
template<typename PathsProvider>
|
||||
static ClipperLib::Paths raw_offset_polyline(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type = ClipperLib::etOpenButt)
|
||||
{
|
||||
assert(offset > 0);
|
||||
return raw_offset<PathsProvider, ClipperLib::etOpenButt>(std::forward<PathsProvider>(paths), offset, joinType, miterLimit);
|
||||
return raw_offset<PathsProvider>(std::forward<PathsProvider>(paths), offset, joinType, miterLimit, end_type);
|
||||
}
|
||||
|
||||
template<class TResult, typename PathsProvider>
|
||||
|
@ -415,10 +415,10 @@ Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, Cli
|
|||
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{ return PolyTreeToExPolygons(offset_paths<ClipperLib::PolyTree>(ClipperUtils::PolygonsProvider(polygons), delta, joinType, miterLimit)); }
|
||||
|
||||
Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{ assert(delta > 0); return to_polygons(clipper_union<ClipperLib::Paths>(raw_offset_polyline(ClipperUtils::SinglePathProvider(polyline.points), delta, joinType, miterLimit))); }
|
||||
Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{ assert(delta > 0); return to_polygons(clipper_union<ClipperLib::Paths>(raw_offset_polyline(ClipperUtils::PolylinesProvider(polylines), delta, joinType, miterLimit))); }
|
||||
Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type)
|
||||
{ assert(delta > 0); return to_polygons(clipper_union<ClipperLib::Paths>(raw_offset_polyline(ClipperUtils::SinglePathProvider(polyline.points), delta, joinType, miterLimit, end_type))); }
|
||||
Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type)
|
||||
{ assert(delta > 0); return to_polygons(clipper_union<ClipperLib::Paths>(raw_offset_polyline(ClipperUtils::PolylinesProvider(polylines), delta, joinType, miterLimit, end_type))); }
|
||||
|
||||
// returns number of expolygons collected (0 or 1).
|
||||
static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
|
||||
|
|
|
@ -29,6 +29,7 @@ class BoundingBox;
|
|||
static constexpr const float ClipperSafetyOffset = 10.f;
|
||||
|
||||
static constexpr const Slic3r::ClipperLib::JoinType DefaultJoinType = Slic3r::ClipperLib::jtMiter;
|
||||
static constexpr const Slic3r::ClipperLib::EndType DefaultEndType = Slic3r::ClipperLib::etOpenButt;
|
||||
//FIXME evaluate the default miter limit. 3 seems to be extreme, Cura uses 1.2.
|
||||
// Mitter Limit 3 is useful for perimeter generator, where sharp corners are extruded without needing a gap fill.
|
||||
// However such a high limit causes issues with large positive or negative offsets, where a sharp corner
|
||||
|
@ -342,8 +343,8 @@ Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, Clipp
|
|||
// offset Polylines
|
||||
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
|
||||
// Input polygons for negative offset shall be "normalized": There must be no overlap / intersections between the input polygons.
|
||||
Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit);
|
||||
Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit);
|
||||
Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, ClipperLib::EndType end_type = DefaultEndType);
|
||||
Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, ClipperLib::EndType end_type = DefaultEndType);
|
||||
Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
||||
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
||||
Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
||||
|
|
|
@ -50,7 +50,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
|||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||
case ipAdaptiveCubic: return new FillAdaptive::Filler();
|
||||
case ipSupportCubic: return new FillAdaptive::Filler();
|
||||
case ipSupportBase: return new FillSupportBase();
|
||||
case ipSupportBase: return new FillSupportBase(); // simply line fill
|
||||
case ipLightning: return new FillLightning::Filler();
|
||||
// BBS: for internal solid infill only
|
||||
case ipConcentricInternal: return new FillConcentricInternal();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,150 @@
|
|||
///|/ Copyright (c) Prusa Research 2023 Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_SupportCommon_hpp_
|
||||
#define slic3r_SupportCommon_hpp_
|
||||
|
||||
#include "../Layer.hpp"
|
||||
#include "../Polygon.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "SupportLayer.hpp"
|
||||
#include "SupportParameters.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class PrintObject;
|
||||
class SupportLayer;
|
||||
|
||||
// Turn some of the base layers into base interface layers.
|
||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
||||
// extruder to improve adhesion of the soluble filament to the base.
|
||||
// For Organic supports, merge top_interface_layers & top_base_interface_layers with the interfaces
|
||||
// produced by this function.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||
const PrintObjectConfig &config,
|
||||
const SupportParameters &support_params,
|
||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
||||
const SupportGeneratorLayersPtr &top_contacts,
|
||||
// Input / output, will be merged with output
|
||||
SupportGeneratorLayersPtr &top_interface_layers,
|
||||
SupportGeneratorLayersPtr &top_base_interface_layers,
|
||||
// Input, will be trimmed with the newly created interface layers.
|
||||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
SupportGeneratorLayerStorage &layer_storage);
|
||||
|
||||
// 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);
|
||||
|
||||
void fill_expolygons_with_sheath_generate_paths(ExtrusionEntitiesPtr& dst, const Polygons& polygons, Fill* filler, float density, ExtrusionRole role, const Flow& flow, bool with_sheath, bool no_sort);
|
||||
|
||||
// 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 Slic3r
|
||||
|
||||
#endif /* slic3r_SupportCommon_hpp_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -19,14 +19,6 @@ inline double layer_z(const SlicingParameters& slicing_params, const size_t laye
|
|||
{
|
||||
return slicing_params.object_print_z_min + slicing_params.first_object_layer_height + layer_idx * slicing_params.layer_height;
|
||||
}
|
||||
inline LayerIndex layer_idx_ceil(const SlicingParameters& slicing_params, const double z)
|
||||
{
|
||||
return LayerIndex(ceil((z - slicing_params.object_print_z_min - slicing_params.first_object_layer_height) / slicing_params.layer_height));
|
||||
}
|
||||
inline LayerIndex layer_idx_floor(const SlicingParameters& slicing_params, const double z)
|
||||
{
|
||||
return LayerIndex(floor((z - slicing_params.object_print_z_min - slicing_params.first_object_layer_height) / slicing_params.layer_height));
|
||||
}
|
||||
|
||||
inline SupportGeneratorLayer& layer_initialize(
|
||||
SupportGeneratorLayer& layer_new,
|
||||
|
@ -53,67 +45,6 @@ inline SupportGeneratorLayer& layer_allocate(
|
|||
return layer_initialize(layer_storage.back(), layer_type, slicing_params, layer_idx);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Turn some of the base layers into base interface layers.
|
||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
||||
// extruder to improve adhesion of the soluble filament to the base.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||
const PrintObjectConfig& config,
|
||||
const SupportParameters& support_params,
|
||||
const SupportGeneratorLayersPtr& bottom_contacts,
|
||||
const SupportGeneratorLayersPtr& top_contacts,
|
||||
// Input / output, will be merged with output. Only provided for Organic supports.
|
||||
SupportGeneratorLayersPtr& top_interface_layers,
|
||||
SupportGeneratorLayersPtr& top_base_interface_layers,
|
||||
SupportGeneratorLayersPtr& intermediate_layers,
|
||||
SupportGeneratorLayerStorage& layer_storage);
|
||||
|
||||
// Produce the support G-code.
|
||||
// Used by both classic and tree supports.
|
||||
void generate_support_toolpaths(
|
||||
PrintObject &object,
|
||||
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 fill_expolygons_with_sheath_generate_paths(
|
||||
ExtrusionEntitiesPtr& dst,
|
||||
const Polygons& polygons,
|
||||
Fill* filler,
|
||||
float density,
|
||||
ExtrusionRole role,
|
||||
const Flow& flow,
|
||||
bool with_sheath,
|
||||
bool no_sort);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
struct SupportParameters {
|
||||
SupportParameters() = default;
|
||||
SupportParameters(const PrintObject& object)
|
||||
{
|
||||
const PrintConfig& print_config = object.print()->config();
|
||||
|
@ -43,6 +44,7 @@ struct SupportParameters {
|
|||
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);
|
||||
|
@ -89,6 +91,8 @@ struct SupportParameters {
|
|||
this->interface_angle = Geometry::deg2rad(float(object_config.support_angle.value + 90.));
|
||||
this->interface_spacing = object_config.support_interface_spacing.value + this->support_material_interface_flow.spacing();
|
||||
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->interface_spacing);
|
||||
double raft_interface_spacing = object_config.support_interface_spacing.value + this->raft_interface_flow.spacing();
|
||||
this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing);
|
||||
this->support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing();
|
||||
this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing);
|
||||
if (object_config.support_interface_top_layers.value == 0) {
|
||||
|
@ -98,11 +102,12 @@ struct SupportParameters {
|
|||
}
|
||||
|
||||
SupportMaterialPattern support_pattern = object_config.support_base_pattern;
|
||||
this->with_sheath = /*is_tree(object_config.support_type) &&*/ object_config.tree_support_wall_count > 0;
|
||||
this->with_sheath = object_config.tree_support_wall_count > 0;
|
||||
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;
|
||||
if (object_config.support_interface_pattern == smipGrid)
|
||||
this->contact_fill_pattern = ipGrid;
|
||||
else if (object_config.support_interface_pattern == smipRectilinearInterlaced)
|
||||
|
@ -113,6 +118,40 @@ struct SupportParameters {
|
|||
object_config.support_interface_pattern == smipConcentric ?
|
||||
ipConcentric :
|
||||
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
double tree_support_branch_diameter_double_wall = 3.0; // in organic support, Branches with area larger than the area of a circle of this diameter will be printed with double walls for stability
|
||||
this->tree_branch_diameter_double_wall_area_scaled = 0.25 * sqr(scaled<double>(tree_support_branch_diameter_double_wall)) * M_PI;
|
||||
}
|
||||
// Both top / bottom contacts and interfaces are soluble.
|
||||
bool soluble_interface;
|
||||
|
@ -142,6 +181,8 @@ struct SupportParameters {
|
|||
Flow support_material_flow;
|
||||
Flow support_material_interface_flow;
|
||||
Flow support_material_bottom_interface_flow;
|
||||
// Flow at raft inteface & contact layers.
|
||||
Flow raft_interface_flow;
|
||||
coordf_t support_extrusion_width;
|
||||
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
|
||||
bool can_merge_support_regions;
|
||||
|
@ -157,13 +198,28 @@ struct SupportParameters {
|
|||
coordf_t interface_spacing;
|
||||
coordf_t support_expansion=0;
|
||||
coordf_t interface_density;
|
||||
// Density of the raft interface and contact layers.
|
||||
coordf_t raft_interface_density;
|
||||
coordf_t support_spacing;
|
||||
coordf_t support_density;
|
||||
|
||||
InfillPattern base_fill_pattern;
|
||||
InfillPattern interface_fill_pattern;
|
||||
// Pattern of the raft interface and contact layers.
|
||||
InfillPattern raft_interface_fill_pattern;
|
||||
InfillPattern contact_fill_pattern;
|
||||
bool with_sheath;
|
||||
// Branches of organic supports with area larger than this threshold will be extruded with double lines.
|
||||
double tree_branch_diameter_double_wall_area_scaled = 0.25 * sqr(scaled<double>(3.0)) * M_PI;;
|
||||
|
||||
float raft_angle_1st_layer;
|
||||
float raft_angle_base;
|
||||
float raft_angle_interface;
|
||||
|
||||
// Produce a raft interface angle for a given SupportLayer::interface_id()
|
||||
float raft_interface_angle(size_t interface_id) const
|
||||
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
|
||||
|
||||
bool independent_layer_height = false;
|
||||
const double thresh_big_overhang = Slic3r::sqr(scale_(10));
|
||||
};
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
#include <math.h>
|
||||
#include <chrono>
|
||||
#include <math.h>
|
||||
|
||||
#include "MinimumSpanningTree.hpp"
|
||||
#include "TreeSupport.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "Fill/FillConcentric.hpp"
|
||||
#include "CurveAnalyzer.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include <libnest2d/backends/libslic3r/geometries.hpp>
|
||||
#include <libnest2d/placers/nfpplacer.hpp>
|
||||
#include "TreeModelVolumes.hpp"
|
||||
#include "TreeSupport3D.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "CurveAnalyzer.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "Fill/FillConcentric.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "MinimumSpanningTree.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "SupportCommon.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include "TreeSupportCommon.hpp"
|
||||
#include "TreeSupport.hpp"
|
||||
#include "TreeSupport3D.hpp"
|
||||
#include <libnest2d/backends/libslic3r/geometries.hpp>
|
||||
#include <libnest2d/placers/nfpplacer.hpp>
|
||||
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <tbb/concurrent_unordered_set.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/concurrent_unordered_set.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_for_each.h>
|
||||
|
||||
|
@ -618,21 +619,9 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
|
|||
SupportMaterialPattern support_pattern = m_object_config->support_base_pattern;
|
||||
if (support_style == smsTreeHybrid && support_pattern == smpDefault)
|
||||
support_pattern = smpRectilinear;
|
||||
m_support_params.base_fill_pattern =
|
||||
support_pattern == smpLightning ? ipLightning :
|
||||
support_pattern == smpHoneycomb ? ipHoneycomb :
|
||||
m_support_params.support_density > 0.95 || m_support_params.with_sheath ? ipRectilinear : ipSupportBase;
|
||||
|
||||
m_support_params.interface_fill_pattern = (m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||
if (m_object_config->support_interface_pattern == smipGrid)
|
||||
m_support_params.contact_fill_pattern = ipGrid;
|
||||
else if (m_object_config->support_interface_pattern == smipRectilinearInterlaced)
|
||||
m_support_params.contact_fill_pattern = ipRectilinear;
|
||||
else
|
||||
m_support_params.contact_fill_pattern = (m_object_config->support_interface_pattern == smipAuto && m_slicing_params.soluble_interface) ||
|
||||
m_object_config->support_interface_pattern == smipConcentric ?
|
||||
ipConcentric :
|
||||
(m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||
if(support_pattern == smpLightning)
|
||||
m_support_params.base_fill_pattern = ipLightning;
|
||||
m_support_params.support_extrusion_width = m_object_config->support_line_width.value > 0 ? m_object_config->support_line_width : m_object_config->line_width;
|
||||
// Check if set to zero, use default if so.
|
||||
if (m_support_params.support_extrusion_width <= 0.0) {
|
||||
|
@ -1657,8 +1646,6 @@ void deleteDirectoryContents(const std::filesystem::path& dir)
|
|||
|
||||
void TreeSupport::generate()
|
||||
{
|
||||
auto t_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (support_style == smsTreeOrganic) {
|
||||
generate_tree_support_3D(*m_object, this, this->throw_on_cancel);
|
||||
return;
|
||||
|
@ -1676,9 +1663,6 @@ void TreeSupport::generate()
|
|||
m_ts_data = m_object->alloc_tree_support_preview_cache();
|
||||
m_ts_data->is_slim = is_slim;
|
||||
|
||||
// Generate contact points of tree support
|
||||
std::vector<std::vector<SupportNode*>> contact_nodes(m_object->layers().size());
|
||||
|
||||
#if USE_SUPPORT_3D
|
||||
std::vector<TreeSupport3D::SupportElements> move_bounds(m_highest_overhang_layer + 1);
|
||||
profiler.stage_start(STAGE_GENERATE_CONTACT_NODES);
|
||||
|
@ -1713,22 +1697,22 @@ void TreeSupport::generate()
|
|||
TreeSupport3D::generate_initial_areas(*m_object, *m_model_volumes.get(), tree_support_3d_config, overhangs, move_bounds, top_contacts, layer_storage, throw_on_cancel);
|
||||
}
|
||||
#endif
|
||||
generate_contact_points(contact_nodes);
|
||||
generate_contact_points();
|
||||
profiler.stage_finish(STAGE_GENERATE_CONTACT_NODES);
|
||||
|
||||
|
||||
//Drop nodes to lower layers.
|
||||
profiler.stage_start(STAGE_DROP_DOWN_NODES);
|
||||
m_object->print()->set_status(60, _u8L("Generating support"));
|
||||
drop_nodes(contact_nodes);
|
||||
drop_nodes();
|
||||
profiler.stage_finish(STAGE_DROP_DOWN_NODES);
|
||||
|
||||
smooth_nodes(contact_nodes);// , tree_support_3d_config);
|
||||
smooth_nodes();// , tree_support_3d_config);
|
||||
|
||||
//Generate support areas.
|
||||
profiler.stage_start(STAGE_DRAW_CIRCLES);
|
||||
m_object->print()->set_status(65, _u8L("Generating support"));
|
||||
draw_circles(contact_nodes);
|
||||
draw_circles();
|
||||
profiler.stage_finish(STAGE_DRAW_CIRCLES);
|
||||
|
||||
|
||||
|
@ -1775,7 +1759,6 @@ coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, coordf_t mm_to_to
|
|||
{
|
||||
radius = mm_to_top;// this is a 45 degree tip
|
||||
}
|
||||
|
||||
radius = std::max(radius, MIN_BRANCH_RADIUS);
|
||||
radius = std::min(radius, MAX_BRANCH_RADIUS);
|
||||
// if have interface layers, radius should be larger
|
||||
|
@ -1943,7 +1926,7 @@ Polygons TreeSupport::get_trim_support_regions(
|
|||
return polygons_trimming;
|
||||
}
|
||||
|
||||
void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||
void TreeSupport::draw_circles()
|
||||
{
|
||||
const PrintObjectConfig &config = m_object->config();
|
||||
const Print* print = m_object->print();
|
||||
|
@ -2045,11 +2028,11 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
}
|
||||
};
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << contact_nodes[layer_nr].size();
|
||||
BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << curr_layer_nodes.size();
|
||||
//Draw the support areas and add the roofs appropriately to the support roof instead of normal areas.
|
||||
ts_layer->lslices.reserve(contact_nodes[layer_nr].size());
|
||||
ts_layer->lslices.reserve(curr_layer_nodes.size());
|
||||
ExPolygons area_poly; // the polygon node area which will be printed as normal support
|
||||
for (const SupportNode* p_node : contact_nodes[layer_nr])
|
||||
for (const SupportNode* p_node : curr_layer_nodes)
|
||||
{
|
||||
if (print->canceled())
|
||||
break;
|
||||
|
@ -2441,7 +2424,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& con
|
|||
|
||||
double SupportNode::diameter_angle_scale_factor;
|
||||
|
||||
void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||
void TreeSupport::drop_nodes()
|
||||
{
|
||||
const PrintObjectConfig &config = m_object->config();
|
||||
// Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
|
||||
|
@ -2477,7 +2460,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
return move_dist;
|
||||
};
|
||||
|
||||
m_ts_data->layer_heights = plan_layer_heights(contact_nodes);
|
||||
m_ts_data->layer_heights = plan_layer_heights();
|
||||
std::vector<LayerHeightData> &layer_heights = m_ts_data->layer_heights;
|
||||
if (layer_heights.empty()) return;
|
||||
|
||||
|
@ -2540,7 +2523,6 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
coordf_t height_next = layer_heights[layer_nr_next].height;
|
||||
|
||||
std::deque<std::pair<size_t, SupportNode*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
|
||||
const Layer* ts_layer = m_object->get_support_layer(layer_nr);
|
||||
|
||||
m_object->print()->set_status(60 + int(10 * (1 - float(layer_nr) / contact_nodes.size())), _u8L("Generating support"));// (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str());
|
||||
|
||||
|
@ -2803,7 +2785,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
// 1. do not merge neighbors under 5mm
|
||||
// 2. Only merge node with single neighbor in distance between [max_move_distance, 10mm/layer_height]
|
||||
float dist2_to_first_neighbor = neighbours.empty() ? 0 : vsize2_with_unscale(neighbours[0] - node.position);
|
||||
if (ts_layer->print_z > DO_NOT_MOVER_UNDER_MM &&
|
||||
if (node.print_z > DO_NOT_MOVER_UNDER_MM &&
|
||||
(neighbours.size() > 1 || (neighbours.size() == 1 && dist2_to_first_neighbor >= max_move_distance2))) // Only nodes that aren't about to collapse.
|
||||
{
|
||||
// Move towards the average position of all neighbours.
|
||||
|
@ -2819,7 +2801,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
|
||||
coordf_t branch_bottom_radius = calc_branch_radius(branch_radius, node.dist_mm_to_top + node.print_z, diameter_angle_scale_factor);
|
||||
coordf_t neighbour_bottom_radius = calc_branch_radius(branch_radius, neighbour_node->dist_mm_to_top + neighbour_node->print_z, diameter_angle_scale_factor);
|
||||
double max_converge_distance = tan_angle * (ts_layer->print_z - DO_NOT_MOVER_UNDER_MM) + std::max(branch_bottom_radius, neighbour_bottom_radius);
|
||||
double max_converge_distance = tan_angle * (p_node->print_z - DO_NOT_MOVER_UNDER_MM) + std::max(branch_bottom_radius, neighbour_bottom_radius);
|
||||
if (dist2_to_neighbor > max_converge_distance * max_converge_distance) continue;
|
||||
|
||||
if (is_line_cut_by_contour(node.position, neighbour)) continue;
|
||||
|
@ -2967,7 +2949,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nod
|
|||
|
||||
}
|
||||
|
||||
void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode *>> &contact_nodes)
|
||||
void TreeSupport::smooth_nodes()
|
||||
{
|
||||
for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) {
|
||||
std::vector<SupportNode *> &curr_layer_nodes = contact_nodes[layer_nr];
|
||||
|
@ -3039,7 +3021,7 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode *>> &contact_
|
|||
}
|
||||
|
||||
#if USE_SUPPORT_3D
|
||||
void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes, const TreeSupport3D::TreeSupportSettings& config)
|
||||
void TreeSupport::smooth_nodes(const TreeSupport3D::TreeSupportSettings& config)
|
||||
{
|
||||
const coordf_t branch_radius = m_object_config->tree_support_branch_diameter.value / 2;
|
||||
const coordf_t branch_radius_scaled = scale_(branch_radius);
|
||||
|
@ -3115,23 +3097,23 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode*>>& contact_n
|
|||
break;
|
||||
|
||||
|
||||
std::vector<std::pair<Node*, int>> map_downwards_old;
|
||||
std::vector<std::pair<Node*, int>> map_downwards_new;
|
||||
std::vector<std::pair<SupportNode*, int>> map_downwards_old;
|
||||
std::vector<std::pair<SupportNode*, int>> map_downwards_new;
|
||||
linear_data_layers.emplace_back(0);
|
||||
for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(contact_nodes.size()); ++layer_idx) {
|
||||
std::sort(map_downwards_old.begin(), map_downwards_old.end(), [](auto& l, auto& r) { return l.first < r.first; });
|
||||
auto& layer = contact_nodes[layer_idx];
|
||||
for (size_t elem_idx = 0; elem_idx < layer.size(); ++elem_idx) {
|
||||
Node* node = layer[elem_idx];
|
||||
SupportNode* node = layer[elem_idx];
|
||||
int child = -1;
|
||||
if (layer_idx > 0) {
|
||||
auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), node, [](auto& l, const Node* r) { return l.first < r; });
|
||||
auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), node, [](auto& l, const SupportNode* r) { return l.first < r; });
|
||||
if (it != map_downwards_old.end() && it->first == node) {
|
||||
child = it->second;
|
||||
// Only one link points to a node above from below.
|
||||
assert(!(++it != map_downwards_old.end() && it->first == node));
|
||||
}
|
||||
const Node* pchild = child == -1 ? nullptr : contact_nodes[layer_idx - 1][child];
|
||||
const SupportNode* pchild = child == -1 ? nullptr : contact_nodes[layer_idx - 1][child];
|
||||
}
|
||||
TreeSupport3D::SupportElement* elem = &move_bounds[node2elemIdx[node]];
|
||||
if (node->parent) {
|
||||
|
@ -3159,7 +3141,7 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode*>>& contact_n
|
|||
}
|
||||
#endif
|
||||
|
||||
std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::vector<SupportNode *>> &contact_nodes)
|
||||
std::vector<LayerHeightData> TreeSupport::plan_layer_heights()
|
||||
{
|
||||
std::vector<LayerHeightData> layer_heights(contact_nodes.size());
|
||||
std::map<int, std::pair<coordf_t,coordf_t>> bounds; // layer_nr:(print_z, height)
|
||||
|
@ -3257,7 +3239,7 @@ std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::ve
|
|||
return layer_heights;
|
||||
}
|
||||
|
||||
void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||
void TreeSupport::generate_contact_points()
|
||||
{
|
||||
const PrintObjectConfig &config = m_object->config();
|
||||
const coordf_t point_spread = scale_(config.tree_support_branch_distance.value);
|
||||
|
@ -3315,8 +3297,11 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>
|
|||
// fix bug of generating support for very thin objects
|
||||
if (m_object->layers().size() <= z_distance_top_layers + 1)
|
||||
return;
|
||||
//if (m_object->support_layer_count() <= m_raft_layers)
|
||||
// return;
|
||||
|
||||
contact_nodes.clear();
|
||||
contact_nodes.resize(m_object->layers().size());
|
||||
|
||||
tbb::spin_mutex mtx;
|
||||
|
||||
int nonempty_layers = 0;
|
||||
tbb::concurrent_vector<Slic3r::Vec3f> all_nodes;
|
||||
|
|
|
@ -378,7 +378,7 @@ public:
|
|||
void detect_overhangs(bool check_support_necessity = false);
|
||||
|
||||
int avg_node_per_layer = 0;
|
||||
float nodes_angle = 0;
|
||||
float nodes_angle = 0;
|
||||
bool has_sharp_tails = false;
|
||||
bool has_cantilever = false;
|
||||
double max_cantilever_dist = 0;
|
||||
|
@ -405,6 +405,7 @@ private:
|
|||
* Lazily computes volumes as needed.
|
||||
* \warning This class is NOT currently thread-safe and should not be accessed in OpenMP blocks
|
||||
*/
|
||||
std::vector<std::vector<SupportNode*>> contact_nodes;
|
||||
std::shared_ptr<TreeSupportData> m_ts_data;
|
||||
std::unique_ptr<TreeSupport3D::TreeModelVolumes> m_model_volumes;
|
||||
PrintObject *m_object;
|
||||
|
@ -440,7 +441,7 @@ private:
|
|||
* save the resulting support polygons to.
|
||||
* \param contact_nodes The nodes to draw as support.
|
||||
*/
|
||||
void draw_circles(const std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||
void draw_circles();
|
||||
|
||||
/*!
|
||||
* \brief Drops down the nodes of the tree support towards the build plate.
|
||||
|
@ -454,18 +455,18 @@ private:
|
|||
* dropped down. The nodes are dropped to lower layers inside the same
|
||||
* vector of layers.
|
||||
*/
|
||||
void drop_nodes(std::vector<std::vector<SupportNode *>> &contact_nodes);
|
||||
void drop_nodes();
|
||||
|
||||
void smooth_nodes(std::vector<std::vector<SupportNode *>> &contact_nodes);
|
||||
void smooth_nodes();
|
||||
|
||||
void smooth_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes, const TreeSupport3D::TreeSupportSettings& config);
|
||||
void smooth_nodes(const TreeSupport3D::TreeSupportSettings& config);
|
||||
|
||||
/*! BBS: MusangKing: maximum layer height
|
||||
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
||||
*
|
||||
*/
|
||||
|
||||
std::vector<LayerHeightData> plan_layer_heights(std::vector<std::vector<SupportNode *>> &contact_nodes);
|
||||
std::vector<LayerHeightData> plan_layer_heights();
|
||||
/*!
|
||||
* \brief Creates points where support contacts the model.
|
||||
*
|
||||
|
@ -479,7 +480,7 @@ private:
|
|||
* \return For each layer, a list of points where the tree should connect
|
||||
* with the model.
|
||||
*/
|
||||
void generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||
void generate_contact_points();
|
||||
|
||||
/*!
|
||||
* \brief Add a node to the next layer.
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
#include "MutablePolygon.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "SupportCommon.hpp"
|
||||
#include "TriangleMeshSlicer.hpp"
|
||||
#include "TreeSupport.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
@ -63,16 +63,6 @@ namespace Slic3r
|
|||
namespace TreeSupport3D
|
||||
{
|
||||
|
||||
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, LineStatus>>;
|
||||
using LineInformations = std::vector<LineInformation>;
|
||||
using namespace std::literals;
|
||||
|
@ -350,6 +340,28 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||
return max_layer;
|
||||
}
|
||||
|
||||
// picked from convert_lines_to_internal()
|
||||
[[nodiscard]] LineStatus get_avoidance_status(const Point& p, coord_t radius, LayerIndex layer_idx,
|
||||
const TreeModelVolumes& volumes, const TreeSupportSettings& config)
|
||||
{
|
||||
const bool min_xy_dist = config.xy_distance > config.xy_min_distance;
|
||||
|
||||
LineStatus type = LineStatus::INVALID;
|
||||
|
||||
if (!contains(volumes.getAvoidance(radius, layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, false, min_xy_dist), p))
|
||||
type = LineStatus::TO_BP_SAFE;
|
||||
else if (!contains(volumes.getAvoidance(radius, layer_idx, TreeModelVolumes::AvoidanceType::Fast, false, min_xy_dist), p))
|
||||
type = LineStatus::TO_BP;
|
||||
else if (config.support_rests_on_model && !contains(volumes.getAvoidance(radius, layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, true, min_xy_dist), p))
|
||||
type = LineStatus::TO_MODEL_GRACIOUS_SAFE;
|
||||
else if (config.support_rests_on_model && !contains(volumes.getAvoidance(radius, layer_idx, TreeModelVolumes::AvoidanceType::Fast, true, min_xy_dist), p))
|
||||
type = LineStatus::TO_MODEL_GRACIOUS;
|
||||
else if (config.support_rests_on_model && !contains(volumes.getCollision(radius, layer_idx, min_xy_dist), p))
|
||||
type = LineStatus::TO_MODEL;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts a Polygons object representing a line into the internal format.
|
||||
*
|
||||
|
@ -1201,15 +1213,6 @@ void sample_overhang_area(
|
|||
}
|
||||
}
|
||||
|
||||
inline SupportGeneratorLayer& layer_allocate(
|
||||
SupportGeneratorLayerStorage& layer_storage,
|
||||
SupporLayerType layer_type,
|
||||
const SlicingParameters &slicing_params,
|
||||
size_t layer_idx)
|
||||
{
|
||||
auto& layer = layer_storage.allocate(layer_type);
|
||||
return layer_initialize(layer, layer_type, slicing_params, layer_idx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang.
|
||||
|
@ -1932,7 +1935,7 @@ static void increase_areas_one_layer(
|
|||
inc_wo_collision.clear();
|
||||
if (!settings.no_error) {
|
||||
// ERROR CASE
|
||||
// if the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, it still actually has an area that can be increased
|
||||
// if the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if it would be a line wrongly, it still actually has an area that can be increased
|
||||
Polygons lines_offset = offset(to_polylines(parent.influence_area), scaled<float>(0.005), jtMiter, 1.2);
|
||||
Polygons base_error_area = union_(parent.influence_area, lines_offset);
|
||||
result = increase_single_area(volumes, config, settings, layer_idx, parent,
|
||||
|
@ -4097,7 +4100,7 @@ void slice_branches(
|
|||
if (! slices[layer_idx].empty()) {
|
||||
SupportGeneratorLayer *&l = intermediate_layers[layer_idx];
|
||||
if (l == nullptr)
|
||||
l = &layer_allocate(layer_storage, SupporLayerType::sltBase, slicing_params, layer_idx);
|
||||
l = &layer_allocate(layer_storage, SupporLayerType::sltBase, slicing_params, config, layer_idx);
|
||||
append(l->polygons, to_polygons(std::move(slices[layer_idx])));
|
||||
}
|
||||
|
||||
|
@ -4312,7 +4315,7 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
|||
|
||||
// Don't fill in the tree supports, make them hollow with just a single sheath line.
|
||||
print.set_status(69, _L("Generating support"));
|
||||
generate_support_toolpaths(print_object, print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(),
|
||||
generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(),
|
||||
raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
|
||||
|
||||
#if 0
|
||||
|
@ -4785,7 +4788,9 @@ void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_suppo
|
|||
}
|
||||
|
||||
Points bedpts = tree_support->m_machine_border.contour.points;
|
||||
BuildVolume build_volume{ Pointfs{ unscaled(bedpts[0]), unscaled(bedpts[1]),unscaled(bedpts[2]),unscaled(bedpts[3])}, tree_support->m_print_config->printable_height };
|
||||
Pointfs bedptsf;
|
||||
std::transform(bedpts.begin(), bedpts.end(), std::back_inserter(bedptsf), [](const Point &p) { return unscale(p); });
|
||||
BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height };
|
||||
|
||||
TreeSupport3D::generate_support_areas(*print_object.print(), tree_support, build_volume, { idx }, throw_on_cancel);
|
||||
}
|
||||
|
|
|
@ -45,8 +45,6 @@ using SupportGeneratorLayersPtr = std::vector<SupportGeneratorLayer*>;
|
|||
namespace TreeSupport3D
|
||||
{
|
||||
|
||||
// The number of vertices in each circle.
|
||||
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
|
||||
|
||||
struct AreaIncreaseSettings
|
||||
{
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
#include "../BoundingBox.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "../Slicing.hpp" // SlicingParams
|
||||
#include "TreeModelVolumes.hpp"
|
||||
#include "SupportLayer.hpp"
|
||||
#include "SupportParameters.hpp"
|
||||
namespace Slic3r
|
||||
{
|
||||
// The number of vertices in each circle.
|
||||
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
|
||||
namespace TreeSupport3D
|
||||
{
|
||||
using LayerIndex = int;
|
||||
|
@ -78,6 +79,7 @@ struct TreeSupportMeshGroupSettings {
|
|||
double support_tree_angle_slow = 25;// TODO add a setting?
|
||||
double support_tree_branch_diameter_angle = 5; // TODO add a setting?
|
||||
double tree_support_tip_diameter = 0.8;
|
||||
this->support_tree_branch_distance = scaled<coord_t>(config.tree_support_branch_distance.value);
|
||||
this->support_tree_angle = std::clamp<double>(config.tree_support_branch_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
|
||||
this->support_tree_angle_slow = std::clamp<double>(support_tree_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON);
|
||||
this->support_tree_branch_diameter = scaled<coord_t>(config.tree_support_branch_diameter.value);
|
||||
|
@ -728,5 +730,16 @@ private:
|
|||
std::mutex m_mutex_layer_storage;
|
||||
};
|
||||
|
||||
enum class LineStatus
|
||||
{
|
||||
INVALID,
|
||||
TO_MODEL,
|
||||
TO_MODEL_GRACIOUS,
|
||||
TO_MODEL_GRACIOUS_SAFE,
|
||||
TO_BP,
|
||||
TO_BP_SAFE
|
||||
};
|
||||
|
||||
|
||||
} // namespace TreeSupport3D
|
||||
} // namespace slic3r
|
|
@ -1449,44 +1449,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
|||
new_conf.set_key_value("support_style", new ConfigOptionEnum<SupportMaterialStyle>(smsDefault));
|
||||
m_config_manipulation.apply(m_config, &new_conf);
|
||||
}
|
||||
#if 0
|
||||
// BBS popup a message to ask the user to set optimum parameters for tree support
|
||||
if (opt_key == "support_type" || opt_key == "support_style") {
|
||||
if (is_tree_slim(m_config->opt_enum<SupportType>("support_type"), m_config->opt_enum<SupportMaterialStyle>("support_style")) &&
|
||||
!(m_config->opt_float("support_top_z_distance") == 0 && m_config->opt_int("support_interface_top_layers") == 0 && m_config->opt_int("tree_support_wall_count") == 2)) {
|
||||
wxString msg_text = _L("We have added an experimental style \"Tree Slim\" that features smaller support volume but weaker strength.\n"
|
||||
"We recommend using it with: 0 interface layers, 0 top distance, 2 walls.");
|
||||
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
||||
"Yes - Change these settings automatically\n"
|
||||
"No - Do not change these settings for me");
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
||||
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(0));
|
||||
new_conf.set_key_value("tree_support_wall_count", new ConfigOptionInt(2));
|
||||
m_config_manipulation.apply(m_config, &new_conf);
|
||||
}
|
||||
wxGetApp().plater()->update();
|
||||
} else if ((m_config->opt_enum<SupportType>("support_type")==stTreeAuto && (m_config->opt_enum<SupportMaterialStyle>("support_style")==smsTreeStrong || m_config->opt_enum<SupportMaterialStyle>("support_style") == smsTreeHybrid)) &&
|
||||
!((m_config->opt_float("support_top_z_distance") >=0.1 || is_support_filament(m_config->opt_int("support_interface_filament") - 1))
|
||||
&& m_config->opt_int("support_interface_top_layers") >1) ) {
|
||||
wxString msg_text = _L("For \"Tree Strong\" and \"Tree Hybrid\" styles, we recommend the following settings: at least 2 interface layers, at least 0.1mm top z distance or using support materials on interface.");
|
||||
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
||||
"Yes - Change these settings automatically\n"
|
||||
"No - Do not change these settings for me");
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
if (!is_support_filament(m_config->opt_int("support_interface_filament") - 1) && m_config->opt_float("support_top_z_distance") < 0.1)
|
||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0.2));
|
||||
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(2));
|
||||
m_config_manipulation.apply(m_config, &new_conf);
|
||||
}
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// BBS popup a message to ask the user to set optimum parameters for support interface if support materials are used
|
||||
if (opt_key == "support_interface_filament") {
|
||||
int interface_filament_id = m_config->opt_int("support_interface_filament") - 1; // the displayed id is based from 1, while internal id is based from 0
|
||||
|
|
Loading…
Reference in New Issue