Merge remote-tracking branch 'origin/et_labels'

This commit is contained in:
Enrico Turri 2020-02-06 09:58:44 +01:00
commit a430ff546e
12 changed files with 249 additions and 5 deletions

View file

@ -1101,7 +1101,11 @@ static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(c
}
// Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model().
static inline std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print &print)
#if ENABLE_SHOW_SCENE_LABELS
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print)
#else
static inline std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print)
#endif // ENABLE_SHOW_SCENE_LABELS
{
// Build up map from ModelInstance* to PrintInstance*
std::vector<std::pair<const ModelInstance*, const PrintInstance*>> model_instance_to_print_instance;

View file

@ -418,6 +418,10 @@ private:
friend class WipeTowerIntegration;
};
#if ENABLE_SHOW_SCENE_LABELS
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print);
#endif // ENABLE_SHOW_SCENE_LABELS
}
#endif

View file

@ -62,5 +62,7 @@
// Enhance reload from disk to be able to work with 3mf/amf files saved with PrusaSlicer 2.1.0 and earlier
#define ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK (1 && ENABLE_2_2_0_BETA1)
// Enable showing object/instance info with labels into the 3D scene
#define ENABLE_SHOW_SCENE_LABELS (1 && ENABLE_2_2_0_BETA1)
#endif // _technologies_h_

View file

