Bugfix in extrusion quality estimator, Refactoring of alerts, rename of autogenerate button

This commit is contained in:
PavelMikus 2023-01-25 14:18:14 +01:00 committed by Pavel Mikuš
parent a4de5c6553
commit c31e3ec1a2
5 changed files with 143 additions and 134 deletions

View File

@ -201,7 +201,7 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
new_points.push_back(ExtendedPoint{pos, float(p_dist + boundary_offset), p_near_l});
}
}
new_points.push_back(new_points.back());
new_points.push_back(points.back());
}
points = new_points;
}

View File

@ -1,4 +1,5 @@
#include "Exception.hpp"
#include "KDTreeIndirect.hpp"
#include "Point.hpp"
#include "Print.hpp"
#include "BoundingBox.hpp"
@ -34,6 +35,7 @@
#include <boost/log/trivial.hpp>
#include <tbb/parallel_for.h>
#include <vector>
using namespace std::literals;
@ -425,123 +427,37 @@ void PrintObject::generate_support_spots()
this->m_shared_regions->generated_support_points = {this->trafo_centered(), supp_points};
m_print->throw_if_canceled();
auto check_problems = [&]() {
std::unordered_map<SupportSpotsGenerator::SupportPointCause, SupportSpotsGenerator::SupportPoints> sp_by_cause{};
for (const SupportSpotsGenerator::SupportPoint &sp : supp_points) {
sp_by_cause[sp.cause].push_back(sp);
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::SeparationFromBed].empty()) {
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
L("Object part may break from the bed. Consider adding brim and/or supports."));
}
std::reverse(partial_objects.begin(), partial_objects.end());
std::sort(partial_objects.begin(), partial_objects.end(),
[](const SupportSpotsGenerator::PartialObject &left, const SupportSpotsGenerator::PartialObject &right) {
return left.volume > right.volume;
});
float max_volume_part = partial_objects.front().volume;
for (const SupportSpotsGenerator::PartialObject &p : partial_objects) {
if (p.volume > max_volume_part / 1000.0f && !p.connected_to_bed) {
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
L("Floating object parts detected. Please add supports."));
return;
auto alert_fn = [&](PrintStateBase::WarningLevel level, SupportSpotsGenerator::SupportPointCause cause) {
switch (cause) {
case SupportSpotsGenerator::SupportPointCause::LongBridge:
this->active_step_add_warning(level, L("There are bridges longer than allowed distance. Consider adding supports. "));
break;
case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor:
this->active_step_add_warning(level, L("Unsupported bridges will collapse. Supports are needed."));
break;
case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion:
if (level == PrintStateBase::WarningLevel::CRITICAL) {
this->active_step_add_warning(level, L("Clusters of unsupported extrusions found. Supports are needed."));
} else {
this->active_step_add_warning(level, L("Some unspported extrusions found. Consider adding supports. "));
}
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::WeakObjectPart].empty()) {
break;
case SupportSpotsGenerator::SupportPointCause::SeparationFromBed:
this->active_step_add_warning(level, L("Object part may break from the bed. Consider adding brim and/or supports."));
break;
case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart:
this->active_step_add_warning(level, L("Floating object parts detected. Supports are needed."));
break;
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart:
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
L("Thin parts of the object may break. Please add supports."));
return;
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor].empty()) {
Vec3f last_pos = Vec3f::Zero();
size_t count = 0;
for (const SupportSpotsGenerator::SupportPoint &sp :
sp_by_cause[SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor]) {
if ((sp.position - last_pos).squaredNorm() < 9.0f) {
count++;
last_pos = sp.position;
} else {
last_pos = sp.position;
count = 1;
}
if (count > 1) {
this->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL,
L("Bridges without supported endpoints will collapse. Please add supports. "));
break;
}
}
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::LongUnsupportedExtrusion].empty()) {
Vec3f last_pos = Vec3f::Zero();
size_t count = 0;
for (const SupportSpotsGenerator::SupportPoint &sp :
sp_by_cause[SupportSpotsGenerator::SupportPointCause::LongUnsupportedExtrusion]) {
if ((sp.position - last_pos).squaredNorm() < 9.0f) {
count++;
last_pos = sp.position;
} else {
last_pos = sp.position;
count = 1;
}
if (count > 1) {
this->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL,
L("Long unsupported extrusions will collapse. Please add supports. "));
break;
}
}
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::LongBridge].empty()) {
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
L("There are bridges longer than allowed distance. Consider adding supports. "));
}
if (!sp_by_cause[SupportSpotsGenerator::SupportPointCause::FloatingExtrusion].empty()) {
Vec3f last_pos = Vec3f::Zero();
size_t count = 0;
bool small_warning = false;
for (const SupportSpotsGenerator::SupportPoint &sp :
sp_by_cause[SupportSpotsGenerator::SupportPointCause::FloatingExtrusion]) {
if ((sp.position - last_pos).squaredNorm() <
params.bridge_distance + EPSILON) {
count++;
last_pos = sp.position;
} else {
if (count > 6) {
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
L("Object has large part with loose extrusions. Please enable supports. "));
small_warning = false;
break;
}
if (count > 3) {
small_warning = true;
}
last_pos = sp.position;
count = 1;
}
}
if (small_warning) {
this->active_step_add_warning(
PrintStateBase::WarningLevel::NON_CRITICAL,
L("Object has parts with loose extrusions and may look bad. Consider enabling supports. "));
} else if (sp_by_cause[SupportSpotsGenerator::SupportPointCause::FloatingExtrusion].size() > max_volume_part / 100) {
this->active_step_add_warning(
PrintStateBase::WarningLevel::NON_CRITICAL,
L("There are many loose surface extrusions on this object. Consider enabling supports. "));
}
L("Thin parts of the object may break. Supports are needed."));
break;
}
};
check_problems();
if (!this->has_support()) {
SupportSpotsGenerator::raise_alerts_for_issues(supp_points, partial_objects, alert_fn);
}
}
BOOST_LOG_TRIVIAL(debug) << "Searching support spots - end";
this->set_done(posSupportSpotsSearch);

