diff --git a/resources/data/printer_gantries/geometries.txt b/resources/data/printer_gantries/geometries.json similarity index 85% rename from resources/data/printer_gantries/geometries.txt rename to resources/data/printer_gantries/geometries.json index dabf55f65b..592a0d117e 100644 --- a/resources/data/printer_gantries/geometries.txt +++ b/resources/data/printer_gantries/geometries.json @@ -281,6 +281,55 @@ ] } ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_HT90.*", + "gantry_model_filename": "prusa3d_ht90_actuator.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5; 5,-5; 5,5; -5,5" + ] + }, + { + "height": "1", + "type": "convex", + "polygons": [ + "-33,-2; 33,-2; 33,48; -33,48", + "-46,-37; 46,-37; 46,2; -46,2" + ] + }, + { + "height": "20", + "type": "convex", + "polygons": [ + "-55,-55; 55,-55; 55,55; -55,55" + ] + }, + { + "height": "28", + "type": "convex", + "polygons": [ + "-76,-68; 76,-68; 76,65; -76,65" + ] + }, + { + "height": "40", + "type": "convex", + "polygons": [ + "-120,-118; 120,-118; 120,94; -120,94" + ] + }, + { + "height": "60", + "type": "box", + "polygons": [ + "-200,-200; 200,-200; 200,200; -200,200" + ] + } + ] } ] } diff --git a/resources/data/printer_gantries/prusa3d_ht90_actuator.stl b/resources/data/printer_gantries/prusa3d_ht90_actuator.stl new file mode 100644 index 0000000000..05b7fb75e2 Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_ht90_actuator.stl differ diff --git a/src/libslic3r/ArrangeHelper.cpp b/src/libslic3r/ArrangeHelper.cpp index b34c7924ca..ac22083dd6 100644 --- a/src/libslic3r/ArrangeHelper.cpp +++ b/src/libslic3r/ArrangeHelper.cpp @@ -71,7 +71,7 @@ static Sequential::PrinterGeometry get_printer_geometry(const ConfigBase& config { if (! printer_notes.empty()) { try { - boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.txt"); + boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.json"); boost::property_tree::ptree pt; boost::property_tree::read_json(in, pt); for (const auto& printer : pt.get_child("printers")) { diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 86796dff5f..d425012ed1 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -217,12 +217,13 @@ int GCodeViewer::SequentialView::ActualSpeedImguiWidget::plot(const char* label, } #endif // ENABLE_ACTUAL_SPEED_DEBUG -void GCodeViewer::SequentialView::Marker::init(std::optional>& model_opt) +void GCodeViewer::SequentialView::Marker::init(std::optional>& model_opt, bool is_ht90) { if (! model_opt.has_value()) return; m_model.reset(); + m_is_ht90 = is_ht90; m_generic_marker = (model_opt->get() == nullptr); if (m_generic_marker) @@ -233,6 +234,85 @@ void GCodeViewer::SequentialView::Marker::init(std::optional(0,0); + transform.translation() = p1; + return transform; +} + +static void render_ht90_rods(const Vec3d& pos, GLShaderProgram* shader, const Transform3d& view_matrix, const Vec3d& bed_offset, GLModel& model) +{ + Vec3d start(30.06, 27.70, 35); // Position of the back-right ball bearing, on the extruder head. + Vec3d end(32.33, 212.92, 338.8); // The other ball bearing, on the printer. + double r=4.725; // Diameter of the rod. + double rods_spacing = 60.; + double height = (end-start).norm(); + + + if (!model.is_initialized()) { + auto t0 = its_make_sphere(r, 0.5); + auto t1 = its_make_sphere(r, 0.5); + auto t2 = its_make_cylinder(r, height); + its_translate(t1, Vec3f(0., 0., height)); + its_merge(t2, t0); + its_merge(t2, t1); + model.init_from(t2); + model.set_color({ 1.0f, 1.0f, 1.0f, 0.5f }); + } + + + // trans transforms extruder to world coord system of the first bed + Transform3d trans = Geometry::translation_transform(pos); + + Vec3d p1 = trans * start; + Vec3d p2 = end; // already in world coords + + for (int j=0; j<6; ++j) { + if (j == 3) { + p1.x() = p1.x() - rods_spacing; + p2.x() = p2.x() - rods_spacing; + } + + p1 = trans * Geometry::rotation_transform(Vec3d(0,0,2*M_PI/3)) * trans.inverse() * p1; + p2 = Geometry::rotation_transform(Vec3d(0,0,2*M_PI/3)) * p2; + + double dx = p2.x() - p1.x(); + double dy = p2.y() - p1.y(); + double dz = std::sqrt(height * height - dx * dx - dy * dy); + p2.z() = p1.z() + dz; + + Transform3d wm = align_cylinder(p1, p2, r); + shader->set_uniform("view_model_matrix", view_matrix * wm); + shader->set_uniform("volume_world_matrix", Geometry::translation_transform(bed_offset) * wm); + model.render(); + } + +} + + + + + + void GCodeViewer::SequentialView::Marker::render() { if (!m_visible) @@ -263,7 +343,7 @@ void GCodeViewer::SequentialView::Marker::render() BoundingBoxf box = s_multiple_beds.get_build_volume_box(); box.translate(to_2d(bed_inst_offset)); // add a bit on both sides - box = box.inflated(40.0f); + box = box.inflated(m_is_ht90 ? 60.f : 40.f); clip_planes = {{ { 1.0f, 0.0f, 0.0f, -box.min.cast().x() } , { -1.0f, 0.0f, 0.0f, box.max.cast().x() }}}; } @@ -287,8 +367,12 @@ void GCodeViewer::SequentialView::Marker::render() shader->set_uniform("clipping_planes[0]", clip_planes[0]); shader->set_uniform("clipping_planes[1]", clip_planes[1]); + shader->set_uniform("volume_world_matrix", volume_world_matrix); m_model.render(); + if (m_is_ht90) + render_ht90_rods(m_world_position.cast(), shader, view_matrix, bed_inst_offset, m_model_ht90_rod); + shader->stop_using(); if (curr_cull_face) @@ -1204,8 +1288,8 @@ void GCodeViewer::render() m_sequential_view.marker.set_z_offset(m_z_offset); // Following just makes sure that the shown marker is correct. - auto marker_model_opt = wxGetApp().plater()->get_current_canvas3D()->get_current_marker_model(); - m_sequential_view.marker.init(marker_model_opt); + auto [marker_model_opt, is_ht90] = wxGetApp().plater()->get_current_canvas3D()->get_current_marker_model(); + m_sequential_view.marker.init(marker_model_opt, is_ht90); if (marker_model_opt.has_value()) m_max_bounding_box.reset(); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index f37cd8c70d..26efe7a59e 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -115,6 +115,7 @@ public: class Marker { GLModel m_model; + GLModel m_model_ht90_rod; Vec3f m_world_position; // For seams, the position of the marker is on the last endpoint of the toolpath containing it. // This offset is used to show the correct value of tool position in the "ToolPosition" window. @@ -128,14 +129,20 @@ public: bool m_fixed_screen_size{ false }; float m_scale_factor{ 1.0f }; bool m_generic_marker{ true }; + bool m_is_ht90{false}; #if ENABLE_ACTUAL_SPEED_DEBUG ActualSpeedImguiWidget m_actual_speed_imgui_widget; #endif // ENABLE_ACTUAL_SPEED_DEBUG public: - void init(std::optional>& model_opt); + void init(std::optional>& model_opt, bool is_ht90); - const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); } + BoundingBoxf3 get_bounding_box() const { + auto bb = m_model.get_bounding_box(); + if (m_is_ht90) + bb.max.z() += scale_(400); + return bb; + } void set_world_position(const Vec3f& position) { m_world_position = position; } void set_world_offset(const Vec3f& offset) { m_world_offset = offset; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9e91642cd0..3776e41f77 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -162,9 +162,10 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user) // - nullopt = same as before // - nullptr = none available, use generic // - GLModel = the model to use -std::optional> GLCanvas3D::get_current_marker_model() const +// The other field is whether the printer is HT90. +std::pair>, bool> GLCanvas3D::get_current_marker_model() const { - std::optional> out; + auto out = std::make_pair>, bool>(std::nullopt, false); static std::string last_printer_notes; static double old_r = 0.; @@ -182,11 +183,13 @@ std::optional> GLCanvas3D::get_current_marker_model() c old_h = h; old_seq = seq; - out = std::make_optional(nullptr); + out.second = (printer_notes.find("PRINTER_MODEL_HT90") != std::string::npos); + + out.first = std::make_optional(nullptr); if (! seq) return out; try { - boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.txt"); + boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.json"); boost::property_tree::ptree pt; boost::property_tree::read_json(in, pt); for (const auto& printer : pt.get_child("printers")) { @@ -197,7 +200,7 @@ std::optional> GLCanvas3D::get_current_marker_model() c if (boost::filesystem::exists(filename)) { std::unique_ptr m = std::make_unique(); if (m->init_from_file(filename)) - out = std::make_optional(std::move(m)); + out.first = std::make_optional(std::move(m)); } break; } @@ -205,7 +208,7 @@ std::optional> GLCanvas3D::get_current_marker_model() c } catch (...) { // Whatever happened, ignore it. We will return nullptr. } - if (*out == nullptr && seq) { + if (*(out.first) == nullptr && seq) { // Generic sequential extruder model. double gantry_height = 10; auto mesh = its_make_cylinder(r, h + gantry_height - 0.001); @@ -215,7 +218,7 @@ std::optional> GLCanvas3D::get_current_marker_model() c its_merge(mesh, mesh2); std::unique_ptr m = std::make_unique(); m->init_from(mesh); - out = std::make_optional(std::move(m)); + out.first = std::make_optional(std::move(m)); } } return out; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0a75e241bb..dbaacc3666 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -729,7 +729,7 @@ public: const libvgcode::Interval& get_gcode_view_visible_range() const { return m_gcode_viewer.get_gcode_view_visible_range(); } const libvgcode::PathVertex& get_gcode_vertex_at(size_t id) const { return m_gcode_viewer.get_gcode_vertex_at(id); } - std::optional> get_current_marker_model() const; + std::pair>, bool> get_current_marker_model() const; void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1, const ModelVolume* mv = nullptr);