@ -6,6 +6,9 @@
#include "polypartition.h"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#if ENABLE_SHOW_SCENE_LABELS
#include "libslic3r/GCode.hpp"
#endif // ENABLE_SHOW_SCENE_LABELS
#include "libslic3r/GCode/PreviewData.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "libslic3r/GCode/ThumbnailData.hpp"
@ -65,6 +68,10 @@
#include <chrono>
#endif // ENABLE_RENDER_STATISTICS
#if ENABLE_SHOW_SCENE_LABELS
#include <imgui/imgui_internal.h>
#endif // ENABLE_SHOW_SCENE_LABELS
static const float TRACKBALLSIZE = 0.8f;
static const float DEFAULT_BG_DARK_COLOR[3] = { 0.478f, 0.478f, 0.478f };
@ -1230,6 +1237,142 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
}
}
#if ENABLE_SHOW_SCENE_LABELS
void GLCanvas3D::Labels::render(const std::vector<const PrintInstance*>& sorted_instances) const
{
if (!m_enabled || !is_shown())
return;
const Camera& camera = m_canvas.get_camera();
const Model* model = m_canvas.get_model();
if (model == nullptr)
return;
Transform3d world_to_eye = camera.get_view_matrix();
Transform3d world_to_screen = camera.get_projection_matrix() * world_to_eye;
const std::array<int, 4>& viewport = camera.get_viewport();
struct Owner
{
int obj_idx;
int inst_idx;
size_t model_instance_id;
BoundingBoxf3 world_box;
double eye_center_z;
std::string title;
std::string label;
std::string print_order;
bool selected;
};
// collect owners world bounding boxes and data from volumes
std::vector<Owner> owners;
const GLVolumeCollection& volumes = m_canvas.get_volumes();
for (const GLVolume* volume : volumes.volumes) {
int obj_idx = volume->object_idx();
if (0 <= obj_idx && obj_idx < (int)model->objects.size()) {
int inst_idx = volume->instance_idx();
std::vector<Owner>::iterator it = std::find_if(owners.begin(), owners.end(), [obj_idx, inst_idx](const Owner& owner) {
return (owner.obj_idx == obj_idx) && (owner.inst_idx == inst_idx);
});
if (it != owners.end()) {
it->world_box.merge(volume->transformed_bounding_box());
it->selected &= volume->selected;
} else {
const ModelObject* model_object = model->objects[obj_idx];
Owner owner;
owner.obj_idx = obj_idx;
owner.inst_idx = inst_idx;
owner.model_instance_id = model_object->instances[inst_idx]->id().id;
owner.world_box = volume->transformed_bounding_box();
owner.title = "object" + std::to_string(obj_idx) + "_inst##" + std::to_string(inst_idx);
owner.label = model_object->name;
if (model_object->instances.size() > 1)
owner.label += " (" + std::to_string(inst_idx + 1) + ")";
owner.selected = volume->selected;
owners.push_back(owner);
}
}
}
// updates print order strings
if (sorted_instances.size() > 1) {
for (int i = 0; i < sorted_instances.size(); ++i) {
size_t id = sorted_instances[i]->model_instance->id().id;
std::vector<Owner>::iterator it = std::find_if(owners.begin(), owners.end(), [id](const Owner& owner) {
return owner.model_instance_id == id;
});
if (it != owners.end())
it->print_order = _(L("Seq.")) + "#: " + std::to_string(i + 1);
}
}
// calculate eye bounding boxes center zs
for (Owner& owner : owners) {
owner.eye_center_z = (world_to_eye * owner.world_box.center())(2);
}
// sort owners by center eye zs and selection
std::sort(owners.begin(), owners.end(), [](const Owner& owner1, const Owner& owner2) {
if (!owner1.selected && owner2.selected)
return true;
else if (owner1.selected && !owner2.selected)
return false;
else
return (owner1.eye_center_z < owner2.eye_center_z);
});
ImGuiWrapper& imgui = *wxGetApp().imgui();
// render info windows
for (const Owner& owner : owners) {
Vec3d screen_box_center = world_to_screen * owner.world_box.center();
float x = 0.0f;
float y = 0.0f;
if (camera.get_type() == Camera::Perspective) {
x = (0.5f + 0.001f * 0.5f * (float)screen_box_center(0)) * viewport[2];
y = (0.5f - 0.001f * 0.5f * (float)screen_box_center(1)) * viewport[3];
} else {
x = (0.5f + 0.5f * (float)screen_box_center(0)) * viewport[2];
y = (0.5f - 0.5f * (float)screen_box_center(1)) * viewport[3];
}
if (x < 0.0f || viewport[2] < x || y < 0.0f || viewport[3] < y)
continue;
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, owner.selected ? 3.0f : 1.5f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleColor(ImGuiCol_Border, owner.selected ? ImVec4(0.757f, 0.404f, 0.216f, 1.0f) : ImVec4(0.75f, 0.75f, 0.75f, 1.0f));
imgui.set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.5f);
imgui.begin(owner.title, ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
float win_w = ImGui::GetWindowWidth();
float label_len = imgui.calc_text_size(owner.label).x;
ImGui::SetCursorPosX(0.5f * (win_w - label_len));
ImGui::AlignTextToFramePadding();
imgui.text(owner.label);
if (!owner.print_order.empty())
{
ImGui::Separator();
float po_len = imgui.calc_text_size(owner.print_order).x;
ImGui::SetCursorPosX(0.5f * (win_w - po_len));
ImGui::AlignTextToFramePadding();
imgui.text(owner.print_order);
}
// force re-render while the windows gets to its final size (it takes several frames)
float content_w = 1 + ImGui::GetWindowContentRegionWidth();
if (content_w < label_len)
m_canvas.request_extra_frame();
imgui.end();
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
}
}
#endif // ENABLE_SHOW_SCENE_LABELS
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@ -1299,6 +1442,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
, m_show_picking_texture(false)
#endif // ENABLE_RENDER_PICKING_PASS
, m_render_sla_auxiliaries(true)
, m_labels(*this)
{
if (m_canvas != nullptr) {
m_timer.SetOwner(m_canvas);
@ -2681,6 +2825,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
case 'B':
case 'b': { zoom_to_bed(); break; }
#if ENABLE_SHOW_SCENE_LABELS
case 'E':
case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; }
#endif // ENABLE_SHOW_SCENE_LABELS
case 'I':
case 'i': { _update_camera_zoom(1.0); break; }
case 'K':
@ -4949,6 +5097,18 @@ void GLCanvas3D::_render_overlays() const
if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f))
m_layers_editing.render_overlay(*this);
#if ENABLE_SHOW_SCENE_LABELS
const ConfigOptionBool* opt = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"));
bool sequential_print = (opt != nullptr) ? m_config->opt_bool("complete_objects") : false;
std::vector<const PrintInstance*> sorted_instances;
if (sequential_print) {
const Print* print = fff_print();
if (print != nullptr)
sorted_instances = sort_object_instances_by_model_order(*print);
}
m_labels.render(sorted_instances);
#endif // ENABLE_SHOW_SCENE_LABELS
glsafe(::glPopMatrix());
}

