Merge branch 'main' into fix/network-logs
This commit is contained in:
@@ -554,7 +554,12 @@ const ModelObjectPtrs& Cut::perform_by_contour(const ModelObject* src_object, st
|
||||
}
|
||||
|
||||
|
||||
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts/* = false*/)
|
||||
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove,
|
||||
const Transform3d& rotation_m,
|
||||
const int groove_count,
|
||||
const float groove_gap,
|
||||
const float m_radius,
|
||||
bool keep_as_parts /* = false*/)
|
||||
{
|
||||
ModelObject* cut_mo = m_model.objects.front();
|
||||
|
||||
@@ -615,7 +620,7 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
|
||||
reset_instance_transformation(object, m_instance);
|
||||
};
|
||||
|
||||
// cut by upper plane
|
||||
// cut by upper plane (+Z)
|
||||
{
|
||||
const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
|
||||
|
||||
@@ -623,7 +628,7 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
|
||||
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// cut by lower plane
|
||||
// cut by lower plane (-Z)
|
||||
{
|
||||
const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
|
||||
|
||||
@@ -631,45 +636,92 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
|
||||
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// cut middle part with 2 angles and add parts to related upper/lower objects
|
||||
// Compute same slot outer width used in preview plane
|
||||
const float groove_width = calculate_groove_width(groove, m_radius);
|
||||
|
||||
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
|
||||
ModelObject* groove_object{nullptr};
|
||||
|
||||
// cut by angle1 plane
|
||||
{
|
||||
const Transform3d cut_matrix_angle1 = translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
|
||||
// multiple cuts
|
||||
for (int i = 0; i < groove_count; i++) {
|
||||
bool is_first_groove = i == 0;
|
||||
bool is_last_groove = i == groove_count - 1;
|
||||
|
||||
cut(tmp_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
// Calculate the x-axis offset for this dovetail
|
||||
float groove_offset_factor_start = -.5 * ((groove_count - 1));
|
||||
float groove_offset_factor = groove_offset_factor_start + i;
|
||||
|
||||
float offset_x = groove_offset_factor * (groove_gap + groove_width);
|
||||
|
||||
|
||||
tmp_object->clone_for_cut(&groove_object);
|
||||
for (ModelVolume* volume : tmp_object->volumes) {
|
||||
ModelVolume* new_vol = groove_object->add_volume(*volume);
|
||||
new_vol->reset_from_upper();
|
||||
}
|
||||
|
||||
// isolate area of current groove
|
||||
if (!is_first_groove) {
|
||||
float left_cut_position = (-groove_gap / 2.f) - (groove_width / 2.f) + offset_x;
|
||||
|
||||
const Transform3d cut_matrix_left = translation_transform(rotation_m * (left_cut_position * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
|
||||
|
||||
cut(groove_object, cut_matrix_left, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
if (!is_last_groove) {
|
||||
float right_cut_position = (groove_gap / 2.f) + (groove_width / 2.f) + offset_x;
|
||||
|
||||
const Transform3d cut_matrix_right = translation_transform(rotation_m * (right_cut_position * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
|
||||
cut(groove_object, cut_matrix_right, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
const Transform3d groove_translation = translation_transform(rotation_m * (offset_x * Vec3d::UnitX()));
|
||||
// cut middle part with 2 angles and add parts to related upper/lower objects
|
||||
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
|
||||
|
||||
// cut by angle1 plane
|
||||
{
|
||||
const Transform3d cut_matrix_angle1 = groove_translation * translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
|
||||
|
||||
cut(groove_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// cut by angle2 plane
|
||||
{
|
||||
const Transform3d cut_matrix_angle2 = groove_translation * translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
|
||||
|
||||
cut(groove_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// apply tolerance to the middle part
|
||||
{
|
||||
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
|
||||
|
||||
const Transform3d cut_matrix_lower_tolerance = groove_translation * translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) *
|
||||
m_cut_matrix;
|
||||
cut(groove_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
|
||||
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
|
||||
|
||||
const Transform3d cut_matrix_angle1_tolerance = groove_translation * translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
|
||||
cut(groove_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
|
||||
const Transform3d cut_matrix_angle2_tolerance = groove_translation * translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) *
|
||||
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
|
||||
cut(groove_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
|
||||
groove_object->clear_volumes();
|
||||
}
|
||||
|
||||
// cut by angle2 plane
|
||||
{
|
||||
const Transform3d cut_matrix_angle2 = translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
|
||||
|
||||
cut(tmp_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// apply tolerance to the middle part
|
||||
{
|
||||
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
|
||||
|
||||
const Transform3d cut_matrix_lower_tolerance = translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) * m_cut_matrix;
|
||||
cut(tmp_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
|
||||
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
|
||||
|
||||
const Transform3d cut_matrix_angle1_tolerance = translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
|
||||
cut(tmp_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
|
||||
const Transform3d cut_matrix_angle2_tolerance = translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
|
||||
cut(tmp_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
|
||||
}
|
||||
|
||||
// this part can be added to the upper object now
|
||||
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
|
||||
|
||||
ModelObjectPtrs cut_object_ptrs;
|
||||
|
||||
if (keep_as_parts) {
|
||||
@@ -713,5 +765,19 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
|
||||
return m_model.objects;
|
||||
}
|
||||
|
||||
float Cut::calculate_groove_width (const Cut::Groove& groove, const float m_radius)
|
||||
{
|
||||
// Compute same slot outer width used in preview plane
|
||||
const double flap_width = is_approx(groove.flaps_angle, 0.f) ? groove.depth : groove.depth / sin(groove.flaps_angle);
|
||||
const double total_flap_width = 2.0 * flap_width * cos(groove.flaps_angle);
|
||||
const double slot_neck_half_width = 0.5f * (groove.width);
|
||||
const double slot_mouth_half_width = 0.5 * (groove.width + total_flap_width);
|
||||
const double plane_half_height = 0.5f* (1.5f * (1.5f *m_radius));
|
||||
const double flap_taper_offset = plane_half_height * tan(groove.angle);
|
||||
const double slot_outer_x_max = std::max(slot_mouth_half_width + flap_taper_offset, slot_neck_half_width + flap_taper_offset);
|
||||
|
||||
return float(2.0 * slot_outer_x_max);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
@@ -57,9 +57,15 @@ public:
|
||||
|
||||
const ModelObjectPtrs& perform_with_plane();
|
||||
const ModelObjectPtrs& perform_by_contour(const ModelObject* src_object, std::vector<Part> parts, int dowels_count);
|
||||
const ModelObjectPtrs& perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts = false);
|
||||
const ModelObjectPtrs& perform_with_groove(const Groove& groove,
|
||||
const Transform3d& rotation_m,
|
||||
const int groove_count,
|
||||
const float groove_gap,
|
||||
const float m_radius,
|
||||
bool keep_as_parts = false);
|
||||
|
||||
}; // namespace Cut
|
||||
static float calculate_groove_width(const Cut::Groove& groove, const float m_radius);
|
||||
}; // namespace Cut
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ bool GLCanvas3D::LayersEditing::is_allowed() const
|
||||
|
||||
float GLCanvas3D::LayersEditing::s_overlay_window_width;
|
||||
|
||||
void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanvas3D& canvas) {
|
||||
void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(GLCanvas3D& canvas) {
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
@@ -336,8 +336,23 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv
|
||||
GLGizmoUtils::render_tooltip_button(&imgui, canvas, shortcuts, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (imgui.button(_L("Reset")))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
|
||||
imgui.disabled_begin(check_object_layers_fixed(*m_slicing_parameters, m_layer_height_profile));
|
||||
if (imgui.button(_L("Reset"))) {
|
||||
wxPostEvent((wxEvtHandler*) canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
|
||||
}
|
||||
imgui.disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (imgui.button(_L("Done"))) {
|
||||
m_enabled = false;
|
||||
|
||||
GLToolbarItem* item = canvas.m_main_toolbar.get_item("layersediting");
|
||||
item->set_state(GLToolbarItem::Normal);
|
||||
|
||||
canvas.set_as_dirty();
|
||||
canvas.request_extra_frame();
|
||||
}
|
||||
|
||||
GLCanvas3D::LayersEditing::s_overlay_window_width = ImGui::GetWindowSize().x;
|
||||
imgui.end();
|
||||
@@ -345,7 +360,7 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv
|
||||
imgui.pop_toolbar_style();
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas)
|
||||
void GLCanvas3D::LayersEditing::render_overlay(GLCanvas3D& canvas)
|
||||
{
|
||||
render_variable_layer_height_dialog(canvas);
|
||||
render_active_object_annotations(canvas);
|
||||
|
||||
@@ -290,8 +290,8 @@ class GLCanvas3D
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enabled) { m_enabled = is_allowed() && enabled; }
|
||||
|
||||
void render_variable_layer_height_dialog(const GLCanvas3D& canvas);
|
||||
void render_overlay(const GLCanvas3D& canvas);
|
||||
void render_variable_layer_height_dialog(GLCanvas3D& canvas);
|
||||
void render_overlay(GLCanvas3D& canvas);
|
||||
void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes);
|
||||
|
||||
void adjust_layer_height_profile();
|
||||
|
||||
@@ -1644,17 +1644,6 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men
|
||||
[]() { return true; }, m_parent);
|
||||
}
|
||||
|
||||
if (init) {
|
||||
append_menu_item(
|
||||
menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) {
|
||||
plater()->sidebar().delete_filament(-2); }, "", nullptr,
|
||||
[]() {
|
||||
return plater()->sidebar().combos_filament().size() > 1
|
||||
// Orca: only show delete filament option for SEMM machines unless is BBL
|
||||
&& Sidebar::should_show_SEMM_buttons();
|
||||
}, m_parent);
|
||||
}
|
||||
|
||||
const int item_id = menu->FindItem(_L("Merge with"));
|
||||
if (item_id != wxNOT_FOUND)
|
||||
menu->Destroy(item_id);
|
||||
@@ -1675,6 +1664,20 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men
|
||||
}
|
||||
append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "",
|
||||
[filaments_cnt]() { return filaments_cnt > 1; }, m_parent);
|
||||
|
||||
// ORCA use delete item on end of menu to prevent accidental clicks. clicking to submenus(merge) already not allowed by OS
|
||||
const int delete_id = menu->FindItem(_L("Delete"));
|
||||
if (delete_id != wxNOT_FOUND)
|
||||
menu->Destroy(delete_id);
|
||||
|
||||
append_menu_item(
|
||||
menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) {
|
||||
plater()->sidebar().delete_filament(-2); }, "", nullptr,
|
||||
[]() {
|
||||
return plater()->sidebar().combos_filament().size() > 1
|
||||
// Orca: only show delete filament option for SEMM machines unless is BBL
|
||||
&& Sidebar::should_show_SEMM_buttons();
|
||||
}, m_parent);
|
||||
}
|
||||
|
||||
//BBS: add part plate related logic
|
||||
|
||||
@@ -104,20 +104,24 @@ void GLGizmoAssembly::on_render_input_window(float x, float y, float bottom_limi
|
||||
}
|
||||
show_selection_ui();
|
||||
show_face_face_assembly_common();
|
||||
|
||||
ImGui::Separator();
|
||||
show_face_face_assembly_senior();
|
||||
show_distance_xyz_ui();
|
||||
render_input_window_warning(m_same_model_object);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") });
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
render_input_window_warning(m_same_model_object);
|
||||
|
||||
if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) {
|
||||
// the dialog may have changed its size, ask for an extra frame to render it properly
|
||||
@@ -127,21 +131,40 @@ void GLGizmoAssembly::on_render_input_window(float x, float y, float bottom_limi
|
||||
m_imgui->set_requires_extra_frame();
|
||||
}
|
||||
m_last_active_item_imgui = m_current_active_imgui_id;
|
||||
|
||||
GizmoImguiEnd();
|
||||
// Orca
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
void GLGizmoAssembly::render_input_window_warning(bool same_model_object)
|
||||
{
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasView3D) {
|
||||
if (m_hit_different_volumes.size() == 2) {
|
||||
if (same_model_object == false) {
|
||||
m_imgui->warning_text(_L("Warning") + ": " +
|
||||
_L("It is recommended to assemble the objects first,\nbecause the objects is restriced to bed \nand only parts can be lifted."));
|
||||
}
|
||||
const bool same_mesh_warning = m_hit_different_volumes.size() == 1;
|
||||
const bool wrong_feature_warning = m_selected_wrong_feature_waring_tip;
|
||||
const bool not_assembled_warning = m_hit_different_volumes.size() == 2 && same_model_object == false &&
|
||||
wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasView3D;
|
||||
|
||||
if (same_mesh_warning || not_assembled_warning || wrong_feature_warning) {
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
if (same_mesh_warning) {
|
||||
m_imgui->warning_text(_L("Warning: please select two different meshes."));
|
||||
}
|
||||
if (wrong_feature_warning) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
|
||||
m_imgui->warning_text(_L("Warning: please select Plane's feature."));
|
||||
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
|
||||
m_imgui->warning_text(_L("Warning: please select Point's or Circle's feature."));
|
||||
}
|
||||
}
|
||||
if (not_assembled_warning) {
|
||||
m_imgui->warning_text(
|
||||
_L("Warning") + ": " +
|
||||
_L("It is recommended to assemble the objects first,\nbecause the objects is restriced to bed \nand only parts can be lifted.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoAssembly::render_assembly_mode_combo(double label_width, float item_width)
|
||||
|
||||
@@ -48,19 +48,22 @@ bool GLGizmoBrimEars::on_init()
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
|
||||
m_desc["head_diameter"] = _L("Head diameter");
|
||||
m_desc["max_angle"] = _L("Max angle");
|
||||
m_desc["detection_radius"] = _L("Detection radius");
|
||||
m_desc["remove_selected"] = _L("Remove selected points");
|
||||
m_desc["remove_all"] = _L("Remove all");
|
||||
m_desc["auto_generate"] = _L("Auto-generate points");
|
||||
m_desc["section_view"] = _L("Section view");
|
||||
m_desc["head_diameter"] = _L("Head diameter");
|
||||
m_desc["max_angle"] = _L("Max angle");
|
||||
m_desc["detection_radius"] = _L("Detection radius");
|
||||
m_desc["remove"] = _L("Remove");
|
||||
m_desc["remove_selected"] = _L("Selected");
|
||||
m_desc["remove_all"] = _L("All");
|
||||
m_desc["create"] = _L("Create");
|
||||
m_desc["auto_generate"] = _L("Auto-generate");
|
||||
m_desc["auto-generate-tooltip"] = _L("Generate brim ears using Max angle and Detection radius");
|
||||
m_desc["section_view"] = _L("Section view");
|
||||
|
||||
m_shortcuts = {
|
||||
{_L("Left mouse button"), _L("Add a brim ear")},
|
||||
{_L("Right mouse button"), _L("Delete a brim ear")},
|
||||
{ctrl + _L("Mouse wheel"), _L("Adjust head diameter")},
|
||||
{alt + _L("Mouse wheel"), _L("Adjust section view")},
|
||||
{_L("Left mouse button"), _L("Add or Select")},
|
||||
{_L("Right mouse button"), _L("Remove")},
|
||||
{ctrl + _L("Mouse wheel"), m_desc["head_diameter"]},
|
||||
{alt + _L("Mouse wheel"), m_desc["section_view"]},
|
||||
};
|
||||
|
||||
return true;
|
||||
@@ -545,6 +548,15 @@ void GLGizmoBrimEars::delete_selected_points()
|
||||
update_model_object();
|
||||
}
|
||||
|
||||
bool GLGizmoBrimEars::has_selected_points() const
|
||||
{
|
||||
for (const auto& entry : m_editing_cache) {
|
||||
if (entry.selected)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoBrimEars::on_dragging(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
@@ -634,21 +646,21 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
y = std::min(y, bottom_limit - win_h);
|
||||
GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f);
|
||||
|
||||
const float currt_scale = m_parent.get_scale();
|
||||
ImGuiWrapper::push_toolbar_style(currt_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0 * currt_scale, 5.0 * currt_scale));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale);
|
||||
const float f_scale = m_parent.get_scale();
|
||||
ImGuiWrapper::push_toolbar_style(f_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
GizmoImguiBegin(get_name(),
|
||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
float space_size = m_imgui->get_style_scaling() * 8;
|
||||
std::vector<wxString> text_list = {m_desc["head_diameter"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"]};
|
||||
std::vector<wxString> text_list = {m_desc["head_diameter"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"],
|
||||
m_desc["create"], m_desc["remove"]};
|
||||
float widest_text = m_imgui->find_widest_text(text_list);
|
||||
float caption_size = widest_text + space_size + ImGui::GetStyle().WindowPadding.x;
|
||||
float input_text_size = m_imgui->scaled(10.0f);
|
||||
float button_size = ImGui::GetFrameHeight();
|
||||
|
||||
float list_width = input_text_size + ImGui::GetStyle().ScrollbarSize + 2 * currt_scale;
|
||||
float list_width = input_text_size + ImGui::GetStyle().ScrollbarSize + 2 * f_scale;
|
||||
|
||||
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
|
||||
const float slider_width = list_width - space_size;
|
||||
@@ -662,12 +674,12 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
if (last_y != y) last_y = y;
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
// Following is a nasty way to:
|
||||
// - save the initial value of the slider before one starts messing with it
|
||||
// - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene
|
||||
// - take correct undo/redo snapshot after the user is done with moving the slider
|
||||
ImGui::AlignTextToFramePadding();
|
||||
float initial_value = m_new_point_head_diameter;
|
||||
m_imgui->text(m_desc["head_diameter"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
@@ -684,8 +696,10 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##head_diameter_input", &m_new_point_head_diameter, 0.05f, 0.0f, 0.0f, "%.1f");
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["max_angle"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
ImGui::PushItemWidth(slider_width);
|
||||
@@ -693,8 +707,8 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##max_angle_input", &m_max_angle, 0.05f, 0.0f, 180.0f, "%.1f");
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["detection_radius"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
ImGui::PushItemWidth(slider_width);
|
||||
@@ -702,8 +716,37 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##detection_radius_input", &m_detection_radius, 0.05f, 0.0f, static_cast<float>(m_detection_radius_max), "%.1f");
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["create"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
if (m_imgui->button(m_desc["auto_generate"], m_desc["auto-generate-tooltip"])) {
|
||||
auto_generate();
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["remove"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
m_imgui->disabled_begin(has_selected_points() == false);
|
||||
if (m_imgui->button(m_desc["remove_selected"])) {
|
||||
delete_selected_points();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(m_editing_cache.empty());
|
||||
if (m_imgui->button(m_desc["remove_all"])) {
|
||||
if (m_editing_cache.size() > 0) {
|
||||
select_point(AllPoints);
|
||||
delete_selected_points();
|
||||
}
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
float clp_dist = float(m_c->object_clipper()->get_position());
|
||||
m_imgui->text(m_desc["section_view"]);
|
||||
ImGui::SameLine(caption_size);
|
||||
@@ -712,79 +755,72 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##section_view_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, false, true); }
|
||||
ImGui::Separator();
|
||||
|
||||
// ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
if (m_imgui->button(m_desc["auto_generate"])) { auto_generate(); }
|
||||
|
||||
if (m_imgui->button(m_desc["remove_selected"])) { delete_selected_points(); }
|
||||
float font_size = ImGui::GetFontSize();
|
||||
//ImGui::Dummy(ImVec2(font_size * 1, font_size * 1.3));
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(m_desc["remove_all"])) {
|
||||
if (m_editing_cache.size() > 0) {
|
||||
select_point(AllPoints);
|
||||
delete_selected_points();
|
||||
}
|
||||
if (slider_clp_dist || b_clp_dist_input) {
|
||||
m_c->object_clipper()->set_position_by_ratio(clp_dist, false, true);
|
||||
}
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
ImGui::Separator();
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
if (glb_cfg.opt_enum<BrimType>("brim_type") != btPainted) {
|
||||
ImGui::SameLine();
|
||||
auto link_text = [&]() {
|
||||
ImColor HyperColor = ImGuiWrapper::COL_ORCA;
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(ColorRGB::WARNING()));
|
||||
float parent_width = ImGui::GetContentRegionAvail().x;
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
bool brim_not_painted = (obj_cfg.option("brim_type")) ? (obj_cfg.opt_enum<BrimType>("brim_type") != btPainted) :
|
||||
(glb_cfg.opt_enum<BrimType>("brim_type") != btPainted);
|
||||
bool has_invalid_ears = !m_single_brim.empty();
|
||||
|
||||
if (brim_not_painted || has_invalid_ears) {
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_WARNING);
|
||||
|
||||
float parent_width = ImGui::GetContentRegionAvail().x;
|
||||
float font_size = ImGui::GetFontSize();
|
||||
|
||||
if (brim_not_painted) {
|
||||
m_imgui->text_wrapped(_L("Warning: The brim type is not set to \"painted\", the brim ears will not take effect!"), parent_width);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImColor HyperColor = ImGuiWrapper::COL_ORCA;
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
|
||||
ImGui::Dummy(ImVec2(font_size * 1.8, font_size * 1.3));
|
||||
|
||||
ImGui::Dummy(ImVec2(font_size * 1.8f, 0.0f)); // Horizontal indent
|
||||
ImGui::SameLine();
|
||||
m_imgui->bold_text(_u8L("Set the brim type of this object to \"painted\""));
|
||||
ImGui::PopStyleColor();
|
||||
// underline
|
||||
ImVec2 lineEnd = ImGui::GetItemRectMax();
|
||||
lineEnd.y -= 2.0f;
|
||||
ImVec2 lineStart = lineEnd;
|
||||
lineStart.x = ImGui::GetItemRectMin().x;
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, HyperColor);
|
||||
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
|
||||
|
||||
ImVec2 min = ImGui::GetItemRectMin();
|
||||
ImVec2 max = ImGui::GetItemRectMax();
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(min.x, max.y - 2.0f), ImVec2(max.x, max.y - 2.0f), HyperColor);
|
||||
|
||||
if (ImGui::IsMouseHoveringRect(min, max)) {
|
||||
m_link_text_hover = true;
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
DynamicPrintConfig new_conf = obj_cfg;
|
||||
new_conf.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btPainted));
|
||||
mo->config.assign_config(new_conf);
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
m_link_text_hover = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (obj_cfg.option("brim_type")) {
|
||||
if (obj_cfg.opt_enum<BrimType>("brim_type") != btPainted) {
|
||||
link_text();
|
||||
}
|
||||
}else {
|
||||
link_text();
|
||||
ImGui::PopStyleColor(1); // Pop HyperColor
|
||||
}
|
||||
|
||||
}
|
||||
if (has_invalid_ears) {
|
||||
wxString out = _L("Warning") + ": " + std::to_string(m_single_brim.size()) + " " + _L("invalid brim ears");
|
||||
m_imgui->text_wrapped(out, parent_width);
|
||||
}
|
||||
|
||||
if (!m_single_brim.empty()) {
|
||||
wxString out = _L("Warning") + ": " + std::to_string(m_single_brim.size()) + _L(" invalid brim ears");
|
||||
m_imgui->warning_text(out);
|
||||
ImGui::PopStyleColor(1); // Pop Warning Color
|
||||
} else {
|
||||
// Reset hover state if no warnings are active
|
||||
m_link_text_hover = false;
|
||||
}
|
||||
|
||||
GizmoImguiEnd();
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ public:
|
||||
bool on_mouse(const wxMouseEvent& mouse_event) override;
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
void delete_selected_points();
|
||||
bool has_selected_points() const;
|
||||
void update_model_object();
|
||||
//ClippingPlane get_sla_clipping_plane() const;
|
||||
|
||||
|
||||
@@ -227,6 +227,10 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
|
||||
{"Groove Angle" , _u8L("Groove Angle")},
|
||||
{"Cut position" , _u8L("Cut position")}, // ORCA
|
||||
{"Build Volume" , _u8L("Build Volume")}, // ORCA
|
||||
{"Multiple" , _u8L("Multiple")}, // ORCA
|
||||
{"Count" , _u8L("Count")}, // ORCA
|
||||
{"Gap" , _u8L("Gap")}, // ORCA
|
||||
{"Spacing" , _u8L("Spacing")} // ORCA
|
||||
};
|
||||
|
||||
// update_connector_shape();
|
||||
@@ -543,7 +547,7 @@ bool GLGizmoCut3D::render_double_input(const std::string& label, double& value_i
|
||||
return !is_approx(old_val, value);
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val/* = -0.1f*/, float max_tolerance/* = -0.1f*/)
|
||||
bool GLGizmoCut3D::render_slider_two_input(const std::string& label, float& value_in, float& tolerance_in, float min_val/* = -0.1f*/, float max_tolerance/* = -0.1f*/)
|
||||
{
|
||||
// -------- [ ] -------- [ ]
|
||||
// slider_with + item_in_gap + first_input_width + item_out_gap + slider_with + item_in_gap + second_input_width
|
||||
@@ -613,6 +617,55 @@ bool GLGizmoCut3D::render_slider_double_input(const std::string& label, float& v
|
||||
return !is_approx(old_val, value) || !is_approx(old_tolerance, tolerance);
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::render_slider_input(const std::string& label, float& value_in, float min_val /* = -0.1f*/, float max_val /* = 100.f*/)
|
||||
{
|
||||
// -------- [ ]
|
||||
// slider_with + input_width + slider_with + item_in_gap
|
||||
double slider_with = 0.42 * m_editing_window_width; // m_control_width * 0.35;
|
||||
double item_in_gap = 0.01 * m_editing_window_width;
|
||||
double input_width = 0.29 * m_editing_window_width;
|
||||
|
||||
constexpr float UndefMinVal = -0.1f;
|
||||
const float f_mm_to_in = static_cast<float>(GizmoObjectManipulation::mm_to_in);
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(label);
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::PushItemWidth(slider_with);
|
||||
|
||||
double left_width = m_label_width + slider_with + item_in_gap;
|
||||
|
||||
bool m_imperial_units = false;
|
||||
|
||||
float value = value_in;
|
||||
float max_value = max_val;
|
||||
if (m_imperial_units) {
|
||||
value *= f_mm_to_in;
|
||||
max_value *= f_mm_to_in;
|
||||
}
|
||||
float old_val = value;
|
||||
|
||||
const BoundingBoxf3 bbox = m_bounding_box;
|
||||
//const float mean_size = float((bbox.size().x() + bbox.size().y() + bbox.size().z())) * (m_imperial_units ? f_mm_to_in : 1.f);
|
||||
const float min_v = min_val > 0.f ? /*std::min(max_val, mean_size)*/ min_val : 1.f;
|
||||
|
||||
float min_size = value_in < 0.f ? UndefMinVal : min_v;
|
||||
if (m_imperial_units) {
|
||||
min_size *= f_mm_to_in;
|
||||
}
|
||||
std::string format = value_in < 0.f ? " " : m_imperial_units ? "%.4f " + _u8L("in") : "%.2f " + _u8L("mm");
|
||||
|
||||
m_imgui->bbl_slider_float_style(("##" + label).c_str(), &value, min_size, max_value, format.c_str());
|
||||
|
||||
ImGui::SameLine(left_width);
|
||||
ImGui::PushItemWidth(input_width);
|
||||
ImGui::BBLDragFloat(("##input_" + label).c_str(), &value, 0.05f, min_size, max_value, format.c_str());
|
||||
|
||||
value_in = value * float(m_imperial_units ? GizmoObjectManipulation::in_to_mm : 1.0);
|
||||
|
||||
return !is_approx(old_val, value);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_move_center_input(int axis)
|
||||
{
|
||||
m_imgui->text(m_axis_names[axis]+":");
|
||||
@@ -691,223 +744,299 @@ static double get_grabber_mean_size(const BoundingBoxf3& bb)
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<Vec3i32> GLGizmoCut3D::offset_indices(const std::vector<Vec3i32>& base_indices, size_t vo)
|
||||
{
|
||||
std::vector<Vec3i32> offset;
|
||||
int vo_int = static_cast<int>(vo);
|
||||
for (const auto& tri : base_indices) {
|
||||
offset.push_back({tri[0] + vo_int, tri[1] + vo_int, tri[2] + vo_int});
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
|
||||
{
|
||||
// values for calculation
|
||||
// This function generates a dovetail slot in a wall, viewed from above (top-down).
|
||||
// The slot has a wide "mouth" (closest to the wall surface) and a narrow "neck" (deepest into the wall).
|
||||
// The flaps are the tapered sides connecting the mouth to the neck.
|
||||
|
||||
const float side_width = is_approx(m_groove.flaps_angle, 0.f) ? m_groove.depth : (m_groove.depth / sin(m_groove.flaps_angle));
|
||||
const float flaps_width = 2.f * side_width * cos(m_groove.flaps_angle);
|
||||
const float flap_taper_width = is_approx(m_groove.flaps_angle, 0.f) ? m_groove.depth : (m_groove.depth / sin(m_groove.flaps_angle));
|
||||
const float total_flap_taper_width = 2.f * flap_taper_width * cos(m_groove.flaps_angle);
|
||||
|
||||
const float groove_half_width_upper = 0.5f * (m_groove.width);
|
||||
const float groove_half_width_lower = 0.5f * (m_groove.width + flaps_width);
|
||||
const float slot_neck_half_width = 0.5f * (m_groove.width);
|
||||
const float slot_mouth_half_width = 0.5f * (m_groove.width + total_flap_taper_width);
|
||||
|
||||
const float cut_plane_radius = 1.5f * float(m_radius);
|
||||
const float cut_plane_length = 1.5f * cut_plane_radius;
|
||||
|
||||
const float groove_half_depth = 0.5f * m_groove.depth;
|
||||
const float plane_half_width = 0.5f * cut_plane_radius; // x
|
||||
const float plane_half_height = 0.5f * cut_plane_length; // y
|
||||
|
||||
const float x = 0.5f * cut_plane_radius;
|
||||
const float y = 0.5f * cut_plane_length;
|
||||
float z_upper = groove_half_depth;
|
||||
float z_lower = -groove_half_depth;
|
||||
const float slot_half_depth = 0.5f * m_groove.depth; // z
|
||||
float slot_front_z = slot_half_depth;
|
||||
float slot_back_z = -slot_half_depth;
|
||||
|
||||
const float proj = y * tan(m_groove.angle);
|
||||
const float flap_taper_offset = plane_half_height * tan(m_groove.angle);
|
||||
|
||||
float ext_upper_x = groove_half_width_upper + proj; // upper_x extension
|
||||
float ext_lower_x = groove_half_width_lower + proj; // lower_x extension
|
||||
float slot_mouth_outer_x = slot_neck_half_width + flap_taper_offset; // upper_x extension
|
||||
float slot_neck_outer_x = slot_mouth_half_width + flap_taper_offset; // lower_x extension
|
||||
float slot_outer_x_max = Max(slot_neck_outer_x, slot_mouth_outer_x); // max x extension
|
||||
|
||||
float nar_upper_x = groove_half_width_upper - proj; // upper_x narrowing
|
||||
float nar_lower_x = groove_half_width_lower - proj; // lower_x narrowing
|
||||
float slot_neck_inner_x = slot_neck_half_width - flap_taper_offset; // upper_x narrowing
|
||||
float slot_mouth_inner_x = slot_mouth_half_width - flap_taper_offset; // lower_x narrowing
|
||||
|
||||
const float cut_plane_thiknes = 0.02f;// 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes
|
||||
const float wall_thickness = 0.02f; // 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes
|
||||
|
||||
// Vertices of the groove used to detection if groove is valid
|
||||
// They are written as:
|
||||
// {left_ext_lower, left_nar_lower, left_ext_upper, left_nar_upper,
|
||||
// right_ext_lower, right_nar_lower, right_ext_upper, right_nar_upper }
|
||||
{
|
||||
m_groove_vertices.clear();
|
||||
m_groove_vertices.reserve(8);
|
||||
|
||||
m_groove_vertices.emplace_back(Vec3f(-ext_lower_x, -y, z_lower).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-nar_lower_x, y, z_lower).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-ext_upper_x, -y, z_upper).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-nar_upper_x, y, z_upper).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f( ext_lower_x, -y, z_lower).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f( nar_lower_x, y, z_lower).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f( ext_upper_x, -y, z_upper).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f( nar_upper_x, y, z_upper).cast<double>());
|
||||
}
|
||||
|
||||
// Different cases of groove plane:
|
||||
|
||||
// groove is open
|
||||
|
||||
if (groove_half_width_upper > proj && groove_half_width_lower > proj) {
|
||||
indexed_triangle_set mesh;
|
||||
|
||||
auto get_vertices = [x, y](float z_upper, float z_lower, float nar_upper_x, float nar_lower_x, float ext_upper_x, float ext_lower_x) {
|
||||
return std::vector<stl_vertex>({
|
||||
// upper left part vertices
|
||||
{-x, -y, z_upper}, {-x, y, z_upper}, {-nar_upper_x, y, z_upper}, {-ext_upper_x, -y, z_upper},
|
||||
// lower part vertices
|
||||
{-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower},
|
||||
// upper right part vertices
|
||||
{ext_upper_x, -y, z_upper}, {nar_upper_x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper}
|
||||
});
|
||||
};
|
||||
|
||||
mesh.vertices = get_vertices(z_upper, z_lower, nar_upper_x, nar_lower_x, ext_upper_x, ext_lower_x);
|
||||
mesh.vertices.reserve(2 * mesh.vertices.size());
|
||||
|
||||
z_upper -= cut_plane_thiknes;
|
||||
z_lower -= cut_plane_thiknes;
|
||||
|
||||
const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle);
|
||||
|
||||
nar_upper_x += under_x_shift;
|
||||
nar_lower_x += under_x_shift;
|
||||
ext_upper_x += under_x_shift;
|
||||
ext_lower_x += under_x_shift;
|
||||
|
||||
std::vector<stl_vertex> vertices = get_vertices(z_upper, z_lower, nar_upper_x, nar_lower_x, ext_upper_x, ext_lower_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
mesh.indices = {
|
||||
// above view
|
||||
{5,4,7}, {5,7,6}, // lower part
|
||||
{3,4,5}, {3,5,2}, // left side
|
||||
{9,6,8}, {8,6,7}, // right side
|
||||
{1,0,2}, {2,0,3}, // upper left part
|
||||
{9,8,10}, {10,8,11}, // upper right part
|
||||
// under view
|
||||
{20,21,22}, {20,22,23}, // upper right part
|
||||
{12,13,14}, {12,14,15}, // upper left part
|
||||
{18,21,20}, {18,20,19}, // right side
|
||||
{16,15,14}, {16,14,17}, // left side
|
||||
{16,17,18}, {16,18,19}, // lower part
|
||||
// left edge
|
||||
{1,13,0}, {0,13,12},
|
||||
// front edge
|
||||
{0,12,3}, {3,12,15}, {3,15,4}, {4,15,16}, {4,16,7}, {7,16,19}, {7,19,20}, {7,20,8}, {8,20,11}, {11,20,23},
|
||||
// right edge
|
||||
{11,23,10}, {10,23,22},
|
||||
// back edge
|
||||
{1,13,2}, {2,13,14}, {2,14,17}, {2,17,5}, {5,17,6}, {6,17,18}, {6,18,9}, {9,18,21}, {9,21,10}, {10,21,22}
|
||||
};
|
||||
return mesh;
|
||||
}
|
||||
|
||||
float cross_pt_upper_y = groove_half_width_upper / tan(m_groove.angle);
|
||||
|
||||
// groove is closed
|
||||
|
||||
if (groove_half_width_upper < proj && groove_half_width_lower < proj) {
|
||||
float cross_pt_lower_y = groove_half_width_lower / tan(m_groove.angle);
|
||||
|
||||
indexed_triangle_set mesh;
|
||||
|
||||
auto get_vertices = [x, y](float z_upper, float z_lower, float cross_pt_upper_y, float cross_pt_lower_y, float ext_upper_x, float ext_lower_x) {
|
||||
return std::vector<stl_vertex>({
|
||||
// upper part vertices
|
||||
{-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper},
|
||||
{ext_upper_x, -y, z_upper}, {0.f, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper},
|
||||
// lower part vertices
|
||||
{-ext_lower_x, -y, z_lower}, {0.f, cross_pt_lower_y, z_lower}, {ext_lower_x, -y, z_lower}
|
||||
});
|
||||
};
|
||||
|
||||
mesh.vertices = get_vertices(z_upper, z_lower, cross_pt_upper_y, cross_pt_lower_y, ext_upper_x, ext_lower_x);
|
||||
mesh.vertices.reserve(2 * mesh.vertices.size());
|
||||
|
||||
z_upper -= cut_plane_thiknes;
|
||||
z_lower -= cut_plane_thiknes;
|
||||
|
||||
const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle);
|
||||
|
||||
cross_pt_upper_y += cut_plane_thiknes;
|
||||
cross_pt_lower_y += cut_plane_thiknes;
|
||||
ext_upper_x += under_x_shift;
|
||||
ext_lower_x += under_x_shift;
|
||||
|
||||
std::vector<stl_vertex> vertices = get_vertices(z_upper, z_lower, cross_pt_upper_y, cross_pt_lower_y, ext_upper_x, ext_lower_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
mesh.indices = {
|
||||
// above view
|
||||
{8,7,9}, // lower part
|
||||
{5,8,6}, {6,8,7}, // left side
|
||||
{4,9,8}, {4,8,5}, // right side
|
||||
{1,0,6}, {1,6,5},{1,5,2}, {2,5,4}, {2,4,3}, // upper part
|
||||
// under view
|
||||
{10,11,16}, {16,11,15}, {15,11,12}, {15,12,14}, {14,12,13}, // upper part
|
||||
{18,15,14}, {14,18,19}, // right side
|
||||
{17,16,15}, {17,15,18}, // left side
|
||||
{17,18,19}, // lower part
|
||||
// left edge
|
||||
{1,11,0}, {0,11,10},
|
||||
// front edge
|
||||
{0,10,6}, {6,10,16}, {6,17,16}, {6,7,17}, {7,17,19}, {7,19,9}, {4,14,19}, {4,19,9}, {4,14,13}, {4,13,3},
|
||||
// right edge
|
||||
{3,13,12}, {3,12,2},
|
||||
// back edge
|
||||
{2,12,11}, {2,11,1}
|
||||
};
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// groove is closed from the roof
|
||||
int groove_count = this->m_groove_count;
|
||||
float groove_gap = this->m_groove_gap;
|
||||
|
||||
indexed_triangle_set mesh;
|
||||
mesh.vertices = {
|
||||
// upper part vertices
|
||||
{-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper},
|
||||
{ext_upper_x, -y, z_upper}, {0.f, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper},
|
||||
// lower part vertices
|
||||
{-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower}
|
||||
};
|
||||
|
||||
mesh.vertices.reserve(2 * mesh.vertices.size() + 1);
|
||||
// handle multiple dovetails/grooves
|
||||
for (int i = 0; i < groove_count; ++i) {
|
||||
bool is_first_groove = i == 0; // when a groove is not the last groove, then limit the extent of the right plane so that it doesnt overlap the next groove
|
||||
bool is_last_groove = i == groove_count - 1; // do the same in reverse if a groove is not the first groove
|
||||
size_t vertex_index_offset = mesh.vertices.size();
|
||||
|
||||
z_upper -= cut_plane_thiknes;
|
||||
z_lower -= cut_plane_thiknes;
|
||||
// Calculate the x-axis offset for this dovetail
|
||||
float groove_offset_factor_start = -.5 * ((groove_count - 1));
|
||||
float groove_offset_factor = groove_offset_factor_start + i;
|
||||
// Recalculate x with offset (only X-axis offset)
|
||||
float offset_x = groove_offset_factor * (groove_gap + (2 * slot_outer_x_max));
|
||||
|
||||
const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle);
|
||||
// Vertices of the groove used to detection if groove is valid (not used in mesh)
|
||||
{
|
||||
m_groove_vertices.clear();
|
||||
m_groove_vertices.reserve(8);
|
||||
|
||||
nar_lower_x += under_x_shift;
|
||||
ext_upper_x += under_x_shift;
|
||||
ext_lower_x += under_x_shift;
|
||||
m_groove_vertices.emplace_back(Vec3f(-slot_neck_outer_x, -plane_half_height, slot_front_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-slot_mouth_inner_x, plane_half_height, slot_front_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-slot_mouth_outer_x, -plane_half_height, slot_back_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(-slot_neck_outer_x, plane_half_height, slot_back_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(slot_neck_outer_x, -plane_half_height, slot_front_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(slot_mouth_inner_x, plane_half_height, slot_front_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(slot_mouth_outer_x, -plane_half_height, slot_back_z).cast<double>());
|
||||
m_groove_vertices.emplace_back(Vec3f(slot_neck_outer_x, plane_half_height, slot_back_z).cast<double>());
|
||||
}
|
||||
|
||||
std::vector<stl_vertex> vertices = {
|
||||
// upper part vertices
|
||||
{-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper},
|
||||
{ext_upper_x, -y, z_upper}, {under_x_shift, cross_pt_upper_y, z_upper}, {-under_x_shift, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper},
|
||||
// lower part vertices
|
||||
{-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower}
|
||||
};
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
// ___
|
||||
// Case: Groove is open (Top&bottom: __\ /__ )
|
||||
if (slot_neck_half_width > flap_taper_offset && slot_mouth_half_width > flap_taper_offset) {
|
||||
auto get_vertices = [plane_half_width, plane_half_height]
|
||||
(float slot_front_z, float slot_back_z, float slot_neck_inner_x, float slot_mouth_inner_x, float slot_mouth_outer_x, float slot_neck_outer_x,
|
||||
float slot_outer_x_max, bool is_first_groove, bool is_last_groove, float groove_gap, float offset_x)
|
||||
{
|
||||
|
||||
mesh.indices = {
|
||||
// above view
|
||||
{8,7,10}, {8,10,9}, // lower part
|
||||
{5,8,7}, {5,7,6}, // left side
|
||||
{4,10,9}, {4,9,5}, // right side
|
||||
{1,0,6}, {1,6,5},{1,5,2}, {2,5,4}, {2,4,3}, // upper part
|
||||
// under view
|
||||
{11,12,18}, {18,12,17}, {17,12,16}, {16,12,13}, {16,13,15}, {15,13,14}, // upper part
|
||||
{21,16,15}, {21,15,22}, // right side
|
||||
{19,18,17}, {19,17,20}, // left side
|
||||
{19,20,21}, {19,21,22}, // lower part
|
||||
// left edge
|
||||
{1,12,11}, {1,11,0},
|
||||
// front edge
|
||||
{0,11,18}, {0,18,6}, {7,19,18}, {7,18,6}, {7,19,22}, {7,22,10}, {10,22,15}, {10,15,4}, {4,15,14}, {4,14,3},
|
||||
// right edge
|
||||
{3,14,13}, {3,14,2},
|
||||
// back edge
|
||||
{2,13,12}, {2,12,1}, {5,16,21}, {5,21,9}, {9,21,20}, {9,20,8}, {5,17,20}, {5,20,8}
|
||||
};
|
||||
return std::vector<stl_vertex>({
|
||||
// front left part vertices
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, -plane_half_height, slot_front_z}, // *__/ \__
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, plane_half_height, slot_front_z}, // *__/ \__
|
||||
{-slot_neck_inner_x + offset_x, plane_half_height, slot_front_z}, // __*/ \__
|
||||
{-slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z}, // __/* \__
|
||||
// back part vertices
|
||||
{-slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}, // __*/ \__
|
||||
{-slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z}, // __/* \__
|
||||
{slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z}, // __/ *\__
|
||||
{slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}, // __/ \*__
|
||||
// front right part vertices
|
||||
{slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z}, // __/ \*__
|
||||
{slot_neck_inner_x + offset_x, plane_half_height, slot_front_z}, // __/ *\__
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, plane_half_height, slot_front_z}, // __/ \__*
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, -plane_half_height, slot_front_z}}); // __/ \__*
|
||||
};
|
||||
|
||||
std::vector<stl_vertex> vertices = get_vertices(slot_front_z, slot_back_z, slot_neck_inner_x, slot_mouth_inner_x, slot_mouth_outer_x, slot_neck_outer_x, slot_outer_x_max,
|
||||
is_first_groove, is_last_groove, groove_gap, offset_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
// Back face
|
||||
slot_front_z -= wall_thickness;
|
||||
slot_back_z -= wall_thickness;
|
||||
|
||||
const float slot_back_face_x_offset = wall_thickness / tan(0.5f * m_groove.flaps_angle);
|
||||
slot_neck_inner_x += slot_back_face_x_offset;
|
||||
slot_mouth_inner_x += slot_back_face_x_offset;
|
||||
slot_mouth_outer_x += slot_back_face_x_offset;
|
||||
slot_neck_outer_x += slot_back_face_x_offset;
|
||||
|
||||
vertices = get_vertices(slot_front_z, slot_back_z, slot_neck_inner_x, slot_mouth_inner_x, slot_mouth_outer_x, slot_neck_outer_x,
|
||||
slot_outer_x_max, is_first_groove,
|
||||
is_last_groove, groove_gap, offset_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
std::vector<Vec3i32> base_indices;
|
||||
|
||||
base_indices = {
|
||||
// above view
|
||||
{5,4,7}, {5,7,6}, // lower part
|
||||
{3,4,5}, {3,5,2}, // left side
|
||||
{9,6,8}, {8,6,7}, // right side
|
||||
{1,0,2}, {2,0,3}, // upper left part
|
||||
{9,8,10}, {10,8,11}, // upper right part
|
||||
// under view
|
||||
{20,21,22}, {20,22,23}, // upper right part
|
||||
{12,13,14}, {12,14,15}, // upper left part
|
||||
{18,21,20}, {18,20,19}, // right side
|
||||
{16,15,14}, {16,14,17}, // left side
|
||||
{16,17,18}, {16,18,19}, // lower part
|
||||
// left edge
|
||||
{1,13,0}, {0,13,12},
|
||||
// front edge
|
||||
{0,12,3}, {3,12,15}, {3,15,4}, {4,15,16}, {4,16,7}, {7,16,19}, {7,19,20}, {7,20,8}, {8,20,11}, {11,20,23},
|
||||
// right edge
|
||||
{11,23,10}, {10,23,22},
|
||||
// back edge
|
||||
{1,13,2}, {2,13,14}, {2,14,17}, {2,17,5}, {5,17,6}, {6,17,18}, {6,18,9}, {9,18,21}, {9,21,10}, {10,21,22}
|
||||
};
|
||||
|
||||
std::vector<Vec3i32> indices = offset_indices(base_indices, vertex_index_offset);
|
||||
mesh.indices.insert(mesh.indices.end(), indices.begin(), indices.end());
|
||||
}
|
||||
|
||||
// __
|
||||
// CASE: Groove is closed (Top&Bottom: ___/ \___)
|
||||
else if (slot_neck_half_width < flap_taper_offset && slot_mouth_half_width < flap_taper_offset) {
|
||||
float slot_neck_apex_y = slot_neck_half_width / tan(m_groove.angle);
|
||||
float slot_mouth_apex_y = slot_mouth_half_width / tan(m_groove.angle);
|
||||
|
||||
auto get_vertices = [plane_half_width, plane_half_height]
|
||||
(float slot_front_z, float slot_back_z, float slot_neck_apex_y, float slot_mouth_apex_y, float slot_mouth_outer_x, float slot_neck_outer_x,
|
||||
float slot_outer_x_max, bool is_first_groove, bool is_last_groove, float groove_gap, float offset_x)
|
||||
{
|
||||
return std::vector<stl_vertex>({
|
||||
// front part vertices
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, -plane_half_height, slot_front_z}, // *__/\__
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, plane_half_height, slot_front_z}, // *__/\__
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, plane_half_height, slot_front_z}, // __/\__*
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, -plane_half_height, slot_front_z}, // __/\__*
|
||||
{slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z}, // __*/\__
|
||||
{offset_x, slot_neck_apex_y, slot_front_z}, // __/*\__
|
||||
{-slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z}, // __/\*__
|
||||
// back part vertices
|
||||
{-slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}, // __*/\__
|
||||
{offset_x, slot_mouth_apex_y, slot_back_z}, // __/*\__
|
||||
{slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}}); // __/\*__
|
||||
};
|
||||
|
||||
std::vector<stl_vertex> vertices = get_vertices(slot_front_z, slot_back_z, slot_neck_apex_y, slot_mouth_apex_y,
|
||||
slot_mouth_outer_x, slot_neck_outer_x, slot_outer_x_max,
|
||||
is_first_groove, is_last_groove, groove_gap, offset_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
// Back face
|
||||
slot_front_z -= wall_thickness;
|
||||
slot_back_z -= wall_thickness;
|
||||
slot_neck_apex_y += wall_thickness;
|
||||
slot_mouth_apex_y += wall_thickness;
|
||||
|
||||
const float slot_back_face_x_offset = wall_thickness / tan(0.5f * m_groove.flaps_angle);
|
||||
slot_mouth_outer_x += slot_back_face_x_offset;
|
||||
slot_neck_outer_x += slot_back_face_x_offset;
|
||||
|
||||
vertices = get_vertices(slot_front_z, slot_back_z, slot_neck_apex_y, slot_mouth_apex_y, slot_mouth_outer_x, slot_neck_outer_x,
|
||||
slot_outer_x_max, is_first_groove,
|
||||
is_last_groove, groove_gap, offset_x);
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
std::vector<Vec3i32> base_indices = {
|
||||
// above view
|
||||
{8,7,9}, // lower part
|
||||
{5,8,6}, {6,8,7}, // left side
|
||||
{4,9,8}, {4,8,5}, // right side
|
||||
{1,0,6}, {1,6,5},{1,5,2},
|
||||
{2,5,4}, {2,4,3}, // upper part
|
||||
// under view
|
||||
{10,11,16}, {16,11,15},
|
||||
{15,11,12}, {15,12,14}, {14,12,13}, // upper part
|
||||
{18,15,14}, {14,18,19}, // right side
|
||||
{17,16,15}, {17,15,18}, // left side
|
||||
{17,18,19}, // lower part
|
||||
// left edge
|
||||
{1,11,0}, {0,11,10},
|
||||
// front edge
|
||||
{0,10,6}, {6,10,16}, {6,17,16}, {6,7,17}, {7,17,19}, {7,19,9}, {4,14,19}, {4,19,9}, {4,14,13}, {4,13,3},
|
||||
// right edge
|
||||
{3,13,12}, {3,12,2},
|
||||
// back edge
|
||||
{2,12,11}, {2,11,1}
|
||||
};
|
||||
std::vector<Vec3i32> indices = offset_indices(base_indices, vertex_index_offset);
|
||||
|
||||
mesh.indices.insert(mesh.indices.end(), indices.begin(), indices.end());
|
||||
}
|
||||
|
||||
// Case: Groove is closed from the roof (TOP&Bottom: __/\__ )
|
||||
else {
|
||||
float slot_neck_apex_y = slot_neck_half_width / tan(m_groove.angle);
|
||||
|
||||
std::vector<stl_vertex> vertices = {
|
||||
// front part vertices
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, -plane_half_height, slot_front_z},
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, plane_half_height, slot_front_z},
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, plane_half_height, slot_front_z},
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, -plane_half_height, slot_front_z},
|
||||
{slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z},
|
||||
{offset_x, slot_neck_apex_y, slot_front_z},
|
||||
{-slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z},
|
||||
// back part vertices
|
||||
{-slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z},
|
||||
{-slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z},
|
||||
{slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z},
|
||||
{slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}};
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
// Back face
|
||||
slot_front_z -= wall_thickness;
|
||||
slot_back_z -= wall_thickness;
|
||||
|
||||
const float slot_back_face_x_offset = wall_thickness / tan(0.5f * m_groove.flaps_angle);
|
||||
slot_mouth_inner_x += slot_back_face_x_offset;
|
||||
slot_mouth_outer_x += slot_back_face_x_offset;
|
||||
slot_neck_outer_x += slot_back_face_x_offset;
|
||||
|
||||
vertices = {
|
||||
// upper part vertices
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, -plane_half_height, slot_front_z},
|
||||
{is_first_groove ? -plane_half_width + offset_x : -(groove_gap / 2.f) - slot_outer_x_max + offset_x, plane_half_height, slot_front_z},
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, plane_half_height, slot_front_z},
|
||||
{is_last_groove ? plane_half_width + offset_x : (groove_gap / 2.f) + slot_outer_x_max + offset_x, -plane_half_height, slot_front_z},
|
||||
{slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z},
|
||||
{slot_back_face_x_offset + offset_x, slot_neck_apex_y, slot_front_z},
|
||||
{-slot_back_face_x_offset + offset_x, slot_neck_apex_y, slot_front_z},
|
||||
{-slot_mouth_outer_x + offset_x, -plane_half_height, slot_front_z},
|
||||
// lower part vertices
|
||||
{-slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z},
|
||||
{-slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z},
|
||||
{slot_mouth_inner_x + offset_x, plane_half_height, slot_back_z},
|
||||
{slot_neck_outer_x + offset_x, -plane_half_height, slot_back_z}};
|
||||
mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
// Indices for this dovetail
|
||||
std::vector<Vec3i32> base_indices = {
|
||||
// above view
|
||||
{8,7,10}, {8,10,9}, // lower part
|
||||
{5,8,7}, {5,7,6}, // left side
|
||||
{4,10,9}, {4,9,5}, // right side
|
||||
{1,0,6}, {1,6,5},{1,5,2}, {2,5,4}, {2,4,3}, // upper part
|
||||
// under view
|
||||
{11,12,18}, {18,12,17}, {17,12,16}, {16,12,13}, {16,13,15}, {15,13,14}, // upper part
|
||||
{21,16,15}, {21,15,22}, // right side
|
||||
{19,18,17}, {19,17,20}, // left side
|
||||
{19,20,21}, {19,21,22}, // lower part
|
||||
// left edge
|
||||
{1,12,11}, {1,11,0},
|
||||
// front edge
|
||||
{0,11,18}, {0,18,6}, {7,19,18}, {7,18,6}, {7,19,22}, {7,22,10}, {10,22,15}, {10,15,4}, {4,15,14}, {4,14,3},
|
||||
// right edge
|
||||
{3,14,13}, {3,14,2},
|
||||
// back edge
|
||||
{2,13,12}, {2,12,1}, {5,16,21}, {5,21,9}, {9,21,20}, {9,20,8}, {5,17,20}, {5,20,8}
|
||||
};
|
||||
std::vector<Vec3i32> indices = offset_indices(base_indices, vertex_index_offset);
|
||||
|
||||
mesh.indices.insert(mesh.indices.end(), indices.begin(), indices.end());
|
||||
}
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
@@ -2240,7 +2369,10 @@ void GLGizmoCut3D::apply_selected_connectors(std::function<void(size_t idx)> app
|
||||
void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, float x, float y, float bottom_limit)
|
||||
{
|
||||
// Connectors section
|
||||
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// WIP : Auto : Need to implement
|
||||
@@ -2290,7 +2422,7 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
||||
m_imgui->disabled_end();
|
||||
|
||||
const float depth_min_value = m_connector_type == CutConnectorType::Snap ? m_connector_size : -0.1f;
|
||||
if (render_slider_double_input(m_labels_map["Depth"], m_connector_depth_ratio, m_connector_depth_ratio_tolerance, depth_min_value))
|
||||
if (render_slider_two_input(m_labels_map["Depth"], m_connector_depth_ratio, m_connector_depth_ratio_tolerance, depth_min_value))
|
||||
apply_selected_connectors([this, &connectors](size_t idx) {
|
||||
if (m_connector_depth_ratio > 0)
|
||||
connectors[idx].height = m_connector_depth_ratio;
|
||||
@@ -2298,7 +2430,7 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
||||
connectors[idx].height_tolerance = m_connector_depth_ratio_tolerance;
|
||||
});
|
||||
|
||||
if (render_slider_double_input(m_labels_map["Size"], m_connector_size, m_connector_size_tolerance))
|
||||
if (render_slider_two_input(m_labels_map["Size"], m_connector_size, m_connector_size_tolerance))
|
||||
apply_selected_connectors([this, &connectors](size_t idx) {
|
||||
if (m_connector_size > 0)
|
||||
connectors[idx].radius = 0.5f * m_connector_size;
|
||||
@@ -2318,26 +2450,24 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Confirm connectors"), _L("Cancel")});
|
||||
GLGizmoUtils::push_orca_button_style();
|
||||
if (m_imgui->button(_L("Confirm connectors"))) {
|
||||
unselect_all_connectors();
|
||||
set_connectors_editing(false);
|
||||
}
|
||||
GLGizmoUtils::pop_orca_button_style();
|
||||
|
||||
ImGui::SameLine(m_label_width + m_editing_window_width - m_imgui->calc_text_size(_L("Cancel")).x - m_imgui->get_style_scaling() * 8);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(_L("Cancel"))) {
|
||||
reset_connectors();
|
||||
set_connectors_editing(false);
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_build_size()
|
||||
@@ -2430,7 +2560,7 @@ void GLGizmoCut3D::process_contours()
|
||||
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
||||
if (has_valid_groove()) {
|
||||
Cut cut(model_objects[object_idx], instance_idx, get_cut_matrix(selection));
|
||||
const ModelObjectPtrs& new_objects = cut.perform_with_groove(m_groove, m_rotation_m, true);
|
||||
const ModelObjectPtrs& new_objects = cut.perform_with_groove(m_groove, m_rotation_m, m_groove_count, m_groove_gap, m_radius, true);
|
||||
if (!new_objects.empty())
|
||||
m_part_selection = PartSelection(new_objects.front(), instance_idx);
|
||||
}
|
||||
@@ -2485,13 +2615,13 @@ void GLGizmoCut3D::render_color_marker(float size, const ImU32& color)
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in_val, const float& init_val, float& in_tolerance)
|
||||
void GLGizmoCut3D::render_groove_two_float_input(const std::string& label, float& in_val, const float& init_val, float& in_tolerance)
|
||||
{
|
||||
bool is_changed{false};
|
||||
|
||||
float val = in_val;
|
||||
float tolerance = in_tolerance;
|
||||
if (render_slider_double_input(label, val, tolerance, -0.1f, std::min(0.3f*in_val, 1.5f))) {
|
||||
if (render_slider_two_input(label, val, tolerance, -0.1f, std::min(0.3f*in_val, 1.5f))) {
|
||||
if (m_imgui->get_last_slider_status().can_take_snapshot) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", _u8L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction);
|
||||
m_imgui->get_last_slider_status().invalidate_snapshot();
|
||||
@@ -2525,6 +2655,82 @@ void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in_val, const float& init_val, const bool disabled)
|
||||
{
|
||||
if (disabled)
|
||||
m_imgui->disabled_begin(true);
|
||||
|
||||
bool is_changed{false};
|
||||
Vec2d plate_size = wxGetApp().plater()->get_partplate_list().get_plate(0)->get_size();
|
||||
float max_val = std::max(plate_size.x(), plate_size.y()) / (std::max(m_groove_count - 1, 1));
|
||||
|
||||
float val = in_val;
|
||||
if (render_slider_input(label, val, -0.1f, max_val)) {
|
||||
if (m_imgui->get_last_slider_status().can_take_snapshot) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", _u8L("Groove change"), label),
|
||||
UndoRedo::SnapshotType::GizmoAction);
|
||||
m_imgui->get_last_slider_status().invalidate_snapshot();
|
||||
m_groove_editing = true;
|
||||
}
|
||||
in_val = val;
|
||||
is_changed = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (!disabled) m_imgui->disabled_begin(is_approx(in_val, init_val) );
|
||||
const std::string act_name = _u8L("Reset");
|
||||
if (render_reset_button("##groove_" + label + act_name, act_name)) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", act_name, label), UndoRedo::SnapshotType::GizmoAction);
|
||||
in_val = init_val;
|
||||
is_changed = true;
|
||||
}
|
||||
if (!disabled) m_imgui->disabled_end();
|
||||
|
||||
if (is_changed) {
|
||||
update_plane_model();
|
||||
reset_cut_by_contours();
|
||||
}
|
||||
|
||||
if (m_is_slider_editing_done) {
|
||||
m_groove_editing = false;
|
||||
reset_cut_by_contours();
|
||||
}
|
||||
|
||||
if (disabled)
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_groove_int_input(const std::string& label, int& in_val, const int& init_val, int min_val, int max_val)
|
||||
{
|
||||
bool is_changed{false};
|
||||
|
||||
m_imgui->text(label);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::PushItemWidth(m_control_width);
|
||||
if (ImGui::InputInt("##int_input", &in_val, 1, 5)) {
|
||||
in_val = std::clamp(in_val, min_val, max_val);
|
||||
|
||||
is_changed = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(in_val == init_val);
|
||||
const std::string act_name = _u8L("Reset");
|
||||
if (render_reset_button("##int_" + label + act_name, act_name)) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", act_name, label), UndoRedo::SnapshotType::GizmoAction);
|
||||
in_val = init_val;
|
||||
is_changed = true;
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
if (is_changed) {
|
||||
update_plane_model();
|
||||
reset_cut_by_contours();
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val)
|
||||
{
|
||||
// -------- [ ]
|
||||
@@ -2641,10 +2847,14 @@ void GLGizmoCut3D::render_snap_specific_input(const std::string& label, const wx
|
||||
|
||||
void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, float x, float y, float bottom_limit)
|
||||
{
|
||||
// if (m_mode == size_t(CutMode::cutPlanar)) {
|
||||
const bool has_connectors = !connectors.empty();
|
||||
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && m_bb_center.isApprox(m_plane_center);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
CutMode mode = CutMode(m_mode);
|
||||
if (mode == CutMode::cutPlanar || mode == CutMode::cutTongueAndGroove) {
|
||||
const bool has_connectors = !connectors.empty();
|
||||
|
||||
m_imgui->disabled_begin(has_connectors);
|
||||
if (render_cut_mode_combo())
|
||||
@@ -2659,7 +2869,6 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, floa
|
||||
render_move_center_input(Z);
|
||||
ImGui::SameLine();
|
||||
|
||||
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && m_bb_center.isApprox(m_plane_center);
|
||||
m_imgui->disabled_begin(is_cut_plane_init);
|
||||
std::string act_name = _u8L("Reset cutting plane");
|
||||
if (render_reset_button("cut_plane", act_name)) {
|
||||
@@ -2668,35 +2877,36 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, floa
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
// render_flip_plane_button();
|
||||
|
||||
if (mode == CutMode::cutPlanar) {
|
||||
add_vertical_scaled_interval(0.75f);
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_keep_as_parts || (m_part_selection.valid() && m_part_selection.is_one_object()));
|
||||
if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors")))
|
||||
set_connectors_editing(true);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine(1.5f * m_control_width);
|
||||
|
||||
m_imgui->disabled_begin(is_cut_plane_init && !has_connectors);
|
||||
act_name = _u8L("Reset cut");
|
||||
if (m_imgui->button(wxString::FromUTF8(act_name), _L("Reset cutting plane and remove connectors"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), act_name, UndoRedo::SnapshotType::GizmoAction);
|
||||
reset_cut_plane();
|
||||
reset_connectors();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
else if (mode == CutMode::cutTongueAndGroove) {
|
||||
m_is_slider_editing_done = false;
|
||||
ImGui::Separator();
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, m_labels_map["Groove"] + ": ");
|
||||
render_groove_float_input(m_labels_map["Depth"], m_groove.depth, m_groove.depth_init, m_groove.depth_tolerance);
|
||||
render_groove_float_input(m_labels_map["Width"], m_groove.width, m_groove.width_init, m_groove.width_tolerance);
|
||||
render_groove_two_float_input(m_labels_map["Depth"], m_groove.depth, m_groove.depth_init, m_groove.depth_tolerance);
|
||||
render_groove_two_float_input(m_labels_map["Width"], m_groove.width, m_groove.width_init, m_groove.width_tolerance);
|
||||
render_groove_angle_input(m_labels_map["Flap Angle"], m_groove.flaps_angle, m_groove.flaps_angle_init, 30.f, 120.f);
|
||||
render_groove_angle_input(m_labels_map["Groove Angle"], m_groove.angle, m_groove.angle_init, 0.f, 15.f);
|
||||
|
||||
ImGui::Spacing();
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, m_labels_map["Multiple"] + ": ");
|
||||
render_groove_int_input(m_labels_map["Count"], m_groove_count, m_groove_count_init , 1, 100);
|
||||
render_groove_float_input(m_labels_map["Gap"], m_groove_gap, m_groove_gap_init, m_groove_count == 1);
|
||||
|
||||
m_imgui->disabled_begin(true);
|
||||
const float groove_width = Cut::calculate_groove_width(m_groove, m_radius);
|
||||
m_imgui->text(m_labels_map["Spacing"]);
|
||||
ImGui::SameLine(m_label_width);
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(2) << (m_groove_gap + groove_width);
|
||||
m_imgui->text(oss.str() + "mm");
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -2759,21 +2969,35 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, floa
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
render_tooltip_button(x, get_cur_y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
if (mode == CutMode::cutPlanar) {
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(is_cut_plane_init && !has_connectors);
|
||||
if (m_imgui->button(_L("Reset"), _L("Reset cutting plane and remove connectors"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset Cut", UndoRedo::SnapshotType::GizmoAction);
|
||||
reset_cut_plane();
|
||||
reset_connectors();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Perform cut"), _L("Cancel")});
|
||||
m_imgui->disabled_begin(!can_perform_cut());
|
||||
if(m_imgui->button(_L("Perform cut")))
|
||||
perform_cut(m_parent.get_selection());
|
||||
GLGizmoUtils::push_orca_button_style();
|
||||
if(m_imgui->button(_L("Perform cut")))
|
||||
perform_cut(m_parent.get_selection());
|
||||
GLGizmoUtils::pop_orca_button_style();
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(_L("Cancel"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::validate_connector_settings()
|
||||
@@ -2876,7 +3100,16 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors)
|
||||
|
||||
void GLGizmoCut3D::render_input_window_warning() const
|
||||
{
|
||||
if (! m_invalid_connectors_idxs.empty()) {
|
||||
const bool invalid_connector_warning = !m_invalid_connectors_idxs.empty();
|
||||
const bool keep_after_cut_warning = !m_keep_upper && !m_keep_lower;
|
||||
const bool invalid_contour_warning = !has_valid_contour();
|
||||
const bool invalid_groove_warning = !has_valid_groove();
|
||||
|
||||
if (invalid_connector_warning || keep_after_cut_warning || invalid_contour_warning || invalid_groove_warning) {
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
if (invalid_connector_warning) {
|
||||
wxString out = /*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Invalid connectors detected") + ":";
|
||||
if (m_info_stats.outside_cut_contour > size_t(0))
|
||||
out += "\n - " + format_wxstr(_L_PLURAL("%1$d connector is out of cut contour", "%1$d connectors are out of cut contour", m_info_stats.outside_cut_contour),
|
||||
@@ -2886,14 +3119,14 @@ void GLGizmoCut3D::render_input_window_warning() const
|
||||
m_info_stats.outside_bb);
|
||||
if (m_info_stats.is_overlap)
|
||||
out += "\n - " + _L("Some connectors are overlapped");
|
||||
m_imgui->text(out);
|
||||
m_imgui->warning_text(out);
|
||||
}
|
||||
if (!m_keep_upper && !m_keep_lower)
|
||||
m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Select at least one object to keep after cutting."));
|
||||
if (!has_valid_contour())
|
||||
m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane is placed out of object"));
|
||||
else if (!has_valid_groove())
|
||||
m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane with groove is invalid"));
|
||||
if (keep_after_cut_warning)
|
||||
m_imgui->warning_text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Select at least one object to keep after cutting."));
|
||||
if (invalid_contour_warning)
|
||||
m_imgui->warning_text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane is placed out of object"));
|
||||
else if (invalid_groove_warning)
|
||||
m_imgui->warning_text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane with groove is invalid"));
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
@@ -3338,7 +3571,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
|
||||
Cut cut(cut_mo, instance_idx, get_cut_matrix(selection), attributes);
|
||||
const ModelObjectPtrs& new_objects = cut_by_contour ? cut.perform_by_contour(mo, m_part_selection.get_cut_parts(), dowels_count):
|
||||
cut_with_groove ? cut.perform_with_groove(m_groove, m_rotation_m) :
|
||||
cut_with_groove ? cut.perform_with_groove(m_groove, m_rotation_m, m_groove_count, m_groove_gap, m_radius) :
|
||||
cut.perform_with_plane();
|
||||
|
||||
// fix_non_manifold_edges
|
||||
|
||||
@@ -124,6 +124,12 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
|
||||
bool m_is_slider_editing_done { false };
|
||||
|
||||
// Multiple Dovetail cuts
|
||||
int m_groove_count_init { 1 };
|
||||
int m_groove_count { 1 };
|
||||
float m_groove_gap { 10.f }; // distance between multiple dovetail cuts
|
||||
float m_groove_gap_init { 10.f };
|
||||
|
||||
// Input params for cut with snaps
|
||||
float m_snap_bulge_proportion{ 0.15f };
|
||||
float m_snap_space_proportion{ 0.3f };
|
||||
@@ -301,8 +307,10 @@ protected:
|
||||
void add_horizontal_scaled_interval(float interval);
|
||||
void add_horizontal_shift(float shift);
|
||||
void render_color_marker(float size, const ImU32& color);
|
||||
void render_groove_float_input(const std::string &label, float &in_val, const float &init_val, float &in_tolerance);
|
||||
void render_groove_two_float_input(const std::string &label, float &in_val, const float &init_val, float &in_tolerance);
|
||||
void render_groove_float_input(const std::string &label, float &in_val, const float &init_val, const bool disabled);
|
||||
void render_groove_angle_input(const std::string &label, float &in_val, const float &init_val, float min_val, float max_val);
|
||||
void render_groove_int_input(const std::string& label, int& in_val, const int& init_val, int min_val, int max_val);
|
||||
bool render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val);
|
||||
void render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val);
|
||||
void render_cut_plane_input_window(CutConnectors &connectors, float x, float y, float bottom_limit);
|
||||
@@ -338,7 +346,8 @@ private:
|
||||
void switch_to_mode(size_t new_mode);
|
||||
bool render_cut_mode_combo();
|
||||
bool render_double_input(const std::string& label, double& value_in);
|
||||
bool render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val = -0.1f, float max_tolerance = -0.1f);
|
||||
bool render_slider_two_input(const std::string& label, float& value_in, float& tolerance_in, float min_val = -0.1f, float max_tolerance = -0.1f);
|
||||
bool render_slider_input(const std::string& label, float& value_in, float min_val = -0.1f, float max_val = 100.f);
|
||||
void render_move_center_input(int axis);
|
||||
void render_connect_mode_radio_button(CutConnectorMode mode);
|
||||
bool render_reset_button(const std::string& label_id, const std::string& tooltip) const;
|
||||
@@ -378,6 +387,7 @@ private:
|
||||
|
||||
void toggle_model_objects_visibility();
|
||||
|
||||
std::vector<Vec3i32> offset_indices(const std::vector<Vec3i32>& base_indices, size_t vo);
|
||||
indexed_triangle_set its_make_groove_plane();
|
||||
|
||||
indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes);
|
||||
|
||||
@@ -1267,6 +1267,59 @@ void GLGizmoEmboss::reset_volume()
|
||||
remove_notification_not_valid_font();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// FIX IT: It should not change volume position before successfull change volume by process
|
||||
void fix_transformation(const StyleManager::Style& from, const StyleManager::Style& to, GLCanvas3D& canvas)
|
||||
{
|
||||
// fix Z rotation when exists difference in styles
|
||||
const std::optional<float>& f_angle_opt = from.angle;
|
||||
const std::optional<float>& t_angle_opt = to.angle;
|
||||
if (!is_approx(f_angle_opt, t_angle_opt)) {
|
||||
// fix rotation
|
||||
float f_angle = f_angle_opt.value_or(.0f);
|
||||
float t_angle = t_angle_opt.value_or(.0f);
|
||||
do_local_z_rotate(canvas.get_selection(), t_angle - f_angle);
|
||||
std::string no_snapshot;
|
||||
canvas.do_rotate(no_snapshot);
|
||||
}
|
||||
|
||||
// fix distance (Z move) when exists difference in styles
|
||||
const std::optional<float>& f_move_opt = from.distance;
|
||||
const std::optional<float>& t_move_opt = to.distance;
|
||||
if (!is_approx(f_move_opt, t_move_opt)) {
|
||||
float f_move = f_move_opt.value_or(.0f);
|
||||
float t_move = t_move_opt.value_or(.0f);
|
||||
do_local_z_move(canvas.get_selection(), t_move - f_move);
|
||||
std::string no_snapshot;
|
||||
canvas.do_move(no_snapshot);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool GLGizmoEmboss::is_changed_from_default_style()
|
||||
{
|
||||
int default_index = 0;
|
||||
const StyleManager::Style& default_style = m_style_manager.get_styles()[default_index];
|
||||
const StyleManager::Style& current_style = m_style_manager.get_style();
|
||||
|
||||
return default_style == current_style;
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::reset_to_default_style()
|
||||
{
|
||||
int default_index = 0;
|
||||
const StyleManager::Style& current_style = m_style_manager.get_style();
|
||||
const StyleManager::Style& default_style = m_style_manager.get_styles()[default_index];
|
||||
|
||||
StyleManager::Style cur_s = current_style; // copy
|
||||
StyleManager::Style new_s = default_style; // copy
|
||||
|
||||
if (m_style_manager.load_style(default_index)) {
|
||||
::fix_transformation(cur_s, new_s, m_parent);
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::calculate_scale() {
|
||||
Transform3d to_world = m_parent.get_selection().get_first_volume()->world_matrix();
|
||||
auto to_world_linear = to_world.linear();
|
||||
@@ -1406,9 +1459,29 @@ void GLGizmoEmboss::draw_window(float x, float y)
|
||||
draw_model_type();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(is_changed_from_default_style());
|
||||
if (m_imgui->button(_L("Reset"), _L("Reset all options except the text and operation"))) {
|
||||
reset_to_default_style();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
|
||||
#ifdef SHOW_WX_FONT_DESCRIPTOR
|
||||
if (is_selected_style)
|
||||
@@ -2155,34 +2228,6 @@ void GLGizmoEmboss::draw_delete_style_button() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// FIX IT: It should not change volume position before successfull change volume by process
|
||||
void fix_transformation(const StyleManager::Style &from, const StyleManager::Style &to, GLCanvas3D &canvas) {
|
||||
// fix Z rotation when exists difference in styles
|
||||
const std::optional<float> &f_angle_opt = from.angle;
|
||||
const std::optional<float> &t_angle_opt = to.angle;
|
||||
if (!is_approx(f_angle_opt, t_angle_opt)) {
|
||||
// fix rotation
|
||||
float f_angle = f_angle_opt.value_or(.0f);
|
||||
float t_angle = t_angle_opt.value_or(.0f);
|
||||
do_local_z_rotate(canvas.get_selection(), t_angle - f_angle);
|
||||
std::string no_snapshot;
|
||||
canvas.do_rotate(no_snapshot);
|
||||
}
|
||||
|
||||
// fix distance (Z move) when exists difference in styles
|
||||
const std::optional<float> &f_move_opt = from.distance;
|
||||
const std::optional<float> &t_move_opt = to.distance;
|
||||
if (!is_approx(f_move_opt, t_move_opt)) {
|
||||
float f_move = f_move_opt.value_or(.0f);
|
||||
float t_move = t_move_opt.value_or(.0f);
|
||||
do_local_z_move(canvas.get_selection(), t_move - f_move);
|
||||
std::string no_snapshot;
|
||||
canvas.do_move(no_snapshot);
|
||||
}
|
||||
}
|
||||
} // namesapce
|
||||
|
||||
void GLGizmoEmboss::draw_style_list() {
|
||||
if (!m_style_manager.is_active_font()) return;
|
||||
|
||||
|
||||
@@ -109,6 +109,9 @@ private:
|
||||
void set_volume_by_selection();
|
||||
void reset_volume();
|
||||
|
||||
bool is_changed_from_default_style();
|
||||
void reset_to_default_style();
|
||||
|
||||
// create volume from text - main functionality
|
||||
bool process(bool make_snapshot = true);
|
||||
void close();
|
||||
|
||||
@@ -82,7 +82,7 @@ bool GLGizmoFdmSupports::on_init()
|
||||
|
||||
m_desc["perform"] = _L("Perform");
|
||||
m_desc["on_overhangs_only"] = _L("On highlighted overhangs only");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["remove_all"] = _L("Erase all");
|
||||
m_desc["highlight_by_angle"] = _L("Highlight overhang areas");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["gap_fill"] = _L("Gap fill");
|
||||
@@ -215,6 +215,9 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
|
||||
//BBS
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
@@ -225,11 +228,10 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
const float highlight_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.5f);
|
||||
const float reset_button_slider_left = m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2;
|
||||
const float on_overhangs_only_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(1.5f);
|
||||
const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.5f);
|
||||
const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.5f);
|
||||
const float gap_area_txt_width = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f);
|
||||
const float smart_fill_angle_txt_width = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f);
|
||||
const float buttons_width = remove_btn_width + filter_btn_width + m_imgui->scaled(1.5f);
|
||||
const float buttons_width = filter_btn_width + m_imgui->scaled(1.5f);
|
||||
const float empty_button_width = m_imgui->calc_button_size("").x;
|
||||
|
||||
const float tips_width = m_imgui->calc_text_size(_L("Auto support threshold angle: ") + " 90 ").x + m_imgui->scaled(1.5f);
|
||||
@@ -358,12 +360,27 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
// Apply gap fill button
|
||||
if (m_imgui->button(m_desc.at("perform"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
for (int i = 0; i < m_triangle_selectors.size(); i++) {
|
||||
TriangleSelectorPatch* ts_mm = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
||||
ts_mm->update_selector_triangles();
|
||||
ts_mm->request_update_render_data(true);
|
||||
}
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
m_imgui->bbl_checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]),
|
||||
max_tooltip_width);
|
||||
if (m_current_tool != ImGui::GapFillIcon) {
|
||||
m_imgui->bbl_checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]),
|
||||
max_tooltip_width);
|
||||
}
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -427,33 +444,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
|
||||
if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// Perform button is for gap fill
|
||||
if (m_current_tool == ImGui::GapFillIcon) {
|
||||
if (m_imgui->button(m_desc.at("perform"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
for (int i = 0; i < m_triangle_selectors.size(); i++) {
|
||||
TriangleSelectorPatch* ts_mm = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
||||
ts_mm->update_selector_triangles();
|
||||
ts_mm->request_update_render_data(true);
|
||||
}
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
m_imgui->disabled_begin(m_c->selection_info()->model_object()->is_fdm_support_painted() == false);
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction);
|
||||
ModelObject * mo = m_c->selection_info()->model_object();
|
||||
@@ -468,11 +464,18 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
GizmoImguiEnd();
|
||||
|
||||
// BBS
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ bool GLGizmoFuzzySkin::on_init()
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["remove_all"] = _L("Erase all");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
@@ -137,6 +137,8 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
|
||||
// BBS
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
@@ -151,7 +153,6 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
|
||||
const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f);
|
||||
|
||||
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
|
||||
const float buttons_width = m_imgui->scaled(0.5f);
|
||||
const float minimal_slider_width = m_imgui->scaled(4.f);
|
||||
|
||||
@@ -176,7 +177,6 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
const float empty_button_width = m_imgui->calc_button_size("").x;
|
||||
|
||||
window_width = std::max(window_width, total_text_max);
|
||||
window_width = std::max(window_width, button_width);
|
||||
window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer);
|
||||
window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill);
|
||||
window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f));
|
||||
@@ -299,14 +299,10 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
m_imgui->disabled_begin(mo->is_fuzzy_skin_painted() == false);
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
|
||||
int idx = -1;
|
||||
@@ -320,6 +316,13 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
const DynamicPrintConfig &glb_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
const bool has_object_fuzzy_override = obj_cfg.option("fuzzy_skin");
|
||||
@@ -329,7 +332,7 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
float font_size = ImGui::GetFontSize();
|
||||
auto link_text = [&]() {
|
||||
ImColor HyperColor = ImGuiWrapper::COL_ORCA;
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(ColorRGB::WARNING()));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_WARNING);
|
||||
float parent_width = ImGui::GetContentRegionAvail().x;
|
||||
m_imgui->text_wrapped(_L("Warning: Fuzzy skin is disabled, painted fuzzy skin will not take effect!"), parent_width);
|
||||
ImGui::PopStyleColor();
|
||||
@@ -350,10 +353,11 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
mo->config.assign_config(new_conf);
|
||||
}
|
||||
};
|
||||
ImGui::Separator();
|
||||
|
||||
link_text();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
GizmoImguiEnd();
|
||||
|
||||
// BBS
|
||||
|
||||
@@ -1917,18 +1917,6 @@ void GLGizmoMeasure::show_selection_ui()
|
||||
if (m_show_reset_first_tip) {
|
||||
m_imgui->text(_L("Feature 1 has been reset, \nfeature 2 has been feature 1"));
|
||||
}
|
||||
if (m_selected_wrong_feature_waring_tip) {
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
|
||||
m_imgui->warning_text(_L("Warning: please select Plane's feature."));
|
||||
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
|
||||
m_imgui->warning_text(_L("Warning: please select Point's or Circle's feature."));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY && m_hit_different_volumes.size() == 1) {
|
||||
m_imgui->warning_text(_L("Warning: please select two different meshes."));
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::show_distance_xyz_ui()
|
||||
@@ -2175,10 +2163,21 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
|
||||
|
||||
ImGui::Separator();
|
||||
show_distance_xyz_ui();
|
||||
|
||||
ImGui::Separator();
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") });
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
|
||||
if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) {
|
||||
// the dialog may have changed its size, ask for an extra frame to render it properly
|
||||
last_feature = m_curr_feature;
|
||||
|
||||
@@ -103,7 +103,7 @@ bool GLGizmoMmuSegmentation::on_init()
|
||||
m_desc["edge_detection"] = _L("Edge detection");
|
||||
m_desc["gap_area"] = _L("Gap area");
|
||||
m_desc["perform"] = _L("Perform");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["remove_all"] = _L("Erase all");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
@@ -362,6 +362,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
|
||||
// BBS
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
@@ -374,10 +377,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
const float gap_area_slider_left = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f) + space_size;
|
||||
const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(2.f);
|
||||
|
||||
const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
|
||||
const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.f);
|
||||
const float remap_btn_width = m_imgui->calc_text_size(m_desc.at("perform_remap")).x + m_imgui->scaled(1.f);
|
||||
const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f);
|
||||
const float buttons_width = filter_btn_width + remap_btn_width + m_imgui->scaled(2.f);
|
||||
const float minimal_slider_width = m_imgui->scaled(4.f);
|
||||
const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f);
|
||||
|
||||
@@ -566,8 +568,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
m_tool_type = ToolType::BUCKET_FILL;
|
||||
|
||||
m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge);
|
||||
|
||||
if (m_detect_geometry_edge) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["smart_fill_angle"]);
|
||||
@@ -587,6 +587,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
// set to negative value to disable edge detection
|
||||
m_smart_fill_angle = -1.f;
|
||||
}
|
||||
|
||||
m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge);
|
||||
}
|
||||
else if (m_current_tool == ImGui::HeightRangeIcon) {
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
@@ -613,6 +615,19 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
// Apply Gap fill button
|
||||
if (m_imgui->button(m_desc.at("perform"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Gap fill", UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
for (int i = 0; i < m_triangle_selectors.size(); i++) {
|
||||
TriangleSelectorPatch* ts_mm = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
||||
ts_mm->update_selector_triangles();
|
||||
ts_mm->request_update_render_data(true);
|
||||
}
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -639,30 +654,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (m_current_tool == ImGui::GapFillIcon) {
|
||||
if (m_imgui->button(m_desc.at("perform"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Gap fill", UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
for (int i = 0; i < m_triangle_selectors.size(); i++) {
|
||||
TriangleSelectorPatch* ts_mm = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
||||
ts_mm->update_selector_triangles();
|
||||
ts_mm->request_update_render_data(true);
|
||||
}
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
m_imgui->disabled_begin(m_c->selection_info()->model_object()->is_mm_painted() == false);
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction);
|
||||
ModelObject * mo = m_c->selection_info()->model_object();
|
||||
@@ -677,7 +672,15 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
GizmoImguiEnd();
|
||||
|
||||
// BBS
|
||||
|
||||
@@ -41,7 +41,7 @@ bool GLGizmoSeam::on_init()
|
||||
m_desc["enforce"] = _L("Enforce seam");
|
||||
m_desc["block"] = _L("Block seam");
|
||||
m_desc["remove"] = _L("Erase");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["remove_all"] = _L("Erase all");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
|
||||
@@ -140,6 +140,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
wchar_t old_tool = m_current_tool;
|
||||
//BBS
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
@@ -256,14 +258,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
m_imgui->disabled_begin(m_c->selection_info()->model_object()->is_seam_painted() == false);
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Reset selection", UndoRedo::SnapshotType::GizmoAction);
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
@@ -278,7 +276,15 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({_L("Done")});
|
||||
if (m_imgui->button(_L("Done"))) {
|
||||
m_parent.reset_all_gizmos();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1); // ImGuiStyleVar_FramePadding
|
||||
GizmoImguiEnd();
|
||||
|
||||
//BBS
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
- [Confirm], [Cancel], [Done], ... are buttons that close the Tool Dialog
|
||||
- [Reset], [Button1], ... are buttons that do not!
|
||||
- Non-consequential buttons like [Cancel] and [Done] are always the right-most buttons
|
||||
- [Confirm] buttons should use the orca_button_style to differentiate them from other buttons
|
||||
- Multiple warnings can show, but should only have one ImGui::Separator above
|
||||
- If no warnings is shown, dont render the ImGui::Separator
|
||||
|
||||
@@ -33,43 +34,101 @@
|
||||
|
||||
namespace Slic3r::GUI::GLGizmoUtils {
|
||||
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y)
|
||||
{
|
||||
float caption_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_x_max = 0.f;
|
||||
for (const auto& item : shortcuts) {
|
||||
caption_x_max = std::max(caption_x_max, imgui_wrapper->calc_text_size(item.first).x);
|
||||
}
|
||||
caption_x_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y)
|
||||
{
|
||||
float caption_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_x_max = 0.f;
|
||||
for (const auto& item : shortcuts) {
|
||||
caption_x_max = std::max(caption_x_max, imgui_wrapper->calc_text_size(item.first).x);
|
||||
}
|
||||
caption_x_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
auto& gizmos_manager = canvas.get_gizmos_manager();
|
||||
ImTextureID normal_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
auto& gizmos_manager = canvas.get_gizmos_manager();
|
||||
ImTextureID normal_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
float scale = canvas.get_scale();
|
||||
float scale = canvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float)dpi / (float)DPI_DEFAULT;
|
||||
#endif
|
||||
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale);
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 });
|
||||
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, caption_y));
|
||||
for (const auto& item : shortcuts) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, item.first + ": ");
|
||||
ImGui::SameLine(caption_x_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, item.second);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, caption_y));
|
||||
for (const auto& item : shortcuts) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, item.first + ": ");
|
||||
ImGui::SameLine(caption_x_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, item.second);
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void begin_right_aligned_buttons(const std::vector<wxString>& labels)
|
||||
{
|
||||
float total_width = 0.0f;
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
float spacing = style.ItemSpacing.x;
|
||||
float padding = style.FramePadding.x * 2.0f;
|
||||
|
||||
// Calculate width
|
||||
for (size_t i = 0; i < labels.size(); ++i) {
|
||||
total_width += ImGuiWrapper::calc_text_size(labels[i]).x + padding;
|
||||
if (i < labels.size() - 1)
|
||||
total_width += spacing;
|
||||
}
|
||||
|
||||
float avail = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
// Handle Overlap: If the total width of the buttons exceeds available space, move to a new line
|
||||
if (total_width > avail) {
|
||||
ImGui::NewLine();
|
||||
avail = ImGui::GetContentRegionAvail().x; // Reset to full window width
|
||||
}
|
||||
|
||||
float posX = ImGui::GetCursorPosX() + std::max(0.0f, avail - total_width);
|
||||
ImGui::SetCursorPosX(posX);
|
||||
}
|
||||
|
||||
void push_orca_button_style()
|
||||
{
|
||||
ImVec4 base_orca = ImGuiWrapper::COL_ORCA;
|
||||
|
||||
float h, s, v;
|
||||
ImGui::ColorConvertRGBtoHSV(base_orca.x, base_orca.y, base_orca.z, h, s, v);
|
||||
|
||||
ImVec4 hover, active;
|
||||
|
||||
// Lighter variant for Hover (Increase Value by ~12%)
|
||||
ImGui::ColorConvertHSVtoRGB(h, s, std::min(v + 0.12f, 1.0f), hover.x, hover.y, hover.z);
|
||||
hover.w = base_orca.w;
|
||||
|
||||
// Darker variant for Active (Decrease Value by ~12%)
|
||||
ImGui::ColorConvertHSVtoRGB(h, s, std::max(v - 0.12f, 0.0f), active.x, active.y, active.z);
|
||||
active.w = base_orca.w;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, base_orca);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hover);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, active);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_WINDOW_BG);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
}
|
||||
|
||||
void pop_orca_button_style()
|
||||
{
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleColor(4);
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI::GLGizmoUtils
|
||||
@@ -15,9 +15,16 @@ class GLCanvas3D;
|
||||
|
||||
namespace GLGizmoUtils {
|
||||
|
||||
// Renders a tooltip button using the provided shortcuts
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y);
|
||||
// Renders a tooltip button using the provided shortcuts
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y);
|
||||
|
||||
// Sets up ImGui to render buttons that are right-aligned within the current window, using the provided labels to calculate spacing.
|
||||
void begin_right_aligned_buttons(const std::vector<wxString>& labels);
|
||||
|
||||
void push_orca_button_style();
|
||||
|
||||
void pop_orca_button_style();
|
||||
|
||||
} // namespace GLGizmoUtils
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
@@ -62,16 +62,21 @@ GizmoObjectManipulation::GizmoObjectManipulation(GLCanvas3D& glcanvas)
|
||||
|
||||
m_shortcuts_move = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{shift + _L("Left mouse button"), _L("Fixed step drag")}
|
||||
{shift + _L("Left mouse button"), _L("Fixed step drag")},
|
||||
{_L("Context Menu"), _L("Toggle Auto-Drop")}
|
||||
};
|
||||
|
||||
m_shortcuts_rotate = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")}};
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{_L("Context Menu"), _L("Toggle Auto-Drop")}
|
||||
};
|
||||
|
||||
m_shortcuts_scale = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{shift + _L("Left mouse button"), _L("Fixed step drag")},
|
||||
{ctrl + _L("Left mouse button"), _L("Single sided scaling")}};
|
||||
{ctrl + _L("Left mouse button"), _L("Single sided scaling")},
|
||||
{_L("Context Menu"), _L("Toggle Auto-Drop")}
|
||||
};
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::UpdateAndShow(const bool show)
|
||||
@@ -860,13 +865,25 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
|
||||
}
|
||||
}
|
||||
if (!focued_on_text) m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
float f_scale = m_glcanvas.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_move, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") });
|
||||
if (imgui_wrapper->button(_L("Done"))) {
|
||||
m_glcanvas.reset_all_gizmos();
|
||||
}
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
last_move_input_window_width = ImGui::GetWindowWidth();
|
||||
imgui_wrapper->end();
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
@@ -1052,14 +1069,26 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
|
||||
if (!focued_on_text && !absolute_focued_on_text)
|
||||
m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
|
||||
ImGui::Spacing(); // needed after Text
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
float f_scale = m_glcanvas.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_rotate, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") });
|
||||
if (imgui_wrapper->button(_L("Done"))) {
|
||||
m_glcanvas.reset_all_gizmos();
|
||||
}
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
last_rotate_input_window_width = ImGui::GetWindowWidth();
|
||||
imgui_wrapper->end();
|
||||
|
||||
// BBS
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
@@ -1214,7 +1243,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
||||
if (display_size.x() > 0 && display_size.y() > 0 && display_size.z() > 0) {
|
||||
m_buffered_size = display_size;
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
bool is_avoid_one_update{false};
|
||||
if (combox_changed) {
|
||||
@@ -1286,15 +1315,26 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
||||
}
|
||||
if (!focued_on_text)
|
||||
m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
|
||||
ImGui::Separator();
|
||||
float f_scale = m_glcanvas.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_scale, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") });
|
||||
if (imgui_wrapper->button(_L("Done"))) {
|
||||
m_glcanvas.reset_all_gizmos();
|
||||
}
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
|
||||
last_scale_input_window_width = ImGui::GetWindowWidth();
|
||||
imgui_wrapper->end();
|
||||
|
||||
//BBS
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ const ImVec4 ImGuiWrapper::COL_TOOLBAR_BG = { 250 / 255.f, 250 / 255.f, 2
|
||||
const ImVec4 ImGuiWrapper::COL_TOOLBAR_BG_DARK = { 57 / 255.f, 60 / 255.f, 66 / 255.f, 1.f }; // ORCA color matches with toolbar_background_dark.png
|
||||
const ImVec4 ImGuiWrapper::COL_ORCA = to_ImVec4(ColorRGBA::ORCA());
|
||||
const ImVec4 ImGuiWrapper::COL_MODIFIED = { 253.f / 255.f, 111.f / 255.f, 40.f / 255.f, 1}; // ORCA same color with m_color_label_modified
|
||||
const ImVec4 ImGuiWrapper::COL_WARNING = to_ImVec4(ColorRGB::WARNING());
|
||||
|
||||
int ImGuiWrapper::TOOLBAR_WINDOW_FLAGS = ImGuiWindowFlags_AlwaysAutoResize
|
||||
| ImGuiWindowFlags_NoMove
|
||||
@@ -871,8 +872,8 @@ bool ImGuiWrapper::button(const wxString &label, const wxString& tooltip)
|
||||
const bool ret = ImGui::Button(label_utf8.c_str());
|
||||
|
||||
if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) {
|
||||
auto tooltip_utf8 = into_u8(tooltip);
|
||||
ImGui::SetTooltip(tooltip_utf8.c_str(), nullptr);
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
this->tooltip(tooltip, max_tooltip_width);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -884,8 +885,8 @@ bool ImGuiWrapper::bbl_button(const wxString &label, const wxString& tooltip)
|
||||
const bool ret = ImGui::BBLButton(label_utf8.c_str());
|
||||
|
||||
if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) {
|
||||
auto tooltip_utf8 = into_u8(tooltip);
|
||||
ImGui::SetTooltip(tooltip_utf8.c_str(), nullptr);
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
this->tooltip(tooltip, max_tooltip_width);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1055,7 +1056,7 @@ void ImGuiWrapper::text(const wxString &label)
|
||||
|
||||
void ImGuiWrapper::warning_text(const char *label)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(ColorRGB::WARNING()));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_WARNING);
|
||||
this->text(label);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ public:
|
||||
static const ImVec4 COL_SEPARATOR_DARK;
|
||||
static const ImVec4 COL_ORCA;
|
||||
static const ImVec4 COL_MODIFIED;
|
||||
static const ImVec4 COL_WARNING;
|
||||
|
||||
//BBS
|
||||
static void on_change_color_mode(bool is_dark);
|
||||
|
||||
@@ -2403,13 +2403,23 @@ void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filame
|
||||
edit_btn->SetToolTip(_L("Click to edit preset"));
|
||||
|
||||
PlaterPresetComboBox* combobox = (*combo);
|
||||
edit_btn->Bind(wxEVT_BUTTON, [this, edit_btn, filament_idx](wxCommandEvent) {
|
||||
auto menu = p->plater->filament_action_menu(filament_idx);
|
||||
wxPoint pt { 0, edit_btn->GetSize().GetHeight() + 10 };
|
||||
pt = edit_btn->ClientToScreen(pt);
|
||||
pt = wxGetApp().mainframe->ScreenToClient(pt);
|
||||
p->m_menu_filament_id = filament_idx;
|
||||
p->plater->PopupMenu(menu, (int) pt.x, pt.y);
|
||||
edit_btn->Bind(wxEVT_BUTTON, [this, edit_btn, combobox, filament_idx](wxCommandEvent) {
|
||||
bool single_or_bbl = should_show_SEMM_buttons();
|
||||
bool is_multi_material = p->combos_filament.size() > 1;
|
||||
if(single_or_bbl && is_multi_material) {
|
||||
// MULTI MATERIAL Show menu
|
||||
auto menu = p->plater->filament_action_menu(filament_idx);
|
||||
wxPoint pt { 0, edit_btn->GetSize().GetHeight() + FromDIP(2) };
|
||||
pt = edit_btn->ClientToScreen(pt);
|
||||
pt = wxGetApp().mainframe->ScreenToClient(pt);
|
||||
p->m_menu_filament_id = filament_idx;
|
||||
p->plater->PopupMenu(menu, (int) pt.x, pt.y);
|
||||
}
|
||||
else {
|
||||
// SINGLE MATERIAL / MULTI EXTRUDER / TOOLCHANGER / IDEX Opens Dialog directly
|
||||
p->editing_filament = filament_idx;
|
||||
combobox->switch_to_tab();
|
||||
}
|
||||
});
|
||||
combobox->edit_btn = edit_btn;
|
||||
|
||||
@@ -2510,7 +2520,7 @@ void Sidebar::update_all_preset_comboboxes()
|
||||
p->m_filament_icon->SetBitmap_("filament");
|
||||
}
|
||||
|
||||
show_SEMM_buttons(should_show_SEMM_buttons());
|
||||
show_SEMM_buttons();
|
||||
|
||||
//p->m_staticText_filament_settings->Update();
|
||||
|
||||
@@ -3112,16 +3122,7 @@ void Sidebar::on_filament_count_change(size_t num_filaments)
|
||||
// remove unused choices if any
|
||||
remove_unused_filament_combos(num_filaments);
|
||||
|
||||
auto sizer = p->m_panel_filament_title->GetSizer();
|
||||
if (p->m_flushing_volume_btn != nullptr && sizer != nullptr) {
|
||||
if (num_filaments > 1) {
|
||||
sizer->Show(p->m_flushing_volume_btn);
|
||||
sizer->Show(p->m_bpButton_del_filament); // ORCA: Show delete filament button if multiple filaments
|
||||
} else {
|
||||
sizer->Hide(p->m_flushing_volume_btn);
|
||||
sizer->Hide(p->m_bpButton_del_filament); // ORCA: Hide delete filament button if there is only one filament
|
||||
}
|
||||
}
|
||||
show_SEMM_buttons(); // ORCA
|
||||
|
||||
update_filaments_area_height(); // ORCA
|
||||
|
||||
@@ -3168,16 +3169,7 @@ void Sidebar::on_filaments_delete(size_t filament_id)
|
||||
}
|
||||
}
|
||||
|
||||
auto sizer = p->m_panel_filament_title->GetSizer();
|
||||
if (p->m_flushing_volume_btn != nullptr && sizer != nullptr) {
|
||||
if (p->combos_filament.size() > 1) {
|
||||
sizer->Show(p->m_flushing_volume_btn);
|
||||
sizer->Show(p->m_bpButton_del_filament); // ORCA: Show delete filament button if multiple filaments
|
||||
} else {
|
||||
sizer->Hide(p->m_flushing_volume_btn);
|
||||
sizer->Hide(p->m_bpButton_del_filament); // ORCA: Hide delete filament button if there is only one filament
|
||||
}
|
||||
}
|
||||
show_SEMM_buttons(); // ORCA
|
||||
|
||||
for (size_t idx = filament_id ; idx < p->combos_filament.size(); ++idx) {
|
||||
p->combos_filament[idx]->update();
|
||||
@@ -3736,14 +3728,31 @@ bool Sidebar::should_show_SEMM_buttons()
|
||||
return cfg.opt_bool("single_extruder_multi_material") || is_bbl_vendor;
|
||||
}
|
||||
|
||||
void Sidebar::show_SEMM_buttons(bool bshow)
|
||||
void Sidebar::show_SEMM_buttons()
|
||||
{
|
||||
if(p->m_bpButton_add_filament)
|
||||
p->m_bpButton_add_filament->Show(bshow);
|
||||
if (p->m_bpButton_del_filament && p->combos_filament.size() > 1) // ORCA add filament count as condition to prevent showing Flushing volumes and Del Filament icon visible while only 1 filament exist
|
||||
p->m_bpButton_del_filament->Show(bshow);
|
||||
if (p->m_flushing_volume_btn && p->combos_filament.size() > 1) // ORCA add filament count as condition to prevent showing Flushing volumes and Del Filament icon visible while only 1 filament exist
|
||||
p->m_flushing_volume_btn->Show(bshow);
|
||||
// ORCA
|
||||
if (!p || p->combos_filament.empty() || !p->m_bpButton_add_filament || !p->m_bpButton_del_filament || !p->m_flushing_volume_btn)
|
||||
return;
|
||||
|
||||
bool is_multi_material = p->combos_filament.size() > 1;
|
||||
bool single_or_bbl = should_show_SEMM_buttons();
|
||||
bool is_single = single_or_bbl && !is_multi_material; // SINGLE EXTRUDER / BBL WITH 1 MATERIAL
|
||||
bool is_multi = single_or_bbl && is_multi_material; // MULTI MATERIAL WITH SINGLE EXTRUDER
|
||||
bool is_fixed = !is_single && !is_multi; // MULTI EXTRUDER / TOOLCHANGER / IDEX WITH FIXED MATERIAL
|
||||
|
||||
p->m_bpButton_add_filament->Show(single_or_bbl);
|
||||
p->m_bpButton_del_filament->Show(is_multi);
|
||||
p->m_flushing_volume_btn->Show( is_multi);
|
||||
|
||||
if (is_multi) {
|
||||
for (auto &c : p->combos_filament)
|
||||
c->edit_btn->SetBitmap_("menu_filament");
|
||||
}
|
||||
else if (is_single || is_fixed) {
|
||||
for (auto &c : p->combos_filament)
|
||||
c->edit_btn->SetBitmap_("edit");
|
||||
}
|
||||
|
||||
Layout();
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ public:
|
||||
void get_small_btn_sync_pos_size(wxPoint &pt, wxSize &size);
|
||||
// Orca
|
||||
static bool should_show_SEMM_buttons();
|
||||
void show_SEMM_buttons(bool bshow);
|
||||
void show_SEMM_buttons();
|
||||
void update_dynamic_filament_list();
|
||||
|
||||
PlaterPresetComboBox * printer_combox();
|
||||
|
||||
@@ -1554,8 +1554,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
|
||||
if (opt_key == "single_extruder_multi_material" ){
|
||||
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||
wxGetApp().sidebar().show_SEMM_buttons(bSEMM);
|
||||
wxGetApp().sidebar().show_SEMM_buttons();
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
|
||||
}
|
||||
|
||||
@@ -1606,8 +1605,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
|
||||
if (opt_key == "single_extruder_multi_material" ){
|
||||
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||
wxGetApp().sidebar().show_SEMM_buttons(bSEMM);
|
||||
wxGetApp().sidebar().show_SEMM_buttons();
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user