Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_sla_switch_view
This commit is contained in:
commit
eb0f03aa9b
@ -2406,11 +2406,7 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
|||||||
{
|
{
|
||||||
// static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
// static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||||
|
|
||||||
Vec3d rotation = get_rotation();
|
Polygon p = get_object()->convex_hull_2d(this->get_matrix());
|
||||||
rotation.z() = 0.;
|
|
||||||
Transform3d trafo_instance = Geometry::assemble_transform(get_offset().z() * Vec3d::UnitZ(), rotation, get_scaling_factor(), get_mirror());
|
|
||||||
|
|
||||||
Polygon p = get_object()->convex_hull_2d(trafo_instance);
|
|
||||||
|
|
||||||
// if (!p.points.empty()) {
|
// if (!p.points.empty()) {
|
||||||
// Polygons pp{p};
|
// Polygons pp{p};
|
||||||
@ -2420,12 +2416,24 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
|||||||
|
|
||||||
arrangement::ArrangePolygon ret;
|
arrangement::ArrangePolygon ret;
|
||||||
ret.poly.contour = std::move(p);
|
ret.poly.contour = std::move(p);
|
||||||
ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))};
|
ret.translation = Vec2crd::Zero();
|
||||||
ret.rotation = get_rotation(Z);
|
ret.rotation = 0.;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelInstance::apply_arrange_result(const Vec2d &offs, double rotation)
|
||||||
|
{
|
||||||
|
// write the transformation data into the model instance
|
||||||
|
auto trafo = get_transformation().get_matrix();
|
||||||
|
auto tr = Transform3d::Identity();
|
||||||
|
tr.translate(to_3d(unscaled(offs), 0.));
|
||||||
|
trafo = tr * Eigen::AngleAxisd(rotation, Vec3d::UnitZ()) * trafo;
|
||||||
|
m_transformation.set_matrix(trafo);
|
||||||
|
|
||||||
|
this->object->invalidate_bounding_box();
|
||||||
|
}
|
||||||
|
|
||||||
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
|
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
|
||||||
{
|
{
|
||||||
TriangleSelector selector(mv.mesh());
|
TriangleSelector selector(mv.mesh());
|
||||||
|
@ -1167,14 +1167,7 @@ public:
|
|||||||
arrangement::ArrangePolygon get_arrange_polygon() const;
|
arrangement::ArrangePolygon get_arrange_polygon() const;
|
||||||
|
|
||||||
// Apply the arrange result on the ModelInstance
|
// Apply the arrange result on the ModelInstance
|
||||||
void apply_arrange_result(const Vec2d& offs, double rotation)
|
void apply_arrange_result(const Vec2d& offs, double rotation);
|
||||||
{
|
|
||||||
// write the transformation data into the model instance
|
|
||||||
set_rotation(Z, rotation);
|
|
||||||
set_offset(X, unscale<double>(offs(X)));
|
|
||||||
set_offset(Y, unscale<double>(offs(Y)));
|
|
||||||
this->object->invalidate_bounding_box();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -681,7 +682,7 @@ Polylines reconnect_polylines(const Polylines &polylines, double limit_distance)
|
|||||||
if (polylines.empty())
|
if (polylines.empty())
|
||||||
return polylines;
|
return polylines;
|
||||||
|
|
||||||
ankerl::unordered_dense::map<size_t, Polyline> connected;
|
std::unordered_map<size_t, Polyline> connected;
|
||||||
connected.reserve(polylines.size());
|
connected.reserve(polylines.size());
|
||||||
for (size_t i = 0; i < polylines.size(); i++) {
|
for (size_t i = 0; i < polylines.size(); i++) {
|
||||||
if (!polylines[i].empty()) {
|
if (!polylines[i].empty()) {
|
||||||
@ -731,7 +732,7 @@ ExtrusionPaths sort_extra_perimeters(ExtrusionPaths extra_perims, int index_of_f
|
|||||||
{
|
{
|
||||||
if (extra_perims.empty()) return {};
|
if (extra_perims.empty()) return {};
|
||||||
|
|
||||||
std::vector<ankerl::unordered_dense::set<size_t>> dependencies(extra_perims.size());
|
std::vector<std::unordered_set<size_t>> dependencies(extra_perims.size());
|
||||||
for (size_t path_idx = 0; path_idx < extra_perims.size(); path_idx++) {
|
for (size_t path_idx = 0; path_idx < extra_perims.size(); path_idx++) {
|
||||||
for (size_t prev_path_idx = 0; prev_path_idx < path_idx; prev_path_idx++) {
|
for (size_t prev_path_idx = 0; prev_path_idx < path_idx; prev_path_idx++) {
|
||||||
if (paths_touch(extra_perims[path_idx], extra_perims[prev_path_idx], extrusion_spacing * 1.5f)) {
|
if (paths_touch(extra_perims[path_idx], extra_perims[prev_path_idx], extrusion_spacing * 1.5f)) {
|
||||||
|
@ -880,7 +880,6 @@ void Print::process()
|
|||||||
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
obj->make_perimeters();
|
obj->make_perimeters();
|
||||||
this->set_status(70, _u8L("Infilling layers"));
|
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
obj->infill();
|
obj->infill();
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
|
@ -305,7 +305,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
|||||||
|
|
||||||
bench.stop();
|
bench.stop();
|
||||||
|
|
||||||
if (!m.empty())
|
if (!po.m_preview_meshes[step]->empty())
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Preview gen took: " << bench.getElapsedSec();
|
BOOST_LOG_TRIVIAL(trace) << "Preview gen took: " << bench.getElapsedSec();
|
||||||
else
|
else
|
||||||
BOOST_LOG_TRIVIAL(error) << "Preview failed!";
|
BOOST_LOG_TRIVIAL(error) << "Preview failed!";
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <oneapi/tbb/concurrent_vector.h>
|
||||||
|
#include <oneapi/tbb/parallel_for.h>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -172,6 +174,69 @@ struct SliceConnection
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SliceConnection estimate_slice_connection(size_t slice_idx, const Layer *layer)
|
||||||
|
{
|
||||||
|
SliceConnection connection;
|
||||||
|
|
||||||
|
const LayerSlice &slice = layer->lslices_ex[slice_idx];
|
||||||
|
Polygons slice_polys = to_polygons(layer->lslices[slice_idx]);
|
||||||
|
BoundingBox slice_bb = get_extents(slice_polys);
|
||||||
|
const Layer *lower_layer = layer->lower_layer;
|
||||||
|
|
||||||
|
ExPolygons below{};
|
||||||
|
for (const auto &link : slice.overlaps_below) { below.push_back(lower_layer->lslices[link.slice_idx]); }
|
||||||
|
Polygons below_polys = to_polygons(below);
|
||||||
|
|
||||||
|
BoundingBox below_bb = get_extents(below_polys);
|
||||||
|
|
||||||
|
Polygons overlap = intersection(ClipperUtils::clip_clipper_polygons_with_subject_bbox(slice_polys, below_bb),
|
||||||
|
ClipperUtils::clip_clipper_polygons_with_subject_bbox(below_polys, slice_bb));
|
||||||
|
|
||||||
|
for (const Polygon &poly : overlap) {
|
||||||
|
Vec2f p0 = unscaled(poly.first_point()).cast<float>();
|
||||||
|
for (size_t i = 2; i < poly.points.size(); i++) {
|
||||||
|
Vec2f p1 = unscaled(poly.points[i - 1]).cast<float>();
|
||||||
|
Vec2f p2 = unscaled(poly.points[i]).cast<float>();
|
||||||
|
|
||||||
|
float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f;
|
||||||
|
|
||||||
|
auto [area, first_moment_of_area, second_moment_area,
|
||||||
|
second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2);
|
||||||
|
connection.area += sign * area;
|
||||||
|
connection.centroid_accumulator += sign * Vec3f(first_moment_of_area.x(), first_moment_of_area.y(), layer->print_z * area);
|
||||||
|
connection.second_moment_of_area_accumulator += sign * second_moment_area;
|
||||||
|
connection.second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PrecomputedSliceConnections = std::vector<std::vector<SliceConnection>>;
|
||||||
|
PrecomputedSliceConnections precompute_slices_connections(const PrintObject *po)
|
||||||
|
{
|
||||||
|
PrecomputedSliceConnections result{};
|
||||||
|
for (size_t lidx = 0; lidx < po->layer_count(); lidx++) {
|
||||||
|
result.emplace_back(std::vector<SliceConnection>{});
|
||||||
|
for (size_t slice_idx = 0; slice_idx < po->get_layer(lidx)->lslices_ex.size(); slice_idx++) {
|
||||||
|
result[lidx].push_back(SliceConnection{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, po->layers().size()), [po, &result](tbb::blocked_range<size_t> r) {
|
||||||
|
for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
|
||||||
|
const Layer *l = po->get_layer(lidx);
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, l->lslices_ex.size()), [lidx, l, &result](tbb::blocked_range<size_t> r2) {
|
||||||
|
for (size_t slice_idx = r2.begin(); slice_idx < r2.end(); slice_idx++) {
|
||||||
|
result[lidx][slice_idx] = estimate_slice_connection(slice_idx, l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
float get_flow_width(const LayerRegion *region, ExtrusionRole role)
|
float get_flow_width(const LayerRegion *region, ExtrusionRole role)
|
||||||
{
|
{
|
||||||
if (role == ExtrusionRole::BridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width();
|
if (role == ExtrusionRole::BridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width();
|
||||||
@ -253,15 +318,8 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
|||||||
const AABBTreeLines::LinesDistancer<Linef> &prev_layer_boundary,
|
const AABBTreeLines::LinesDistancer<Linef> &prev_layer_boundary,
|
||||||
const Params ¶ms)
|
const Params ¶ms)
|
||||||
{
|
{
|
||||||
if (entity->is_collection()) {
|
assert(!entity->is_collection());
|
||||||
std::vector<ExtrusionLine> checked_lines_out;
|
if (entity->role().is_bridge() && !entity->role().is_perimeter()) {
|
||||||
checked_lines_out.reserve(prev_layer_lines.get_lines().size() / 3);
|
|
||||||
for (const auto *e : static_cast<const ExtrusionEntityCollection *>(entity)->entities) {
|
|
||||||
auto tmp = check_extrusion_entity_stability(e, layer_region, prev_layer_lines, prev_layer_boundary, params);
|
|
||||||
checked_lines_out.insert(checked_lines_out.end(), tmp.begin(), tmp.end());
|
|
||||||
}
|
|
||||||
return checked_lines_out;
|
|
||||||
} else if (entity->role().is_bridge() && !entity->role().is_perimeter()) {
|
|
||||||
// pure bridges are handled separately, beacuse we need to align the forward and backward direction support points
|
// pure bridges are handled separately, beacuse we need to align the forward and backward direction support points
|
||||||
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
|
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
|
||||||
return {};
|
return {};
|
||||||
@ -344,9 +402,10 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
|||||||
curr_point.distance *= sign;
|
curr_point.distance *= sign;
|
||||||
|
|
||||||
SupportPointCause potential_cause = SupportPointCause::FloatingExtrusion;
|
SupportPointCause potential_cause = SupportPointCause::FloatingExtrusion;
|
||||||
if (bridged_distance + line_len > params.bridge_distance * 0.8 && std::abs(curr_point.curvature) < 0.1) {
|
// Bridges are now separated. While long overhang perimeter is technically bridge, it would confuse the users
|
||||||
potential_cause = SupportPointCause::FloatingExtrusion;
|
// if (bridged_distance + line_len > params.bridge_distance * 0.8 && std::abs(curr_point.curvature) < 0.1) {
|
||||||
}
|
// potential_cause = SupportPointCause::FloatingExtrusion;
|
||||||
|
// }
|
||||||
|
|
||||||
float max_bridge_len = std::max(params.support_points_interface_radius * 2.0f,
|
float max_bridge_len = std::max(params.support_points_interface_radius * 2.0f,
|
||||||
params.bridge_distance /
|
params.bridge_distance /
|
||||||
@ -383,44 +442,6 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SliceConnection estimate_slice_connection(size_t slice_idx, const Layer *layer)
|
|
||||||
{
|
|
||||||
SliceConnection connection;
|
|
||||||
|
|
||||||
const LayerSlice &slice = layer->lslices_ex[slice_idx];
|
|
||||||
Polygons slice_polys = to_polygons(layer->lslices[slice_idx]);
|
|
||||||
BoundingBox slice_bb = get_extents(slice_polys);
|
|
||||||
const Layer *lower_layer = layer->lower_layer;
|
|
||||||
|
|
||||||
ExPolygons below{};
|
|
||||||
for (const auto &link : slice.overlaps_below) { below.push_back(lower_layer->lslices[link.slice_idx]); }
|
|
||||||
Polygons below_polys = to_polygons(below);
|
|
||||||
|
|
||||||
BoundingBox below_bb = get_extents(below_polys);
|
|
||||||
|
|
||||||
Polygons overlap = intersection(ClipperUtils::clip_clipper_polygons_with_subject_bbox(slice_polys, below_bb),
|
|
||||||
ClipperUtils::clip_clipper_polygons_with_subject_bbox(below_polys, slice_bb));
|
|
||||||
|
|
||||||
for (const Polygon &poly : overlap) {
|
|
||||||
Vec2f p0 = unscaled(poly.first_point()).cast<float>();
|
|
||||||
for (size_t i = 2; i < poly.points.size(); i++) {
|
|
||||||
Vec2f p1 = unscaled(poly.points[i - 1]).cast<float>();
|
|
||||||
Vec2f p2 = unscaled(poly.points[i]).cast<float>();
|
|
||||||
|
|
||||||
float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f;
|
|
||||||
|
|
||||||
auto [area, first_moment_of_area, second_moment_area,
|
|
||||||
second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2);
|
|
||||||
connection.area += sign * area;
|
|
||||||
connection.centroid_accumulator += sign * Vec3f(first_moment_of_area.x(), first_moment_of_area.y(), layer->print_z * area);
|
|
||||||
connection.second_moment_of_area_accumulator += sign * second_moment_area;
|
|
||||||
connection.second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectPart
|
class ObjectPart
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -761,7 +782,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po, const PrintTryCancel &cancel_func, const Params ¶ms)
|
std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
||||||
|
const PrecomputedSliceConnections &precomputed_slices_connections,
|
||||||
|
const PrintTryCancel &cancel_func,
|
||||||
|
const Params ¶ms)
|
||||||
{
|
{
|
||||||
SupportPoints supp_points{};
|
SupportPoints supp_points{};
|
||||||
SupportGridFilter supports_presence_grid(po, params.min_distance_between_support_points);
|
SupportGridFilter supports_presence_grid(po, params.min_distance_between_support_points);
|
||||||
@ -791,7 +815,7 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
|||||||
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) {
|
||||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||||
auto [new_part, covered_area] = build_object_part_from_slice(slice_idx, layer, params);
|
auto [new_part, covered_area] = build_object_part_from_slice(slice_idx, layer, params);
|
||||||
SliceConnection connection_to_below = estimate_slice_connection(slice_idx, layer);
|
const SliceConnection &connection_to_below = precomputed_slices_connections[layer_idx][slice_idx];
|
||||||
|
|
||||||
#ifdef DETAILED_DEBUG_LOGS
|
#ifdef DETAILED_DEBUG_LOGS
|
||||||
std::cout << "SLICE IDX: " << slice_idx << std::endl;
|
std::cout << "SLICE IDX: " << slice_idx << std::endl;
|
||||||
@ -858,25 +882,87 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
|||||||
prev_slice_idx_to_weakest_connection = next_slice_idx_to_weakest_connection;
|
prev_slice_idx_to_weakest_connection = next_slice_idx_to_weakest_connection;
|
||||||
next_slice_idx_to_weakest_connection.clear();
|
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 (const auto &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 (const 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());
|
||||||
|
|
||||||
|
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) {
|
||||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
|
||||||
ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[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];
|
SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
|
||||||
|
|
||||||
std::vector<Linef> boundary_lines;
|
|
||||||
for (const auto &link : slice.overlaps_below) {
|
|
||||||
auto ls = to_unscaled_linesf({layer->lower_layer->lslices[link.slice_idx]});
|
|
||||||
boundary_lines.insert(boundary_lines.end(), ls.begin(), ls.end());
|
|
||||||
}
|
|
||||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<ExtrusionLine> current_slice_ext_perims_lines{};
|
|
||||||
current_slice_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size() / layer->lslices_ex.size());
|
|
||||||
#ifdef DETAILED_DEBUG_LOGS
|
#ifdef DETAILED_DEBUG_LOGS
|
||||||
weakest_conn.print_info("weakest connection info: ");
|
weakest_conn.print_info("weakest connection info: ");
|
||||||
#endif
|
#endif
|
||||||
@ -911,73 +997,15 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// first we will check local extrusion stability of bridges, then of perimeters. Perimeters are more important, they
|
for (const auto &l : unstable_lines_per_slice[slice_idx]) {
|
||||||
// account for most of the curling and possible crashes, so on them we will run also global stability check
|
assert(l.support_point_generated.has_value());
|
||||||
for (const auto &island : slice.islands) {
|
reckon_new_support_point(*l.support_point_generated, create_support_point_position(l.b), float(-EPSILON), Vec2f::Zero());
|
||||||
// Support bridges where needed.
|
|
||||||
for (const LayerExtrusionRange &fill_range : island.fills) {
|
|
||||||
const LayerRegion *fill_region = layer->get_region(fill_range.region());
|
|
||||||
for (const auto &fill_idx : fill_range) {
|
|
||||||
const ExtrusionEntity *entity = fill_region->fills().entities[fill_idx];
|
|
||||||
if (entity->role() == ExtrusionRole::BridgeInfill) {
|
|
||||||
for (const ExtrusionLine &bridge :
|
|
||||||
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines, prev_layer_boundary,
|
|
||||||
params)) {
|
|
||||||
if (bridge.support_point_generated.has_value()) {
|
|
||||||
reckon_new_support_point(*bridge.support_point_generated, create_support_point_position(bridge.b),
|
|
||||||
float(-EPSILON), Vec2f::Zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region());
|
LD current_slice_lines_distancer({ext_perim_lines_per_slice[slice_idx].begin(), ext_perim_lines_per_slice[slice_idx].end()});
|
||||||
for (const auto &perimeter_idx : island.perimeters) {
|
|
||||||
const ExtrusionEntity *entity = perimeter_region->perimeters().entities[perimeter_idx];
|
|
||||||
std::vector<ExtrusionLine> perims = check_extrusion_entity_stability(entity, perimeter_region,
|
|
||||||
prev_layer_ext_perim_lines, prev_layer_boundary,
|
|
||||||
params);
|
|
||||||
for (const ExtrusionLine &perim : perims) {
|
|
||||||
if (perim.support_point_generated.has_value()) {
|
|
||||||
reckon_new_support_point(*perim.support_point_generated, create_support_point_position(perim.b), float(-EPSILON),
|
|
||||||
Vec2f::Zero());
|
|
||||||
}
|
|
||||||
if (perim.is_external_perimeter()) {
|
|
||||||
current_slice_ext_perims_lines.push_back(perim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// DEBUG EXPORT, NOT USED NOW
|
|
||||||
// if (BR_bridge) {
|
|
||||||
// Lines scaledl;
|
|
||||||
// for (const auto &l : prev_layer_boundary.get_lines()) {
|
|
||||||
// scaledl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Lines perimsl;
|
|
||||||
// for (const auto &l : current_slice_ext_perims_lines) {
|
|
||||||
// perimsl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// BoundingBox bb = get_extents(scaledl);
|
|
||||||
// bb.merge(get_extents(perimsl));
|
|
||||||
|
|
||||||
// ::Slic3r::SVG svg(debug_out_path(
|
|
||||||
// ("slice" + std::to_string(slice_idx) + "_" + std::to_string(layer_idx).c_str()).c_str()),
|
|
||||||
// get_extents(scaledl));
|
|
||||||
// svg.draw(scaledl, "red", scale_(0.4));
|
|
||||||
// svg.draw(perimsl, "blue", scale_(0.25));
|
|
||||||
|
|
||||||
|
|
||||||
// svg.Close();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
LD current_slice_lines_distancer(current_slice_ext_perims_lines);
|
|
||||||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
||||||
|
|
||||||
for (const ExtrusionLine &line : current_slice_ext_perims_lines) {
|
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) ||
|
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < params.curling_tolerance_limit) ||
|
||||||
line.len < EPSILON) {
|
line.len < EPSILON) {
|
||||||
unchecked_dist += line.len;
|
unchecked_dist += line.len;
|
||||||
@ -993,8 +1021,8 @@ std::tuple<SupportPoints, PartialObjects> check_stability(const PrintObject *po,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_ext_perims_lines.begin(),
|
current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_lines_distancer.get_lines().begin(),
|
||||||
current_slice_ext_perims_lines.end());
|
current_slice_lines_distancer.get_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
|
||||||
@ -1048,7 +1076,8 @@ void debug_export(const SupportPoints& support_points,const PartialObjects& obje
|
|||||||
|
|
||||||
std::tuple<SupportPoints, PartialObjects> full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms)
|
std::tuple<SupportPoints, PartialObjects> full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms)
|
||||||
{
|
{
|
||||||
auto results = check_stability(po, cancel_func, params);
|
auto precomputed_slices_connections = precompute_slices_connections(po);
|
||||||
|
auto results = check_stability(po, precomputed_slices_connections, cancel_func, params);
|
||||||
#ifdef DEBUG_FILES
|
#ifdef DEBUG_FILES
|
||||||
auto [supp_points, objects] = results;
|
auto [supp_points, objects] = results;
|
||||||
debug_export(supp_points, objects, "issues");
|
debug_export(supp_points, objects, "issues");
|
||||||
|
@ -85,6 +85,17 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||||||
|
|
||||||
// describe control behavior
|
// describe control behavior
|
||||||
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) {
|
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) {
|
||||||
|
// do not allow to change selection while the sla support gizmo is in editing mode
|
||||||
|
const GLGizmosManager& gizmos = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
|
||||||
|
if (gizmos.get_current_type() == GLGizmosManager::EType::SlaSupports && gizmos.is_in_editing_mode(true)) {
|
||||||
|
wxDataViewItemArray sels;
|
||||||
|
GetSelections(sels);
|
||||||
|
if (sels.size() > 1 || event.GetItem() != m_last_selected_item) {
|
||||||
|
select_item(m_last_selected_item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// detect the current mouse position here, to pass it to list_manipulation() method
|
// detect the current mouse position here, to pass it to list_manipulation() method
|
||||||
// if we detect it later, the user may have moved the mouse pointer while calculations are performed, and this would mess-up the HitTest() call performed into list_manipulation()
|
// if we detect it later, the user may have moved the mouse pointer while calculations are performed, and this would mess-up the HitTest() call performed into list_manipulation()
|
||||||
// see: https://github.com/prusa3d/PrusaSlicer/issues/3802
|
// see: https://github.com/prusa3d/PrusaSlicer/issues/3802
|
||||||
@ -4964,6 +4975,11 @@ void ObjectList::update_printable_state(int obj_idx, int instance_idx)
|
|||||||
|
|
||||||
void ObjectList::toggle_printable_state()
|
void ObjectList::toggle_printable_state()
|
||||||
{
|
{
|
||||||
|
// do not allow to toggle the printable state while the sla support gizmo is in editing mode
|
||||||
|
const GLGizmosManager& gizmos = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
|
||||||
|
if (gizmos.get_current_type() == GLGizmosManager::EType::SlaSupports && gizmos.is_in_editing_mode(true))
|
||||||
|
return;
|
||||||
|
|
||||||
wxDataViewItemArray sels;
|
wxDataViewItemArray sels;
|
||||||
GetSelections(sels);
|
GetSelections(sels);
|
||||||
if (sels.IsEmpty())
|
if (sels.IsEmpty())
|
||||||
|
@ -24,14 +24,8 @@ GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filen
|
|||||||
|
|
||||||
bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
if (mouse_event.Moving()) {
|
|
||||||
// only for sure
|
|
||||||
m_mouse_left_down = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mouse_event.LeftDown()) {
|
if (mouse_event.LeftDown()) {
|
||||||
if (m_hover_id != -1) {
|
if (m_hover_id != -1) {
|
||||||
m_mouse_left_down = true;
|
|
||||||
Selection &selection = m_parent.get_selection();
|
Selection &selection = m_parent.get_selection();
|
||||||
if (selection.is_single_full_instance()) {
|
if (selection.is_single_full_instance()) {
|
||||||
// Rotate the object so the normal points downward:
|
// Rotate the object so the normal points downward:
|
||||||
@ -42,16 +36,8 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mouse_event.LeftUp()) {
|
else if (mouse_event.LeftUp())
|
||||||
if (m_mouse_left_down) {
|
return m_hover_id != -1;
|
||||||
// responsible for mouse left up after selecting plane
|
|
||||||
m_mouse_left_down = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (mouse_event.Leaving())
|
|
||||||
m_mouse_left_down = false;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ private:
|
|||||||
|
|
||||||
std::vector<PlaneData> m_planes;
|
std::vector<PlaneData> m_planes;
|
||||||
std::vector<std::shared_ptr<SceneRaycasterItem>> m_planes_casters;
|
std::vector<std::shared_ptr<SceneRaycasterItem>> m_planes_casters;
|
||||||
bool m_mouse_left_down = false; // for detection left_up of this gizmo
|
|
||||||
const ModelObject* m_old_model_object = nullptr;
|
const ModelObject* m_old_model_object = nullptr;
|
||||||
int m_old_instance_id{ -1 };
|
int m_old_instance_id{ -1 };
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user