View file

@ -40,6 +40,9 @@ class GCodePreviewData;
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
struct SlicingParameters;
#if ENABLE_SHOW_SCENE_LABELS
struct PrintInstance;
#endif // ENABLE_SHOW_SCENE_LABELS
enum LayerHeightEditActionType : unsigned int;
namespace GUI {
@ -375,6 +378,22 @@ private:
};
#endif // ENABLE_RENDER_STATISTICS
#if ENABLE_SHOW_SCENE_LABELS
class Labels
{
bool m_enabled{ false };
bool m_shown{ false };
GLCanvas3D& m_canvas;
public:
explicit Labels(GLCanvas3D& canvas) : m_canvas(canvas) {}
void enable(bool enable) { m_enabled = enable; }
void show(bool show) { m_shown = m_enabled ? show : false; }
bool is_shown() const { return m_shown; }
void render(const std::vector<const PrintInstance*>& sorted_instances) const;
};
#endif // ENABLE_SHOW_SCENE_LABELS
public:
enum ECursorType : unsigned char
{
@ -452,6 +471,10 @@ private:
mutable int m_imgui_undo_redo_hovered_pos{ -1 };
int m_selected_extruder;
#if ENABLE_SHOW_SCENE_LABELS
Labels m_labels;
#endif // ENABLE_SHOW_SCENE_LABELS
public:
GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
~GLCanvas3D();
@ -467,6 +490,9 @@ public:
void set_as_dirty();
unsigned int get_volumes_count() const;
#if ENABLE_SHOW_SCENE_LABELS
const GLVolumeCollection& get_volumes() const { return m_volumes; }
#endif // ENABLE_SHOW_SCENE_LABELS
void reset_volumes();
int check_volumes_outside_state() const;
@ -478,6 +504,9 @@ public:
void set_config(const DynamicPrintConfig* config);
void set_process(BackgroundSlicingProcess* process);
void set_model(Model* model);
#if ENABLE_SHOW_SCENE_LABELS
const Model* get_model() const { return m_model; }
#endif // ENABLE_SHOW_SCENE_LABELS
const Selection& get_selection() const { return m_selection; }
Selection& get_selection() { return m_selection; }
@ -525,6 +554,9 @@ public:
void enable_main_toolbar(bool enable);
void enable_undoredo_toolbar(bool enable);
void enable_dynamic_background(bool enable);
#if ENABLE_SHOW_SCENE_LABELS
void enable_labels(bool enable) { m_labels.enable(enable); }
#endif // ENABLE_SHOW_SCENE_LABELS
void allow_multisample(bool allow);
void zoom_to_bed();
@ -646,6 +678,11 @@ public:
void mouse_up_cleanup();
#if ENABLE_SHOW_SCENE_LABELS
bool are_labels_shown() const { return m_labels.is_shown(); }
void show_labels(bool show) { m_labels.show(show); }
#endif // ENABLE_SHOW_SCENE_LABELS
private:
bool _is_shown_on_screen() const;

View file

@ -65,6 +65,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_
m_canvas->enable_selection(true);
m_canvas->enable_main_toolbar(true);
m_canvas->enable_undoredo_toolbar(true);
#if ENABLE_SHOW_SCENE_LABELS
m_canvas->enable_labels(true);
#endif // ENABLE_SHOW_SCENE_LABELS
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);

View file

