mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 08:41:57 +08:00
Split check_stability into multiple functions.
In the SupportSpotsGenerator the function check_stability got out of hand. It is refactored into multiple smaller functions.
This commit is contained in:
parent
26fbf6e111
commit
5e8a1ffd38
@ -796,6 +796,249 @@ void reckon_new_support_point(ObjectPart &part,
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalSupports {
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> unstable_lines_per_slice;
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> ext_perim_lines_per_slice;
|
||||
};
|
||||
|
||||
struct EnitityToCheck
|
||||
{
|
||||
const ExtrusionEntity *e;
|
||||
const LayerRegion *region;
|
||||
size_t slice_idx;
|
||||
};
|
||||
|
||||
// TODO DRY: Very similar to gather extrusions.
|
||||
std::vector<EnitityToCheck> gather_entities_to_check(const Layer* layer) {
|
||||
auto get_flat_entities = [](const ExtrusionEntity *e) {
|
||||
std::vector<const ExtrusionEntity *> entities;
|
||||
std::vector<const ExtrusionEntity *> queue{e};
|
||||
while (!queue.empty()) {
|
||||
const ExtrusionEntity *next = queue.back();
|
||||
queue.pop_back();
|
||||
if (next->is_collection()) {
|
||||
for (const ExtrusionEntity *e : static_cast<const ExtrusionEntityCollection *>(next)->entities) {
|
||||
queue.push_back(e);
|
||||
}
|
||||
} else {
|
||||
entities.push_back(next);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
};
|
||||
|
||||
std::vector<EnitityToCheck> entities_to_check;
|
||||
for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
|
||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
for (const auto &island : slice.islands) {
|
||||
for (const LayerExtrusionRange &fill_range : island.fills) {
|
||||
const LayerRegion *fill_region = layer->get_region(fill_range.region());
|
||||
for (size_t fill_idx : fill_range) {
|
||||
for (const ExtrusionEntity *e : get_flat_entities(fill_region->fills().entities[fill_idx])) {
|
||||
if (e->role() == ExtrusionRole::BridgeInfill) {
|
||||
entities_to_check.push_back({e, fill_region, slice_idx});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region());
|
||||
for (size_t perimeter_idx : island.perimeters) {
|
||||
for (const ExtrusionEntity *e : get_flat_entities(perimeter_region->perimeters().entities[perimeter_idx])) {
|
||||
entities_to_check.push_back({e, perimeter_region, slice_idx});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return entities_to_check;
|
||||
}
|
||||
|
||||
LocalSupports compute_local_supports(
|
||||
const std::vector<EnitityToCheck>& entities_to_check,
|
||||
const std::optional<Linesf>& previous_layer_boundary,
|
||||
const LD& prev_layer_ext_perim_lines,
|
||||
size_t slices_count,
|
||||
const Params& params
|
||||
) {
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> unstable_lines_per_slice(slices_count);
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> ext_perim_lines_per_slice(slices_count);
|
||||
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary_distancer =
|
||||
(previous_layer_boundary ? AABBTreeLines::LinesDistancer<Linef>{*previous_layer_boundary} : AABBTreeLines::LinesDistancer<Linef>{});
|
||||
|
||||
if constexpr (debug_files) {
|
||||
for (const auto &e_to_check : entities_to_check) {
|
||||
for (const auto &line : check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines,
|
||||
prev_layer_boundary_distancer, params)) {
|
||||
if (line.support_point_generated.has_value()) {
|
||||
unstable_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
if (line.is_external_perimeter()) {
|
||||
ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, entities_to_check.size()),
|
||||
[&entities_to_check, &prev_layer_ext_perim_lines, &prev_layer_boundary_distancer, &unstable_lines_per_slice,
|
||||
&ext_perim_lines_per_slice, ¶ms](tbb::blocked_range<size_t> r) {
|
||||
for (size_t entity_idx = r.begin(); entity_idx < r.end(); ++entity_idx) {
|
||||
const auto &e_to_check = entities_to_check[entity_idx];
|
||||
for (const auto &line :
|
||||
check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines,
|
||||
prev_layer_boundary_distancer, params)) {
|
||||
if (line.support_point_generated.has_value()) {
|
||||
unstable_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
if (line.is_external_perimeter()) {
|
||||
ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return {unstable_lines_per_slice, ext_perim_lines_per_slice};
|
||||
}
|
||||
|
||||
struct SliceMappings
|
||||
{
|
||||
std::unordered_map<size_t, size_t> index_to_object_part_mapping;
|
||||
std::unordered_map<size_t, SliceConnection> index_to_weakest_connection;
|
||||
};
|
||||
|
||||
std::optional<PartialObject> to_partial_object(const ObjectPart& part) {
|
||||
if (part.volume > EPSILON) {
|
||||
return PartialObject{part.volume_centroid_accumulator / part.volume, part.volume,
|
||||
part.connected_to_bed};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
SliceMappings update_active_object_parts(const Layer *layer,
|
||||
const Params ¶ms,
|
||||
const std::vector<SliceConnection> &precomputed_slice_connections,
|
||||
const SliceMappings &previous_slice_mappings,
|
||||
ActiveObjectParts &active_object_parts,
|
||||
PartialObjects &partial_objects)
|
||||
{
|
||||
SliceMappings new_slice_mappings;
|
||||
|
||||
for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
|
||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
const std::vector<const ExtrusionEntityCollection*> extrusion_collections{gather_extrusions(slice, layer)};
|
||||
const bool connected_to_bed = int(layer->id()) == params.raft_layers_count;
|
||||
|
||||
const std::optional<Polygons> brim{
|
||||
has_brim(layer, params) ?
|
||||
std::optional{get_brim(layer->lslices[slice_idx], params.brim_type, params.brim_width)} :
|
||||
std::nullopt
|
||||
};
|
||||
ObjectPart new_part{
|
||||
extrusion_collections,
|
||||
connected_to_bed,
|
||||
layer->print_z,
|
||||
layer->height,
|
||||
brim
|
||||
};
|
||||
|
||||
const SliceConnection &connection_to_below = precomputed_slice_connections[slice_idx];
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
std::cout << "SLICE IDX: " << slice_idx << std::endl;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
std::cout << "connected to slice below: " << link.slice_idx << " by area : " << link.area << std::endl;
|
||||
}
|
||||
connection_to_below.print_info("CONNECTION TO BELOW");
|
||||
#endif
|
||||
|
||||
if (connection_to_below.area < EPSILON) { // new object part emerging
|
||||
size_t part_id = active_object_parts.insert(new_part);
|
||||
new_slice_mappings.index_to_object_part_mapping.emplace(slice_idx, part_id);
|
||||
new_slice_mappings.index_to_weakest_connection.emplace(slice_idx, connection_to_below);
|
||||
} else {
|
||||
size_t final_part_id{};
|
||||
SliceConnection transfered_weakest_connection{};
|
||||
// MERGE parts
|
||||
{
|
||||
std::unordered_set<size_t> parts_ids;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
size_t part_id = active_object_parts.get_flat_id(previous_slice_mappings.index_to_object_part_mapping.at(link.slice_idx));
|
||||
parts_ids.insert(part_id);
|
||||
transfered_weakest_connection.add(previous_slice_mappings.index_to_weakest_connection.at(link.slice_idx));
|
||||
}
|
||||
|
||||
final_part_id = *parts_ids.begin();
|
||||
for (size_t part_id : parts_ids) {
|
||||
if (final_part_id != part_id) {
|
||||
auto object_part = active_object_parts.access(part_id);
|
||||
if (auto object = to_partial_object(object_part)) {
|
||||
partial_objects.push_back(std::move(*object));
|
||||
}
|
||||
active_object_parts.merge(part_id, final_part_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
const float bottom_z = layer->bottom_z();
|
||||
auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) {
|
||||
if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the
|
||||
// weakest connection.
|
||||
return INFINITY;
|
||||
}
|
||||
Vec3f centroid = conn.centroid_accumulator / conn.area;
|
||||
Vec2f variance = (conn.second_moment_of_area_accumulator / conn.area -
|
||||
centroid.head<2>().cwiseProduct(centroid.head<2>()));
|
||||
float xy_variance = variance.x() + variance.y();
|
||||
float arm_len_estimate = std::max(1.0f, bottom_z - (conn.centroid_accumulator.z() / conn.area));
|
||||
return conn.area * sqrt(xy_variance) / arm_len_estimate;
|
||||
};
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
connection_to_below.print_info("new_weakest_connection");
|
||||
transfered_weakest_connection.print_info("transfered_weakest_connection");
|
||||
#endif
|
||||
|
||||
if (estimate_conn_strength(transfered_weakest_connection) > estimate_conn_strength(connection_to_below)) {
|
||||
transfered_weakest_connection = connection_to_below;
|
||||
}
|
||||
new_slice_mappings.index_to_weakest_connection.emplace(slice_idx, transfered_weakest_connection);
|
||||
new_slice_mappings.index_to_object_part_mapping.emplace(slice_idx, final_part_id);
|
||||
ObjectPart &part = active_object_parts.access(final_part_id);
|
||||
part.add(new_part);
|
||||
}
|
||||
}
|
||||
return new_slice_mappings;
|
||||
}
|
||||
|
||||
void reckon_global_supports(const tbb::concurrent_vector<ExtrusionLine> &external_perimeter_lines,
|
||||
const coordf_t layer_bottom_z,
|
||||
const Params ¶ms,
|
||||
ObjectPart &part,
|
||||
SliceConnection &weakest_connection,
|
||||
SupportPoints &supp_points,
|
||||
SupportGridFilter &supports_presence_grid)
|
||||
{
|
||||
LD current_slice_lines_distancer({external_perimeter_lines.begin(), external_perimeter_lines.end()});
|
||||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
||||
|
||||
for (const ExtrusionLine &line : external_perimeter_lines) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points &&
|
||||
line.curled_up_height < params.curling_tolerance_limit) ||
|
||||
line.len < EPSILON) {
|
||||
unchecked_dist += line.len;
|
||||
} else {
|
||||
unchecked_dist = line.len;
|
||||
Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f);
|
||||
auto [dist, nidx, nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
|
||||
Vec3f position = to_3d(nearest_point, layer_bottom_z);
|
||||
auto [force, cause] = part.is_stable_while_extruding(weakest_connection, line, position, layer_bottom_z, params);
|
||||
if (force > 0) {
|
||||
SupportPoint support_point{cause, position, params.support_points_interface_radius};
|
||||
reckon_new_support_point(part, weakest_connection, supp_points, supports_presence_grid, support_point, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
||||
const PrecomputedSliceConnections &precomputed_slices_connections,
|
||||
const PrintTryCancel &cancel_func,
|
||||
@ -807,248 +1050,55 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject
|
||||
PartialObjects partial_objects{};
|
||||
LD prev_layer_ext_perim_lines;
|
||||
|
||||
std::unordered_map<size_t, size_t> prev_slice_idx_to_object_part_mapping;
|
||||
std::unordered_map<size_t, size_t> next_slice_idx_to_object_part_mapping;
|
||||
std::unordered_map<size_t, SliceConnection> prev_slice_idx_to_weakest_connection;
|
||||
std::unordered_map<size_t, SliceConnection> next_slice_idx_to_weakest_connection;
|
||||
SliceMappings slice_mappings;
|
||||
|
||||
auto remember_partial_object = [&active_object_parts, &partial_objects](size_t object_part_id) {
|
||||
auto object_part = active_object_parts.access(object_part_id);
|
||||
if (object_part.volume > EPSILON) {
|
||||
partial_objects.emplace_back(object_part.volume_centroid_accumulator / object_part.volume, object_part.volume,
|
||||
object_part.connected_to_bed);
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t layer_idx = 0; layer_idx < po->layer_count(); ++layer_idx) {
|
||||
cancel_func();
|
||||
const Layer *layer = po->get_layer(layer_idx);
|
||||
float bottom_z = layer->bottom_z();
|
||||
auto create_support_point_position = [bottom_z](const Vec2f &layer_pos) { return Vec3f{layer_pos.x(), layer_pos.y(), bottom_z}; };
|
||||
|
||||
for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
|
||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
const std::vector<const ExtrusionEntityCollection*> extrusion_collections{gather_extrusions(slice, layer)};
|
||||
const bool connected_to_bed = int(layer->id()) == params.raft_layers_count;
|
||||
slice_mappings = update_active_object_parts(layer, params, precomputed_slices_connections[layer_idx], slice_mappings, active_object_parts, partial_objects);
|
||||
|
||||
const std::optional<Polygons> brim{
|
||||
has_brim(layer, params) ?
|
||||
std::optional{get_brim(layer->lslices[slice_idx], params.brim_type, params.brim_width)} :
|
||||
std::nullopt
|
||||
};
|
||||
ObjectPart new_part{
|
||||
extrusion_collections,
|
||||
connected_to_bed,
|
||||
layer->print_z,
|
||||
layer->height,
|
||||
brim
|
||||
};
|
||||
std::optional<Linesf> prev_layer_boundary = layer->lower_layer != nullptr ?
|
||||
std::optional{to_unscaled_linesf(layer->lower_layer->lslices)} :
|
||||
std::nullopt;
|
||||
|
||||
const SliceConnection &connection_to_below = precomputed_slices_connections[layer_idx][slice_idx];
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
std::cout << "SLICE IDX: " << slice_idx << std::endl;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
std::cout << "connected to slice below: " << link.slice_idx << " by area : " << link.area << std::endl;
|
||||
}
|
||||
connection_to_below.print_info("CONNECTION TO BELOW");
|
||||
#endif
|
||||
|
||||
if (connection_to_below.area < EPSILON) { // new object part emerging
|
||||
size_t part_id = active_object_parts.insert(new_part);
|
||||
next_slice_idx_to_object_part_mapping.emplace(slice_idx, part_id);
|
||||
next_slice_idx_to_weakest_connection.emplace(slice_idx, connection_to_below);
|
||||
} else {
|
||||
size_t final_part_id{};
|
||||
SliceConnection transfered_weakest_connection{};
|
||||
// MERGE parts
|
||||
{
|
||||
std::unordered_set<size_t> parts_ids;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
size_t part_id = active_object_parts.get_flat_id(prev_slice_idx_to_object_part_mapping.at(link.slice_idx));
|
||||
parts_ids.insert(part_id);
|
||||
transfered_weakest_connection.add(prev_slice_idx_to_weakest_connection.at(link.slice_idx));
|
||||
}
|
||||
|
||||
final_part_id = *parts_ids.begin();
|
||||
for (size_t part_id : parts_ids) {
|
||||
if (final_part_id != part_id) {
|
||||
remember_partial_object(part_id);
|
||||
active_object_parts.merge(part_id, final_part_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) {
|
||||
if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the
|
||||
// weakest connection.
|
||||
return INFINITY;
|
||||
}
|
||||
Vec3f centroid = conn.centroid_accumulator / conn.area;
|
||||
Vec2f variance = (conn.second_moment_of_area_accumulator / conn.area -
|
||||
centroid.head<2>().cwiseProduct(centroid.head<2>()));
|
||||
float xy_variance = variance.x() + variance.y();
|
||||
float arm_len_estimate = std::max(1.0f, bottom_z - (conn.centroid_accumulator.z() / conn.area));
|
||||
return conn.area * sqrt(xy_variance) / arm_len_estimate;
|
||||
};
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
connection_to_below.print_info("new_weakest_connection");
|
||||
transfered_weakest_connection.print_info("transfered_weakest_connection");
|
||||
#endif
|
||||
|
||||
if (estimate_conn_strength(transfered_weakest_connection) > estimate_conn_strength(connection_to_below)) {
|
||||
transfered_weakest_connection = connection_to_below;
|
||||
}
|
||||
next_slice_idx_to_weakest_connection.emplace(slice_idx, transfered_weakest_connection);
|
||||
next_slice_idx_to_object_part_mapping.emplace(slice_idx, final_part_id);
|
||||
ObjectPart &part = active_object_parts.access(final_part_id);
|
||||
part.add(new_part);
|
||||
}
|
||||
}
|
||||
|
||||
prev_slice_idx_to_object_part_mapping = next_slice_idx_to_object_part_mapping;
|
||||
next_slice_idx_to_object_part_mapping.clear();
|
||||
prev_slice_idx_to_weakest_connection = next_slice_idx_to_weakest_connection;
|
||||
next_slice_idx_to_weakest_connection.clear();
|
||||
|
||||
auto get_flat_entities = [](const ExtrusionEntity *e) {
|
||||
std::vector<const ExtrusionEntity *> entities;
|
||||
std::vector<const ExtrusionEntity *> queue{e};
|
||||
while (!queue.empty()) {
|
||||
const ExtrusionEntity *next = queue.back();
|
||||
queue.pop_back();
|
||||
if (next->is_collection()) {
|
||||
for (const ExtrusionEntity *e : static_cast<const ExtrusionEntityCollection *>(next)->entities) {
|
||||
queue.push_back(e);
|
||||
}
|
||||
} else {
|
||||
entities.push_back(next);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
};
|
||||
|
||||
struct EnitityToCheck
|
||||
{
|
||||
const ExtrusionEntity *e;
|
||||
const LayerRegion *region;
|
||||
size_t slice_idx;
|
||||
};
|
||||
std::vector<EnitityToCheck> entities_to_check;
|
||||
for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
|
||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
for (const auto &island : slice.islands) {
|
||||
for (const LayerExtrusionRange &fill_range : island.fills) {
|
||||
const LayerRegion *fill_region = layer->get_region(fill_range.region());
|
||||
for (size_t fill_idx : fill_range) {
|
||||
for (const ExtrusionEntity *e : get_flat_entities(fill_region->fills().entities[fill_idx])) {
|
||||
if (e->role() == ExtrusionRole::BridgeInfill) {
|
||||
entities_to_check.push_back({e, fill_region, slice_idx});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region());
|
||||
for (size_t perimeter_idx : island.perimeters) {
|
||||
for (const ExtrusionEntity *e : get_flat_entities(perimeter_region->perimeters().entities[perimeter_idx])) {
|
||||
entities_to_check.push_back({e, perimeter_region, slice_idx});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary = layer->lower_layer != nullptr ?
|
||||
AABBTreeLines::LinesDistancer<Linef>{
|
||||
to_unscaled_linesf(layer->lower_layer->lslices)} :
|
||||
AABBTreeLines::LinesDistancer<Linef>{};
|
||||
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> unstable_lines_per_slice(layer->lslices_ex.size());
|
||||
std::vector<tbb::concurrent_vector<ExtrusionLine>> ext_perim_lines_per_slice(layer->lslices_ex.size());
|
||||
|
||||
if constexpr (debug_files) {
|
||||
for (const auto &e_to_check : entities_to_check) {
|
||||
for (const auto &line : check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines,
|
||||
prev_layer_boundary, params)) {
|
||||
if (line.support_point_generated.has_value()) {
|
||||
unstable_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
if (line.is_external_perimeter()) {
|
||||
ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, entities_to_check.size()),
|
||||
[&entities_to_check, &prev_layer_ext_perim_lines, &prev_layer_boundary, &unstable_lines_per_slice,
|
||||
&ext_perim_lines_per_slice, ¶ms](tbb::blocked_range<size_t> r) {
|
||||
for (size_t entity_idx = r.begin(); entity_idx < r.end(); ++entity_idx) {
|
||||
const auto &e_to_check = entities_to_check[entity_idx];
|
||||
for (const auto &line :
|
||||
check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines,
|
||||
prev_layer_boundary, params)) {
|
||||
if (line.support_point_generated.has_value()) {
|
||||
unstable_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
if (line.is_external_perimeter()) {
|
||||
ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
LocalSupports local_supports{
|
||||
compute_local_supports(gather_entities_to_check(layer), prev_layer_boundary, prev_layer_ext_perim_lines, layer->lslices_ex.size(), params)};
|
||||
|
||||
std::vector<ExtrusionLine> current_layer_ext_perims_lines{};
|
||||
current_layer_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size());
|
||||
// All object parts updated, and for each slice we have coresponding weakest connection.
|
||||
// We can now check each slice and its corresponding weakest connection and object part for stability.
|
||||
for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
|
||||
ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[slice_idx]);
|
||||
SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
weakest_conn.print_info("weakest connection info: ");
|
||||
#endif
|
||||
ObjectPart &part = active_object_parts.access(slice_mappings.index_to_object_part_mapping[slice_idx]);
|
||||
SliceConnection &weakest_conn = slice_mappings.index_to_weakest_connection[slice_idx];
|
||||
|
||||
if (layer_idx > 1) {
|
||||
for (const auto &l : unstable_lines_per_slice[slice_idx]) {
|
||||
for (const auto &l : local_supports.unstable_lines_per_slice[slice_idx]) {
|
||||
assert(l.support_point_generated.has_value());
|
||||
SupportPoint support_point{*l.support_point_generated, create_support_point_position(l.b),
|
||||
SupportPoint support_point{*l.support_point_generated, to_3d(l.b, bottom_z),
|
||||
params.support_points_interface_radius};
|
||||
reckon_new_support_point(part, weakest_conn, supp_points, supports_presence_grid, support_point);
|
||||
}
|
||||
}
|
||||
|
||||
LD current_slice_lines_distancer({ext_perim_lines_per_slice[slice_idx].begin(), ext_perim_lines_per_slice[slice_idx].end()});
|
||||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
||||
|
||||
for (const ExtrusionLine &line : current_slice_lines_distancer.get_lines()) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < params.curling_tolerance_limit) ||
|
||||
line.len < EPSILON) {
|
||||
unchecked_dist += line.len;
|
||||
} else {
|
||||
unchecked_dist = line.len;
|
||||
Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f);
|
||||
auto [dist, nidx,
|
||||
nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
|
||||
Vec3f position = create_support_point_position(nearest_point);
|
||||
auto [force, cause] = part.is_stable_while_extruding(weakest_conn, line, position, bottom_z, params);
|
||||
if (force > 0 && layer_idx > 1) {
|
||||
SupportPoint support_point{
|
||||
cause, position, params.support_points_interface_radius
|
||||
};
|
||||
reckon_new_support_point(part, weakest_conn, supp_points, supports_presence_grid, support_point, true);
|
||||
}
|
||||
}
|
||||
const tbb::concurrent_vector<ExtrusionLine> &external_perimeter_lines = local_supports.ext_perim_lines_per_slice[slice_idx];
|
||||
if (layer_idx > 1) {
|
||||
reckon_global_supports(external_perimeter_lines, bottom_z, params, part, weakest_conn, supp_points, supports_presence_grid);
|
||||
}
|
||||
current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_lines_distancer.get_lines().begin(),
|
||||
current_slice_lines_distancer.get_lines().end());
|
||||
|
||||
current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), external_perimeter_lines.begin(), external_perimeter_lines.end());
|
||||
} // slice iterations
|
||||
prev_layer_ext_perim_lines = LD(current_layer_ext_perims_lines);
|
||||
} // layer iterations
|
||||
|
||||
for (const auto& active_obj_pair : prev_slice_idx_to_object_part_mapping) {
|
||||
remember_partial_object(active_obj_pair.second);
|
||||
for (const auto& active_obj_pair : slice_mappings.index_to_object_part_mapping) {
|
||||
auto object_part = active_object_parts.access(active_obj_pair.second);
|
||||
if (auto object = to_partial_object(object_part)) {
|
||||
partial_objects.push_back(std::move(*object));
|
||||
}
|
||||
}
|
||||
|
||||
return {supp_points, partial_objects};
|
||||
|
@ -117,11 +117,6 @@ struct SupportPoint
|
||||
SupportPointCause cause; // reason why this support point was generated. Used for the user alerts
|
||||
// position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes
|
||||
Vec3f position;
|
||||
// force that destabilizes the object to the point of falling/breaking. g*mm/s^2 units
|
||||
// It is valid only for global_object_support. For local extrusion support points, the force is -EPSILON
|
||||
// values gathered from large XL model: Min : 0 | Max : 18713800 | Average : 1361186 | Median : 329103
|
||||
// For reference 18713800 is weight of 1.8 Kg object, 329103 is weight of 0.03 Kg
|
||||
// The final sliced object weight was approx 0.5 Kg
|
||||
// Expected spot size. The support point strength is calculated from the area defined by this value.
|
||||
// Currently equal to the support_points_interface_radius parameter above
|
||||
float spot_radius;
|
||||
|
Loading…
x
Reference in New Issue
Block a user