mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 06:49:00 +08:00
SPE-2702: Seq arrange data for HT90, printhead model, extended delta visualization
This commit is contained in:
parent
606d3f1ef4
commit
302a662a50
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
BIN
resources/data/printer_gantries/prusa3d_ht90_actuator.stl
Normal file
BIN
resources/data/printer_gantries/prusa3d_ht90_actuator.stl
Normal file
Binary file not shown.
@ -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")) {
|
||||
|
@ -217,12 +217,13 @@ int GCodeViewer::SequentialView::ActualSpeedImguiWidget::plot(const char* label,
|
||||
}
|
||||
#endif // ENABLE_ACTUAL_SPEED_DEBUG
|
||||
|
||||
void GCodeViewer::SequentialView::Marker::init(std::optional<std::unique_ptr<GLModel>>& model_opt)
|
||||
void GCodeViewer::SequentialView::Marker::init(std::optional<std::unique_ptr<GLModel>>& 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<std::unique_ptr<GLM
|
||||
m_model.set_color({ 1.0f, 1.0f, 1.0f, 0.5f });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// This does not do any scaling!
|
||||
static Transform3d align_cylinder(const Vec3d& p1, const Vec3d& p2, double r) {
|
||||
Vec3d direction = p2 - p1;
|
||||
Vec3d axis = direction.normalized();
|
||||
Vec3d z0(0, 0, 1);
|
||||
Matrix3d rotation;
|
||||
if (axis.isApprox(z0))
|
||||
rotation = Eigen::Matrix3d::Identity(); // Already aligned, use identity rotation
|
||||
else if (axis.isApprox(-z0)) {
|
||||
// 180-degree rotation around x or y (choose any perpendicular axis)
|
||||
rotation = Eigen::AngleAxisd(M_PI, Vec3d(1, 0, 0)).toRotationMatrix();
|
||||
} else {
|
||||
Vec3d rotationAxis = z0.cross(axis);
|
||||
double angle = acos(z0.dot(axis));
|
||||
rotation = Eigen::AngleAxisd(angle, rotationAxis.normalized()).toRotationMatrix();
|
||||
}
|
||||
Transform3d transform = Transform3d::Identity();
|
||||
transform.linear() = rotation;// * Geometry::scale_transform(Vec3d(2*r,2*r,length)).matrix().block<3,3>(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<float>().x() } , { -1.0f, 0.0f, 0.0f, box.max.cast<float>().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<double>(), 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();
|
||||
|
||||
|
@ -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<std::unique_ptr<GLModel>>& model_opt);
|
||||
void init(std::optional<std::unique_ptr<GLModel>>& 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; }
|
||||
|
@ -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<std::unique_ptr<GLModel>> GLCanvas3D::get_current_marker_model() const
|
||||
// The other field is whether the printer is HT90.
|
||||
std::pair<std::optional<std::unique_ptr<GLModel>>, bool> GLCanvas3D::get_current_marker_model() const
|
||||
{
|
||||
std::optional<std::unique_ptr<GLModel>> out;
|
||||
auto out = std::make_pair<std::optional<std::unique_ptr<GLModel>>, bool>(std::nullopt, false);
|
||||
|
||||
static std::string last_printer_notes;
|
||||
static double old_r = 0.;
|
||||
@ -182,11 +183,13 @@ std::optional<std::unique_ptr<GLModel>> 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<std::unique_ptr<GLModel>> GLCanvas3D::get_current_marker_model() c
|
||||
if (boost::filesystem::exists(filename)) {
|
||||
std::unique_ptr<GLModel> m = std::make_unique<GLModel>();
|
||||
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<std::unique_ptr<GLModel>> 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<std::unique_ptr<GLModel>> GLCanvas3D::get_current_marker_model() c
|
||||
its_merge(mesh, mesh2);
|
||||
std::unique_ptr<GLModel> m = std::make_unique<GLModel>();
|
||||
m->init_from(mesh);
|
||||
out = std::make_optional(std::move(m));
|
||||
out.first = std::make_optional(std::move(m));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
@ -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<std::unique_ptr<GLModel>> get_current_marker_model() const;
|
||||
std::pair<std::optional<std::unique_ptr<GLModel>>, 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user