mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-06 05:24:01 -06:00
ENH: Cut optimization, support for custom connectors
Change-Id: I65163314374fb74f0b16df47dacae82caa6fab0d (cherry picked from commit 7bacc2c2a89be471f6fee51dd07a42222a28b55a)
This commit is contained in:
parent
9f71a8c5dd
commit
cd4cddfca4
51 changed files with 3663 additions and 466 deletions
File diff suppressed because it is too large
Load diff
|
@ -3,9 +3,15 @@
|
|||
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
enum class CutConnectorType : int;
|
||||
class ModelVolume;
|
||||
struct CutConnectorAttributes;
|
||||
|
||||
namespace GUI {
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
class GLGizmoAdvancedCut : public GLGizmoRotate3D
|
||||
{
|
||||
|
@ -42,8 +48,11 @@ private:
|
|||
|
||||
bool m_keep_upper;
|
||||
bool m_keep_lower;
|
||||
bool m_cut_to_parts;
|
||||
bool m_rotate_lower;
|
||||
bool m_place_on_cut_upper{true};
|
||||
bool m_place_on_cut_lower{false};
|
||||
bool m_rotate_upper{false};
|
||||
bool m_rotate_lower{false};
|
||||
|
||||
bool m_do_segment;
|
||||
double m_segment_smoothing_alpha;
|
||||
int m_segment_number;
|
||||
|
@ -54,25 +63,93 @@ private:
|
|||
|
||||
unsigned int m_last_active_id;
|
||||
|
||||
bool m_connectors_editing{false};
|
||||
bool m_show_shortcuts{false};
|
||||
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
double m_label_width{150.0};
|
||||
double m_control_width{ 200.0 };
|
||||
|
||||
CutConnectorType m_connector_type;
|
||||
size_t m_connector_style;
|
||||
size_t m_connector_shape_id;
|
||||
|
||||
float m_connector_depth_ratio{3.f};
|
||||
float m_connector_depth_ratio_tolerance{0.1f};
|
||||
|
||||
float m_connector_size{2.5f};
|
||||
float m_connector_size_tolerance{0.f};
|
||||
|
||||
TriangleMesh m_connector_mesh;
|
||||
bool m_has_invalid_connector{false};
|
||||
|
||||
// remember the connectors which is selected
|
||||
mutable std::vector<bool> m_selected;
|
||||
int m_selected_count{0};
|
||||
|
||||
Vec3d m_cut_plane_center{Vec3d::Zero()};
|
||||
Vec3d m_cut_plane_normal{Vec3d::UnitZ()};
|
||||
|
||||
Vec3d m_cut_line_begin{Vec3d::Zero()};
|
||||
Vec3d m_cut_line_end{Vec3d::Zero()};
|
||||
|
||||
Transform3d m_rotate_matrix{Transform3d::Identity()};
|
||||
|
||||
std::map<CutConnectorAttributes, GLModel> m_shapes;
|
||||
|
||||
struct InvalidConnectorsStatistics
|
||||
{
|
||||
unsigned int outside_cut_contour;
|
||||
unsigned int outside_bb;
|
||||
bool is_overlap;
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
outside_cut_contour = 0;
|
||||
outside_bb = 0;
|
||||
is_overlap = false;
|
||||
}
|
||||
} m_info_stats;
|
||||
|
||||
//GLSelectionRectangle m_selection_rectangle;
|
||||
|
||||
public:
|
||||
GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
bool on_key(wxKeyEvent &evt);
|
||||
|
||||
double get_movement() const { return m_movement; }
|
||||
void set_movement(double movement) const;
|
||||
void finish_rotation();
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
BoundingBoxf3 bounding_box() const;
|
||||
//BoundingBoxf3 transformed_bounding_box(const Vec3d &plane_center, bool revert_move = false) const;
|
||||
|
||||
bool is_looking_forward() const;
|
||||
|
||||
bool unproject_on_cut_plane(const Vec2d &mouse_pos, Vec3d &pos, Vec3d &pos_world);
|
||||
|
||||
virtual bool apply_clipping_plane() { return m_connectors_editing; }
|
||||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual void on_load(cereal::BinaryInputArchive &ar) override;
|
||||
virtual void on_save(cereal::BinaryOutputArchive &ar) const override;
|
||||
virtual std::string on_get_name() const;
|
||||
virtual void on_set_state();
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual CommonGizmosDataID on_get_requirements() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_stop_dragging() override;
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render();
|
||||
virtual void on_render_for_picking();
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
void show_tooltip_information(float x, float y);
|
||||
|
||||
virtual void on_enable_grabber(unsigned int id)
|
||||
{
|
||||
if (id < 3)
|
||||
|
@ -97,6 +174,12 @@ protected:
|
|||
|
||||
private:
|
||||
void perform_cut(const Selection& selection);
|
||||
bool can_perform_cut() const;
|
||||
void apply_connectors_in_model(ModelObject *mo, bool &create_dowels_as_separate_object);
|
||||
|
||||
bool is_selection_changed(bool alt_down, bool shift_down);
|
||||
void select_connector(int idx, bool select);
|
||||
|
||||
double calc_projection(const Linef3& mouse_ray) const;
|
||||
Vec3d calc_plane_normal(const std::array<Vec3d, 4>& plane_points) const;
|
||||
Vec3d calc_plane_center(const std::array<Vec3d, 4>& plane_points) const;
|
||||
|
@ -107,6 +190,46 @@ private:
|
|||
std::array<Vec3d, 4> get_plane_points_world_coord() const;
|
||||
void reset_cut_plane();
|
||||
void reset_all();
|
||||
|
||||
// update the connectors position so that the connectors are on the cut plane
|
||||
void put_connectors_on_cut_plane(const Vec3d &cp_normal, double cp_offset);
|
||||
void update_clipper();
|
||||
// on render
|
||||
void render_cut_plane_and_grabbers();
|
||||
void render_connectors();
|
||||
void render_clipper_cut();
|
||||
void render_cut_line();
|
||||
void render_connector_model(GLModel &model, const std::array<float, 4>& color, Transform3d view_model_matrix);
|
||||
|
||||
void clear_selection();
|
||||
void init_connector_shapes();
|
||||
void set_connectors_editing(bool connectors_editing);
|
||||
void reset_connectors();
|
||||
void update_connector_shape();
|
||||
void apply_selected_connectors(std::function<void(size_t idx)> apply_fn);
|
||||
void select_all_connectors();
|
||||
void unselect_all_connectors();
|
||||
void validate_connector_settings();
|
||||
bool add_connector(CutConnectors &connectors, const Vec2d &mouse_position);
|
||||
bool delete_selected_connectors();
|
||||
bool is_outside_of_cut_contour(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos);
|
||||
bool is_conflict_for_connector(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos);
|
||||
void check_conflict_for_all_connectors();
|
||||
|
||||
// render input window
|
||||
void render_cut_plane_input_window(float x, float y, float bottom_limit);
|
||||
void init_connectors_input_window_data();
|
||||
void render_connectors_input_window(float x, float y, float bottom_limit);
|
||||
void render_input_window_warning() const;
|
||||
bool render_reset_button(const std::string &label_id, const std::string &tooltip) const;
|
||||
bool render_connect_type_radio_button(CutConnectorType type);
|
||||
|
||||
bool render_combo(const std::string &label, const std::vector<std::string> &lines, size_t &selection_idx);
|
||||
bool render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in);
|
||||
|
||||
bool cut_line_processing() const;
|
||||
void discard_cut_line_processing();
|
||||
bool process_cut_line(SLAGizmoEventType action, const Vec2d &mouse_position);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -162,6 +162,8 @@ public:
|
|||
virtual std::string get_action_snapshot_name() { return "Gizmo action"; }
|
||||
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
|
||||
|
||||
virtual bool apply_clipping_plane() { return true; }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
||||
int get_hover_id() const { return m_hover_id; }
|
||||
|
|
|
@ -336,8 +336,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
|||
if (action == SLAGizmoEventType::LeftUp) {
|
||||
if (m_wait_for_up_event) {
|
||||
m_wait_for_up_event = false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// dragging the selection rectangle:
|
||||
|
|
|
@ -83,7 +83,7 @@ bool GLGizmoRotate::on_init()
|
|||
void GLGizmoRotate::on_start_dragging()
|
||||
{
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_center = box.center();
|
||||
m_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center;
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
|
||||
|
@ -135,7 +135,7 @@ void GLGizmoRotate::on_render()
|
|||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
|
||||
if (m_hover_id != 0 && !m_grabbers[0].dragging) {
|
||||
m_center = box.center();
|
||||
m_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center;
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
|
||||
|
|
|
@ -34,6 +34,7 @@ private:
|
|||
Axis m_axis;
|
||||
double m_angle;
|
||||
|
||||
mutable Vec3d m_custom_center{Vec3d::Zero()};
|
||||
mutable Vec3d m_center;
|
||||
mutable float m_radius;
|
||||
|
||||
|
@ -52,6 +53,8 @@ public:
|
|||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
void set_center(const Vec3d &point) { m_custom_center = point; }
|
||||
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override { return ""; }
|
||||
|
@ -101,6 +104,13 @@ public:
|
|||
return tooltip;
|
||||
}
|
||||
|
||||
void set_center(const Vec3d &point)
|
||||
{
|
||||
m_gizmos[X].set_center(point);
|
||||
m_gizmos[Y].set_center(point);
|
||||
m_gizmos[Z].set_center(point);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
|
|
|
@ -63,6 +63,12 @@ std::string GLGizmoScale3D::get_tooltip() const
|
|||
return "";
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
|
||||
{
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
m_grabbers[i].enabled = enable;
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_init()
|
||||
{
|
||||
for (int i = 0; i < 10; ++i)
|
||||
|
@ -228,9 +234,11 @@ void GLGizmoScale3D::on_render()
|
|||
|
||||
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
|
||||
//if (single_instance || single_volume) {
|
||||
|
||||
if (m_grabbers[4].enabled && m_grabbers[5].enabled) {
|
||||
glsafe(::glColor4fv(m_grabbers[4].color.data()));
|
||||
render_grabbers_connection(4, 5);
|
||||
//}
|
||||
}
|
||||
|
||||
glsafe(::glColor4fv(m_grabbers[2].color.data()));
|
||||
render_grabbers_connection(6, 7);
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
void enable_ununiversal_scale(bool enable);
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
|
|
|
@ -427,8 +427,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
if (action == SLAGizmoEventType::LeftUp) {
|
||||
if (m_wait_for_up_event) {
|
||||
m_wait_for_up_event = false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// dragging the selection rectangle:
|
||||
|
|
|
@ -449,7 +449,26 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
|
|||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
void ObjectClipper::set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos)
|
||||
{
|
||||
m_clp.reset(new ClippingPlane(cpl_normal, cpl_offset));
|
||||
m_clp_ratio = pos;
|
||||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
bool ObjectClipper::is_projection_inside_cut(const Vec3d &point) const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const auto &cl) {
|
||||
return cl->is_projection_inside_cut(point);
|
||||
});
|
||||
}
|
||||
|
||||
bool ObjectClipper::has_valid_contour() const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto &cl) {
|
||||
return cl->has_valid_contour();
|
||||
});
|
||||
}
|
||||
|
||||
void SupportsClipper::on_update()
|
||||
{
|
||||
|
|
|
@ -266,6 +266,10 @@ public:
|
|||
ClippingPlane* get_clipping_plane() const { return m_clp.get(); }
|
||||
void render_cut() const;
|
||||
|
||||
void set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos);
|
||||
|
||||
bool is_projection_inside_cut(const Vec3d &point_in) const;
|
||||
bool has_valid_contour() const;
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
|
|
|
@ -627,6 +627,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
|
|||
return dynamic_cast<GLGizmoMmuSegmentation*>(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Text)
|
||||
return dynamic_cast<GLGizmoText*>(m_gizmos[Text].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Cut)
|
||||
return dynamic_cast<GLGizmoAdvancedCut *>(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -872,7 +874,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
m_tooltip.clear();
|
||||
|
||||
if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) {
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Text)
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports ||
|
||||
m_current == Seam || m_current == MmuSegmentation || m_current == Text || m_current == Cut)
|
||||
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown()))
|
||||
// the gizmo got the event and took some action, there is no need to do anything more
|
||||
processed = true;
|
||||
|
@ -902,7 +905,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
// event was taken care of by the SlaSupports gizmo
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.RightDown() && !control_down && selected_object_idx != -1 && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
else if (evt.RightDown() && !control_down && selected_object_idx != -1
|
||||
&& (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut)
|
||||
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) {
|
||||
// event was taken care of by the FdmSupports / Seam / MMUPainting gizmo
|
||||
processed = true;
|
||||
|
@ -911,7 +915,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation))
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
processed = true;
|
||||
else if (evt.Dragging() && !control_down && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
else if (evt.Dragging() && !control_down
|
||||
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut)
|
||||
&& gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown())) {
|
||||
// the gizmo got the event and took some action, no need to do anything more here
|
||||
m_parent.set_as_dirty();
|
||||
|
@ -924,10 +929,12 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
else if (evt.RightIsDown())
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true);
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) && !m_parent.is_mouse_dragging()) {
|
||||
else if (evt.LeftUp()
|
||||
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut)
|
||||
&& !m_parent.is_mouse_dragging()
|
||||
&& gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down)) {
|
||||
// in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
||||
// object moving or selecting is suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && m_current == Flatten && m_gizmos[m_current]->get_hover_id() != -1) {
|
||||
|
@ -937,8 +944,9 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
//wxGetApp().obj_manipul()->set_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) && !m_parent.is_mouse_dragging()) {
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||
else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut)
|
||||
&& !m_parent.is_mouse_dragging()
|
||||
&& gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down)) {
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp()) {
|
||||
|
@ -1111,6 +1119,13 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
|||
const int keyCode = evt.GetKeyCode();
|
||||
bool processed = false;
|
||||
|
||||
// todo: zhimin Each gizmo should handle key event in it own on_key() function
|
||||
if (m_current == Cut) {
|
||||
if (GLGizmoAdvancedCut *gizmo_cut = dynamic_cast<GLGizmoAdvancedCut *>(get_current())) {
|
||||
return gizmo_cut->on_key(evt);
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.GetEventType() == wxEVT_KEY_UP)
|
||||
{
|
||||
if (m_current == SlaSupports || m_current == Hollow)
|
||||
|
@ -1479,6 +1494,11 @@ GLGizmoBase* GLGizmosManager::get_current() const
|
|||
return ((m_current == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[m_current].get();
|
||||
}
|
||||
|
||||
GLGizmoBase* GLGizmosManager::get_gizmo(GLGizmosManager::EType type) const
|
||||
{
|
||||
return ((type == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[type].get();
|
||||
}
|
||||
|
||||
GLGizmosManager::EType GLGizmosManager::get_gizmo_from_name(const std::string& gizmo_name) const
|
||||
{
|
||||
std::vector<size_t> selectable_idxs = get_selectable_idxs();
|
||||
|
|
|
@ -230,6 +230,7 @@ public:
|
|||
|
||||
EType get_current_type() const { return m_current; }
|
||||
GLGizmoBase* get_current() const;
|
||||
GLGizmoBase *get_gizmo(GLGizmosManager::EType type) const;
|
||||
EType get_gizmo_from_name(const std::string& gizmo_name) const;
|
||||
|
||||
bool is_running() const;
|
||||
|
@ -311,7 +312,7 @@ public:
|
|||
//BBS: GUI refactor: GLToolbar adjust
|
||||
float get_scaled_total_height() const;
|
||||
float get_scaled_total_width() const;
|
||||
//GizmoObjectManipulation& get_object_manipulation() { return m_object_manipulation; }
|
||||
GizmoObjectManipulation& get_object_manipulation() { return m_object_manipulation; }
|
||||
bool get_uniform_scaling() const { return m_object_manipulation.get_uniform_scaling();}
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue