Merge branch 'master' into fs_emboss
This commit is contained in:
commit
ce2e0e7978
@ -622,7 +622,7 @@ std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::funct
|
|||||||
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback);
|
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask)
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<char> &face_mask)
|
||||||
{
|
{
|
||||||
return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){});
|
return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){});
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ private:
|
|||||||
// Used for chaining slice lines into polygons.
|
// Used for chaining slice lines into polygons.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<char> &face_mask);
|
||||||
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
||||||
|
|
||||||
|
@ -1805,7 +1805,7 @@ Polygons slice_mesh(
|
|||||||
{
|
{
|
||||||
bool trafo_identity = is_identity(params.trafo);
|
bool trafo_identity = is_identity(params.trafo);
|
||||||
Transform3f tf;
|
Transform3f tf;
|
||||||
std::vector<bool> face_mask(mesh.indices.size(), false);
|
std::vector<char> face_mask(mesh.indices.size(), 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
// 1) Mark vertices as below or above the slicing plane.
|
// 1) Mark vertices as below or above the slicing plane.
|
||||||
|
@ -1416,6 +1416,15 @@ void ColourPicker::sys_color_changed()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointCtrl::~PointCtrl()
|
||||||
|
{
|
||||||
|
if (sizer) {
|
||||||
|
sizer->Clear();
|
||||||
|
delete sizer;
|
||||||
|
sizer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PointCtrl::BUILD()
|
void PointCtrl::BUILD()
|
||||||
{
|
{
|
||||||
auto temp = new wxBoxSizer(wxHORIZONTAL);
|
auto temp = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
@ -425,7 +425,7 @@ class PointCtrl : public Field {
|
|||||||
public:
|
public:
|
||||||
PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||||
PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||||
~PointCtrl() {}
|
~PointCtrl();
|
||||||
|
|
||||||
wxSizer* sizer{ nullptr };
|
wxSizer* sizer{ nullptr };
|
||||||
wxTextCtrl* x_textctrl{ nullptr };
|
wxTextCtrl* x_textctrl{ nullptr };
|
||||||
|
@ -5660,10 +5660,10 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
|
|||||||
if (wxGetApp().plater()->is_preview_shown())
|
if (wxGetApp().plater()->is_preview_shown())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float scale = wxGetApp().toolbar_icon_scale();
|
const float scale = wxGetApp().toolbar_icon_scale();
|
||||||
Size cnv_size = get_canvas_size();
|
const Size cnv_size = get_canvas_size();
|
||||||
|
|
||||||
float size = GLToolbar::Default_Icons_Size * scale;
|
int size = int(GLToolbar::Default_Icons_Size * scale);
|
||||||
|
|
||||||
// Set current size for all top toolbars. It will be used for next calculations
|
// Set current size for all top toolbars. It will be used for next calculations
|
||||||
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
|
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
|
||||||
@ -5672,28 +5672,28 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
|
|||||||
m_main_toolbar.set_scale(sc);
|
m_main_toolbar.set_scale(sc);
|
||||||
m_undoredo_toolbar.set_scale(sc);
|
m_undoredo_toolbar.set_scale(sc);
|
||||||
collapse_toolbar.set_scale(sc);
|
collapse_toolbar.set_scale(sc);
|
||||||
size *= m_retina_helper->get_scale_factor();
|
size *= int(m_retina_helper->get_scale_factor());
|
||||||
#else
|
#else
|
||||||
m_main_toolbar.set_icons_size(size);
|
m_main_toolbar.set_icons_size(size);
|
||||||
m_undoredo_toolbar.set_icons_size(size);
|
m_undoredo_toolbar.set_icons_size(size);
|
||||||
collapse_toolbar.set_icons_size(size);
|
collapse_toolbar.set_icons_size(size);
|
||||||
#endif // ENABLE_RETINA_GL
|
#endif // ENABLE_RETINA_GL
|
||||||
|
|
||||||
float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width();
|
const float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width();
|
||||||
int items_cnt = m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + collapse_toolbar.get_visible_items_cnt();
|
int items_cnt = m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + collapse_toolbar.get_visible_items_cnt();
|
||||||
float noitems_width = top_tb_width - size * items_cnt; // width of separators and borders in top toolbars
|
const float noitems_width = top_tb_width - float(size) * items_cnt; // width of separators and borders in top toolbars
|
||||||
|
|
||||||
// calculate scale needed for items in all top toolbars
|
// calculate scale needed for items in all top toolbars
|
||||||
// the std::max() is there because on some Linux dialects/virtual machines this code is called when the canvas has not been properly initialized yet,
|
// the std::max() is there because on some Linux dialects/virtual machines this code is called when the canvas has not been properly initialized yet,
|
||||||
// leading to negative values for the scale.
|
// leading to negative values for the scale.
|
||||||
// See: https://github.com/prusa3d/PrusaSlicer/issues/8563
|
// See: https://github.com/prusa3d/PrusaSlicer/issues/8563
|
||||||
// https://github.com/supermerill/SuperSlicer/issues/854
|
// https://github.com/supermerill/SuperSlicer/issues/854
|
||||||
float new_h_scale = std::max((cnv_size.get_width() - noitems_width), 1.0f) / (items_cnt * GLToolbar::Default_Icons_Size);
|
const float new_h_scale = std::max((cnv_size.get_width() - noitems_width), 1.0f) / (items_cnt * GLToolbar::Default_Icons_Size);
|
||||||
|
|
||||||
items_cnt = m_gizmos.get_selectable_icons_cnt() + 3; // +3 means a place for top and view toolbars and separators in gizmos toolbar
|
items_cnt = m_gizmos.get_selectable_icons_cnt() + 3; // +3 means a place for top and view toolbars and separators in gizmos toolbar
|
||||||
|
|
||||||
// calculate scale needed for items in the gizmos toolbar
|
// calculate scale needed for items in the gizmos toolbar
|
||||||
float new_v_scale = cnv_size.get_height() / (items_cnt * GLGizmosManager::Default_Icons_Size);
|
const float new_v_scale = cnv_size.get_height() / (items_cnt * GLGizmosManager::Default_Icons_Size);
|
||||||
|
|
||||||
// set minimum scale as a auto scale for the toolbars
|
// set minimum scale as a auto scale for the toolbars
|
||||||
float new_scale = std::min(new_h_scale, new_v_scale);
|
float new_scale = std::min(new_h_scale, new_v_scale);
|
||||||
@ -5708,24 +5708,12 @@ void GLCanvas3D::_render_overlays()
|
|||||||
{
|
{
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
|
// main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed
|
||||||
|
// to correctly place them
|
||||||
_check_and_update_toolbar_icon_scale();
|
_check_and_update_toolbar_icon_scale();
|
||||||
|
|
||||||
_render_gizmos_overlay();
|
_render_gizmos_overlay();
|
||||||
|
|
||||||
// main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed
|
|
||||||
// to correctly place them
|
|
||||||
#if ENABLE_RETINA_GL
|
|
||||||
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(/*true*/);
|
|
||||||
m_main_toolbar.set_scale(scale);
|
|
||||||
m_undoredo_toolbar.set_scale(scale);
|
|
||||||
wxGetApp().plater()->get_collapse_toolbar().set_scale(scale);
|
|
||||||
#else
|
|
||||||
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(/*true*/));
|
|
||||||
m_main_toolbar.set_icons_size(size);
|
|
||||||
m_undoredo_toolbar.set_icons_size(size);
|
|
||||||
wxGetApp().plater()->get_collapse_toolbar().set_icons_size(size);
|
|
||||||
#endif // ENABLE_RETINA_GL
|
|
||||||
|
|
||||||
_render_main_toolbar();
|
_render_main_toolbar();
|
||||||
_render_undoredo_toolbar();
|
_render_undoredo_toolbar();
|
||||||
_render_collapse_toolbar();
|
_render_collapse_toolbar();
|
||||||
|
@ -1144,11 +1144,11 @@ void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data)
|
|||||||
void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data)
|
void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data)
|
||||||
{
|
{
|
||||||
CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors;
|
CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors;
|
||||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
Vec3d pos;
|
||||||
Vec3d pos_world;
|
Vec3d pos_world;
|
||||||
|
|
||||||
if (unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos_and_normal, pos_world)) {
|
if (unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos, pos_world)) {
|
||||||
connectors[m_hover_id - m_connectors_group_id].pos = pos_and_normal.first;
|
connectors[m_hover_id - m_connectors_group_id].pos = pos;
|
||||||
update_raycasters_for_picking_transform();
|
update_raycasters_for_picking_transform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2006,44 +2006,41 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
|||||||
|
|
||||||
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
||||||
// Return false if no intersection was found, true otherwise.
|
// Return false if no intersection was found, true otherwise.
|
||||||
bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world)
|
bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, Vec3d& pos, Vec3d& pos_world)
|
||||||
{
|
{
|
||||||
const float sla_shift = m_c->selection_info()->get_sla_shift();
|
const float sla_shift = m_c->selection_info()->get_sla_shift();
|
||||||
|
|
||||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||||
const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()];
|
const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()];
|
||||||
const Transform3d instance_trafo = sla_shift > 0.f ?
|
|
||||||
translation_transform(sla_shift * Vec3d::UnitZ()) * mi->get_transformation().get_matrix() : mi->get_transformation().get_matrix();
|
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
|
|
||||||
int mesh_id = -1;
|
// Calculate intersection with the clipping plane.
|
||||||
for (const ModelVolume* mv : mo->volumes) {
|
const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(true);
|
||||||
++mesh_id;
|
Vec3d point;
|
||||||
if (!mv->is_model_part())
|
Vec3d direction;
|
||||||
continue;
|
Vec3d hit;
|
||||||
Vec3f normal;
|
MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, point, direction);
|
||||||
Vec3f hit;
|
Vec3d normal = -cp->get_normal().cast<double>();
|
||||||
bool clipping_plane_was_hit = false;
|
double den = normal.dot(direction);
|
||||||
|
if (den != 0.) {
|
||||||
|
double t = (-cp->get_offset() - normal.dot(point))/den;
|
||||||
|
hit = (point + t * direction);
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
|
||||||
// const Transform3d volume_trafo = get_volume_transformation(mv);
|
if (! m_c->object_clipper()->is_projection_inside_cut(hit))
|
||||||
const Transform3d volume_trafo = mv->get_transformation().get_matrix();
|
return false;
|
||||||
|
|
||||||
m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo,
|
|
||||||
camera, hit, normal, m_c->object_clipper()->get_clipping_plane(true),
|
|
||||||
nullptr, &clipping_plane_was_hit);
|
|
||||||
if (clipping_plane_was_hit) {
|
|
||||||
// recalculate hit to object's local position
|
// recalculate hit to object's local position
|
||||||
Vec3d hit_d = hit.cast<double>();
|
Vec3d hit_d = hit;
|
||||||
hit_d -= mi->get_offset();
|
hit_d -= mi->get_offset();
|
||||||
hit_d[Z] -= sla_shift;
|
hit_d[Z] -= sla_shift;
|
||||||
|
|
||||||
// Return both the point and the facet normal.
|
// Return both the point and the facet normal.
|
||||||
pos_and_normal = std::make_pair(hit_d, normal.cast<double>());
|
pos = hit_d;
|
||||||
pos_world = hit.cast<double>();
|
pos_world = hit;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::clear_selection()
|
void GLGizmoCut3D::clear_selection()
|
||||||
@ -2139,17 +2136,13 @@ bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_p
|
|||||||
if (!m_connectors_editing)
|
if (!m_connectors_editing)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
Vec3d pos;
|
||||||
Vec3d pos_world;
|
Vec3d pos_world;
|
||||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal, pos_world)) {
|
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos, pos_world)) {
|
||||||
// check if pos is out of enabled clipping plane
|
|
||||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(pos_world))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction);
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction);
|
||||||
unselect_all_connectors();
|
unselect_all_connectors();
|
||||||
|
|
||||||
connectors.emplace_back(pos_and_normal.first, m_rotation_m,
|
connectors.emplace_back(pos, m_rotation_m,
|
||||||
m_connector_size * 0.5f, m_connector_depth_ratio,
|
m_connector_size * 0.5f, m_connector_depth_ratio,
|
||||||
m_connector_size_tolerance, m_connector_depth_ratio_tolerance,
|
m_connector_size_tolerance, m_connector_depth_ratio_tolerance,
|
||||||
CutConnectorAttributes( CutConnectorType(m_connector_type),
|
CutConnectorAttributes( CutConnectorType(m_connector_type),
|
||||||
@ -2247,9 +2240,9 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
|
|||||||
if (!m_connectors_editing) {
|
if (!m_connectors_editing) {
|
||||||
if (0 && action == SLAGizmoEventType::LeftDown) {
|
if (0 && action == SLAGizmoEventType::LeftDown) {
|
||||||
// disable / enable current contour
|
// disable / enable current contour
|
||||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
Vec3d pos;
|
||||||
Vec3d pos_world;
|
Vec3d pos_world;
|
||||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal, pos_world)) {
|
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos, pos_world)) {
|
||||||
// Following would inform the clipper about the mouse click, so it can
|
// Following would inform the clipper about the mouse click, so it can
|
||||||
// toggle the respective contour as disabled.
|
// toggle the respective contour as disabled.
|
||||||
m_c->object_clipper()->pass_mouse_click(pos_world);
|
m_c->object_clipper()->pass_mouse_click(pos_world);
|
||||||
|
@ -155,7 +155,7 @@ public:
|
|||||||
GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||||
|
|
||||||
std::string get_tooltip() const override;
|
std::string get_tooltip() const override;
|
||||||
bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world);
|
bool unproject_on_cut_plane(const Vec2d& mouse_pos, Vec3d& pos, Vec3d& pos_world);
|
||||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||||
|
|
||||||
bool is_in_editing_mode() const override { return m_connectors_editing; }
|
bool is_in_editing_mode() const override { return m_connectors_editing; }
|
||||||
|
@ -22,7 +22,7 @@ namespace GUI {
|
|||||||
|
|
||||||
void MeshClipper::set_behaviour(bool fill_cut, double contour_width)
|
void MeshClipper::set_behaviour(bool fill_cut, double contour_width)
|
||||||
{
|
{
|
||||||
if (fill_cut != m_fill_cut || is_approx(contour_width, m_contour_width))
|
if (fill_cut != m_fill_cut || ! is_approx(contour_width, m_contour_width))
|
||||||
m_result.reset();
|
m_result.reset();
|
||||||
m_fill_cut = fill_cut;
|
m_fill_cut = fill_cut;
|
||||||
m_contour_width = contour_width;
|
m_contour_width = contour_width;
|
||||||
@ -365,11 +365,8 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3
|
|||||||
|
|
||||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||||
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
|
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
|
||||||
size_t* facet_idx, bool* was_clipping_plane_hit) const
|
size_t* facet_idx) const
|
||||||
{
|
{
|
||||||
if (was_clipping_plane_hit)
|
|
||||||
*was_clipping_plane_hit = false;
|
|
||||||
|
|
||||||
Vec3d point;
|
Vec3d point;
|
||||||
Vec3d direction;
|
Vec3d direction;
|
||||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
||||||
@ -390,26 +387,9 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i==hits.size()) {
|
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
|
||||||
// All hits are clipped.
|
// All hits are either clipped, or there is an odd number of unclipped
|
||||||
return false;
|
// hits - meaning the nearest must be from inside the mesh.
|
||||||
}
|
|
||||||
if (clipping_plane && (hits.size()-i) % 2 != 0) {
|
|
||||||
// There is an odd number of unclipped hits - meaning the nearest must be from inside the mesh.
|
|
||||||
// In that case, calculate intersection with the clipping place.
|
|
||||||
if (was_clipping_plane_hit) {
|
|
||||||
direction = direction + point;
|
|
||||||
point = trafo * point; // transform to world coords
|
|
||||||
direction = trafo * direction - point;
|
|
||||||
|
|
||||||
Vec3d normal = -clipping_plane->get_normal().cast<double>();
|
|
||||||
double den = normal.dot(direction);
|
|
||||||
if (den != 0.) {
|
|
||||||
double t = (-clipping_plane->get_offset() - normal.dot(point))/den;
|
|
||||||
position = (point + t * direction).cast<float>();
|
|
||||||
*was_clipping_plane_hit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,24 +403,7 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
|
||||||
Vec3d& position, Vec3d& normal) const
|
|
||||||
{
|
|
||||||
Vec3d point;
|
|
||||||
Vec3d direction;
|
|
||||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
|
||||||
|
|
||||||
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
|
||||||
|
|
||||||
if (hits.empty())
|
|
||||||
return false; // no intersection found
|
|
||||||
|
|
||||||
// Now stuff the points in the provided vector and calculate normals if asked about them:
|
|
||||||
position = hits[0].position();
|
|
||||||
normal = hits[0].normal();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
||||||
{
|
{
|
||||||
|
@ -153,16 +153,12 @@ public:
|
|||||||
const Vec2d& mouse_pos,
|
const Vec2d& mouse_pos,
|
||||||
const Transform3d& trafo, // how to get the mesh into world coords
|
const Transform3d& trafo, // how to get the mesh into world coords
|
||||||
const Camera& camera, // current camera position
|
const Camera& camera, // current camera position
|
||||||
Vec3f& position, // where to save the positibon of the hit (mesh coords if mesh, world coords if clipping plane)
|
Vec3f& position, // where to save the positibon of the hit (mesh coords)
|
||||||
Vec3f& normal, // normal of the triangle that was hit
|
Vec3f& normal, // normal of the triangle that was hit
|
||||||
const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active)
|
const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active)
|
||||||
size_t* facet_idx = nullptr, // index of the facet hit
|
size_t* facet_idx = nullptr // index of the facet hit
|
||||||
bool* was_clipping_plane_hit = nullptr // is the hit on the clipping place cross section?
|
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
// Given a mouse position, this returns true in case it is on the mesh.
|
|
||||||
bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& position, Vec3d& normal) const;
|
|
||||||
|
|
||||||
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
||||||
|
|
||||||
// Given a vector of points in woorld coordinates, this returns vector
|
// Given a vector of points in woorld coordinates, this returns vector
|
||||||
|
@ -118,6 +118,24 @@ OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Line::clear()
|
||||||
|
{
|
||||||
|
if (near_label_widget_win)
|
||||||
|
near_label_widget_win = nullptr;
|
||||||
|
|
||||||
|
if (widget_sizer) {
|
||||||
|
widget_sizer->Clear(true);
|
||||||
|
delete widget_sizer;
|
||||||
|
widget_sizer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra_widget_sizer) {
|
||||||
|
extra_widget_sizer->Clear(true);
|
||||||
|
delete extra_widget_sizer;
|
||||||
|
extra_widget_sizer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxWindow* OptionsGroup::ctrl_parent() const
|
wxWindow* OptionsGroup::ctrl_parent() const
|
||||||
{
|
{
|
||||||
return this->custom_ctrl && m_use_custom_ctrl_as_parent ? static_cast<wxWindow*>(this->custom_ctrl) : (this->stb ? static_cast<wxWindow*>(this->stb) : this->parent());
|
return this->custom_ctrl && m_use_custom_ctrl_as_parent ? static_cast<wxWindow*>(this->custom_ctrl) : (this->stb ? static_cast<wxWindow*>(this->stb) : this->parent());
|
||||||
@ -231,7 +249,7 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto option_set = line.get_options();
|
const std::vector<Option>& option_set = line.get_options();
|
||||||
bool is_legend_line = option_set.front().opt.gui_type == ConfigOptionDef::GUIType::legend;
|
bool is_legend_line = option_set.front().opt.gui_type == ConfigOptionDef::GUIType::legend;
|
||||||
|
|
||||||
if (!custom_ctrl && m_use_custom_ctrl) {
|
if (!custom_ctrl && m_use_custom_ctrl) {
|
||||||
@ -263,15 +281,13 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto grid_sizer = m_grid_sizer;
|
|
||||||
|
|
||||||
if (custom_ctrl)
|
if (custom_ctrl)
|
||||||
m_use_custom_ctrl_as_parent = true;
|
m_use_custom_ctrl_as_parent = true;
|
||||||
|
|
||||||
// if we have an extra column, build it
|
// if we have an extra column, build it
|
||||||
if (extra_column) {
|
if (extra_column) {
|
||||||
m_extra_column_item_ptrs.push_back(extra_column(this->ctrl_parent(), line));
|
m_extra_column_item_ptrs.push_back(extra_column(this->ctrl_parent(), line));
|
||||||
grid_sizer->Add(m_extra_column_item_ptrs.back(), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 3);
|
m_grid_sizer->Add(m_extra_column_item_ptrs.back(), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a label if we have it
|
// Build a label if we have it
|
||||||
@ -298,12 +314,12 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
label->Wrap(label_width * wxGetApp().em_unit()); // avoid a Linux/GTK bug
|
label->Wrap(label_width * wxGetApp().em_unit()); // avoid a Linux/GTK bug
|
||||||
}
|
}
|
||||||
if (!line.near_label_widget)
|
if (!line.near_label_widget)
|
||||||
grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5);
|
m_grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5);
|
||||||
else if (!line.label.IsEmpty()) {
|
else if (!line.label.IsEmpty()) {
|
||||||
// If we're here, we have some widget near the label
|
// If we're here, we have some widget near the label
|
||||||
// so we need a horizontal sizer to arrange these things
|
// so we need a horizontal sizer to arrange these things
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
m_grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
||||||
sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5);
|
sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5);
|
||||||
}
|
}
|
||||||
if (label != nullptr && line.label_tooltip != "")
|
if (label != nullptr && line.label_tooltip != "")
|
||||||
@ -317,15 +333,19 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
if (custom_ctrl)
|
if (custom_ctrl)
|
||||||
line.widget_sizer = wgt;
|
line.widget_sizer = wgt;
|
||||||
else
|
else
|
||||||
grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5);
|
m_grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're here, we have more than one option or a single option with sidetext
|
// If we're here, we have more than one option or a single option with sidetext
|
||||||
// so we need a horizontal sizer to arrange these things
|
// so we need a horizontal sizer to arrange these things
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer* h_sizer{ nullptr };
|
||||||
if (!custom_ctrl)
|
if (!custom_ctrl) {
|
||||||
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
// but this sizer is currently used just for NON-custom_ctrl cases
|
||||||
|
h_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
m_grid_sizer->Add(h_sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a single option with no sidetext just add it directly to the grid sizer
|
// If we have a single option with no sidetext just add it directly to the grid sizer
|
||||||
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
||||||
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
|
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
|
||||||
@ -334,23 +354,23 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
|
|
||||||
if (!custom_ctrl) {
|
if (!custom_ctrl) {
|
||||||
if (is_window_field(field))
|
if (is_window_field(field))
|
||||||
sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0,
|
h_sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0,
|
||||||
wxBOTTOM | wxTOP | (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), (wxOSX || !staticbox) ? 0 : 2);
|
wxBOTTOM | wxTOP | (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), (wxOSX || !staticbox) ? 0 : 2);
|
||||||
if (is_sizer_field(field))
|
if (is_sizer_field(field))
|
||||||
sizer->Add(field->getSizer(), 1, (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), 0);
|
h_sizer->Add(field->getSizer(), 1, (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), 0);
|
||||||
} else
|
}
|
||||||
delete sizer;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sizer_is_used = false;
|
for (const Option& opt : option_set) {
|
||||||
bool is_multioption_line = option_set.size() > 1;
|
// add field
|
||||||
for (auto opt : option_set) {
|
auto& field = build_field(opt);
|
||||||
|
|
||||||
|
if (!custom_ctrl) {
|
||||||
ConfigOptionDef option = opt.opt;
|
ConfigOptionDef option = opt.opt;
|
||||||
wxSizer* sizer_tmp = sizer;
|
|
||||||
// add label if any
|
// add label if any
|
||||||
if ((is_multioption_line || line.label.IsEmpty()) && !option.label.empty() && !custom_ctrl) {
|
if ((option_set.size() > 1 || line.label.IsEmpty()) && !option.label.empty()) {
|
||||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
// To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||||
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
||||||
_CTX(option.label, "Layers") :
|
_CTX(option.label, "Layers") :
|
||||||
_(option.label);
|
_(option.label);
|
||||||
@ -358,18 +378,13 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT);
|
wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT);
|
||||||
label->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
label->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||||
label->SetFont(wxGetApp().normal_font());
|
label->SetFont(wxGetApp().normal_font());
|
||||||
sizer_tmp->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0);
|
h_sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||||
sizer_is_used = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add field
|
|
||||||
const Option& opt_ref = opt;
|
|
||||||
auto& field = build_field(opt_ref);
|
|
||||||
if (!custom_ctrl) {
|
|
||||||
if (option_set.size() == 1 && option_set.front().opt.full_width)
|
if (option_set.size() == 1 && option_set.front().opt.full_width)
|
||||||
{
|
{
|
||||||
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
|
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer_tmp->Add(v_sizer, 1, wxEXPAND);
|
h_sizer->Add(v_sizer, 1, wxEXPAND);
|
||||||
is_sizer_field(field) ?
|
is_sizer_field(field) ?
|
||||||
v_sizer->Add(field->getSizer(), 0, wxEXPAND) :
|
v_sizer->Add(field->getSizer(), 0, wxEXPAND) :
|
||||||
v_sizer->Add(field->getWindow(), 0, wxEXPAND);
|
v_sizer->Add(field->getWindow(), 0, wxEXPAND);
|
||||||
@ -377,8 +392,8 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_sizer_field(field) ?
|
is_sizer_field(field) ?
|
||||||
sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) :
|
h_sizer->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) :
|
||||||
sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0);
|
h_sizer->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||||
|
|
||||||
// add sidetext if any
|
// add sidetext if any
|
||||||
if (!option.sidetext.empty() || sidetext_width > 0) {
|
if (!option.sidetext.empty() || sidetext_width > 0) {
|
||||||
@ -386,16 +401,16 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
wxSize(sidetext_width != -1 ? sidetext_width * wxGetApp().em_unit() : -1, -1), wxALIGN_LEFT);
|
wxSize(sidetext_width != -1 ? sidetext_width * wxGetApp().em_unit() : -1, -1), wxALIGN_LEFT);
|
||||||
sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||||
sidetext->SetFont(wxGetApp().normal_font());
|
sidetext->SetFont(wxGetApp().normal_font());
|
||||||
sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
|
h_sizer->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add side widget if any
|
// add side widget if any
|
||||||
if (opt.side_widget != nullptr) {
|
if (opt.side_widget != nullptr) {
|
||||||
sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification
|
h_sizer->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
|
if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
|
||||||
sizer_tmp->AddSpacer(6);
|
h_sizer->AddSpacer(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,18 +421,15 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
{
|
{
|
||||||
// extra widget for non-staticbox option group (like for the frequently used parameters on the sidebar) should be wxALIGN_RIGHT
|
// extra widget for non-staticbox option group (like for the frequently used parameters on the sidebar) should be wxALIGN_RIGHT
|
||||||
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
|
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer->Add(v_sizer, option_set.size() == 1 ? 0 : 1, wxEXPAND);
|
h_sizer->Add(v_sizer, option_set.size() == 1 ? 0 : 1, wxEXPAND);
|
||||||
v_sizer->Add(extra_widget(this->ctrl_parent()), 0, wxALIGN_RIGHT);
|
v_sizer->Add(extra_widget(this->ctrl_parent()), 0, wxALIGN_RIGHT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.extra_widget_sizer = extra_widget(this->ctrl_parent());
|
line.extra_widget_sizer = extra_widget(this->ctrl_parent());
|
||||||
if (!custom_ctrl)
|
if (!custom_ctrl)
|
||||||
sizer->Add(line.extra_widget_sizer, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification
|
h_sizer->Add(line.extra_widget_sizer, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification
|
||||||
}
|
}
|
||||||
|
|
||||||
if (custom_ctrl && !sizer_is_used)
|
|
||||||
delete sizer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create all controls for the option group from the m_lines
|
// create all controls for the option group from the m_lines
|
||||||
@ -484,20 +496,8 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
|
|||||||
m_grid_sizer = nullptr;
|
m_grid_sizer = nullptr;
|
||||||
sizer = nullptr;
|
sizer = nullptr;
|
||||||
|
|
||||||
for (Line& line : m_lines) {
|
for (Line& line : m_lines)
|
||||||
if (line.near_label_widget_win)
|
line.clear();
|
||||||
line.near_label_widget_win = nullptr;
|
|
||||||
|
|
||||||
if (line.widget_sizer) {
|
|
||||||
line.widget_sizer->Clear(true);
|
|
||||||
line.widget_sizer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.extra_widget_sizer) {
|
|
||||||
line.extra_widget_sizer->Clear(true);
|
|
||||||
line.extra_widget_sizer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (custom_ctrl) {
|
if (custom_ctrl) {
|
||||||
for (auto const &item : m_fields) {
|
for (auto const &item : m_fields) {
|
||||||
|
@ -86,6 +86,7 @@ public:
|
|||||||
|
|
||||||
bool is_separator() const { return m_is_separator; }
|
bool is_separator() const { return m_is_separator; }
|
||||||
bool has_only_option(const std::string& opt_key) const { return m_options.size() == 1 && m_options[0].opt_id == opt_key; }
|
bool has_only_option(const std::string& opt_key) const { return m_options.size() == 1 && m_options[0].opt_id == opt_key; }
|
||||||
|
void clear();
|
||||||
|
|
||||||
const std::vector<widget_t>& get_extra_widgets() const {return m_extra_widgets;}
|
const std::vector<widget_t>& get_extra_widgets() const {return m_extra_widgets;}
|
||||||
const std::vector<Option>& get_options() const { return m_options; }
|
const std::vector<Option>& get_options() const { return m_options; }
|
||||||
|
@ -1784,6 +1784,8 @@ void TabPrint::clear_pages()
|
|||||||
m_recommended_thin_wall_thickness_description_line = nullptr;
|
m_recommended_thin_wall_thickness_description_line = nullptr;
|
||||||
m_top_bottom_shell_thickness_explanation = nullptr;
|
m_top_bottom_shell_thickness_explanation = nullptr;
|
||||||
m_post_process_explanation = nullptr;
|
m_post_process_explanation = nullptr;
|
||||||
|
|
||||||
|
m_del_all_substitutions_btn = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode)
|
bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode)
|
||||||
|
Loading…
Reference in New Issue
Block a user