View File

@ -37,7 +37,7 @@
#include "Geometry/ConvexHull.hpp"
// #define DETAILED_DEBUG_LOGS
// #define DEBUG_FILES
#define DEBUG_FILES
#ifdef DEBUG_FILES
#include <boost/nowide/cstdio.hpp>
@ -313,19 +313,16 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
curr_point.position.cast<float>(), line_len, entity};
const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
ExtrusionLine{};
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
ExtrusionLine{};
// correctify the distance sign using slice polygons
float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
curr_point.distance *= sign;
SupportPointCause potential_cause = SupportPointCause::FloatingExtrusion;
if (curr_point.distance > flow_width * 5.0) {
if (std::abs(curr_point.curvature) > 0.1)
potential_cause = SupportPointCause::LongUnsupportedExtrusion;
else
potential_cause = SupportPointCause::LongBridge;
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,
@ -337,6 +334,14 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
line_out.form_quality = 0.8f;
bridged_distance += line_len;
if (bridged_distance > max_bridge_len) {
std::cout << "Problem found A: " << std::endl;
std::cout << "bridged_distance: " << bridged_distance << std::endl;
std::cout << "max_bridge_len: " << max_bridge_len << std::endl;
std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl;
std::cout << "curr_point.distance: " << curr_point.distance << std::endl;
std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl;
std::cout << "flow_width: " << flow_width << std::endl;
line_out.support_point_generated = potential_cause;
bridged_distance = 0.0f;
}
@ -344,6 +349,14 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
bridged_distance += line_len;
line_out.form_quality = nearest_prev_layer_line.form_quality - 0.3f;
if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) {
std::cout << "Problem found B: " << std::endl;
std::cout << "bridged_distance: " << bridged_distance << std::endl;
std::cout << "max_bridge_len: " << max_bridge_len << std::endl;
std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl;
std::cout << "curr_point.distance: " << curr_point.distance << std::endl;
std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl;
std::cout << "flow_width: " << flow_width << std::endl;
line_out.support_point_generated = potential_cause;
line_out.form_quality = 0.5f;
bridged_distance = 0.0f;
@ -557,7 +570,7 @@ public:
params.material_yield_strength;
float conn_weight_arm = (conn_centroid.head<2>() - mass_centroid.head<2>()).norm();
float conn_weight_torque = conn_weight_arm * weight * (1.0f - conn_centroid.z() / layer_z);
float conn_weight_torque = conn_weight_arm * weight * (1.0f - conn_centroid.z() / layer_z) * (1.0f - conn_centroid.z() / layer_z);
float conn_movement_arm = std::max(0.0f, mass_centroid.z() - conn_centroid.z());
float conn_movement_torque = movement_force * conn_movement_arm;
@ -925,7 +938,6 @@ void debug_export(const SupportPoints& support_points,const PartialObjects& obje
case SupportPointCause::FloatingBridgeAnchor: color = {0.863281f, 0.109375f, 0.113281f}; break; //RED
case SupportPointCause::LongBridge: color = {0.960938f, 0.90625f, 0.0625f}; break; // YELLOW
case SupportPointCause::FloatingExtrusion: color = {0.921875f, 0.515625f, 0.101563f}; break; // ORANGE
case SupportPointCause::LongUnsupportedExtrusion: color = {0.863281f, 0.109375f, 0.113281f}; break; // RED
case SupportPointCause::SeparationFromBed: color = {0.0f, 1.0f, 0.0}; break; // GREEN
case SupportPointCause::UnstableFloatingPart: color = {0.105469f, 0.699219f, 0.84375f}; break; // BLUE
case SupportPointCause::WeakObjectPart: color = {0.609375f, 0.210938f, 0.621094f}; break; // PURPLE
@ -1104,5 +1116,84 @@ void estimate_malformations(LayerPtrs &layers, const Params &params)
#endif
}
void raise_alerts_for_issues(const SupportPoints &support_points,
PartialObjects &partial_objects,
std::function<void(PrintStateBase::WarningLevel, SupportPointCause)> alert_fn)
{
for (const SupportPoint &sp : support_points) {
if (sp.cause == SupportPointCause::SeparationFromBed) {
alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::SeparationFromBed);
break;
}
}
std::reverse(partial_objects.begin(), partial_objects.end());
std::sort(partial_objects.begin(), partial_objects.end(),
[](const PartialObject &left, const PartialObject &right) { return left.volume > right.volume; });
float max_volume_part = partial_objects.front().volume;
for (const PartialObject &p : partial_objects) {
if (p.volume > max_volume_part / 500.0f && !p.connected_to_bed) {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::UnstableFloatingPart);
return;
}
}
for (const SupportPoint &sp : support_points) {
if (sp.cause == SupportPointCause::UnstableFloatingPart) {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::UnstableFloatingPart);
return;
}
}
for (const SupportPoint &sp : support_points) {
if (sp.cause == SupportPointCause::WeakObjectPart) {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::WeakObjectPart);
return;
}
}
std::vector<SupportPoint> ext_supp_points{};
ext_supp_points.reserve(support_points.size());
for (const SupportPoint &sp : support_points) {
switch (sp.cause) {
case SupportPointCause::FloatingBridgeAnchor:
case SupportPointCause::FloatingExtrusion: ext_supp_points.push_back(sp); break;
default: break;
}
}
auto coord_fn = [&ext_supp_points](size_t idx, size_t dim) { return ext_supp_points[idx].position[dim]; };
KDTreeIndirect<3, float, decltype(coord_fn)> ext_points_tree{coord_fn, ext_supp_points.size()};
for (const SupportPoint &sp : ext_supp_points) {
auto cluster = find_nearby_points(ext_points_tree, sp.position, 3.0);
int score = 0;
bool floating_bridge = false;
for (size_t idx : cluster) {
score += ext_supp_points[idx].cause == SupportPointCause::FloatingBridgeAnchor ? 3 : 1;
floating_bridge = floating_bridge || ext_supp_points[idx].cause == SupportPointCause::FloatingBridgeAnchor;
}
if (score > 5) {
if (floating_bridge) {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::FloatingBridgeAnchor);
} else {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::FloatingExtrusion);
}
return;
}
}
if (ext_supp_points.size() > 5) {
alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::FloatingExtrusion);
}
for (const SupportPoint &sp : support_points) {
if (sp.cause == SupportPointCause::LongBridge) {
alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::LongBridge);
return;
}
}
}
} // namespace SupportSpotsGenerator
} // namespace Slic3r

