Fix wrong warning info & revert exceeding boundary (#141)

This commit is contained in:
xiaoyeliu
2026-01-26 23:32:52 +08:00
committed by GitHub
parent cf4275198c
commit a9823f19ea
6 changed files with 463 additions and 513 deletions
+2 -3
View File
@@ -4341,9 +4341,8 @@ msgid ""
msgstr "" msgstr ""
msgid "" msgid ""
"An object is too close to the plate boundary. Spiral lift during printing " "Model too close to bed boundary. Disable spiral lifting or keep at least "
"may exceed the bed and cause a crash. Please move the object away from the " "3.5mm gap to avoid collision."
"edge (recommend keeping at least 3mm distance)."
msgstr "" msgstr ""
msgid "Calibration step selection" msgid "Calibration step selection"
@@ -4268,11 +4268,10 @@ msgstr ""
"请通过将其完全移动到构建板内或构建板外,并确认高度在构建空间以内来解决问题。" "请通过将其完全移动到构建板内或构建板外,并确认高度在构建空间以内来解决问题。"
msgid "" msgid ""
"An object is too close to the plate boundary. Spiral lift during printing " "Model too close to bed boundary. Disable spiral lifting or keep at least "
"may exceed the bed and cause a crash. Please move the object away from the " "3.5mm gap to avoid collision."
"edge (recommend keeping at least 3mm distance)."
msgstr "" msgstr ""
"模型距离打印床边界太近。打印过程中的螺旋抬升可能会超出床范围导致撞机。请将模型移离边缘(建议保持至少3mm的距离)。" "模型太靠近热床边界,建议暂时关闭螺旋抬升或至少距离边界3.5mm距离,防止超出打印区域引发撞击。"
msgid "Calibration step selection" msgid "Calibration step selection"
msgstr "校准步骤选择" msgstr "校准步骤选择"
-8
View File
@@ -437,10 +437,6 @@ std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::T
auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f { auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f {
Vec2f out = Eigen::Rotation2Df(alpha) * pt; Vec2f out = Eigen::Rotation2Df(alpha) * pt;
// Simple safety check to prevent extreme out-of-bounds coordinates
// This is a safety net for Rib wall geometry issues
out.x() = std::clamp(out.x(), -50.f, 500.f);
out.y() = std::clamp(out.y(), -50.f, 500.f);
out += m_wipe_tower_pos; out += m_wipe_tower_pos;
return out; return out;
}; };
@@ -701,10 +697,6 @@ std::string WipeTowerIntegration::append_tcr2(GCode& gcodegen, const WipeTower::
auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f { auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f {
Vec2f out = Eigen::Rotation2Df(alpha) * pt; Vec2f out = Eigen::Rotation2Df(alpha) * pt;
// Simple safety check to prevent extreme out-of-bounds coordinates
// This is a safety net for Rib wall geometry issues
out.x() = std::clamp(out.x(), -50.f, 500.f);
out.y() = std::clamp(out.y(), -50.f, 500.f);
out += m_wipe_tower_pos; out += m_wipe_tower_pos;
return out; return out;
}; };
+3 -9
View File
@@ -1237,11 +1237,6 @@ private:
double s = sin(angle); double s = sin(angle);
Vec2f result(float(pt.x() * c - pt.y() * s) + m_wipe_tower_width / 2.f, float(pt.x() * s + pt.y() * c) + m_wipe_tower_depth / 2.f); Vec2f result(float(pt.x() * c - pt.y() * s) + m_wipe_tower_width / 2.f, float(pt.x() * s + pt.y() * c) + m_wipe_tower_depth / 2.f);
// Clamp rotated coordinates to valid range to prevent out-of-bounds positions
// This fixes issues with Rib wall geometry extending beyond expected bounds
result.x() = std::clamp(result.x(), 0.f, m_wipe_tower_width);
result.y() = std::clamp(result.y(), 0.f, m_wipe_tower_depth);
return result; return result;
} }
@@ -1969,10 +1964,9 @@ void WipeTower2::toolchange_Wipe(WipeTowerWriter2& writer, const WipeTower::box_
// We may be going back to the model - wipe the nozzle. If this is followed // We may be going back to the model - wipe the nozzle. If this is followed
// by finish_layer, this wipe path will be overwritten. // by finish_layer, this wipe path will be overwritten.
// Clamp wipe point coordinates to valid range to prevent out-of-bounds positions writer.add_wipe_point(writer.x(), writer.y())
float wipe_y = std::clamp(writer.y() - dy, 0.f, m_wipe_tower_depth); .add_wipe_point(writer.x(), writer.y() - dy)
float wipe_x = std::clamp(!m_left_to_right ? m_wipe_tower_width : 0.f, 0.f, m_wipe_tower_width); .add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy);
writer.add_wipe_point(writer.x(), writer.y()).add_wipe_point(writer.x(), wipe_y).add_wipe_point(wipe_x, wipe_y);
if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool)
m_left_to_right = !m_left_to_right; m_left_to_right = !m_left_to_right;
+161 -193
View File
@@ -51,14 +51,16 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
switch (err) { switch (err) {
case GL_INVALID_ENUM: sErr = "Invalid Enum"; break; case GL_INVALID_ENUM: sErr = "Invalid Enum"; break;
case GL_INVALID_VALUE: sErr = "Invalid Value"; break; case GL_INVALID_VALUE: sErr = "Invalid Value"; break;
// be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin and the corresponding execution of glEnd // be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin and the corresponding
// execution of glEnd
case GL_INVALID_OPERATION: sErr = "Invalid Operation"; break; case GL_INVALID_OPERATION: sErr = "Invalid Operation"; break;
case GL_STACK_OVERFLOW: sErr = "Stack Overflow"; break; case GL_STACK_OVERFLOW: sErr = "Stack Overflow"; break;
case GL_STACK_UNDERFLOW: sErr = "Stack Underflow"; break; case GL_STACK_UNDERFLOW: sErr = "Stack Underflow"; break;
case GL_OUT_OF_MEMORY: sErr = "Out Of Memory"; break; case GL_OUT_OF_MEMORY: sErr = "Out Of Memory"; break;
default: sErr = "Unknown"; break; default: sErr = "Unknown"; break;
} }
BOOST_LOG_TRIVIAL(error) << "OpenGL error in " << file_name << ":" << line << ", function " << function_name << "() : " << (int)err << " - " << sErr; BOOST_LOG_TRIVIAL(error) << "OpenGL error in " << file_name << ":" << line << ", function " << function_name << "() : " << (int) err
<< " - " << sErr;
assert(false); assert(false);
} }
#endif // HAS_GLSAFE #endif // HAS_GLSAFE
@@ -94,17 +96,14 @@ Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors)
{ {
if (colors.a() < FullyTransparentMaterialThreshold) { // completely transparent if (colors.a() < FullyTransparentMaterialThreshold) { // completely transparent
return {1, 1, 1, FullTransparentModdifiedToFixAlpha}; return {1, 1, 1, FullTransparentModdifiedToFixAlpha};
} } else if (colors.r() < FULL_BLACK_THRESHOLD && colors.g() < FULL_BLACK_THRESHOLD && colors.b() < FULL_BLACK_THRESHOLD) { // black
else if(colors.r() < FULL_BLACK_THRESHOLD && colors.g() < FULL_BLACK_THRESHOLD && colors.b() < FULL_BLACK_THRESHOLD) { // black
return {FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, colors.a()}; return {FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, FULL_BLACK_THRESHOLD, colors.a()};
} } else
else
return colors; return colors;
} }
namespace Slic3r { namespace Slic3r {
const float GLVolume::SinkingContours::HalfWidth = 0.25f; const float GLVolume::SinkingContours::HalfWidth = 0.25f;
void GLVolume::SinkingContours::render() void GLVolume::SinkingContours::render()
@@ -154,11 +153,9 @@ void GLVolume::SinkingContours::update()
} }
} }
m_model.init_from(std::move(init_data)); m_model.init_from(std::move(init_data));
} } else
else
m_shift = box.center() - m_old_box.center(); m_shift = box.center() - m_old_box.center();
} } else
else
m_model.reset(); m_model.reset();
} }
@@ -176,13 +173,8 @@ ColorRGBA GLVolume::SUPPORT_BLOCKER_COL = {1.0f, 0.3f, 0.3f, 0.4f};
ColorRGBA GLVolume::MODEL_HIDDEN_COL = {0.f, 0.f, 0.f, 0.3f}; ColorRGBA GLVolume::MODEL_HIDDEN_COL = {0.f, 0.f, 0.f, 0.3f};
std::array<ColorRGBA, 5> GLVolume::MODEL_COLOR = { { std::array<ColorRGBA, 5> GLVolume::MODEL_COLOR = {
{ 1.0f, 1.0f, 0.0f, 1.f }, {{1.0f, 1.0f, 0.0f, 1.f}, {1.0f, 0.5f, 0.5f, 1.f}, {0.5f, 1.0f, 0.5f, 1.f}, {0.5f, 0.5f, 1.0f, 1.f}, {1.0f, 1.0f, 0.0f, 1.f}}};
{ 1.0f, 0.5f, 0.5f, 1.f },
{ 0.5f, 1.0f, 0.5f, 1.f },
{ 0.5f, 0.5f, 1.0f, 1.f },
{ 1.0f, 1.0f, 0.0f, 1.f }
} };
void GLVolume::update_render_colors() void GLVolume::update_render_colors()
{ {
@@ -193,7 +185,6 @@ void GLVolume::update_render_colors()
GLVolume::MODEL_COLOR[2] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Enforcer]); GLVolume::MODEL_COLOR[2] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Enforcer]);
GLVolume::MODEL_COLOR[3] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Blocker]); GLVolume::MODEL_COLOR[3] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Blocker]);
GLVolume::UNPRINTABLE_COLOR = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Model_Unprintable]); GLVolume::UNPRINTABLE_COLOR = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Model_Unprintable]);
} }
void GLVolume::load_render_colors() void GLVolume::load_render_colors()
@@ -238,7 +229,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
mmuseg_ts = 0; mmuseg_ts = 0;
} }
// BBS // BBS
float GLVolume::explosion_ratio = 1.0; float GLVolume::explosion_ratio = 1.0;
float GLVolume::last_explosion_ratio = 1.0; float GLVolume::last_explosion_ratio = 1.0;
@@ -260,8 +250,7 @@ void GLVolume::set_render_color()
#ifdef ENABLE_OUTSIDE_COLOR #ifdef ENABLE_OUTSIDE_COLOR
} }
#endif #endif
} } else {
else {
/* BBS /* BBS
if (hover == HS_Select) if (hover == HS_Select)
set_render_color(HOVER_SELECT_COLOR); set_render_color(HOVER_SELECT_COLOR);
@@ -362,9 +351,7 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d& trafo) const BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d& trafo) const
{ {
return (m_convex_hull && ! m_convex_hull->empty()) ? return (m_convex_hull && !m_convex_hull->empty()) ? m_convex_hull->transformed_bounding_box(trafo) : bounding_box().transformed(trafo);
m_convex_hull->transformed_bounding_box(trafo) :
bounding_box().transformed(trafo);
} }
BoundingBoxf3 GLVolume::transformed_non_sinking_bounding_box(const Transform3d& trafo) const BoundingBoxf3 GLVolume::transformed_non_sinking_bounding_box(const Transform3d& trafo) const
@@ -395,7 +382,8 @@ void GLVolume::set_range(double min_z, double max_z)
else { else {
// Then find the lowest layer to be displayed. // Then find the lowest layer to be displayed.
size_t i = 0; size_t i = 0;
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i); for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i)
;
if (i == this->print_zs.size()) if (i == this->print_zs.size())
// This shall not happen. // This shall not happen.
this->tverts_range.second = 0; this->tverts_range.second = 0;
@@ -403,7 +391,8 @@ void GLVolume::set_range(double min_z, double max_z)
// Remember start of the layer. // Remember start of the layer.
this->tverts_range.first = this->offsets[i]; this->tverts_range.first = this->offsets[i];
// Some layers are above $min_z. Which? // Some layers are above $min_z. Which?
for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i); for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i)
;
if (i < this->print_zs.size()) if (i < this->print_zs.size())
this->tverts_range.second = this->offsets[i]; this->tverts_range.second = this->offsets[i];
} }
@@ -460,7 +449,8 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT,
GL_FLOAT, nullptr));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0)); glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0));
} else { } else {
@@ -474,7 +464,8 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr)); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT,
GL_FLOAT, nullptr));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0)); glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0));
} }
@@ -515,7 +506,10 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
} }
// BBS add render for simple case // BBS add render for simple case
void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA>& extruder_colors, bool ban_light) void GLVolume::simple_render(GLShaderProgram* shader,
ModelObjectPtrs& model_objects,
std::vector<ColorRGBA>& extruder_colors,
bool ban_light)
{ {
if (this->is_left_handed()) if (this->is_left_handed())
glFrontFace(GL_CW); glFrontFace(GL_CW);
@@ -573,8 +567,7 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
} }
m.set_color(new_color); m.set_color(new_color);
// shader->set_uniform("uniform_color", new_color); // shader->set_uniform("uniform_color", new_color);
} } else {
else {
if (idx <= extruder_colors.size()) { if (idx <= extruder_colors.size()) {
// to make black not too hard too see // to make black not too hard too see
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]);
@@ -583,8 +576,7 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
} }
m.set_color(new_color); m.set_color(new_color);
// shader->set_uniform("uniform_color", new_color); // shader->set_uniform("uniform_color", new_color);
} } else {
else {
// to make black not too hard too see // to make black not too hard too see
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]);
if (ban_light) { if (ban_light) {
@@ -621,21 +613,11 @@ bool GLVolume::is_sinking() const
return box.min.z() < SINKING_Z_THRESHOLD && box.max.z() >= SINKING_Z_THRESHOLD; return box.min.z() < SINKING_Z_THRESHOLD && box.max.z() >= SINKING_Z_THRESHOLD;
} }
bool GLVolume::is_below_printbed() const bool GLVolume::is_below_printbed() const { return transformed_convex_hull_bounding_box().max.z() < 0.0; }
{
return transformed_convex_hull_bounding_box().max.z() < 0.0;
}
void GLVolume::render_sinking_contours() void GLVolume::render_sinking_contours() { m_sinking_contours.render(); }
{
m_sinking_contours.render();
}
GLWipeTowerVolume::GLWipeTowerVolume(const std::vector<ColorRGBA>& colors) GLWipeTowerVolume::GLWipeTowerVolume(const std::vector<ColorRGBA>& colors) : GLVolume() { m_colors = colors; }
: GLVolume()
{
m_colors = colors;
}
void GLWipeTowerVolume::render() void GLWipeTowerVolume::render()
{ {
@@ -663,7 +645,8 @@ void GLWipeTowerVolume::render()
glFrontFace(GL_CCW); glFrontFace(GL_CCW);
} }
bool GLWipeTowerVolume::IsTransparent() { bool GLWipeTowerVolume::IsTransparent()
{
for (size_t i = 0; i < m_colors.size(); i++) { for (size_t i = 0; i < m_colors.size(); i++) {
if (m_colors[i].is_transparent()) { if (m_colors[i].is_transparent()) {
return true; return true;
@@ -672,8 +655,7 @@ bool GLWipeTowerVolume::IsTransparent() {
return false; return false;
} }
std::vector<int> GLVolumeCollection::load_object( std::vector<int> GLVolumeCollection::load_object(const ModelObject* model_object,
const ModelObject *model_object,
int obj_idx, int obj_idx,
const std::vector<int>& instance_idxs, const std::vector<int>& instance_idxs,
const std::string& color_by, const std::string& color_by,
@@ -683,13 +665,12 @@ std::vector<int> GLVolumeCollection::load_object(
std::vector<int> volumes_idx; std::vector<int> volumes_idx;
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
for (int instance_idx : instance_idxs) for (int instance_idx : instance_idxs)
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized, false, false, need_raycaster)); volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by,
opengl_initialized, false, false, need_raycaster));
return volumes_idx; return volumes_idx;
} }
int GLVolumeCollection::load_object_volume(const ModelObject* model_object,
int GLVolumeCollection::load_object_volume(
const ModelObject *model_object,
int obj_idx, int obj_idx,
int volume_idx, int volume_idx,
int instance_idx, int instance_idx,
@@ -715,12 +696,13 @@ int GLVolumeCollection::load_object_volume(
v.model.init_from(mesh, true); v.model.init_from(mesh, true);
#else #else
v.model.init_from(*mesh); v.model.init_from(*mesh);
if (need_raycaster) { v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh); } if (need_raycaster) {
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
}
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
if (model_volume->is_model_part()) if (model_volume->is_model_part()) {
{
// GLVolume will reference a convex hull from model_volume! // GLVolume will reference a convex hull from model_volume!
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
if (extruder_id != -1) if (extruder_id != -1)
@@ -731,8 +713,7 @@ int GLVolumeCollection::load_object_volume(
if (in_assemble_view) { if (in_assemble_view) {
v.set_instance_transformation(instance->get_assemble_transformation()); v.set_instance_transformation(instance->get_assemble_transformation());
v.set_offset_to_assembly(instance->get_offset_to_assembly()); v.set_offset_to_assembly(instance->get_offset_to_assembly());
} } else
else
v.set_instance_transformation(instance->get_transformation()); v.set_instance_transformation(instance->get_transformation());
v.set_volume_transformation(model_volume->get_transformation()); v.set_volume_transformation(model_volume->get_transformation());
// use object's instance id // use object's instance id
@@ -747,8 +728,7 @@ int GLVolumeCollection::load_object_volume(
// Load SLA auxiliary GLVolumes (for support trees or pad). // Load SLA auxiliary GLVolumes (for support trees or pad).
// This function produces volumes for multiple instances in a single shot, // This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive. // as some object specific mesh conversions may be expensive.
void GLVolumeCollection::load_object_auxiliary( void GLVolumeCollection::load_object_auxiliary(const SLAPrintObject* print_object,
const SLAPrintObject* print_object,
int obj_idx, int obj_idx,
// pairs of <instance_idx, print_instance_idx> // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, const std::vector<std::pair<size_t, size_t>>& instances,
@@ -790,8 +770,7 @@ void GLVolumeCollection::load_object_auxiliary(
} }
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width)
float rotation_angle, bool size_unknown, float brim_width)
{ {
int plate_idx = obj_idx - 1000; int plate_idx = obj_idx - 1000;
@@ -851,7 +830,10 @@ GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba)
return out; return out;
} }
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes,
GLVolumeCollection::ERenderType type,
const Transform3d& view_matrix,
std::function<bool(const GLVolume&)> filter_func)
{ {
GLVolumeWithIdAndZList list; GLVolumeWithIdAndZList list;
list.reserve(volumes.size()); list.reserve(volumes.size());
@@ -864,8 +846,7 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
is_transparent = tempGlwipeTowerVolume->IsTransparent(); is_transparent = tempGlwipeTowerVolume->IsTransparent();
} }
if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) || if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) ||
(type == GLVolumeCollection::ERenderType::Transparent && is_transparent) || (type == GLVolumeCollection::ERenderType::Transparent && is_transparent) || type == GLVolumeCollection::ERenderType::All) &&
type == GLVolumeCollection::ERenderType::All) &&
(!filter_func || filter_func(*volume))) (!filter_func || filter_func(*volume)))
list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0))); list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0)));
} }
@@ -876,13 +857,11 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
} }
std::sort(list.begin(), list.end(), std::sort(list.begin(), list.end(),
[](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.second.second < v2.second.second; } [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.second.second < v2.second.second; });
); } else if (type == GLVolumeCollection::ERenderType::Opaque && list.size() > 1) {
} std::sort(list.begin(), list.end(), [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool {
else if (type == GLVolumeCollection::ERenderType::Opaque && list.size() > 1) { return v1.first->selected && !v2.first->selected;
std::sort(list.begin(), list.end(), });
[](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.first->selected && !v2.first->selected; }
);
} }
return list; return list;
@@ -945,8 +924,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
if (sink_shader != nullptr) { if (sink_shader != nullptr) {
sink_shader->start_using(); sink_shader->start_using();
if (m_show_sinking_contours) { if (m_show_sinking_contours) {
if (volume.first->is_sinking() && !volume.first->is_below_printbed() && if (volume.first->is_sinking() && !volume.first->is_below_printbed() && volume.first->hover == GLVolume::HS_None &&
volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { !volume.first->force_sinking_contours) {
volume.first->render_sinking_contours(); volume.first->render_sinking_contours();
} }
} }
@@ -976,8 +955,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type)); shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
shader->set_uniform("print_volume.xy_data", m_print_volume.data); shader->set_uniform("print_volume.xy_data", m_print_volume.data);
shader->set_uniform("print_volume.z_data", m_print_volume.zs); shader->set_uniform("print_volume.z_data", m_print_volume.zs);
} } else {
else {
// use -1 ad a invalid type // use -1 ad a invalid type
shader->set_uniform("print_volume.type", -1); shader->set_uniform("print_volume.type", -1);
} }
@@ -989,7 +967,9 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower); shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower);
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>())); shader->set_uniform("slope.volume_world_normal_matrix",
static_cast<Matrix3f>(
volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
shader->set_uniform("slope.normal_z", normal_z); shader->set_uniform("slope.normal_z", normal_z);
#if ENABLE_ENVIRONMENT_MAP #if ENABLE_ENVIRONMENT_MAP
@@ -1005,7 +985,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
const Transform3d model_matrix = volume.first->world_matrix(); const Transform3d model_matrix = volume.first->world_matrix();
shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
shader->set_uniform("projection_matrix", projection_matrix); shader->set_uniform("projection_matrix", projection_matrix);
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) *
model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
shader->set_uniform("view_normal_matrix", view_normal_matrix); shader->set_uniform("view_normal_matrix", view_normal_matrix);
// BBS: add outline related logic // BBS: add outline related logic
if (volume.first->selected && GUI::wxGetApp().show_outline()) if (volume.first->selected && GUI::wxGetApp().show_outline())
@@ -1049,25 +1030,28 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
bool GLVolumeCollection::check_outside_state(const BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const bool GLVolumeCollection::check_outside_state(const BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const
{ {
if (GUI::wxGetApp().plater() == NULL) if (GUI::wxGetApp().plater() == NULL) {
{
if (out_state != nullptr) if (out_state != nullptr)
*out_state = ModelInstancePVS_Inside; *out_state = ModelInstancePVS_Inside;
return false; return false;
} }
const Model& model = GUI::wxGetApp().plater()->model(); const Model& model = GUI::wxGetApp().plater()->model();
auto volume_below = [](GLVolume& volume) -> bool auto volume_below = [](GLVolume& volume) -> bool {
{ return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed(); }; return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed();
};
// Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used. // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used.
auto volume_sinking = [](GLVolume& volume) -> bool auto volume_sinking = [](GLVolume& volume) -> bool {
{ return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking(); }; return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking();
};
// Cached bounding box of a volume above the print bed. // Cached bounding box of a volume above the print bed.
auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 {
{ return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box();
};
// Cached 3D convex hull of a volume above the print bed. // Cached 3D convex hull of a volume above the print bed.
auto volume_convex_mesh = [volume_sinking, &model](GLVolume& volume) -> const TriangleMesh& auto volume_convex_mesh = [volume_sinking, &model](GLVolume& volume) -> const TriangleMesh& {
{ return volume_sinking(volume) ? model.objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull(); }; return volume_sinking(volume) ? model.objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull();
};
ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside;
bool contained_min_one = false; bool contained_min_one = false;
@@ -1080,9 +1064,13 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height()); BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height());
const std::vector<BoundingBoxf3>& exclude_areas = curr_plate->get_exclude_areas(); const std::vector<BoundingBoxf3>& exclude_areas = curr_plate->get_exclude_areas();
for (GLVolume* volume : this->volumes) for (GLVolume* volume : this->volumes) {
{ // Snapmaker: 初始化螺旋抬升边界状态(在循环开始时就清除所有标志)
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { if (volume != nullptr)
volume->near_boundary_for_spiral_lift = false;
if (!volume->is_modifier &&
(volume->shader_outside_printer_detection_enabled || (!volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
BuildVolume::ObjectState state; BuildVolume::ObjectState state;
if (volume_below(*volume)) if (volume_below(*volume))
state = BuildVolume::ObjectState::Below; state = BuildVolume::ObjectState::Below;
@@ -1092,13 +1080,13 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
// FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. // FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects.
const BoundingBoxf3& bb = volume_bbox(*volume); const BoundingBoxf3& bb = volume_bbox(*volume);
state = plate_build_volume.volume_state_bbox(bb); state = plate_build_volume.volume_state_bbox(bb);
} } break;
break;
case BuildVolume_Type::Circle: case BuildVolume_Type::Circle:
case BuildVolume_Type::Convex: case BuildVolume_Type::Convex:
// FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. // FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case BuildVolume_Type::Custom: case BuildVolume_Type::Custom:
state = plate_build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast<float>(), volume_sinking(*volume)); state = plate_build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast<float>(),
volume_sinking(*volume));
break; break;
default: default:
// Ignore, don't produce any collision. // Ignore, don't produce any collision.
@@ -1112,24 +1100,21 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
volume->is_outside = state != BuildVolume::ObjectState::Inside; volume->is_outside = state != BuildVolume::ObjectState::Inside;
// Snapmaker: 检测模型是否距离床边界太近(螺旋抬升风险) // Snapmaker: 检测模型是否距离床边界太近(螺旋抬升风险)
volume->near_boundary_for_spiral_lift = false; // 只对矩形床进行检测(Snapmaker U1),只检测可打印的对象
// 只对矩形床进行检测(Snapmaker U1) // 只检测完全在床内的对象(state == Inside),避免对跨越边界的对象误报
if (plate_build_volume.type() == BuildVolume_Type::Rectangle && volume->composite_id.volume_id >= 0) { if (plate_build_volume.type() == BuildVolume_Type::Rectangle && volume->composite_id.volume_id >= 0 &&
state == BuildVolume::ObjectState::Inside && volume->printable) {
constexpr double SPIRAL_LIFT_SAFETY_MARGIN = 3.5; // mm constexpr double SPIRAL_LIFT_SAFETY_MARGIN = 3.5; // mm
const BoundingBoxf3& bb = volume_bbox(*volume); const BoundingBoxf3& bb = volume_bbox(*volume);
const BoundingBoxf3& bed_bb = plate_build_volume.bounding_volume(); const BoundingBoxf3& bed_bb = plate_build_volume.bounding_volume();
// 计算模型边界框与床边界的最小距离(使用绝对值处理超出边界的情况) // 计算模型边界框与床边界的最小距离
double min_distance_x = std::min({ double dist_left = std::abs(bb.min.x() - bed_bb.min.x());
std::abs(bb.min.x() - bed_bb.min.x()), double dist_right = std::abs(bed_bb.max.x() - bb.max.x());
std::abs(bed_bb.max.x() - bb.max.x()) double dist_bottom = std::abs(bb.min.y() - bed_bb.min.y());
}); double dist_top = std::abs(bed_bb.max.y() - bb.max.y());
double min_distance_y = std::min({
std::abs(bb.min.y() - bed_bb.min.y()),
std::abs(bed_bb.max.y() - bb.max.y())
});
double min_distance = std::min({min_distance_x, min_distance_y}); double min_distance = std::min({dist_left, dist_right, dist_bottom, dist_top});
// 如果最小距离小于安全余量,触发警告 // 如果最小距离小于安全余量,触发警告
if (min_distance < SPIRAL_LIFT_SAFETY_MARGIN) { if (min_distance < SPIRAL_LIFT_SAFETY_MARGIN) {
volume->near_boundary_for_spiral_lift = true; volume->near_boundary_for_spiral_lift = true;
@@ -1142,8 +1127,8 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
overall_state = ModelInstancePVS_Fully_Outside; overall_state = ModelInstancePVS_Fully_Outside;
} }
if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && (state == BuildVolume::ObjectState::Colliding)) if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside &&
{ (state == BuildVolume::ObjectState::Colliding)) {
overall_state = ModelInstancePVS_Partly_Outside; overall_state = ModelInstancePVS_Partly_Outside;
} }
contained_min_one |= !volume->is_outside; contained_min_one |= !volume->is_outside;
@@ -1158,20 +1143,15 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
else else
volume_state = ModelInstancePVS_Inside; volume_state = ModelInstancePVS_Inside;
if (model_state.find(comp_id) != model_state.end()) if (model_state.find(comp_id) != model_state.end()) {
{ if (model_state[comp_id] != ModelInstancePVS_Partly_Outside) {
if (model_state[comp_id] != ModelInstancePVS_Partly_Outside)
{
if (volume_state == ModelInstancePVS_Partly_Outside) if (volume_state == ModelInstancePVS_Partly_Outside)
model_state[comp_id] = ModelInstancePVS_Partly_Outside; model_state[comp_id] = ModelInstancePVS_Partly_Outside;
else if (model_state[comp_id] != volume_state) else if (model_state[comp_id] != volume_state) {
{
model_state[comp_id] = ModelInstancePVS_Partly_Outside; model_state[comp_id] = ModelInstancePVS_Partly_Outside;
} }
} }
} } else {
else
{
model_state[comp_id] = volume_state; model_state[comp_id] = volume_state;
} }
@@ -1182,17 +1162,14 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
} }
} }
for (GLVolume* volume : this->volumes) for (GLVolume* volume : this->volumes) {
{ if (!volume->is_modifier &&
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) (volume->shader_outside_printer_detection_enabled || (!volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
{
int64_t comp_id = ((int64_t) volume->composite_id.object_id << 32) | ((int64_t) volume->composite_id.instance_id); int64_t comp_id = ((int64_t) volume->composite_id.object_id << 32) | ((int64_t) volume->composite_id.instance_id);
if (model_state.find(comp_id) != model_state.end()) if (model_state.find(comp_id) != model_state.end()) {
{
if (model_state[comp_id] == ModelInstancePVS_Partly_Outside) { if (model_state[comp_id] == ModelInstancePVS_Partly_Outside) {
volume->partly_inside = true; volume->partly_inside = true;
} } else
else
volume->partly_inside = false; volume->partly_inside = false;
} }
} }
@@ -1206,8 +1183,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
void GLVolumeCollection::reset_outside_state() void GLVolumeCollection::reset_outside_state()
{ {
for (GLVolume* volume : this->volumes) for (GLVolume* volume : this->volumes) {
{
if (volume != nullptr) { if (volume != nullptr) {
volume->is_outside = false; volume->is_outside = false;
volume->partly_inside = false; volume->partly_inside = false;
@@ -1219,8 +1195,7 @@ void GLVolumeCollection::reset_outside_state()
// Snapmaker: 检查是否有任何 volume 靠近边界(螺旋抬升风险) // Snapmaker: 检查是否有任何 volume 靠近边界(螺旋抬升风险)
bool GLVolumeCollection::is_any_volume_near_boundary_for_spiral_lift() const bool GLVolumeCollection::is_any_volume_near_boundary_for_spiral_lift() const
{ {
for (const GLVolume* volume : this->volumes) for (const GLVolume* volume : this->volumes) {
{
if (volume != nullptr && volume->near_boundary_for_spiral_lift) if (volume != nullptr && volume->near_boundary_for_spiral_lift)
return true; return true;
} }
@@ -1229,7 +1204,6 @@ bool GLVolumeCollection::is_any_volume_near_boundary_for_spiral_lift() const
void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config, bool is_update_alpha) void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config, bool is_update_alpha)
{ {
using ColorItem = std::pair<std::string, ColorRGBA>; using ColorItem = std::pair<std::string, ColorRGBA>;
std::vector<ColorItem> colors; std::vector<ColorItem> colors;
@@ -1240,8 +1214,7 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig *con
ColorRGBA rgba; ColorRGBA rgba;
if (decode_color(txt_color, rgba)) if (decode_color(txt_color, rgba))
colors.push_back({txt_color, rgba}); colors.push_back({txt_color, rgba});
} } else {
else {
const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("filament_colour")); const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("filament_colour"));
if (filamemts_opt == nullptr) if (filamemts_opt == nullptr)
return; return;
@@ -1294,8 +1267,7 @@ std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) c
{ {
// Collect layer top positions of all volumes. // Collect layer top positions of all volumes.
std::vector<double> print_zs; std::vector<double> print_zs;
for (GLVolume *vol : this->volumes) for (GLVolume* vol : this->volumes) {
{
if (!active_only || vol->is_active) if (!active_only || vol->is_active)
append(print_zs, vol->print_zs); append(print_zs, vol->print_zs);
} }
@@ -1307,7 +1279,8 @@ std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) c
for (int i = 0; i < n;) { for (int i = 0; i < n;) {
int j = i + 1; int j = i + 1;
coordf_t zmax = print_zs[i] + EPSILON; coordf_t zmax = print_zs[i] + EPSILON;
for (; j < n && print_zs[j] <= zmax; ++ j) ; for (; j < n && print_zs[j] <= zmax; ++j)
;
print_zs[k++] = (j > i + 1) ? (0.5 * (print_zs[i] + print_zs[j - 1])) : print_zs[i]; print_zs[k++] = (j > i + 1) ? (0.5 * (print_zs[i] + print_zs[j - 1])) : print_zs[i];
i = j; i = j;
} }
@@ -1335,11 +1308,11 @@ size_t GLVolumeCollection::gpu_memory_used() const
std::string GLVolumeCollection::log_memory_info() const std::string GLVolumeCollection::log_memory_info() const
{ {
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")"; return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) +
" GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
} }
static void thick_lines_to_geometry( static void thick_lines_to_geometry(const Lines& lines,
const Lines& lines,
const std::vector<double>& widths, const std::vector<double>& widths,
const std::vector<double>& heights, const std::vector<double>& heights,
bool closed, bool closed,
@@ -1350,13 +1323,7 @@ static void thick_lines_to_geometry(
if (lines.empty()) if (lines.empty())
return; return;
enum Direction : unsigned char enum Direction : unsigned char { Left, Right, Top, Bottom };
{
Left,
Right,
Top,
Bottom
};
// right, left, top, bottom // right, left, top, bottom
std::array<int, 4> idx_prev = {-1, -1, -1, -1}; std::array<int, 4> idx_prev = {-1, -1, -1, -1};
@@ -1421,8 +1388,7 @@ static void thick_lines_to_geometry(
if (is_first) { if (is_first) {
idx_a[Top] = idx_last++; idx_a[Top] = idx_last++;
geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f)); geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
} } else
else
idx_a[Top] = idx_prev[Top]; idx_a[Top] = idx_prev[Top];
if (is_first || bottom_z_different) { if (is_first || bottom_z_different) {
@@ -1433,8 +1399,7 @@ static void thick_lines_to_geometry(
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
idx_a[Right] = idx_last++; idx_a[Right] = idx_last++;
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
} } else
else
idx_a[Bottom] = idx_prev[Bottom]; idx_a[Bottom] = idx_prev[Bottom];
if (is_first) { if (is_first) {
@@ -1442,8 +1407,7 @@ static void thick_lines_to_geometry(
width_initial = width; width_initial = width;
bottom_z_initial = bottom_z; bottom_z_initial = bottom_z;
idx_initial = idx_a; idx_initial = idx_a;
} } else {
else {
// Continuing a previous segment. // Continuing a previous segment.
// Share left / right vertices if possible. // Share left / right vertices if possible.
const double v_dot = v_prev.dot(v); const double v_dot = v_prev.dot(v);
@@ -1457,7 +1421,8 @@ static void thick_lines_to_geometry(
const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold);
if (sharp) { if (sharp) {
if (!bottom_z_different) { if (!bottom_z_different) {
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. // Allocate new left / right points for the start of this segment as these points will receive their own normals to
// indicate a sharp turn.
idx_a[Right] = idx_last++; idx_a[Right] = idx_last++;
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
idx_a[Left] = idx_last++; idx_a[Left] = idx_last++;
@@ -1466,15 +1431,13 @@ static void thick_lines_to_geometry(
// Right turn. Fill in the right turn wedge. // Right turn. Fill in the right turn wedge.
geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
} } else {
else {
// Left turn. Fill in the left turn wedge. // Left turn. Fill in the left turn wedge.
geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
} }
} }
} } else {
else {
if (!bottom_z_different) { if (!bottom_z_different) {
// The two successive segments are nearly collinear. // The two successive segments are nearly collinear.
idx_a[Left] = idx_prev[Left]; idx_a[Left] = idx_prev[Left];
@@ -1485,8 +1448,10 @@ static void thick_lines_to_geometry(
if (!sharp) { if (!sharp) {
if (!bottom_z_different) { if (!bottom_z_different) {
// Closing a loop with smooth transition. Unify the closing left / right vertices. // Closing a loop with smooth transition. Unify the closing left / right vertices.
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]),
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); geometry.extract_normal_3(idx_prev[Left]));
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]),
geometry.extract_normal_3(idx_prev[Right]));
geometry.remove_vertex(geometry.vertices_count() - 1); geometry.remove_vertex(geometry.vertices_count() - 1);
geometry.remove_vertex(geometry.vertices_count() - 1); geometry.remove_vertex(geometry.vertices_count() - 1);
// Replace the left / right vertex indices to point to the start of the loop. // Replace the left / right vertex indices to point to the start of the loop.
@@ -1567,8 +1532,7 @@ static void thick_lines_to_geometry(
} }
// caller is responsible for supplying NO lines with zero length // caller is responsible for supplying NO lines with zero length
static void thick_lines_to_geometry( static void thick_lines_to_geometry(const Lines3& lines,
const Lines3& lines,
const std::vector<double>& widths, const std::vector<double>& widths,
const std::vector<double>& heights, const std::vector<double>& heights,
bool closed, bool closed,
@@ -1578,13 +1542,7 @@ static void thick_lines_to_geometry(
if (lines.empty()) if (lines.empty())
return; return;
enum Direction : unsigned char enum Direction : unsigned char { Left, Right, Top, Bottom };
{
Left,
Right,
Top,
Bottom
};
// left, right, top, bottom // left, right, top, bottom
std::array<int, 4> idx_prev = {-1, -1, -1, -1}; std::array<int, 4> idx_prev = {-1, -1, -1, -1};
@@ -1623,8 +1581,7 @@ static void thick_lines_to_geometry(
n_right = Vec3d::UnitX(); n_right = Vec3d::UnitX();
if (line.a.z() < line.b.z()) if (line.a.z() < line.b.z())
n_right = -n_right; n_right = -n_right;
} } else {
else {
// horizontal segment // horizontal segment
n_right = unit_v.cross(Vec3d::UnitZ()).normalized(); n_right = unit_v.cross(Vec3d::UnitZ()).normalized();
n_top = n_right.cross(unit_v).normalized(); n_top = n_right.cross(unit_v).normalized();
@@ -1658,8 +1615,7 @@ static void thick_lines_to_geometry(
if (ii == 0) { if (ii == 0) {
idx_a[Top] = idx_last++; idx_a[Top] = idx_last++;
geometry.add_vertex((Vec3f) a[Top].cast<float>(), (Vec3f) n_top.cast<float>()); geometry.add_vertex((Vec3f) a[Top].cast<float>(), (Vec3f) n_top.cast<float>());
} } else
else
idx_a[Top] = idx_prev[Top]; idx_a[Top] = idx_prev[Top];
if (ii == 0 || z_different) { if (ii == 0 || z_different) {
@@ -1670,16 +1626,14 @@ static void thick_lines_to_geometry(
geometry.add_vertex((Vec3f) a[Left].cast<float>(), (Vec3f) n_left.cast<float>()); geometry.add_vertex((Vec3f) a[Left].cast<float>(), (Vec3f) n_left.cast<float>());
idx_a[Right] = idx_last++; idx_a[Right] = idx_last++;
geometry.add_vertex((Vec3f) a[Right].cast<float>(), (Vec3f) n_right.cast<float>()); geometry.add_vertex((Vec3f) a[Right].cast<float>(), (Vec3f) n_right.cast<float>());
} } else
else
idx_a[Bottom] = idx_prev[Bottom]; idx_a[Bottom] = idx_prev[Bottom];
if (ii == 0) { if (ii == 0) {
// Start of the 1st line segment. // Start of the 1st line segment.
width_initial = width; width_initial = width;
idx_initial = idx_a; idx_initial = idx_a;
} } else {
else {
// Continuing a previous segment. // Continuing a previous segment.
// Share left / right vertices if possible. // Share left / right vertices if possible.
const double v_dot = unit_v_prev.dot(unit_v); const double v_dot = unit_v_prev.dot(unit_v);
@@ -1694,7 +1648,8 @@ static void thick_lines_to_geometry(
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met // Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold; const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold;
if (is_sharp) { if (is_sharp) {
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate
// a sharp turn.
idx_a[Right] = idx_last++; idx_a[Right] = idx_last++;
geometry.add_vertex((Vec3f) a[Right].cast<float>(), (Vec3f) n_right.cast<float>()); geometry.add_vertex((Vec3f) a[Right].cast<float>(), (Vec3f) n_right.cast<float>());
idx_a[Left] = idx_last++; idx_a[Left] = idx_last++;
@@ -1704,14 +1659,12 @@ static void thick_lines_to_geometry(
// Right turn. Fill in the right turn wedge. // Right turn. Fill in the right turn wedge.
geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
} } else {
else {
// Left turn. Fill in the left turn wedge. // Left turn. Fill in the left turn wedge.
geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
} }
} } else {
else {
// The two successive segments are nearly collinear. // The two successive segments are nearly collinear.
idx_a[Left] = idx_prev[Left]; idx_a[Left] = idx_prev[Left];
idx_a[Right] = idx_prev[Right]; idx_a[Right] = idx_prev[Right];
@@ -1720,8 +1673,10 @@ static void thick_lines_to_geometry(
if (ii == lines.size()) { if (ii == lines.size()) {
if (!is_sharp) { if (!is_sharp) {
// Closing a loop with smooth transition. Unify the closing left / right vertices. // Closing a loop with smooth transition. Unify the closing left / right vertices.
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]),
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); geometry.extract_normal_3(idx_prev[Left]));
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]),
geometry.extract_normal_3(idx_prev[Right]));
geometry.remove_vertex(geometry.vertices_count() - 1); geometry.remove_vertex(geometry.vertices_count() - 1);
geometry.remove_vertex(geometry.vertices_count() - 1); geometry.remove_vertex(geometry.vertices_count() - 1);
// Replace the left / right vertex indices to point to the start of the loop. // Replace the left / right vertex indices to point to the start of the loop.
@@ -1797,8 +1752,7 @@ static void thick_lines_to_geometry(
} }
} }
void _3DScene::thick_lines_to_verts( void _3DScene::thick_lines_to_verts(const Lines& lines,
const Lines& lines,
const std::vector<double>& widths, const std::vector<double>& widths,
const std::vector<double>& heights, const std::vector<double>& heights,
bool closed, bool closed,
@@ -1808,8 +1762,7 @@ void _3DScene::thick_lines_to_verts(
thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry); thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry);
} }
void _3DScene::thick_lines_to_verts( void _3DScene::thick_lines_to_verts(const Lines3& lines,
const Lines3& lines,
const std::vector<double>& widths, const std::vector<double>& widths,
const std::vector<double>& heights, const std::vector<double>& heights,
bool closed, bool closed,
@@ -1819,7 +1772,10 @@ void _3DScene::thick_lines_to_verts(
} }
// Fill in the qverts and tverts with quads and triangles for the extrusion_path. // Fill in the qverts and tverts with quads and triangles for the extrusion_path.
void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path,
float print_z,
const Point& copy,
GUI::GLModel::Geometry& geometry)
{ {
Polyline polyline = extrusion_path.polyline; Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points(); polyline.remove_duplicate_points();
@@ -1831,7 +1787,10 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, flo
} }
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop. // Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop,
float print_z,
const Point& copy,
GUI::GLModel::Geometry& geometry)
{ {
Lines lines; Lines lines;
std::vector<double> widths; std::vector<double> widths;
@@ -1849,7 +1808,10 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, flo
} }
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path. // Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path,
float print_z,
const Point& copy,
GUI::GLModel::Geometry& geometry)
{ {
Lines lines; Lines lines;
std::vector<double> widths; std::vector<double> widths;
@@ -1866,13 +1828,19 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_mult
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry); thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
} }
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection,
float print_z,
const Point& copy,
GUI::GLModel::Geometry& geometry)
{ {
for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities) for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities)
extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry); extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry);
} }
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity,
float print_z,
const Point& copy,
GUI::GLModel::Geometry& geometry)
{ {
if (extrusion_entity != nullptr) { if (extrusion_entity != nullptr) {
auto* extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity); auto* extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity);
+1 -3
View File
@@ -9706,9 +9706,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
break; break;
// Snapmaker: 螺旋抬升靠近边界警告 // Snapmaker: 螺旋抬升靠近边界警告
case EWarning::SpiralLiftNearBoundary: case EWarning::SpiralLiftNearBoundary:
text = _u8L("An object is too close to the plate boundary. " text = _u8L("Model too close to bed boundary. Disable spiral lifting or keep at least 3.5mm gap to avoid collision.");
"Spiral lift during printing may exceed the bed and cause a crash. "
"Please move the object away from the edge (recommend keeping at least 3mm distance).");
error = ErrorType::SLICING_SERIOUS_WARNING; error = ErrorType::SLICING_SERIOUS_WARNING;
break; break;
} }