Added a 'layer statistics' legend for SLA

This commit is contained in:
Lukas Matena 2024-04-08 12:24:08 +02:00
parent a7cf950674
commit 226b20fa17
7 changed files with 77 additions and 15 deletions

View File

@ -153,8 +153,8 @@ namespace ImGui
const wchar_t PlugMarker = 0x1C;
const wchar_t DowelMarker = 0x1D;
const wchar_t SnapMarker = 0x1E;
const wchar_t HorizontalHide = 0xB1;
const wchar_t HorizontalShow = 0xB2;
const wchar_t HorizontalHide = 0xB4;
const wchar_t HorizontalShow = 0xB6;
// Do not forget use following letters only in wstring
const wchar_t DocumentationButton = 0x2600;
const wchar_t DocumentationHoverButton = 0x2601;

View File

@ -412,7 +412,8 @@ struct SLAPrintStatistics
size_t fast_layers_count;
double total_cost;
double total_weight;
std::vector<double> layers_times;
std::vector<double> layers_times_running_total;
std::vector<double> layers_areas;
// Config with the filled in print statistics.
DynamicConfig config() const;
@ -429,7 +430,8 @@ struct SLAPrintStatistics
fast_layers_count = 0;
total_cost = 0.;
total_weight = 0.;
layers_times.clear();
layers_times_running_total.clear();
layers_areas.clear();
}
};

View File