View File

@ -77,7 +77,6 @@ enum class SupportPointCause {
LongBridge, // point generated on bridge and straight perimeter extrusion longer than the allowed length
FloatingBridgeAnchor, // point generated on unsupported bridge endpoint
FloatingExtrusion, // point generated on extrusion that does not hold on its own
LongUnsupportedExtrusion, // similar to above, but with large distance to object. This really needs supports.
SeparationFromBed, // point generated for object parts that are connected to the bed, but the area is too small and there is a risk of separation (brim may help)
UnstableFloatingPart, // point generated for object parts not connected to the bed, holded only by the other support points (brim will not help here)
WeakObjectPart // point generated when some part of the object is too weak to hold the upper part and may break (imagine hourglass)
@ -143,10 +142,13 @@ using PartialObjects = std::vector<PartialObject>;
std::tuple<SupportPoints, PartialObjects> full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params &params);
void estimate_supports_malformations(std::vector<SupportLayer*> &layers, float supports_flow_width, const Params &params);
void estimate_malformations(std::vector<Layer*> &layers, const Params &params);
void estimate_supports_malformations(std::vector<SupportLayer *> &layers, float supports_flow_width, const Params &params);
void estimate_malformations(std::vector<Layer *> &layers, const Params &params);
} // namespace SupportSpotsGenerator
}
void raise_alerts_for_issues(const SupportPoints &support_points,
PartialObjects &partial_objects,
std::function<void(PrintStateBase::WarningLevel, SupportPointCause)> alert_fn);
}} // namespace Slic3r::SupportSpotsGenerator
#endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */

