mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-29 05:42:33 +00:00
Revert "Feature boundary test lxy (#128)"
This reverts commit a1769a2148.
This commit is contained in:
@@ -1,215 +0,0 @@
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// ============================================================================
|
||||
// BoundaryValidator static methods
|
||||
// ============================================================================
|
||||
|
||||
std::string BoundaryValidator::violation_type_name(ViolationType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ViolationType::Unknown:
|
||||
return "Unknown";
|
||||
case ViolationType::TravelMove:
|
||||
return "Travel Move";
|
||||
case ViolationType::ExtrudeMove:
|
||||
return "Extrude Move";
|
||||
case ViolationType::SpiralLift:
|
||||
return "Spiral Lift";
|
||||
case ViolationType::LazyLift:
|
||||
return "Lazy Lift";
|
||||
case ViolationType::WipeTower:
|
||||
return "Wipe Tower";
|
||||
case ViolationType::Skirt:
|
||||
return "Skirt";
|
||||
case ViolationType::Brim:
|
||||
return "Brim";
|
||||
case ViolationType::Support:
|
||||
return "Support";
|
||||
case ViolationType::ArcMove:
|
||||
return "Arc Move";
|
||||
default:
|
||||
return "Unknown Violation";
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// BuildVolumeBoundaryValidator implementation
|
||||
// ============================================================================
|
||||
|
||||
BuildVolumeBoundaryValidator::BuildVolumeBoundaryValidator(
|
||||
const BuildVolume& build_volume,
|
||||
double epsilon)
|
||||
: m_build_volume(build_volume), m_epsilon(epsilon)
|
||||
{
|
||||
}
|
||||
|
||||
bool BuildVolumeBoundaryValidator::validate_point(const Vec3d& point) const
|
||||
{
|
||||
// Validate Z height first (if printable_height is set)
|
||||
if (m_build_volume.printable_height() > 0.0) {
|
||||
if (point.z() > m_build_volume.printable_height() + m_epsilon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate XY position based on build volume type
|
||||
return is_inside_2d(Vec2d(point.x(), point.y()));
|
||||
}
|
||||
|
||||
bool BuildVolumeBoundaryValidator::validate_line(const Vec3d& from, const Vec3d& to) const
|
||||
{
|
||||
// For line validation, we sample multiple points along the line
|
||||
// to ensure the entire segment is within boundaries
|
||||
const int num_samples = 10;
|
||||
|
||||
for (int i = 0; i <= num_samples; ++i) {
|
||||
double t = static_cast<double>(i) / num_samples;
|
||||
Vec3d sample_point = from + t * (to - from);
|
||||
|
||||
if (!validate_point(sample_point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildVolumeBoundaryValidator::validate_arc(
|
||||
const Vec3d& center,
|
||||
double radius,
|
||||
double start_angle,
|
||||
double end_angle,
|
||||
double z_height) const
|
||||
{
|
||||
// Sample points along the arc and validate each
|
||||
std::vector<Vec3d> arc_points = sample_arc_points(
|
||||
center, radius, start_angle, end_angle, z_height
|
||||
);
|
||||
|
||||
for (const Vec3d& point : arc_points) {
|
||||
if (!validate_point(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildVolumeBoundaryValidator::validate_polygon(const Polygon& poly, double z_height) const
|
||||
{
|
||||
// Check if Z height is valid
|
||||
if (m_build_volume.printable_height() > 0.0) {
|
||||
if (z_height > m_build_volume.printable_height() + m_epsilon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all polygon vertices
|
||||
for (const Point& pt : poly.points) {
|
||||
Vec2d unscaled_pt = unscale(pt);
|
||||
if (!is_inside_2d(unscaled_pt)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Vec3d> BuildVolumeBoundaryValidator::sample_arc_points(
|
||||
const Vec3d& center,
|
||||
double radius,
|
||||
double start_angle,
|
||||
double end_angle,
|
||||
double z_height,
|
||||
int num_samples) const
|
||||
{
|
||||
std::vector<Vec3d> points;
|
||||
points.reserve(num_samples);
|
||||
|
||||
// Handle angle wrapping (e.g., from 350° to 10° should go through 360°/0°)
|
||||
double angle_range = end_angle - start_angle;
|
||||
|
||||
// Normalize to handle wrapping
|
||||
if (angle_range < 0) {
|
||||
angle_range += 2 * PI;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_samples; ++i) {
|
||||
double t = static_cast<double>(i) / (num_samples - 1);
|
||||
double angle = start_angle + t * angle_range;
|
||||
|
||||
double x = center.x() + radius * std::cos(angle);
|
||||
double y = center.y() + radius * std::sin(angle);
|
||||
|
||||
points.emplace_back(x, y, z_height);
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
bool BuildVolumeBoundaryValidator::is_inside_2d(const Vec2d& point) const
|
||||
{
|
||||
const BuildVolume_Type type = m_build_volume.type();
|
||||
|
||||
switch (type) {
|
||||
case BuildVolume_Type::Rectangle:
|
||||
{
|
||||
// Get the bounding box of the build volume
|
||||
const BoundingBoxf& bbox = m_build_volume.bounding_volume2d();
|
||||
BoundingBoxf inflated_bbox = bbox;
|
||||
inflated_bbox.min -= Vec2d(m_epsilon, m_epsilon);
|
||||
inflated_bbox.max += Vec2d(m_epsilon, m_epsilon);
|
||||
|
||||
return inflated_bbox.contains(point);
|
||||
}
|
||||
|
||||
case BuildVolume_Type::Circle:
|
||||
{
|
||||
// Get circle parameters - circle.center is already in scaled coordinates
|
||||
const Geometry::Circled& circle = m_build_volume.circle();
|
||||
const Vec2d center_unscaled(unscale<double>(circle.center.x()),
|
||||
unscale<double>(circle.center.y()));
|
||||
const double radius = unscale<double>(circle.radius) + m_epsilon;
|
||||
|
||||
// Check distance from center
|
||||
double dist_sq = (point - center_unscaled).squaredNorm();
|
||||
return dist_sq <= radius * radius;
|
||||
}
|
||||
|
||||
case BuildVolume_Type::Convex:
|
||||
case BuildVolume_Type::Custom:
|
||||
{
|
||||
// For convex/custom volumes, use point-in-polygon test
|
||||
// Get the convex hull decomposition - this returns pair<top, bottom>
|
||||
const auto& decomp = m_build_volume.top_bottom_convex_hull_decomposition_bed();
|
||||
const std::vector<Vec2d>& top_hull = decomp.first;
|
||||
|
||||
if (top_hull.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if point is inside the top convex hull
|
||||
Point scaled_point = scaled<coord_t>(point);
|
||||
|
||||
// Build polygon from Vec2d points
|
||||
Polygon hull_poly;
|
||||
for (const Vec2d& pt : top_hull) {
|
||||
hull_poly.points.push_back(scaled<coord_t>(pt));
|
||||
}
|
||||
|
||||
return hull_poly.contains(scaled_point);
|
||||
}
|
||||
|
||||
case BuildVolume_Type::Invalid:
|
||||
default:
|
||||
// If build volume type is invalid, allow everything (fail-safe)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -1,168 +0,0 @@
|
||||
#ifndef slic3r_BoundaryValidator_hpp_
|
||||
#define slic3r_BoundaryValidator_hpp_
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/**
|
||||
* @brief Abstract interface for validating geometric elements against print boundaries
|
||||
*
|
||||
* This class provides a unified interface for boundary validation across different
|
||||
* parts of the slicing pipeline. Implementations can validate points, lines, arcs,
|
||||
* and polygons against the build volume.
|
||||
*/
|
||||
class BoundaryValidator {
|
||||
public:
|
||||
/**
|
||||
* @brief Types of boundary violations that can occur
|
||||
*/
|
||||
enum class ViolationType {
|
||||
Unknown = 0,
|
||||
TravelMove, // Travel move exceeds boundaries
|
||||
ExtrudeMove, // Extrude move exceeds boundaries
|
||||
SpiralLift, // Spiral lift arc exceeds boundaries
|
||||
LazyLift, // Lazy lift slope exceeds boundaries
|
||||
WipeTower, // Wipe tower position exceeds boundaries
|
||||
Skirt, // Skirt exceeds boundaries
|
||||
Brim, // Brim exceeds boundaries
|
||||
Support, // Support material exceeds boundaries
|
||||
ArcMove, // G2/G3 arc move exceeds boundaries
|
||||
Count // Sentinel value
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Direction of boundary violation
|
||||
*/
|
||||
enum class BoundaryDirection {
|
||||
Unknown = 0,
|
||||
X_Min, // Beyond X minimum boundary
|
||||
X_Max, // Beyond X maximum boundary
|
||||
Y_Min, // Beyond Y minimum boundary
|
||||
Y_Max, // Beyond Y maximum boundary
|
||||
Z_Max, // Above Z maximum boundary
|
||||
Radius, // Beyond circular bed radius
|
||||
Count // Sentinel value
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes a single boundary violation
|
||||
*/
|
||||
struct BoundaryViolation {
|
||||
ViolationType type; // Type of violation
|
||||
BoundaryDirection direction; // Direction of violation
|
||||
std::string description; // Human-readable description
|
||||
Vec3d position; // Position where violation occurs (unscaled)
|
||||
double distance_out; // How far outside boundaries (unscaled)
|
||||
double layer_z; // Z height of the layer (unscaled)
|
||||
std::string object_name; // Name of related object (if applicable)
|
||||
|
||||
BoundaryViolation(ViolationType t, const std::string& desc,
|
||||
const Vec3d& pos, double z, const std::string& obj = "",
|
||||
BoundaryDirection dir = BoundaryDirection::Unknown, double dist = 0.0)
|
||||
: type(t), direction(dir), description(desc), position(pos), distance_out(dist), layer_z(z), object_name(obj) {}
|
||||
};
|
||||
|
||||
using BoundaryViolations = std::vector<BoundaryViolation>;
|
||||
|
||||
virtual ~BoundaryValidator() = default;
|
||||
|
||||
/**
|
||||
* @brief Validate a single point against boundaries
|
||||
* @param point Point to validate (unscaled coordinates)
|
||||
* @return true if point is within boundaries, false otherwise
|
||||
*/
|
||||
virtual bool validate_point(const Vec3d& point) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Validate a line segment against boundaries
|
||||
* @param from Start point (unscaled coordinates)
|
||||
* @param to End point (unscaled coordinates)
|
||||
* @return true if entire line is within boundaries, false otherwise
|
||||
*/
|
||||
virtual bool validate_line(const Vec3d& from, const Vec3d& to) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Validate an arc path against boundaries
|
||||
* @param center Arc center point (unscaled coordinates)
|
||||
* @param radius Arc radius (unscaled)
|
||||
* @param start_angle Start angle in radians
|
||||
* @param end_angle End angle in radians
|
||||
* @param z_height Z height of the arc (unscaled)
|
||||
* @return true if entire arc is within boundaries, false otherwise
|
||||
*/
|
||||
virtual bool validate_arc(const Vec3d& center, double radius,
|
||||
double start_angle, double end_angle,
|
||||
double z_height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Validate a polygon against boundaries
|
||||
* @param poly Polygon to validate (scaled coordinates)
|
||||
* @param z_height Z height of the polygon (unscaled)
|
||||
* @return true if entire polygon is within boundaries, false otherwise
|
||||
*/
|
||||
virtual bool validate_polygon(const Polygon& poly, double z_height = 0.0) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get human-readable name for violation type
|
||||
*/
|
||||
static std::string violation_type_name(ViolationType type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concrete implementation of BoundaryValidator based on BuildVolume
|
||||
*
|
||||
* This validator uses the BuildVolume class to perform boundary checks.
|
||||
* It supports all build volume types (Rectangle, Circle, Convex, Custom).
|
||||
*/
|
||||
class BuildVolumeBoundaryValidator : public BoundaryValidator {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct validator from BuildVolume
|
||||
* @param build_volume Reference to the build volume
|
||||
* @param epsilon Tolerance for boundary checks (default: BedEpsilon)
|
||||
*/
|
||||
explicit BuildVolumeBoundaryValidator(const BuildVolume& build_volume,
|
||||
double epsilon = BuildVolume::BedEpsilon);
|
||||
|
||||
bool validate_point(const Vec3d& point) const override;
|
||||
bool validate_line(const Vec3d& from, const Vec3d& to) const override;
|
||||
bool validate_arc(const Vec3d& center, double radius,
|
||||
double start_angle, double end_angle,
|
||||
double z_height) const override;
|
||||
bool validate_polygon(const Polygon& poly, double z_height = 0.0) const override;
|
||||
|
||||
private:
|
||||
const BuildVolume& m_build_volume;
|
||||
double m_epsilon;
|
||||
|
||||
/**
|
||||
* @brief Sample points along an arc for validation
|
||||
* @param center Arc center (unscaled)
|
||||
* @param radius Arc radius (unscaled)
|
||||
* @param start_angle Start angle in radians
|
||||
* @param end_angle End angle in radians
|
||||
* @param z_height Z height (unscaled)
|
||||
* @param num_samples Number of sample points (default: 16)
|
||||
* @return Vector of sampled points
|
||||
*/
|
||||
std::vector<Vec3d> sample_arc_points(const Vec3d& center, double radius,
|
||||
double start_angle, double end_angle,
|
||||
double z_height,
|
||||
int num_samples = 16) const;
|
||||
|
||||
/**
|
||||
* @brief Check if a 2D point is inside the build volume
|
||||
* @param point 2D point (unscaled)
|
||||
* @return true if inside, false otherwise
|
||||
*/
|
||||
bool is_inside_2d(const Vec2d& point) const;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_BoundaryValidator_hpp_
|
||||
@@ -8,9 +8,6 @@
|
||||
#include "libslic3r.h"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
@@ -990,7 +987,7 @@ static ExPolygons outer_inner_brim_area(const Print& print,
|
||||
polygons_reverse(ex_poly_holes_reversed);
|
||||
|
||||
if (has_outer_brim) {
|
||||
// Snapmaker: inner and outer boundary are offset from the same polygon incase of round off error.
|
||||
// BBS: inner and outer boundary are offset from the same polygon incase of round off error.
|
||||
auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION);
|
||||
ExPolygons outerExpoly;
|
||||
if (use_brim_ears) {
|
||||
@@ -1693,8 +1690,7 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
|
||||
std::map<ObjectID, ExtrusionEntityCollection>& brimMap,
|
||||
std::map<ObjectID, ExtrusionEntityCollection>& supportBrimMap,
|
||||
std::vector<std::pair<ObjectID, unsigned int>> &objPrintVec,
|
||||
std::vector<unsigned int>& printExtruders,
|
||||
Print* print_ptr)
|
||||
std::vector<unsigned int>& printExtruders)
|
||||
{
|
||||
|
||||
double brim_width_max = 0;
|
||||
@@ -1742,68 +1738,13 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
|
||||
for (size_t iia = 0; iia < islands_area.size(); ++iia)
|
||||
islands_area[iia].translate(plate_shift);
|
||||
|
||||
// Snapmaker: Create BuildVolume and BoundaryValidator for brim boundary checking
|
||||
BuildVolume build_volume(print.config().printable_area.values, print.config().printable_height);
|
||||
BuildVolumeBoundaryValidator validator(build_volume);
|
||||
double first_layer_height = print.skirt_first_layer_height();
|
||||
|
||||
for (auto iter = brimAreaMap.begin(); iter != brimAreaMap.end(); ++iter) {
|
||||
if (!iter->second.empty()) {
|
||||
// Snapmaker: Validate brim area against build volume boundaries
|
||||
for (const ExPolygon& expoly : iter->second) {
|
||||
if (!validator.validate_polygon(expoly.contour, first_layer_height)) {
|
||||
// Record boundary violation
|
||||
if (print_ptr) {
|
||||
BoundingBox bbox = get_extents(expoly.contour);
|
||||
Vec3d violation_pos(
|
||||
unscale<double>(bbox.center().x()),
|
||||
unscale<double>(bbox.center().y()),
|
||||
first_layer_height
|
||||
);
|
||||
PrintObject* obj = const_cast<PrintObject*>(print.get_object(iter->first));
|
||||
std::string obj_name = obj ? obj->model_object()->name : "Unknown";
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Brim),
|
||||
violation_pos,
|
||||
first_layer_height,
|
||||
obj_name
|
||||
);
|
||||
print_ptr->add_boundary_violation(violation);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Brim for object " << obj_name
|
||||
<< " exceeds build volume boundaries at z=" << first_layer_height << " mm";
|
||||
}
|
||||
}
|
||||
}
|
||||
brimMap.insert(std::make_pair(iter->first, makeBrimInfill(iter->second, print, islands_area)));
|
||||
};
|
||||
}
|
||||
for (auto iter = supportBrimAreaMap.begin(); iter != supportBrimAreaMap.end(); ++iter) {
|
||||
if (!iter->second.empty()) {
|
||||
// Snapmaker: Validate support brim area against build volume boundaries
|
||||
for (const ExPolygon& expoly : iter->second) {
|
||||
if (!validator.validate_polygon(expoly.contour, first_layer_height)) {
|
||||
// Record boundary violation
|
||||
if (print_ptr) {
|
||||
BoundingBox bbox = get_extents(expoly.contour);
|
||||
Vec3d violation_pos(
|
||||
unscale<double>(bbox.center().x()),
|
||||
unscale<double>(bbox.center().y()),
|
||||
first_layer_height
|
||||
);
|
||||
PrintObject* obj = const_cast<PrintObject*>(print.get_object(iter->first));
|
||||
std::string obj_name = obj ? obj->model_object()->name : "Unknown";
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Brim),
|
||||
violation_pos,
|
||||
first_layer_height,
|
||||
obj_name + " (support brim)"
|
||||
);
|
||||
print_ptr->add_boundary_violation(violation);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support brim for object " << obj_name
|
||||
<< " exceeds build volume boundaries at z=" << first_layer_height << " mm";
|
||||
}
|
||||
}
|
||||
}
|
||||
supportBrimMap.insert(std::make_pair(iter->first, makeBrimInfill(iter->second, print, islands_area)));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,13 +15,11 @@ class ObjectID;
|
||||
|
||||
// Produce brim lines around those objects, that have the brim enabled.
|
||||
// Collect islands_area to be merged into the final 1st layer convex hull.
|
||||
// If print_ptr is provided (non-const), boundary violations will be reported.
|
||||
void make_brim(const Print& print, PrintTryCancel try_cancel,
|
||||
Polygons& islands_area, std::map<ObjectID, ExtrusionEntityCollection>& brimMap,
|
||||
std::map<ObjectID, ExtrusionEntityCollection>& supportBrimMap,
|
||||
std::vector<std::pair<ObjectID, unsigned int>>& objPrintVec,
|
||||
std::vector<unsigned int>& printExtruders,
|
||||
Print* print_ptr = nullptr);
|
||||
std::vector<unsigned int>& printExtruders);
|
||||
|
||||
// BBS: automatically make brim
|
||||
ExtrusionEntityCollection make_brim_auto(const Print &print, PrintTryCancel try_cancel, Polygons &islands_area);
|
||||
|
||||
@@ -347,7 +347,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
|
||||
const Vec2f c = unscaled<float>(m_circle.center);
|
||||
const float r = unscaled<double>(m_circle.radius) + epsilon;
|
||||
const float r2 = sqr(r);
|
||||
return m_max_print_height == 0.0 ?
|
||||
return m_max_print_height == 0.0 ?
|
||||
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2](const GCodeProcessorResult::MoveVertex &move)
|
||||
{ return ! move_valid(move) || (to_2d(move.position) - c).squaredNorm() <= r2; }) :
|
||||
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex& move)
|
||||
@@ -357,7 +357,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
|
||||
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
|
||||
case BuildVolume_Type::Custom:
|
||||
return m_max_print_height == 0.0 ?
|
||||
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move)
|
||||
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move)
|
||||
{ return ! move_valid(move) || Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast<double>()); }) :
|
||||
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex &move)
|
||||
{ return ! move_valid(move) || (Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast<double>()) && move.position.z() <= z); });
|
||||
|
||||
@@ -75,8 +75,6 @@ set(lisbslic3r_sources
|
||||
BlacklistedLibraryCheck.hpp
|
||||
BoundingBox.cpp
|
||||
BoundingBox.hpp
|
||||
BoundaryValidator.cpp
|
||||
BoundaryValidator.hpp
|
||||
BridgeDetector.cpp
|
||||
BridgeDetector.hpp
|
||||
Brim.cpp
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "Time.hpp"
|
||||
#include "GCode/ExtrusionProcessor.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
@@ -1892,11 +1890,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream& file, ThumbnailsGenerato
|
||||
|
||||
m_writer.set_is_bbl_machine(is_bbl_printers);
|
||||
|
||||
// Snapmaker: Initialize boundary validator for arc path validation
|
||||
BuildVolume build_volume(print.config().printable_area.values, print.config().printable_height);
|
||||
BuildVolumeBoundaryValidator validator(build_volume);
|
||||
m_writer.set_boundary_validator(&validator, &print);
|
||||
|
||||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
m_layer_count = 0;
|
||||
|
||||
@@ -574,7 +574,6 @@ void GCodeProcessorResult::reset() {
|
||||
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
|
||||
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
|
||||
time = 0;
|
||||
boundary_violations.clear();
|
||||
|
||||
//BBS: add mutex for protection of gcode result
|
||||
unlock();
|
||||
@@ -608,7 +607,6 @@ void GCodeProcessorResult::reset() {
|
||||
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
|
||||
bed_match_result = BedMatchResult(true);
|
||||
warnings.clear();
|
||||
boundary_violations.clear();
|
||||
|
||||
//BBS: add mutex for protection of gcode result
|
||||
unlock();
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
#include "libslic3r/BoundaryValidator.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
@@ -105,66 +104,18 @@ class Print;
|
||||
}
|
||||
};
|
||||
|
||||
// Forward declaration for BoundaryValidator
|
||||
class BoundaryValidator;
|
||||
|
||||
struct ConflictResult
|
||||
{
|
||||
// ===== Existing fields for object collision =====
|
||||
std::string _objName1;
|
||||
std::string _objName2;
|
||||
double _height;
|
||||
const void *_obj1; // nullptr means wipe tower
|
||||
const void *_obj2;
|
||||
int layer = -1;
|
||||
|
||||
// ===== New fields for boundary violations =====
|
||||
enum class ConflictType {
|
||||
ObjectCollision, // Original: collision between objects
|
||||
BoundaryViolation // New: path exceeds build volume boundaries
|
||||
};
|
||||
|
||||
ConflictType conflict_type = ConflictType::ObjectCollision;
|
||||
|
||||
// Only valid when conflict_type == BoundaryViolation
|
||||
int violation_type_int = -1; // Stores BoundaryValidator::ViolationType as int
|
||||
Vec3d violation_position{Vec3d::Zero()}; // Position where violation occurs (unscaled)
|
||||
|
||||
// ===== Constructors =====
|
||||
ConflictResult(const std::string &objName1, const std::string &objName2, double height, const void *obj1, const void *obj2)
|
||||
: _objName1(objName1), _objName2(objName2), _height(height), _obj1(obj1), _obj2(obj2),
|
||||
conflict_type(ConflictType::ObjectCollision)
|
||||
: _objName1(objName1), _objName2(objName2), _height(height), _obj1(obj1), _obj2(obj2)
|
||||
{}
|
||||
|
||||
ConflictResult() = default;
|
||||
|
||||
// New: Static factory method for boundary violations
|
||||
// Note: violation_type should be cast from BoundaryValidator::ViolationType
|
||||
static ConflictResult create_boundary_violation(
|
||||
int violation_type,
|
||||
const Vec3d& pos,
|
||||
double height,
|
||||
const std::string& obj_name = ""
|
||||
) {
|
||||
ConflictResult result;
|
||||
result.conflict_type = ConflictType::BoundaryViolation;
|
||||
result.violation_type_int = violation_type;
|
||||
result.violation_position = pos;
|
||||
result._height = height;
|
||||
result._objName1 = obj_name;
|
||||
result.layer = -1; // Will be computed later if needed
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper method to check if this is a boundary violation
|
||||
bool is_boundary_violation() const {
|
||||
return conflict_type == ConflictType::BoundaryViolation;
|
||||
}
|
||||
|
||||
// Helper method to check if this is an object collision
|
||||
bool is_object_collision() const {
|
||||
return conflict_type == ConflictType::ObjectCollision;
|
||||
}
|
||||
};
|
||||
|
||||
struct BedMatchResult
|
||||
@@ -240,18 +191,6 @@ class Print;
|
||||
std::vector<std::string> params; // extra msg info
|
||||
};
|
||||
|
||||
// Snapmaker: Detailed boundary violation information for better user feedback
|
||||
// Uses BoundaryValidator enums to avoid duplication
|
||||
struct BoundaryViolationInfo {
|
||||
BoundaryValidator::ViolationType violation_type{BoundaryValidator::ViolationType::Unknown};
|
||||
BoundaryValidator::BoundaryDirection direction{BoundaryValidator::BoundaryDirection::Unknown};
|
||||
Vec3d position{Vec3d::Zero()}; // Position where violation occurs (mm)
|
||||
double distance_out{0.0}; // How far outside (mm)
|
||||
std::string component_name; // e.g., "Skirt", "Brim", "Support", "Wipe Tower"
|
||||
int layer_num{-1}; // Layer number (if applicable)
|
||||
float print_z{-1.0f}; // Z height at violation (mm)
|
||||
};
|
||||
|
||||
std::string filename;
|
||||
unsigned int id;
|
||||
std::vector<MoveVertex> moves;
|
||||
@@ -283,8 +222,6 @@ class Print;
|
||||
std::vector<std::pair<float, std::pair<size_t, size_t>>> spiral_vase_layers;
|
||||
//BBS
|
||||
std::vector<SliceWarning> warnings;
|
||||
// Snapmaker: Detailed boundary violation information
|
||||
std::vector<BoundaryViolationInfo> boundary_violations;
|
||||
int nozzle_hrc;
|
||||
NozzleType nozzle_type;
|
||||
BedType bed_type = BedType::btCount;
|
||||
@@ -318,7 +255,6 @@ class Print;
|
||||
custom_gcode_per_print_z = other.custom_gcode_per_print_z;
|
||||
spiral_vase_layers = other.spiral_vase_layers;
|
||||
warnings = other.warnings;
|
||||
boundary_violations = other.boundary_violations;
|
||||
bed_type = other.bed_type;
|
||||
bed_match_result = other.bed_match_result;
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <GCode/GCodeProcessor.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
@@ -549,116 +545,29 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
if (delta(2) > 0 && delta_no_z.norm() != 0.0f) {
|
||||
//BBS: SpiralLift
|
||||
if (m_to_lift_type == LiftType::SpiralLift && this->is_current_position_clear()) {
|
||||
// Calculate the radius of the spiral arc
|
||||
//BBS: todo: check the arc move all in bed area, if not, then use lazy lift
|
||||
double radius = delta(2) / (2 * PI * atan(this->extruder()->travel_slope()));
|
||||
|
||||
// Calculate arc center and angles for precise boundary validation
|
||||
Vec2d ij_offset = radius * delta_no_z.normalized();
|
||||
ij_offset = { -ij_offset(1), ij_offset(0) };
|
||||
|
||||
// Arc center is source + ij_offset (in unscaled coordinates)
|
||||
Vec3d arc_center = source + Vec3d(ij_offset(0), ij_offset(1), 0);
|
||||
|
||||
// Calculate start and end angles
|
||||
// ij_offset is perpendicular to delta_no_z, so the arc starts from -ij_offset direction
|
||||
double start_angle = std::atan2(-ij_offset(1), -ij_offset(0));
|
||||
double end_angle = start_angle + 2 * PI; // Full circle
|
||||
|
||||
// Snapmaker: Use BoundaryValidator for precise arc validation
|
||||
bool arc_valid = true;
|
||||
if (m_boundary_validator) {
|
||||
arc_valid = m_boundary_validator->validate_arc(
|
||||
arc_center, radius, start_angle, end_angle, source.z()
|
||||
);
|
||||
|
||||
if (!arc_valid) {
|
||||
// Record boundary violation
|
||||
if (m_print_ptr) {
|
||||
Vec3d violation_pos = arc_center + Vec3d(radius, 0, source.z());
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::SpiralLift),
|
||||
violation_pos,
|
||||
source.z(),
|
||||
"Spiral Lift"
|
||||
);
|
||||
m_print_ptr->add_boundary_violation(violation);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "Spiral lift arc exceeds build volume boundaries, "
|
||||
<< "downgrading to lazy lift. Center: (" << arc_center.x() << ", " << arc_center.y()
|
||||
<< "), Radius: " << radius << " mm";
|
||||
// Fall through to LazyLift check below
|
||||
m_to_lift_type = LiftType::LazyLift;
|
||||
}
|
||||
} else {
|
||||
// Fallback: Simple radius check if validator not available
|
||||
constexpr double MAX_SAFE_SPIRAL_RADIUS = 50.0; // mm
|
||||
if (radius > MAX_SAFE_SPIRAL_RADIUS) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Spiral lift radius (" << radius
|
||||
<< " mm) exceeds safe limit (" << MAX_SAFE_SPIRAL_RADIUS
|
||||
<< " mm), downgrading to lazy lift to prevent boundary violations";
|
||||
m_to_lift_type = LiftType::LazyLift;
|
||||
arc_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (arc_valid) {
|
||||
slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z");
|
||||
}
|
||||
slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z");
|
||||
}
|
||||
//BBS: LazyLift
|
||||
if (m_to_lift_type == LiftType::LazyLift &&
|
||||
this->is_current_position_clear() &&
|
||||
else if (m_to_lift_type == LiftType::LazyLift &&
|
||||
this->is_current_position_clear() &&
|
||||
atan2(delta(2), delta_no_z.norm()) < this->extruder()->travel_slope()) {
|
||||
// Calculate the slope top point
|
||||
//BBS: check whether we can make a travel like
|
||||
// _____
|
||||
// / to make the z list early to avoid to hit some warping place when travel is long.
|
||||
Vec2d temp = delta_no_z.normalized() * delta(2) / tan(this->extruder()->travel_slope());
|
||||
Vec3d slope_top_point = Vec3d(temp(0), temp(1), delta(2)) + source;
|
||||
|
||||
// Snapmaker: Use BoundaryValidator for precise line validation
|
||||
bool slope_valid = true;
|
||||
if (m_boundary_validator) {
|
||||
// Validate the entire slope line from source to slope_top_point
|
||||
slope_valid = m_boundary_validator->validate_line(source, slope_top_point);
|
||||
|
||||
if (!slope_valid) {
|
||||
// Record boundary violation
|
||||
if (m_print_ptr) {
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::LazyLift),
|
||||
slope_top_point,
|
||||
source.z(),
|
||||
"Lazy Lift"
|
||||
);
|
||||
m_print_ptr->add_boundary_violation(violation);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "Lazy lift slope exceeds build volume boundaries, "
|
||||
<< "downgrading to normal lift. Slope point: (" << slope_top_point.x()
|
||||
<< ", " << slope_top_point.y() << ", " << slope_top_point.z() << ")";
|
||||
// Fall through to NormalLift
|
||||
m_to_lift_type = LiftType::NormalLift;
|
||||
}
|
||||
} else {
|
||||
// Fallback: Simple distance check if validator not available
|
||||
constexpr double MAX_SAFE_SLOPE_DISTANCE = 100.0; // mm
|
||||
double slope_distance = temp.norm();
|
||||
if (slope_distance > MAX_SAFE_SLOPE_DISTANCE) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Lazy lift slope distance (" << slope_distance
|
||||
<< " mm) exceeds safe limit (" << MAX_SAFE_SLOPE_DISTANCE
|
||||
<< " mm), downgrading to normal lift to prevent boundary violations";
|
||||
m_to_lift_type = LiftType::NormalLift;
|
||||
slope_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (slope_valid) {
|
||||
GCodeG1Formatter w0;
|
||||
w0.emit_xyz(slope_top_point);
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
//BBS
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
slop_move = w0.string();
|
||||
}
|
||||
GCodeG1Formatter w0;
|
||||
w0.emit_xyz(slope_top_point);
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
//BBS
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
slop_move = w0.string();
|
||||
}
|
||||
if (m_to_lift_type == LiftType::NormalLift) {
|
||||
else if (m_to_lift_type == LiftType::NormalLift) {
|
||||
slop_move = _travel_to_z(target.z(), "normal lift Z");
|
||||
}
|
||||
}
|
||||
@@ -825,59 +734,6 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
||||
//center_offset is I and J axis
|
||||
std::string GCodeWriter::extrude_arc_to_xy(const Vec2d& point, const Vec2d& center_offset, double dE, const bool is_ccw, const std::string& comment, bool force_no_extrusion)
|
||||
{
|
||||
// Snapmaker: Validate arc path against build volume boundaries
|
||||
if (m_boundary_validator) {
|
||||
// Calculate arc center (center_offset is relative to start point)
|
||||
Vec2d start_point = { m_pos(0) - m_x_offset, m_pos(1) - m_y_offset };
|
||||
Vec3d arc_center = Vec3d(start_point(0) + center_offset(0), start_point(1) + center_offset(1), m_pos(2));
|
||||
|
||||
// Calculate radius from center offset
|
||||
double radius = std::sqrt(center_offset(0) * center_offset(0) + center_offset(1) * center_offset(1));
|
||||
|
||||
// Calculate start and end angles
|
||||
Vec2d start_vec = start_point - Vec2d(arc_center.x(), arc_center.y());
|
||||
Vec2d end_vec = Vec2d(point(0) - m_x_offset, point(1) - m_y_offset) - Vec2d(arc_center.x(), arc_center.y());
|
||||
|
||||
double start_angle = std::atan2(start_vec(1), start_vec(0));
|
||||
double end_angle = std::atan2(end_vec(1), end_vec(0));
|
||||
|
||||
// Handle CCW vs CW and angle wrapping
|
||||
if (is_ccw) {
|
||||
// For CCW, ensure end_angle > start_angle (wrapping if needed)
|
||||
if (end_angle < start_angle) {
|
||||
end_angle += 2 * PI;
|
||||
}
|
||||
} else {
|
||||
// For CW, ensure end_angle < start_angle (wrapping if needed)
|
||||
if (end_angle > start_angle) {
|
||||
end_angle -= 2 * PI;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the arc
|
||||
bool arc_valid = m_boundary_validator->validate_arc(
|
||||
arc_center, radius, start_angle, end_angle, m_pos(2)
|
||||
);
|
||||
|
||||
if (!arc_valid) {
|
||||
// Record boundary violation
|
||||
if (m_print_ptr) {
|
||||
Vec3d violation_pos = arc_center + Vec3d(radius, 0, m_pos(2));
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::ArcMove),
|
||||
violation_pos,
|
||||
m_pos(2),
|
||||
"Arc Extrusion"
|
||||
);
|
||||
m_print_ptr->add_boundary_violation(violation);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "Arc extrusion path exceeds build volume boundaries. "
|
||||
<< "Center: (" << arc_center.x() << ", " << arc_center.y()
|
||||
<< "), Radius: " << radius << " mm, Z: " << m_pos(2) << " mm";
|
||||
// Continue anyway (don't fail, just warn)
|
||||
}
|
||||
}
|
||||
|
||||
m_pos(0) = point(0);
|
||||
m_pos(1) = point(1);
|
||||
if (!force_no_extrusion)
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Forward declarations
|
||||
class BoundaryValidator;
|
||||
class Print;
|
||||
|
||||
class GCodeWriter {
|
||||
public:
|
||||
GCodeConfig config;
|
||||
@@ -123,12 +119,6 @@ public:
|
||||
void set_is_first_layer(bool bval) { m_is_first_layer = bval; }
|
||||
GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; }
|
||||
|
||||
// Snapmaker: Set boundary validator for arc path validation
|
||||
void set_boundary_validator(const BoundaryValidator* validator, Print* print_ptr = nullptr) {
|
||||
m_boundary_validator = validator;
|
||||
m_print_ptr = print_ptr;
|
||||
}
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
private:
|
||||
@@ -180,10 +170,6 @@ public:
|
||||
double m_current_speed;
|
||||
bool m_is_first_layer = true;
|
||||
|
||||
// Snapmaker: Boundary validator for arc path validation
|
||||
const BoundaryValidator* m_boundary_validator = nullptr;
|
||||
Print* m_print_ptr = nullptr;
|
||||
|
||||
enum class Acceleration {
|
||||
Travel,
|
||||
Print
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "GCode/ConflictChecker.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
|
||||
#include <codecvt>
|
||||
|
||||
@@ -1288,45 +1287,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Snapmaker: Critical fix - Validate wipe tower position is within build volume boundaries
|
||||
// This addresses vulnerability #3: Wipe tower position was not validated against bed boundaries
|
||||
{
|
||||
const size_t plate_index = this->get_plate_index();
|
||||
const Vec3d plate_origin = this->get_plate_origin();
|
||||
const float x = m_config.wipe_tower_x.get_at(plate_index) + plate_origin(0);
|
||||
const float y = m_config.wipe_tower_y.get_at(plate_index) + plate_origin(1);
|
||||
const float width = m_config.prime_tower_width.value;
|
||||
const float brim_width = m_config.prime_tower_brim_width.value;
|
||||
const float depth = this->wipe_tower_data(extruders.size()).depth;
|
||||
|
||||
// Check all four corners of wipe tower (including brim)
|
||||
// Create a simple bounding box from printable_area config
|
||||
BoundingBoxf bed_bbox;
|
||||
for (const Vec2d& pt : m_config.printable_area.values) {
|
||||
bed_bbox.merge(pt);
|
||||
}
|
||||
|
||||
bool tower_outside = false;
|
||||
// Check all corners
|
||||
if (x - brim_width < bed_bbox.min.x() || x + width + brim_width > bed_bbox.max.x() ||
|
||||
y - brim_width < bed_bbox.min.y() || y + depth + brim_width > bed_bbox.max.y()) {
|
||||
tower_outside = true;
|
||||
}
|
||||
|
||||
if (tower_outside) {
|
||||
const float total_width = width + 2 * brim_width;
|
||||
const float total_depth = depth + 2 * brim_width;
|
||||
return StringObjectException{
|
||||
Slic3r::format(_u8L("The prime tower at position (%.2f, %.2f) with dimensions %.2f x %.2f mm "
|
||||
"(including %.2f mm brim) exceeds the bed boundaries. "
|
||||
"Please adjust the prime tower position in the configuration."),
|
||||
x, y, total_width, total_depth, brim_width),
|
||||
nullptr,
|
||||
"wipe_tower_x"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -2188,7 +2148,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (this->has_brim()) {
|
||||
Polygons islands_area;
|
||||
make_brim(*this, this->make_try_cancel(), islands_area, m_brimMap,
|
||||
m_supportBrimMap, objPrintVec, printExtruders, this);
|
||||
m_supportBrimMap, objPrintVec, printExtruders);
|
||||
for (Polygon& poly_ex : islands_area)
|
||||
poly_ex.douglas_peucker(SCALED_RESOLUTION);
|
||||
for (Polygon &poly : union_(this->first_layer_islands(), islands_area))
|
||||
@@ -2287,37 +2247,6 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
||||
|
||||
//BBS
|
||||
result->conflict_result = m_conflict_result;
|
||||
|
||||
// Snapmaker: Copy boundary violations from Print to GCodeProcessorResult
|
||||
// This allows detailed violation information to be displayed in the GUI
|
||||
if (!m_boundary_violations.empty()) {
|
||||
result->boundary_violations.clear();
|
||||
result->boundary_violations.reserve(m_boundary_violations.size());
|
||||
|
||||
for (const auto& conflict : m_boundary_violations) {
|
||||
if (conflict.is_boundary_violation()) {
|
||||
GCodeProcessorResult::BoundaryViolationInfo info;
|
||||
|
||||
// Directly copy the violation type (enums are now unified)
|
||||
info.violation_type = static_cast<BoundaryValidator::ViolationType>(conflict.violation_type_int);
|
||||
|
||||
// Copy position and height
|
||||
info.position = conflict.violation_position;
|
||||
info.print_z = static_cast<float>(conflict._height);
|
||||
info.layer_num = conflict.layer;
|
||||
|
||||
// Direction is not directly available in ConflictResult, leave as Unknown
|
||||
info.direction = BoundaryValidator::BoundaryDirection::Unknown;
|
||||
info.distance_out = 0.0;
|
||||
|
||||
result->boundary_violations.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Copied " << result->boundary_violations.size()
|
||||
<< " boundary violations from Print to GCodeProcessorResult";
|
||||
}
|
||||
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
@@ -2414,11 +2343,6 @@ void Print::_make_skirt()
|
||||
// Draw outlines from outside to inside.
|
||||
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
|
||||
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
|
||||
|
||||
// Create BuildVolume and BoundaryValidator for skirt boundary checking
|
||||
BuildVolume build_volume(m_config.printable_area.values, m_config.printable_height);
|
||||
BuildVolumeBoundaryValidator validator(build_volume);
|
||||
|
||||
if (m_config.skirt_type == stCombined) {
|
||||
for (size_t i = m_config.skirt_loops, extruder_idx = 0; i > 0; -- i) {
|
||||
this->throw_if_canceled();
|
||||
@@ -2434,28 +2358,6 @@ void Print::_make_skirt()
|
||||
break;
|
||||
loop = loops.front();
|
||||
}
|
||||
|
||||
// Snapmaker: Validate skirt loop against build volume boundaries
|
||||
if (!validator.validate_polygon(loop, initial_layer_print_height)) {
|
||||
// Record boundary violation
|
||||
BoundingBox loop_bbox = get_extents(loop);
|
||||
Vec3d violation_pos(
|
||||
unscale<double>(loop_bbox.center().x()),
|
||||
unscale<double>(loop_bbox.center().y()),
|
||||
initial_layer_print_height
|
||||
);
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Skirt),
|
||||
violation_pos,
|
||||
initial_layer_print_height,
|
||||
"Skirt"
|
||||
);
|
||||
this->add_boundary_violation(violation);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Skirt loop exceeds build volume boundaries at z="
|
||||
<< initial_layer_print_height << " mm";
|
||||
// Continue with remaining loops but record the violation
|
||||
}
|
||||
|
||||
// Extrude the skirt loop.
|
||||
ExtrusionLoop eloop(elrSkirt);
|
||||
eloop.paths.emplace_back(ExtrusionPath(
|
||||
@@ -2514,26 +2416,6 @@ void Print::_make_skirt()
|
||||
loop = loops.front();
|
||||
}
|
||||
|
||||
// Snapmaker: Validate per-object skirt loop against build volume boundaries
|
||||
if (!validator.validate_polygon(loop, initial_layer_print_height)) {
|
||||
// Record boundary violation
|
||||
BoundingBox loop_bbox = get_extents(loop);
|
||||
Vec3d violation_pos(
|
||||
unscale<double>(loop_bbox.center().x()),
|
||||
unscale<double>(loop_bbox.center().y()),
|
||||
initial_layer_print_height
|
||||
);
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Skirt),
|
||||
violation_pos,
|
||||
initial_layer_print_height,
|
||||
object->model_object()->name
|
||||
);
|
||||
this->add_boundary_violation(violation);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Per-object skirt loop for " << object->model_object()->name
|
||||
<< " exceeds build volume boundaries at z=" << initial_layer_print_height << " mm";
|
||||
}
|
||||
|
||||
// Extrude the skirt loop.
|
||||
ExtrusionLoop eloop(elrSkirt);
|
||||
eloop.paths.emplace_back(ExtrusionPath(
|
||||
|
||||
@@ -970,23 +970,6 @@ public:
|
||||
static StringObjectException sequential_print_clearance_valid(const Print &print, Polygons *polygons = nullptr, std::vector<std::pair<Polygon, float>>* height_polygons = nullptr);
|
||||
ConflictResultOpt get_conflict_result() const { return m_conflict_result; }
|
||||
|
||||
// Snapmaker: boundary violations tracking
|
||||
void add_boundary_violation(const ConflictResult& violation) {
|
||||
m_boundary_violations.push_back(violation);
|
||||
}
|
||||
|
||||
const std::vector<ConflictResult>& get_boundary_violations() const {
|
||||
return m_boundary_violations;
|
||||
}
|
||||
|
||||
void clear_boundary_violations() {
|
||||
m_boundary_violations.clear();
|
||||
}
|
||||
|
||||
bool has_boundary_violations() const {
|
||||
return !m_boundary_violations.empty();
|
||||
}
|
||||
|
||||
// Return 4 wipe tower corners in the world coordinates (shifted and rotated), including the wipe tower brim.
|
||||
Points first_layer_wipe_tower_corners(bool check_wipe_tower_existance=true) const;
|
||||
|
||||
@@ -1078,8 +1061,6 @@ private:
|
||||
int m_modified_count {0};
|
||||
//BBS
|
||||
ConflictResultOpt m_conflict_result;
|
||||
//Snapmaker: boundary violations tracking
|
||||
std::vector<ConflictResult> m_boundary_violations;
|
||||
FakeWipeTower m_fake_wipe_tower;
|
||||
|
||||
//SoftFever: calibration
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
#include "Print.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#include "ElephantFootCompensation.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "I18N.hpp"
|
||||
@@ -673,57 +670,6 @@ void PrintObject::generate_support_material()
|
||||
|
||||
this->_generate_support_material();
|
||||
m_print->throw_if_canceled();
|
||||
|
||||
// Snapmaker: Validate support material against build volume boundaries
|
||||
if (!m_support_layers.empty()) {
|
||||
BuildVolume build_volume(m_print->config().printable_area.values, m_print->config().printable_height);
|
||||
BuildVolumeBoundaryValidator validator(build_volume);
|
||||
|
||||
for (const SupportLayer* layer : m_support_layers) {
|
||||
// Check support fills polygons
|
||||
for (const Polygon& support_contour : layer->support_fills.polygons_covered_by_spacing()) {
|
||||
// Apply instance transforms and check boundary
|
||||
for (const PrintInstance& instance : this->instances()) {
|
||||
Polygon translated_contour = support_contour;
|
||||
translated_contour.translate(instance.shift);
|
||||
|
||||
// Convert to unscaled coordinates for validation
|
||||
Vec3d plate_origin = m_print->get_plate_origin();
|
||||
double z_height = layer->print_z;
|
||||
|
||||
// Check if any point of the contour exceeds boundaries
|
||||
bool has_violation = false;
|
||||
Vec3d violation_pos;
|
||||
for (const Point& pt : translated_contour.points) {
|
||||
Vec3d pt_unscaled(
|
||||
unscale<double>(pt.x()) + plate_origin.x(),
|
||||
unscale<double>(pt.y()) + plate_origin.y(),
|
||||
z_height
|
||||
);
|
||||
if (!validator.validate_point(pt_unscaled)) {
|
||||
has_violation = true;
|
||||
violation_pos = pt_unscaled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_violation) {
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Support),
|
||||
violation_pos,
|
||||
z_height,
|
||||
this->model_object()->name
|
||||
);
|
||||
m_print->add_boundary_violation(violation);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support material for object " << this->model_object()->name
|
||||
<< " exceeds build volume boundaries at z=" << z_height << " mm";
|
||||
// Only report once per layer to avoid spam
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this->set_done(posSupportMaterial);
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
#include "Geometry.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "MutablePolygon.hpp"
|
||||
#include "BoundaryValidator.hpp"
|
||||
#include "BuildVolume.hpp"
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
@@ -584,91 +581,6 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
|
||||
// Snapmaker: Validate support polygons against build volume boundaries
|
||||
// This addresses vulnerability #6: Support material boundary validation
|
||||
BOOST_LOG_TRIVIAL(info) << "Support generator - Validating boundaries";
|
||||
BuildVolume build_volume(object.print()->config().printable_area.values,
|
||||
object.print()->config().printable_height);
|
||||
BuildVolumeBoundaryValidator validator(build_volume);
|
||||
|
||||
int support_violations = 0;
|
||||
for (const SupportLayer* layer : object.support_layers()) {
|
||||
if (!layer)
|
||||
continue;
|
||||
|
||||
// Check support extrusions
|
||||
const ExtrusionEntityCollection& support_fills = layer->support_fills;
|
||||
for (const ExtrusionEntity* entity : support_fills.entities) {
|
||||
if (!entity)
|
||||
continue;
|
||||
|
||||
// Check each extrusion path or loop
|
||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(entity)) {
|
||||
// Check each point in the polyline
|
||||
for (const Point& pt : path->polyline.points) {
|
||||
Vec3d pos(unscaled<double>(pt.x()), unscaled<double>(pt.y()), layer->print_z);
|
||||
if (!validator.validate_point(pos)) {
|
||||
support_violations++;
|
||||
if (support_violations <= 5) { // Log first 5
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support path at z=" << layer->print_z
|
||||
<< " exceeds build volume boundaries";
|
||||
}
|
||||
break; // Only record once per path
|
||||
}
|
||||
}
|
||||
} else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(entity)) {
|
||||
for (const ExtrusionPath& path : loop->paths) {
|
||||
// Check each point in the polyline
|
||||
for (const Point& pt : path.polyline.points) {
|
||||
Vec3d pos(unscaled<double>(pt.x()), unscaled<double>(pt.y()), layer->print_z);
|
||||
if (!validator.validate_point(pos)) {
|
||||
support_violations++;
|
||||
if (support_violations <= 5) { // Log first 5
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support loop path at z=" << layer->print_z
|
||||
<< " exceeds build volume boundaries";
|
||||
}
|
||||
break; // Only record once per path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check support base polygons
|
||||
for (const ExPolygon& expoly : layer->lslices) {
|
||||
if (!validator.validate_polygon(expoly.contour, layer->print_z)) {
|
||||
support_violations++;
|
||||
if (support_violations <= 5) { // Log first 5
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support polygon at z=" << layer->print_z
|
||||
<< " exceeds build volume boundaries";
|
||||
}
|
||||
}
|
||||
// Check holes
|
||||
for (const Polygon& hole : expoly.holes) {
|
||||
if (!validator.validate_polygon(hole, layer->print_z)) {
|
||||
support_violations++;
|
||||
if (support_violations <= 5) { // Log first 5
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support hole polygon at z=" << layer->print_z
|
||||
<< " exceeds build volume boundaries";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (support_violations > 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Found " << support_violations
|
||||
<< " support polygons/paths exceeding build volume boundaries";
|
||||
// Record violation
|
||||
ConflictResult violation = ConflictResult::create_boundary_violation(
|
||||
static_cast<int>(BoundaryValidator::ViolationType::Support),
|
||||
Vec3d(object.center_offset().x(), object.center_offset().y(), 0.0),
|
||||
0.0,
|
||||
object.model_object()->name
|
||||
);
|
||||
object.print()->add_boundary_violation(violation);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Support generator - End";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user