@ -157,6 +157,9 @@ void KBShortcutsDialog::fill_shortcuts()
plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object")));
plater_shortcuts.push_back(Shortcut("I", L("Zoom in")));
plater_shortcuts.push_back(Shortcut("O", L("Zoom out")));
#if ENABLE_SHOW_SCENE_LABELS
plater_shortcuts.push_back(Shortcut("E", L("Show/Hide object/instance labels")));
#endif // ENABLE_SHOW_SCENE_LABELS
plater_shortcuts.push_back(Shortcut(ctrl+"M", L("Show/Hide 3Dconnexion devices settings dialog")));
plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection")));
#if ENABLE_RENDER_PICKING_PASS

View file

@ -550,10 +550,10 @@ void MainFrame::init_menubar()
wxString hotkey_delete = "Del";
#endif
append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "A",
_(L("Selects all objects")), [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->select_all(); },
_(L("Selects all objects")), [this](wxCommandEvent&) { m_plater->select_all(); },
"", nullptr, [this](){return can_select(); }, this);
append_menu_item(editMenu, wxID_ANY, _(L("D&eselect all")) + sep + "Esc",
_(L("Deselects all objects")), [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->deselect_all(); },
_(L("Deselects all objects")), [this](wxCommandEvent&) { m_plater->deselect_all(); },
"", nullptr, [this](){return can_deselect(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete,
@ -659,6 +659,12 @@ void MainFrame::init_menubar()
"", nullptr, [this](){return can_change_view(); }, this);
append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); },
"", nullptr, [this](){return can_change_view(); }, this);
#if ENABLE_SHOW_SCENE_LABELS
viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")),
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
#endif // ENABLE_SHOW_SCENE_LABELS
}
// Help menu

View file

@ -1784,6 +1784,11 @@ struct Plater::priv
bool is_preview_loaded() const { return preview->is_loaded(); }
bool is_view3D_shown() const { return current_panel == view3D; }
#if ENABLE_SHOW_SCENE_LABELS
bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); }
void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); }
#endif // ENABLE_SHOW_SCENE_LABELS
void set_current_canvas_as_dirty();
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
GLCanvas3D* get_current_canvas3D();
@ -4673,6 +4678,11 @@ bool Plater::is_preview_shown() const { return p->is_preview_shown(); }
bool Plater::is_preview_loaded() const { return p->is_preview_loaded(); }
bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); }
#if ENABLE_SHOW_SCENE_LABELS
bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); }
void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); }
#endif // ENABLE_SHOW_SCENE_LABELS
void Plater::select_all() { p->select_all(); }
void Plater::deselect_all() { p->deselect_all(); }

View file

@ -170,6 +170,11 @@ public:
bool is_preview_loaded() const;
bool is_view3D_shown() const;
#if ENABLE_SHOW_SCENE_LABELS
bool are_view3D_labels_shown() const;
void show_view3D_labels(bool show);
#endif // ENABLE_SHOW_SCENE_LABELS
// Called after the Preferences dialog is closed and the program settings are saved.
// Update the UI based on the current preferences.
void update_ui_from_settings();

View file

@ -146,7 +146,8 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string,
}
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler)
std::function<void(wxCommandEvent & event)> cb, wxEvtHandler* event_handler,
std::function<bool()> const enable_condition, std::function<bool()> const check_condition, wxWindow* parent)
{
if (id == wxID_ANY)
id = wxNewId();
@ -160,6 +161,13 @@ wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string,
#endif // __WXMSW__
menu->Bind(wxEVT_MENU, cb, id);
if (parent)
parent->Bind(wxEVT_UPDATE_UI, [enable_condition, check_condition](wxUpdateUIEvent& evt)
{
evt.Enable(enable_condition());
evt.Check(check_condition());
}, id);
return item;
}

View file

@ -34,7 +34,9 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
std::function<void(wxCommandEvent & event)> cb, wxEvtHandler* event_handler,
std::function<bool()> const enable_condition = []() { return true; },
std::function<bool()> const check_condition = []() { return true; }, wxWindow* parent = nullptr);
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win);