mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 04:32:01 +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,
|
std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
||||||
const PrecomputedSliceConnections &precomputed_slices_connections,
|
const PrecomputedSliceConnections &precomputed_slices_connections,
|
||||||
const PrintTryCancel &cancel_func,
|
const PrintTryCancel &cancel_func,
|
||||||
@ -807,248 +1050,55 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject
|
|||||||
PartialObjects partial_objects{};
|
PartialObjects partial_objects{};
|
||||||
LD prev_layer_ext_perim_lines;
|
LD prev_layer_ext_perim_lines;
|
||||||
|
|
||||||
std::unordered_map<size_t, size_t> prev_slice_idx_to_object_part_mapping;
|
SliceMappings slice_mappings;
|
||||||
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;
|
|
||||||
|
|
||||||
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) {
|
for (size_t layer_idx = 0; layer_idx < po->layer_count(); ++layer_idx) {
|
||||||
cancel_func();
|
cancel_func();
|
||||||
const Layer *layer = po->get_layer(layer_idx);
|
const Layer *layer = po->get_layer(layer_idx);
|
||||||
float bottom_z = layer->bottom_z();
|
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) {
|
slice_mappings = update_active_object_parts(layer, params, precomputed_slices_connections[layer_idx], slice_mappings, active_object_parts, partial_objects);
|
||||||
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{
|
std::optional<Linesf> prev_layer_boundary = layer->lower_layer != nullptr ?
|
||||||
has_brim(layer, params) ?
|
std::optional{to_unscaled_linesf(layer->lower_layer->lslices)} :
|
||||||
std::optional{get_brim(layer->lslices[slice_idx], params.brim_type, params.brim_width)} :
|
std::nullopt;
|
||||||
std::nullopt
|
|
||||||
};
|
|
||||||
ObjectPart new_part{
|
|
||||||
extrusion_collections,
|
|
||||||
connected_to_bed,
|
|
||||||
layer->print_z,
|
|
||||||
layer->height,
|
|
||||||
brim
|
|
||||||
};
|
|
||||||
|
|
||||||
const SliceConnection &connection_to_below = precomputed_slices_connections[layer_idx][slice_idx];
|
LocalSupports local_supports{
|
||||||
|
compute_local_supports(gather_entities_to_check(layer), prev_layer_boundary, prev_layer_ext_perim_lines, layer->lslices_ex.size(), params)};
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ExtrusionLine> current_layer_ext_perims_lines{};
|
std::vector<ExtrusionLine> current_layer_ext_perims_lines{};
|
||||||
current_layer_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size());
|
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.
|
// 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.
|
// 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) {
|
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]);
|
ObjectPart &part = active_object_parts.access(slice_mappings.index_to_object_part_mapping[slice_idx]);
|
||||||
SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
|
SliceConnection &weakest_conn = slice_mappings.index_to_weakest_connection[slice_idx];
|
||||||
|
|
||||||
#ifdef DETAILED_DEBUG_LOGS
|
|
||||||
weakest_conn.print_info("weakest connection info: ");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (layer_idx > 1) {
|
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());
|
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};
|
params.support_points_interface_radius};
|
||||||
reckon_new_support_point(part, weakest_conn, supp_points, supports_presence_grid, support_point);
|
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()});
|
const tbb::concurrent_vector<ExtrusionLine> &external_perimeter_lines = local_supports.ext_perim_lines_per_slice[slice_idx];
|
||||||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
if (layer_idx > 1) {
|
||||||
|
reckon_global_supports(external_perimeter_lines, bottom_z, params, part, weakest_conn, supp_points, supports_presence_grid);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
} // slice iterations
|
||||||
prev_layer_ext_perim_lines = LD(current_layer_ext_perims_lines);
|
prev_layer_ext_perim_lines = LD(current_layer_ext_perims_lines);
|
||||||
} // layer iterations
|
} // layer iterations
|
||||||
|
|
||||||
for (const auto& active_obj_pair : prev_slice_idx_to_object_part_mapping) {
|
for (const auto& active_obj_pair : slice_mappings.index_to_object_part_mapping) {
|
||||||
remember_partial_object(active_obj_pair.second);
|
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};
|
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
|
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
|
// position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes
|
||||||
Vec3f position;
|
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.
|
// 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
|
// Currently equal to the support_points_interface_radius parameter above
|
||||||
float spot_radius;
|
float spot_radius;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user