diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index f79f48c279..426cc53309 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -175,6 +175,8 @@ void AppConfig::set_defaults() #ifdef _WIN32 if (get("associate_gcode").empty()) set("associate_gcode", "0"); + if (get("associate_bgcode").empty()) + set("associate_bgcode", "0"); #endif // _WIN32 } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 6c295279ad..3989eab3d2 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -61,4 +61,5 @@ // Enable imgui dialog which allows to set the parameters used to export binarized gcode #define ENABLE_BINARIZED_GCODE_DEBUG_WINDOW 0 + #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4d760c7e9f..2b4fbcee5f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -981,7 +981,7 @@ void GLCanvas3D::SequentialPrintClearance::render() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - if (!m_evaluating) + if (!m_evaluating && !m_dragging) m_fill.render(); #if ENABLE_GL_CORE_PROFILE @@ -1029,6 +1029,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MIRRORED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); @@ -3732,6 +3733,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!evt.CmdDown()) m_mouse.drag.start_position_3D = m_mouse.scene_position; m_sequential_print_clearance_first_displacement = true; + m_sequential_print_clearance.start_dragging(); } } } @@ -3856,6 +3858,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) { do_move(L("Move Object")); wxGetApp().obj_manipul()->set_dirty(); + m_sequential_print_clearance.stop_dragging(); // Let the plater know that the dragging finished, so a delayed refresh // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); @@ -4328,7 +4331,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) for (int id : obj_idx_for_update_info_items) wxGetApp().obj_list()->update_info_items(static_cast(id)); - post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MIRRORED)); m_dirty = true; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 26be98665b..0660ca7cc9 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -167,6 +167,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MIRRORED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); @@ -618,6 +619,7 @@ private: // list of transforms used to render the contours std::vector> m_instances; bool m_evaluating{ false }; + bool m_dragging{ false }; std::vector> m_hulls_2d_cache; @@ -627,6 +629,10 @@ private: void render(); bool empty() const { return m_contours.empty(); } + void start_dragging() { m_dragging = true; } + bool is_dragging() const { return m_dragging; } + void stop_dragging() { m_dragging = false; } + friend class GLCanvas3D; }; @@ -965,11 +971,18 @@ public: void reset_sequential_print_clearance() { m_sequential_print_clearance.m_evaluating = false; - m_sequential_print_clearance.set_contours(ContoursList(), false); + if (m_sequential_print_clearance.is_dragging()) + m_sequential_print_clearance_first_displacement = true; + else + m_sequential_print_clearance.set_contours(ContoursList(), false); + set_as_dirty(); + request_extra_frame(); } void set_sequential_print_clearance_contours(const ContoursList& contours, bool generate_fill) { m_sequential_print_clearance.set_contours(contours, generate_fill); + set_as_dirty(); + request_extra_frame(); } bool is_sequential_print_clearance_empty() const { @@ -981,7 +994,11 @@ public: } void update_sequential_clearance(bool force_contours_generation); - void set_sequential_clearance_as_evaluating() { m_sequential_print_clearance.m_evaluating = true; } + void set_sequential_clearance_as_evaluating() { + m_sequential_print_clearance.m_evaluating = true; + set_as_dirty(); + request_extra_frame(); + } const Print* fff_print() const; const SLAPrint* sla_print() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1728bc3c6b..d69f5b33de 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1290,6 +1290,8 @@ bool GUI_App::on_init_inner() #ifdef __WXMSW__ if (app_config->get_bool("associate_gcode")) associate_gcode_files(); + if (app_config->get_bool("associate_bgcode")) + associate_bgcode_files(); #endif // __WXMSW__ } @@ -2583,6 +2585,8 @@ void GUI_App::open_preferences(const std::string& highlight_option /*= std::stri else { if (app_config->get_bool("associate_gcode")) associate_gcode_files(); + if (app_config->get_bool("associate_bgcode")) + associate_bgcode_files(); } #endif // _WIN32 @@ -3370,6 +3374,11 @@ void GUI_App::associate_gcode_files() { associate_file_type(L".gcode", L"PrusaSlicer.GCodeViewer.1", L"PrusaSlicerGCodeViewer", true); } + +void GUI_App::associate_bgcode_files() +{ + associate_file_type(L".bgcode", L"PrusaSlicer.GCodeViewer.1", L"PrusaSlicerGCodeViewer", true); +} #endif // __WXMSW__ void GUI_App::on_version_read(wxCommandEvent& evt) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 467c2aaeb6..6951f654b6 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -368,6 +368,7 @@ public: void associate_3mf_files(); void associate_stl_files(); void associate_gcode_files(); + void associate_bgcode_files(); #endif // __WXMSW__ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 053f24418c..72ca3e3cf9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -204,10 +204,11 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection) const auto [box, box_trafo] = m_force_local_coordinate ? selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system(); m_bounding_box = box; - m_center = box_trafo.translation(); + const std::pair sphere = selection.get_bounding_sphere(); + m_center = sphere.first; + m_radius = Offset + sphere.second; m_orient_matrix = box_trafo; - - m_radius = Offset + m_bounding_box.radius(); + m_orient_matrix.translation() = m_center; m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_fine_in_radius = m_radius; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 39d428c2fe..72d9c1905e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2171,6 +2171,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_RESET_SKEW, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); }); + view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_MIRRORED, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event& evt) { this->sidebar->enable_buttons(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this); view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED, &priv::on_3dcanvas_mouse_dragging_started, this); @@ -3386,8 +3387,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool GLCanvas3D::ContoursList contours; contours.contours = background_process.fff_print()->get_sequential_print_clearance_contours(); canvas->set_sequential_print_clearance_contours(contours, true); - canvas->set_as_dirty(); - canvas->request_extra_frame(); } } } @@ -3402,8 +3401,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool GLCanvas3D::ContoursList contours; contours.contours = background_process.fff_print()->get_sequential_print_clearance_contours(); canvas->set_sequential_print_clearance_contours(contours, true); - canvas->set_as_dirty(); - canvas->request_extra_frame(); } } std::vector warnings; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index ecb1d152eb..6fb2f23258 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -367,6 +367,10 @@ void PreferencesDialog::build() L("Associate .gcode files to PrusaSlicer G-code Viewer"), L("If enabled, sets PrusaSlicer G-code Viewer as default application to open .gcode files."), app_config->get_bool("associate_gcode")); + append_bool_option(m_optgroup_general, "associate_bgcode", + L("Associate .bgcode files to PrusaSlicer G-code Viewer"), + L("If enabled, sets PrusaSlicer G-code Viewer as default application to open .bgcode files."), + app_config->get_bool("associate_bgcode")); } #endif // _WIN32 diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index dbad0e9f04..9e5e68ac59 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -29,6 +29,10 @@ #include #include +#include +#include +#include + static const Slic3r::ColorRGBA UNIFORM_SCALE_COLOR = Slic3r::ColorRGBA::ORANGE(); static const Slic3r::ColorRGBA SOLID_PLANE_COLOR = Slic3r::ColorRGBA::ORANGE(); static const Slic3r::ColorRGBA TRANSPARENT_PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f }; @@ -906,6 +910,41 @@ BoundingBoxf Selection::get_screen_space_bounding_box() return ss_box; } +const std::pair Selection::get_bounding_sphere() const +{ + if (!m_bounding_sphere.has_value()) { + std::optional>* sphere = const_cast>*>(&m_bounding_sphere); + *sphere = { Vec3d::Zero(), 0.0 }; + + using K = CGAL::Simple_cartesian; + using Traits = CGAL::Min_sphere_of_points_d_traits_3; + using Min_sphere = CGAL::Min_sphere_of_spheres_d; + using Point = K::Point_3; + + std::vector points; + if (m_valid) { + for (unsigned int i : m_list) { + const GLVolume& volume = *(*m_volumes)[i]; + const TriangleMesh* hull = volume.convex_hull(); + const indexed_triangle_set& its = (hull != nullptr) ? + hull->its : m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh().its; + const Transform3d& matrix = volume.world_matrix(); + for (const Vec3f& v : its.vertices) { + const Vec3d vv = matrix * v.cast(); + points.push_back(Point(vv.x(), vv.y(), vv.z())); + } + } + + Min_sphere ms(points.begin(), points.end()); + const float* center_x = ms.center_cartesian_begin(); + (*sphere)->first = { *center_x, *(center_x + 1), *(center_x + 2) }; + (*sphere)->second = ms.radius(); + } + } + + return *m_bounding_sphere; +} + void Selection::setup_cache() { if (!m_valid) @@ -993,15 +1032,15 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset; // rotate around selection center - const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.dragging_center - inst_trafo.get_offset()); + const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.rotation_pivot - inst_trafo.get_offset()); rotation_matrix = Geometry::translation_transform(inst_pivot) * rotation_matrix * Geometry::translation_transform(-inst_pivot); } - transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot); } else { if (!is_single_volume_or_modifier()) { assert(transformation_type.world()); - transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot); } else { if (transformation_type.instance()) { @@ -1027,7 +1066,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset; } } - transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot); } } } @@ -1550,10 +1589,7 @@ void Selection::erase() ensure_not_below_bed(); } - GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); - canvas->set_sequential_clearance_as_evaluating(); - canvas->set_as_dirty(); - canvas->request_extra_frame(); + wxGetApp().plater()->canvas3D()->set_sequential_clearance_as_evaluating(); } void Selection::render(float scale_factor) @@ -2039,6 +2075,7 @@ void Selection::set_caches() m_cache.sinking_volumes.push_back(i); } m_cache.dragging_center = get_bounding_box().center(); + m_cache.rotation_pivot = get_bounding_sphere().first; } void Selection::do_add_volume(unsigned int volume_idx) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index e7f4ceb16b..a64519f2e8 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -115,6 +115,7 @@ private: ObjectIdxsToInstanceIdxsMap content; // List of ids of the volumes which are sinking when starting dragging std::vector sinking_volumes; + Vec3d rotation_pivot; }; // Volumes owned by GLCanvas3D. @@ -151,6 +152,8 @@ private: // and transform to place and orient it in world coordinates std::optional> m_bounding_box_in_current_reference_system; + std::optional> m_bounding_sphere; + #if ENABLE_RENDER_SELECTION_CENTER GLModel m_vbo_sphere; #endif // ENABLE_RENDER_SELECTION_CENTER @@ -296,6 +299,9 @@ public: // Returns the screen space bounding box BoundingBoxf get_screen_space_bounding_box(); + // Returns the bounding sphere: first = center, second = radius + const std::pair get_bounding_sphere() const; + void setup_cache(); void translate(const Vec3d& displacement, TransformationType transformation_type); @@ -361,6 +367,7 @@ private: m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset(); m_full_unscaled_instance_local_bounding_box.reset(); m_bounding_box_in_current_reference_system.reset(); + m_bounding_sphere.reset(); } void render_synchronized_volumes(); void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index d41419ebf0..797207552c 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -314,7 +314,7 @@ void Http::priv::set_put_body(const fs::path &path) boost::system::error_code ec; boost::uintmax_t filesize = file_size(path, ec); if (!ec) { - putFile = std::make_unique(path); + putFile = std::make_unique(path, std::ios::binary); ::curl_easy_setopt(curl, CURLOPT_READDATA, (void *) (putFile.get())); ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize); }