mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
Tree support "on build plate only" no interface layers fix (#13192)
This commit is contained in:
@@ -44,6 +44,18 @@ if (SLIC3R_GUI)
|
||||
include(${wxWidgets_USE_FILE})
|
||||
endif()
|
||||
|
||||
if(APPLE AND TARGET wx::wxgl)
|
||||
# Newer wxWidgets CMake exports may inject the macOS OpenGL framework
|
||||
# as a quoted file path inside wx::wxgl, which Ninja then treats as a
|
||||
# missing input file. Orca links OpenGL explicitly elsewhere, so strip
|
||||
# these broken pseudo-paths from the imported target.
|
||||
get_target_property(_wx_gl_libs wx::wxgl INTERFACE_LINK_LIBRARIES)
|
||||
if(_wx_gl_libs)
|
||||
list(FILTER _wx_gl_libs EXCLUDE REGEX "framework OpenGL")
|
||||
set_target_properties(wx::wxgl PROPERTIES INTERFACE_LINK_LIBRARIES "${_wx_gl_libs}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(JPEG QUIET)
|
||||
|
||||
string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES})
|
||||
|
||||
@@ -2076,9 +2076,10 @@ void TreeSupport::draw_circles()
|
||||
if (!area.empty()) has_circle_node = true;
|
||||
if (node.need_extra_wall) need_extra_wall = true;
|
||||
|
||||
// merge overhang to get a smoother interface surface
|
||||
// Do not merge when buildplate_only is on, because some underneath nodes may have been deleted.
|
||||
if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !on_buildplate_only && !node.is_sharp_tail) {
|
||||
// Merge the overhang into the roof area so tree tips can still produce
|
||||
// a continuous support interface. Suppressing this for build-plate-only
|
||||
// support drops the roof polygons entirely in valid tree branches.
|
||||
if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !node.is_sharp_tail) {
|
||||
ExPolygons overhang_expanded;
|
||||
if (node.overhang.contour.size() > 100 || node.overhang.holes.size()>1)
|
||||
overhang_expanded.emplace_back(node.overhang);
|
||||
@@ -2121,6 +2122,17 @@ void TreeSupport::draw_circles()
|
||||
roof_1st_layer = diff_ex(roof_1st_layer, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas,get_extents(roof_1st_layer)));
|
||||
roof_1st_layer = intersection_ex(roof_1st_layer, m_machine_border);
|
||||
|
||||
// Build-plate-only pruning can collapse the roof stack down to a single
|
||||
// printable layer. In that case we still need to emit an interface layer
|
||||
// instead of downgrading the last roof-adjacent layer to base support.
|
||||
if (on_buildplate_only && top_interface_layers > 0 && roof_areas.empty() && !roof_1st_layer.empty()) {
|
||||
append(roof_areas, roof_1st_layer);
|
||||
roof_1st_layer.clear();
|
||||
max_layers_above_roof = std::max(max_layers_above_roof, max_layers_above_roof1);
|
||||
max_layers_above_roof1 = 0;
|
||||
interface_id = obj_layer_nr % top_interface_layers;
|
||||
}
|
||||
|
||||
ExPolygons roofs; append(roofs, roof_1st_layer); append(roofs, roof_areas);append(roofs, roof_gap_areas);
|
||||
base_areas = diff_ex(base_areas, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roofs, get_extents(base_areas)));
|
||||
base_areas = intersection_ex(base_areas, m_machine_border);
|
||||
|
||||
@@ -898,6 +898,7 @@ public:
|
||||
size_t dtt_roof_tip;
|
||||
for (dtt_roof_tip = 0; dtt_roof_tip < roof_tip_layers && insert_layer_idx - dtt_roof_tip >= 1; ++ dtt_roof_tip) {
|
||||
size_t this_layer_idx = insert_layer_idx - dtt_roof_tip;
|
||||
const size_t roof_recovery_depth = dtt_roof_tip + supports_roof_layers;
|
||||
auto evaluateRoofWillGenerate = [&](const std::pair<Point, LineStatus> &p) {
|
||||
//FIXME Vojtech: The circle is just shifted, it has a known size, the infill should fit all the time!
|
||||
#if 0
|
||||
@@ -927,7 +928,9 @@ public:
|
||||
// don't move until
|
||||
roof_tip_layers - dtt_roof_tip,
|
||||
// supports roof
|
||||
dtt_roof_tip + supports_roof_layers > 0,
|
||||
roof_recovery_depth > 0,
|
||||
// recovered roof/contact depth for this slice
|
||||
roof_recovery_depth,
|
||||
// disable ovalization
|
||||
false);
|
||||
}
|
||||
@@ -942,9 +945,10 @@ public:
|
||||
roof_circle.translate(p.first);
|
||||
new_roofs.emplace_back(std::move(roof_circle));
|
||||
}
|
||||
this->add_roof(std::move(new_roofs), this_layer_idx, dtt_roof_tip + supports_roof_layers);
|
||||
this->add_roof(std::move(new_roofs), this_layer_idx, roof_recovery_depth);
|
||||
}
|
||||
|
||||
const size_t roof_recovery_depth = dtt_roof_tip + supports_roof_layers;
|
||||
for (const LineInformation &line : lines) {
|
||||
// If a line consists of enough tips, the assumption is that it is not a single tip, but part of a simulated support pattern.
|
||||
// Ovalisation should be disabled for these to improve the quality of the lines when tip_diameter=line_width
|
||||
@@ -954,14 +958,16 @@ public:
|
||||
// don't move until
|
||||
dont_move_until > dtt_roof_tip ? dont_move_until - dtt_roof_tip : 0,
|
||||
// supports roof
|
||||
dtt_roof_tip + supports_roof_layers > 0,
|
||||
roof_recovery_depth > 0,
|
||||
// recovered roof/contact depth for this slice
|
||||
roof_recovery_depth,
|
||||
disable_ovalistation);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// called by this->add_points_along_lines()
|
||||
void add_point_as_influence_area(std::pair<Point, LineStatus> p, LayerIndex insert_layer, size_t dont_move_until, bool roof, bool skip_ovalisation)
|
||||
void add_point_as_influence_area(std::pair<Point, LineStatus> p, LayerIndex insert_layer, size_t dont_move_until, bool roof, size_t roof_recovery_dtt, bool skip_ovalisation)
|
||||
{
|
||||
bool to_bp = p.second == LineStatus::TO_BP || p.second == LineStatus::TO_BP_SAFE;
|
||||
bool gracious = to_bp || p.second == LineStatus::TO_MODEL_GRACIOUS || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE;
|
||||
@@ -997,7 +1003,7 @@ private:
|
||||
state.supports_roof = roof;
|
||||
state.dont_move_until = dont_move_until;
|
||||
state.can_use_safe_radius = safe_radius;
|
||||
state.missing_roof_layers = force_tip_to_roof ? dont_move_until : 0;
|
||||
state.set_pending_roof_recovery(force_tip_to_roof ? dont_move_until : 0, roof_recovery_dtt);
|
||||
state.skip_ovalisation = skip_ovalisation;
|
||||
move_bounds[insert_layer].emplace_back(state, std::move(circle));
|
||||
}
|
||||
@@ -1095,10 +1101,9 @@ void finalize_raft_contact(
|
||||
// 1) Maximum num_support_roof_layers roof (top interface & contact) layers.
|
||||
// 2) Tree tips supporting either the roof layers or the object itself.
|
||||
// num_support_roof_layers should always be respected:
|
||||
// If num_support_roof_layers contact layers could not be produced, then the tree tip
|
||||
// is augmented with SupportElementState::missing_roof_layers
|
||||
// and the top "missing_roof_layers" of such particular tree tips are supposed to be coverted to
|
||||
// roofs aka interface layers by the tool path generator.
|
||||
// If the requested roof/contact stack cannot be generated directly, the affected tree tips
|
||||
// carry explicit pending roof recovery metadata so the sliced branch geometry can later be
|
||||
// promoted back to top contacts / interfaces at the correct contact depth.
|
||||
void sample_overhang_area(
|
||||
// Area to support
|
||||
Polygons &&overhang_area,
|
||||
@@ -1606,7 +1611,6 @@ static Point move_inside_if_outside(const Polygons &polygons, Point from, int di
|
||||
if (settings.increase_radius)
|
||||
current_elem.effective_radius_height += 1;
|
||||
coord_t radius = support_element_collision_radius(config, current_elem);
|
||||
|
||||
const auto _tiny_area_threshold = tiny_area_threshold();
|
||||
if (settings.move) {
|
||||
increased = relevant_offset;
|
||||
@@ -2059,7 +2063,10 @@ static void increase_areas_one_layer(
|
||||
out.supports_roof = first.supports_roof || second.supports_roof;
|
||||
out.dont_move_until = std::max(first.dont_move_until, second.dont_move_until);
|
||||
out.can_use_safe_radius = first.can_use_safe_radius || second.can_use_safe_radius;
|
||||
out.missing_roof_layers = std::min(first.missing_roof_layers, second.missing_roof_layers);
|
||||
// Preserve the deepest outstanding roof recovery request across merged sub-branches.
|
||||
out.set_pending_roof_recovery(
|
||||
std::max(first.missing_roof_layers, second.missing_roof_layers),
|
||||
std::max(first.roof_recovery_dtt, second.roof_recovery_dtt));
|
||||
out.skip_ovalisation = false;
|
||||
if (first.target_height > second.target_height) {
|
||||
out.target_height = first.target_height;
|
||||
@@ -3473,7 +3480,6 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
||||
|
||||
// value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas
|
||||
std::vector<SupportElements> move_bounds(num_support_layers);
|
||||
|
||||
// ### Place tips of the support tree
|
||||
for (size_t mesh_idx : processing.second)
|
||||
generate_initial_areas(*print.get_object(mesh_idx), volumes, config, overhangs,
|
||||
@@ -3591,7 +3597,33 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
||||
// storage.support.generated = true;
|
||||
}
|
||||
|
||||
// Organic specific: Smooth branches and produce one cummulative mesh to be sliced.
|
||||
static void recover_pending_branch_roofs(
|
||||
InterfacePlacer &interface_placer,
|
||||
const std::vector<const SupportElement*> &branch_path,
|
||||
const LayerIndex layer_begin,
|
||||
std::vector<Polygons> &slices)
|
||||
{
|
||||
if (! interface_placer.support_parameters.has_top_contacts)
|
||||
return;
|
||||
|
||||
for (auto it = branch_path.rbegin(); it != branch_path.rend(); ++ it) {
|
||||
const SupportElement &el = **it;
|
||||
if (! el.state.has_pending_roof_recovery())
|
||||
break;
|
||||
|
||||
const LayerIndex slice_idx = el.state.layer_idx - layer_begin;
|
||||
if (slice_idx < 0 || slice_idx >= LayerIndex(slices.size()))
|
||||
continue;
|
||||
if (slices[size_t(slice_idx)].empty())
|
||||
continue;
|
||||
if (el.state.roof_recovery_dtt > interface_placer.support_parameters.num_top_interface_layers)
|
||||
continue;
|
||||
|
||||
interface_placer.add_roof(std::move(slices[size_t(slice_idx)]), el.state.layer_idx, el.state.roof_recovery_dtt);
|
||||
}
|
||||
}
|
||||
|
||||
// Organic specific: Smooth branches and produce one cumulative mesh to be sliced.
|
||||
void organic_draw_branches(
|
||||
PrintObject &print_object,
|
||||
TreeModelVolumes &volumes,
|
||||
@@ -3770,13 +3802,12 @@ void organic_draw_branches(
|
||||
// ++ ielement;
|
||||
}
|
||||
}
|
||||
|
||||
const SlicingParameters &slicing_params = print_object.slicing_parameters();
|
||||
MeshSlicingParams mesh_slicing_params;
|
||||
mesh_slicing_params.mode = MeshSlicingParams::SlicingMode::Positive;
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, trees.size(), 1),
|
||||
[&trees, &volumes, &config, &slicing_params, &move_bounds, &mesh_slicing_params, &throw_on_cancel](const tbb::blocked_range<size_t> &range) {
|
||||
[&trees, &volumes, &config, &slicing_params, &move_bounds, &mesh_slicing_params, &interface_placer, &throw_on_cancel](const tbb::blocked_range<size_t> &range) {
|
||||
indexed_triangle_set partial_mesh;
|
||||
std::vector<float> slice_z;
|
||||
std::vector<Polygons> bottom_contacts;
|
||||
@@ -3811,7 +3842,7 @@ void organic_draw_branches(
|
||||
num_empty = std::find_if(slices.begin(), slices.end(), [](auto &s) { return !s.empty(); }) - slices.begin();
|
||||
} else {
|
||||
if (branch.has_root) {
|
||||
if (branch.path.front()->state.to_model_gracious) {
|
||||
if (config.support_rests_on_model && branch.path.front()->state.to_model_gracious) {
|
||||
if (config.settings.support_floor_layers > 0)
|
||||
//FIXME one may just take the whole tree slice as bottom interface.
|
||||
bottom_contacts.emplace_back(intersection_clipped(slices.front(), volumes.getPlaceableAreas(0, layer_begin, [] {})));
|
||||
@@ -3860,7 +3891,7 @@ void organic_draw_branches(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (config.settings.support_floor_layers > 0)
|
||||
if (config.support_rests_on_model && config.settings.support_floor_layers > 0)
|
||||
for (int i = int(bottom_extra_slices.size()) - 2; i >= 0; -- i)
|
||||
bottom_contacts.emplace_back(
|
||||
intersection_clipped(bottom_extra_slices[i].polygons, volumes.getPlaceableAreas(0, layer_begin - i - 1, [] {})));
|
||||
@@ -3872,19 +3903,7 @@ void organic_draw_branches(
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
//FIXME branch.has_tip seems to not be reliable.
|
||||
if (branch.has_tip && interface_placer.support_parameters.has_top_contacts)
|
||||
// Add top slices to top contacts / interfaces / base interfaces.
|
||||
for (int i = int(branch.path.size()) - 1; i >= 0; -- i) {
|
||||
const SupportElement &el = *branch.path[i];
|
||||
if (el.state.missing_roof_layers == 0)
|
||||
break;
|
||||
//FIXME Move or not?
|
||||
interface_placer.add_roof(std::move(slices[int(slices.size()) - i - 1]), el.state.layer_idx,
|
||||
interface_placer.support_parameters.num_top_interface_layers + 1 - el.state.missing_roof_layers);
|
||||
}
|
||||
#endif
|
||||
recover_pending_branch_roofs(interface_placer, branch.path, layer_begin, slices);
|
||||
}
|
||||
|
||||
layer_begin += LayerIndex(num_empty);
|
||||
|
||||
@@ -199,9 +199,20 @@ struct SupportElementState : public SupportElementStateBits
|
||||
AreaIncreaseSettings last_area_increase;
|
||||
|
||||
/*!
|
||||
* \brief Amount of roof layers that were not yet added, because the branch needed to move.
|
||||
* \brief Number of pending roof/contact recovery slices from this node downward, including this node.
|
||||
*/
|
||||
uint32_t missing_roof_layers;
|
||||
uint32_t missing_roof_layers = 0;
|
||||
|
||||
/*!
|
||||
* \brief Contact/interface depth that this node should recover when missing_roof_layers > 0.
|
||||
*/
|
||||
uint32_t roof_recovery_dtt = 0;
|
||||
|
||||
void set_pending_roof_recovery(uint32_t pending_layers, uint32_t recovery_depth)
|
||||
{
|
||||
this->missing_roof_layers = pending_layers;
|
||||
this->roof_recovery_dtt = pending_layers > 0 ? recovery_depth : 0;
|
||||
}
|
||||
|
||||
// called by increase_single_area() and increaseAreas()
|
||||
[[nodiscard]] static SupportElementState propagate_down(const SupportElementState &src)
|
||||
@@ -209,6 +220,10 @@ struct SupportElementState : public SupportElementStateBits
|
||||
SupportElementState dst{ src };
|
||||
++ dst.distance_to_top;
|
||||
-- dst.layer_idx;
|
||||
if (dst.has_pending_roof_recovery()) {
|
||||
-- dst.missing_roof_layers;
|
||||
++ dst.roof_recovery_dtt;
|
||||
}
|
||||
// set to invalid as we are a new node on a new layer
|
||||
dst.result_on_layer_reset();
|
||||
dst.skip_ovalisation = false;
|
||||
@@ -216,6 +231,7 @@ struct SupportElementState : public SupportElementStateBits
|
||||
}
|
||||
|
||||
[[nodiscard]] bool locked() const { return this->distance_to_top < this->dont_move_until; }
|
||||
[[nodiscard]] bool has_pending_roof_recovery() const { return this->missing_roof_layers > 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
Reference in New Issue
Block a user