View File

@ -43,8 +43,8 @@ bool GLGizmoFdmSupports::on_init()
{
m_shortcut_key = WXK_CONTROL_L;
m_desc["auto_generate"] = _L("Auto-generate supports");
m_desc["generating"] = _L("Generating supports...");
m_desc["autopaint"] = _L("Automatic painting");
m_desc["painting"] = _L("painting...");
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Brush size") + ": ";
@ -160,9 +160,9 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::Separator();
if (waiting_for_autogenerated_supports) {
m_imgui->text(m_desc.at("generating"));
m_imgui->text(m_desc.at("painting"));
} else {
bool generate = m_imgui->button(m_desc.at("auto_generate"));
bool generate = m_imgui->button(m_desc.at("autopaint"));
if (generate)
auto_generate();
}
@ -525,12 +525,12 @@ void GLGizmoFdmSupports::auto_generate()
});
MessageDialog dlg(GUI::wxGetApp().plater(),
_L("Autogeneration will erase all currently painted areas.") + "\n\n" +
_L("Automatic painting will erase all currently painted areas.") + "\n\n" +
_L("Are you sure you want to do it?") + "\n",
_L("Warning"), wxICON_WARNING | wxYES | wxNO);
if (not_painted || dlg.ShowModal() == wxID_YES) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points"));
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Automatic painting support points"));
int mesh_id = -1.0f;
for (ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) {