mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-24 11:22:07 +00:00
Merge branch '2.2.3' into dev_upgrade_alves
# Conflicts: # localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -185,6 +185,8 @@ public:
|
||||
// Wheter or not this volume is outside print volume.
|
||||
bool is_outside : 1;
|
||||
bool partly_inside : 1;
|
||||
// Snapmaker: Whether or not this volume is too close to boundary for spiral lift
|
||||
bool near_boundary_for_spiral_lift : 1;
|
||||
// Wheter or not this volume has been generated from a modifier
|
||||
bool is_modifier : 1;
|
||||
// Wheter or not this volume has been generated from the wipe tower
|
||||
@@ -516,6 +518,8 @@ public:
|
||||
// returns the containment state in the given out_state, if non-null
|
||||
bool check_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const;
|
||||
void reset_outside_state();
|
||||
// Snapmaker: 检查是否有任何 volume 靠近边界(螺旋抬升风险)
|
||||
bool is_any_volume_near_boundary_for_spiral_lift() const;
|
||||
|
||||
void update_colors_by_extruder(const DynamicPrintConfig *config, bool is_update_alpha = true);
|
||||
|
||||
|
||||
@@ -2399,100 +2399,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const
|
||||
{
|
||||
//BBS: use convex_hull for toolpath outside check
|
||||
m_contained_in_bed = build_volume.all_paths_inside(gcode_result, m_paths_bounding_box);
|
||||
|
||||
// BBS: Enhanced Travel move checking with smart filtering
|
||||
// Skip initial setup moves (G28, G29) and only check moves during actual printing
|
||||
if (m_contained_in_bed) {
|
||||
// Find first extrusion move to determine where actual printing starts
|
||||
size_t first_print_move = 0;
|
||||
for (size_t i = 0; i < gcode_result.moves.size(); ++i) {
|
||||
if (gcode_result.moves[i].type == EMoveType::Extrude &&
|
||||
gcode_result.moves[i].position.z() > 0.1) { // Above first layer
|
||||
first_print_move = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only check moves after printing starts (skip G28/G29 initialization)
|
||||
if (first_print_move > 0) {
|
||||
bool has_travel_violations = false;
|
||||
int violation_count = 0;
|
||||
// Use same epsilon as BuildVolume::all_paths_inside() for consistency
|
||||
static constexpr const double epsilon = BuildVolume::BedEpsilon;
|
||||
|
||||
// Clear existing violations and populate with detailed info
|
||||
auto& gcode_result_writable = const_cast<GCodeProcessorResult&>(gcode_result);
|
||||
gcode_result_writable.boundary_violations.clear();
|
||||
|
||||
for (size_t i = first_print_move; i < gcode_result.moves.size(); ++i) {
|
||||
const auto& move = gcode_result.moves[i];
|
||||
|
||||
// Only check Travel moves (Extrude already checked by all_paths_inside)
|
||||
if (move.type == EMoveType::Travel) {
|
||||
// Quick rectangle bed check with tolerance
|
||||
auto bbox = build_volume.bounding_volume();
|
||||
if (move.position.x() < bbox.min.x() - epsilon ||
|
||||
move.position.x() > bbox.max.x() + epsilon ||
|
||||
move.position.y() < bbox.min.y() - epsilon ||
|
||||
move.position.y() > bbox.max.y() + epsilon) {
|
||||
|
||||
// Create detailed violation info
|
||||
GCodeProcessorResult::BoundaryViolationInfo violation;
|
||||
violation.violation_type = BoundaryValidator::ViolationType::TravelMove;
|
||||
violation.position = Vec3d(move.position.x(), move.position.y(), move.position.z());
|
||||
violation.print_z = move.position.z();
|
||||
violation.component_name = "Travel";
|
||||
|
||||
// Determine which boundary was exceeded
|
||||
double dist_x_min = bbox.min.x() - move.position.x();
|
||||
double dist_x_max = move.position.x() - bbox.max.x();
|
||||
double dist_y_min = bbox.min.y() - move.position.y();
|
||||
double dist_y_max = move.position.y() - bbox.max.y();
|
||||
|
||||
if (dist_x_min > 0) {
|
||||
violation.direction = BoundaryValidator::BoundaryDirection::X_Min;
|
||||
violation.distance_out = dist_x_min;
|
||||
} else if (dist_x_max > 0) {
|
||||
violation.direction = BoundaryValidator::BoundaryDirection::X_Max;
|
||||
violation.distance_out = dist_x_max;
|
||||
} else if (dist_y_min > 0) {
|
||||
violation.direction = BoundaryValidator::BoundaryDirection::Y_Min;
|
||||
violation.distance_out = dist_y_min;
|
||||
} else if (dist_y_max > 0) {
|
||||
violation.direction = BoundaryValidator::BoundaryDirection::Y_Max;
|
||||
violation.distance_out = dist_y_max;
|
||||
}
|
||||
|
||||
gcode_result_writable.boundary_violations.push_back(violation);
|
||||
|
||||
violation_count++;
|
||||
if (violation_count <= 3) { // Log first 3
|
||||
std::string dir_str;
|
||||
switch (violation.direction) {
|
||||
case BoundaryValidator::BoundaryDirection::X_Min: dir_str = "X_min"; break;
|
||||
case BoundaryValidator::BoundaryDirection::X_Max: dir_str = "X_max"; break;
|
||||
case BoundaryValidator::BoundaryDirection::Y_Min: dir_str = "Y_min"; break;
|
||||
case BoundaryValidator::BoundaryDirection::Y_Max: dir_str = "Y_max"; break;
|
||||
default: dir_str = "Unknown"; break;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "Travel move #" << i
|
||||
<< " outside bounds: " << violation.component_name << " " << dir_str
|
||||
<< " at pos=(" << move.position.x()
|
||||
<< ", " << move.position.y() << ", " << move.position.z() << ")";
|
||||
}
|
||||
has_travel_violations = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_travel_violations) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Found " << violation_count
|
||||
<< " Travel moves outside build volume";
|
||||
m_contained_in_bed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_contained_in_bed) {
|
||||
//PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list();
|
||||
//PartPlate* plate = partplate_list.get_curr_plate();
|
||||
|
||||
@@ -849,12 +849,6 @@ public:
|
||||
//BBS: add only gcode mode
|
||||
bool is_only_gcode_in_preview() const { return m_only_gcode_in_preview; }
|
||||
|
||||
// Snapmaker: Get boundary violations from gcode_result
|
||||
const std::vector<GCodeProcessorResult::BoundaryViolationInfo>& get_boundary_violations() const {
|
||||
static const std::vector<GCodeProcessorResult::BoundaryViolationInfo> empty_violations;
|
||||
return (m_gcode_result != nullptr) ? m_gcode_result->boundary_violations : empty_violations;
|
||||
}
|
||||
|
||||
EViewType get_view_type() const { return m_view_type; }
|
||||
void set_view_type(EViewType type, bool reset_feature_type_visible = true) {
|
||||
if (type == EViewType::Count)
|
||||
|
||||
@@ -2823,6 +2823,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
if (printer_technology != ptSLA || !contained_min_one)
|
||||
_set_warning_notification(EWarning::SlaSupportsOutside, false);
|
||||
|
||||
// Snapmaker: 螺旋抬升边界警告 - 无论模型是否超出边界都检测
|
||||
if (contained_min_one) {
|
||||
_set_warning_notification(EWarning::SpiralLiftNearBoundary, _is_any_volume_near_boundary_for_spiral_lift());
|
||||
} else {
|
||||
_set_warning_notification(EWarning::SpiralLiftNearBoundary, false);
|
||||
}
|
||||
|
||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS,
|
||||
contained_min_one && !m_model->objects.empty() && !partlyOut));
|
||||
}
|
||||
@@ -2830,6 +2837,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
_set_warning_notification(EWarning::ObjectOutside, false);
|
||||
_set_warning_notification(EWarning::ObjectClashed, false);
|
||||
_set_warning_notification(EWarning::SlaSupportsOutside, false);
|
||||
_set_warning_notification(EWarning::SpiralLiftNearBoundary, false); // Snapmaker: 清空警告
|
||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
||||
}
|
||||
}
|
||||
@@ -9687,102 +9695,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
}
|
||||
case EWarning::ObjectOutside: text = _u8L("An object is laid over the plate boundaries."); break;
|
||||
case EWarning::ToolHeightOutside: text = _u8L("A G-code path goes beyond the max print height."); error = ErrorType::SLICING_ERROR; break;
|
||||
case EWarning::ToolpathOutside: {
|
||||
error = ErrorType::SLICING_ERROR;
|
||||
// Snapmaker: Enhanced boundary violation reporting with detailed information
|
||||
static std::string prevBoundaryText;
|
||||
text = prevBoundaryText;
|
||||
|
||||
// Helper function to get localized violation type name
|
||||
auto get_localized_type_string = [](BoundaryValidator::ViolationType type) -> std::string {
|
||||
switch (type) {
|
||||
case BoundaryValidator::ViolationType::TravelMove: return _u8L("Travel Move");
|
||||
case BoundaryValidator::ViolationType::ExtrudeMove: return _u8L("Extrude Move");
|
||||
case BoundaryValidator::ViolationType::SpiralLift: return _u8L("Spiral Lift");
|
||||
case BoundaryValidator::ViolationType::LazyLift: return _u8L("Lazy Lift");
|
||||
case BoundaryValidator::ViolationType::WipeTower: return _u8L("Wipe Tower");
|
||||
case BoundaryValidator::ViolationType::Skirt: return _u8L("Skirt");
|
||||
case BoundaryValidator::ViolationType::Brim: return _u8L("Brim");
|
||||
case BoundaryValidator::ViolationType::Support: return _u8L("Support");
|
||||
case BoundaryValidator::ViolationType::ArcMove: return _u8L("Arc Move");
|
||||
default: return _u8L("Unknown");
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to get localized direction string
|
||||
auto get_localized_direction_string = [](BoundaryValidator::BoundaryDirection dir) -> std::string {
|
||||
switch (dir) {
|
||||
case BoundaryValidator::BoundaryDirection::X_Min: return _u8L("beyond X minimum");
|
||||
case BoundaryValidator::BoundaryDirection::X_Max: return _u8L("beyond X maximum");
|
||||
case BoundaryValidator::BoundaryDirection::Y_Min: return _u8L("beyond Y minimum");
|
||||
case BoundaryValidator::BoundaryDirection::Y_Max: return _u8L("beyond Y maximum");
|
||||
case BoundaryValidator::BoundaryDirection::Z_Max: return _u8L("above Z maximum");
|
||||
case BoundaryValidator::BoundaryDirection::Radius: return _u8L("beyond bed radius");
|
||||
default: return _u8L("outside boundaries");
|
||||
}
|
||||
};
|
||||
|
||||
// Try to get detailed violation information from gcode_result
|
||||
const auto& violations = m_gcode_viewer.get_boundary_violations();
|
||||
if (!violations.empty()) {
|
||||
|
||||
// Group violations by type for better summary
|
||||
std::map<BoundaryValidator::ViolationType, int> violation_counts;
|
||||
std::map<BoundaryValidator::ViolationType, std::string> type_names;
|
||||
for (const auto& v : violations) {
|
||||
violation_counts[v.violation_type]++;
|
||||
if (type_names.find(v.violation_type) == type_names.end()) {
|
||||
type_names[v.violation_type] = get_localized_type_string(v.violation_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Build detailed message
|
||||
std::string msg = _u8L("G-code boundary violations detected:\n\n");
|
||||
int total_count = 0;
|
||||
for (const auto& [type, count] : violation_counts) {
|
||||
msg += "• " + type_names[type] + ": " + std::to_string(count) + " " + _u8L("violation(s)") + "\n";
|
||||
total_count += count;
|
||||
}
|
||||
|
||||
if (total_count > 1) {
|
||||
msg += "\n" + _u8L("Total") + ": " + std::to_string(total_count) + " " + _u8L("violations");
|
||||
}
|
||||
|
||||
// Show details of first few violations
|
||||
if (!violations.empty()) {
|
||||
msg += "\n\n" + _u8L("Details") + ":\n";
|
||||
int show_count = std::min((int)violations.size(), 5);
|
||||
for (int i = 0; i < show_count; ++i) {
|
||||
const auto& v = violations[i];
|
||||
// Build localized description
|
||||
std::string desc;
|
||||
if (!v.component_name.empty()) {
|
||||
desc += v.component_name + " - ";
|
||||
}
|
||||
desc += get_localized_type_string(v.violation_type);
|
||||
desc += " " + get_localized_direction_string(v.direction);
|
||||
msg += " " + std::to_string(i + 1) + ". " + desc;
|
||||
if (v.distance_out > 0.001) {
|
||||
msg += " (" + (boost::format(_u8L("%.2f mm out")) % v.distance_out).str() + ")";
|
||||
}
|
||||
if (v.print_z > 0) {
|
||||
msg += " " + _u8L("at Z") + "=" + (boost::format("%.1f") % v.print_z).str();
|
||||
}
|
||||
msg += "\n";
|
||||
}
|
||||
if ((int)violations.size() > show_count) {
|
||||
msg += " " + _u8L("... and more");
|
||||
}
|
||||
}
|
||||
|
||||
text = msg;
|
||||
prevBoundaryText = text;
|
||||
} else {
|
||||
// Fallback to generic message if no detailed info available
|
||||
text = _u8L("A G-code path goes beyond the plate boundaries.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EWarning::ToolpathOutside: text = _u8L("A G-code path goes beyond the plate boundaries."); error = ErrorType::SLICING_ERROR; break;
|
||||
// BBS: remove _u8L() for SLA
|
||||
case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
|
||||
case EWarning::SomethingNotShown: text = _u8L("Only the object being edited is visible."); break;
|
||||
@@ -9791,6 +9704,11 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
"Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume.");
|
||||
error = ErrorType::PLATER_ERROR;
|
||||
break;
|
||||
// Snapmaker: 螺旋抬升靠近边界警告
|
||||
case EWarning::SpiralLiftNearBoundary:
|
||||
text = _u8L("Model too close to bed boundary. Disable spiral lifting or keep at least 3.5mm gap to avoid collision.");
|
||||
error = ErrorType::SLICING_SERIOUS_WARNING;
|
||||
break;
|
||||
}
|
||||
//BBS: this may happened when exit the app, plater is null
|
||||
if (!wxGetApp().plater())
|
||||
@@ -9845,6 +9763,12 @@ bool GLCanvas3D::_is_any_volume_outside() const
|
||||
return false;
|
||||
}
|
||||
|
||||
// Snapmaker: 检查是否有任何 volume 靠近边界(螺旋抬升风险)
|
||||
bool GLCanvas3D::_is_any_volume_near_boundary_for_spiral_lift() const
|
||||
{
|
||||
return m_volumes.is_any_volume_near_boundary_for_spiral_lift();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_update_selection_from_hover()
|
||||
{
|
||||
bool ctrl_pressed = wxGetKeyState(WXK_CONTROL);
|
||||
|
||||
@@ -381,7 +381,8 @@ class GLCanvas3D
|
||||
SomethingNotShown,
|
||||
ObjectClashed,
|
||||
GCodeConflict,
|
||||
ToolHeightOutside
|
||||
ToolHeightOutside,
|
||||
SpiralLiftNearBoundary // Snapmaker: 螺旋抬升靠近边界警告
|
||||
};
|
||||
|
||||
class RenderStats
|
||||
@@ -1238,6 +1239,8 @@ private:
|
||||
void _set_warning_notification(EWarning warning, bool state);
|
||||
|
||||
bool _is_any_volume_outside() const;
|
||||
// Snapmaker: 检查是否有任何 volume 靠近边界(螺旋抬升风险)
|
||||
bool _is_any_volume_near_boundary_for_spiral_lift() const;
|
||||
|
||||
// updates the selection from the content of m_hover_volume_idxs
|
||||
void _update_selection_from_hover();
|
||||
|
||||
Reference in New Issue
Block a user