Bugfix in extrusion quality estimator, Refactoring of alerts, rename of autogenerate button
This commit is contained in:
parent
a4de5c6553
commit
c31e3ec1a2
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 ¶ms)
|
||||
#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
|
||||
|
@ -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 ¶ms);
|
||||
|
||||
void estimate_supports_malformations(std::vector<SupportLayer*> &layers, float supports_flow_width, const Params ¶ms);
|
||||
void estimate_malformations(std::vector<Layer*> &layers, const Params ¶ms);
|
||||
void estimate_supports_malformations(std::vector<SupportLayer *> &layers, float supports_flow_width, const Params ¶ms);
|
||||
void estimate_malformations(std::vector<Layer *> &layers, const Params ¶ms);
|
||||
|
||||
} // 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_ */
|
||||
|
@ -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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user