@ -942,8 +942,10 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
double models_volume(0.0);
double estim_time(0.0);
std::vector<double> layers_times;
std::vector<std::pair<coord_t, double>> layers_times; // level and time
std::vector<std::pair<coord_t, double>> layers_areas; // level and area
layers_times.reserve(printer_input.size());
layers_areas.reserve(printer_input.size());
size_t slow_layers = 0;
size_t fast_layers = 0;
@ -961,7 +963,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// write vars
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
&fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt)
&fast_layers, &fade_layer_time, &layers_times, &layers_areas](size_t sliced_layer_cnt)
{
PrintLayer &layer = m_print->m_printer_input[sliced_layer_cnt];
@ -1029,6 +1031,8 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
Lock lck(mutex); supports_volume += layer_support_area * l_height;
}
double layer_area = layer_model_area + layer_support_area;
// Here we can save the expensively calculated polygons for printing
ExPolygons trslices;
trslices.reserve(model_polygons.size() + supports_polygons.size());
@ -1039,7 +1043,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// Calculation of the slow and fast layers to the future controlling those values on FW
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
const bool is_fast_layer = layer_area <= display_area*area_fill;
const double tilt_time = material_config.material_print_speed == slamsSlow ? slow_tilt :
material_config.material_print_speed == slamsHighViscosity ? hv_tilt :
is_fast_layer ? fast_tilt : slow_tilt;
@ -1082,13 +1086,14 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
+ 120 / 1000 // Magical constant to compensate remaining computation delay in exposure thread
);
layers_times.push_back(layer_times);
layers_times.emplace_back(layer.level(), layer_times);
estim_time += layer_times;
layers_areas.emplace_back(layer.level(), layer_area * SCALING_FACTOR * SCALING_FACTOR);
}
};
// sequential version for debugging:
// for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i);
// for(size_t i = 0; i < printer_input.size(); ++i) printlayerfn(i);
execution::for_each(ex_tbb, size_t(0), printer_input.size(), printlayerfn,
execution::max_concurrency(ex_tbb));
@ -1102,7 +1107,17 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
print_statistics.estimated_print_time = NaNd;
else {
print_statistics.estimated_print_time = estim_time;
print_statistics.layers_times = layers_times;
// Times and areas vectors were filled in parallel, they need to be sorted first.
// The print statistics will contain only the values (in the correct order).
std::sort(layers_times.begin(), layers_times.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
std::sort(layers_areas.begin(), layers_areas.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
print_statistics.layers_times_running_total.clear();
for (size_t i=0; i<layers_times.size(); ++i)
print_statistics.layers_times_running_total.emplace_back(layers_times[i].second + (i==0 ? 0. : print_statistics.layers_times_running_total[i-1]));
print_statistics.layers_areas.clear();
for (const auto& [level, area] : layers_areas)
print_statistics.layers_areas.emplace_back(area);
}
print_statistics.fast_layers_count = fast_layers;

View File

@ -6250,6 +6250,40 @@ void GLCanvas3D::_render_camera_target()
}
#endif // ENABLE_SHOW_CAMERA_TARGET
static void render_sla_layer_legend(const SLAPrint& print, int layer_idx, int cnv_width)
{
const std::vector<double>& areas = print.print_statistics().layers_areas;
const std::vector<double>& times = print.print_statistics().layers_times_running_total;
const double display_area = print.printer_config().display_height * print.printer_config().display_width;
if (layer_idx >= 0 && layer_idx < areas.size()) {
const double area = areas[layer_idx];
const double time = times[layer_idx] - (layer_idx == 0 ? 0. : times[layer_idx-1]);
const double time_until_layer = times[layer_idx];
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGuiPureWrap::set_next_window_pos(float(cnv_width) - imgui.get_style_scaling() * 5.f, imgui.get_style_scaling() * 55.f, ImGuiCond_Always, 1.0f, 0.0f);
ImGui::SetNextWindowBgAlpha(0.6f);
ImGuiPureWrap::begin(_u8L("Layer statistics"), ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::Text(_u8L("Layer area: %.0f mm²").c_str(), area);
int area_percent_int = int(std::round(100. * area/display_area));
ImGui::Text(GUI::format(_u8L("Area fill: %1% %%%%"), area_percent_int == 0 ? "<1" : std::to_string(area_percent_int)).c_str());
ImGui::Separator();
ImGui::Text(GUI::format(_u8L("Layer time: %1%"), get_time_dhms(time)).c_str());
std::string buffer_str = _u8L("Time since start: %1%");
ImGui::Text(GUI::format(buffer_str, get_time_dhms(time_until_layer)).c_str());
// The dummy control below uses the assumption that the total time string will be the longest
// and forces the width of the window large enough so it does not resize depending on the current value.
ImGui::Dummy(ImVec2(ImGui::CalcTextSize(GUI::format(buffer_str, get_time_dhms(82799)).c_str()).x, 0.));
ImGuiPureWrap::end();
}
}
void GLCanvas3D::_render_sla_slices()
{
if (!m_use_clipping_planes || current_printer_technology() != ptSLA)
@ -6261,6 +6295,13 @@ void GLCanvas3D::_render_sla_slices()
// nothing to render, return
return;
if (print->finished()) {
double slider_width = 0.;
if (const Preview* preview = dynamic_cast<Preview*>(m_canvas->GetParent()))
slider_width = preview->get_layers_slider_width();
render_sla_layer_legend(*print, m_layer_slider_index, get_canvas_size().get_width() - slider_width);
}
double clip_min_z = -m_clipping_planes[0].get_data()[3];
double clip_max_z = m_clipping_planes[1].get_data()[3];
for (unsigned int i = 0; i < (unsigned int)print_objects.size(); ++i) {

View File

@ -501,6 +501,7 @@ private:
ClippingPlane m_camera_clipping_plane;
bool m_use_clipping_planes;
std::array<SlaCap, 2> m_sla_caps;
int m_layer_slider_index = -1;
std::string m_sidebar_field;
// when true renders an extra frame by not resetting m_dirty to false
// see request_extra_frame()
@ -763,6 +764,8 @@ public:
void bed_shape_changed();
void set_layer_slider_index(int i) { m_layer_slider_index = i; }
void set_clipping_plane(unsigned int id, const ClippingPlane& plane) {
if (id < 2) {
m_clipping_planes[id] = plane;

View File

@ -328,14 +328,14 @@ void Preview::render_sliders(GLCanvas3D& canvas)
m_moves_slider->Render(canvas_width, canvas_height, extra_scale);
}
float Preview::get_moves_slider_height()
float Preview::get_moves_slider_height() const
{
if (m_moves_slider && m_moves_slider->IsShown())
return m_moves_slider->GetHeight();
return 0.0f;
}
float Preview::get_layers_slider_width()
float Preview::get_layers_slider_width() const
{
if (m_layers_slider && m_layers_slider->IsShown())
return m_layers_slider->GetWidth();
@ -629,7 +629,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
m_layers_slider->SetDrawMode(sla_print_technology, sequential_print);
if (sla_print_technology)
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times);
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times_running_total);
else
m_layers_slider->SetLayersTimes(m_canvas->get_gcode_layers_times_cache(), m_gcode_result->print_statistics.modes.front().time);
@ -1037,6 +1037,7 @@ void Preview::on_layers_slider_scroll_changed()
else if (tech == ptSLA) {
m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValue()));
m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValue()));
m_canvas->set_layer_slider_index(m_layers_slider->GetHigherPos());
m_canvas->render();
}
}

View File

@ -136,8 +136,8 @@ public:
void msw_rescale();
void render_sliders(GLCanvas3D& canvas);
float get_layers_slider_width();
float get_moves_slider_height();
float get_layers_slider_width() const;
float get_moves_slider_height() const;
bool is_loaded() const { return m_loaded; }