feat: Add Z Anti-Aliasing (ZAA) contouring support

Port Z Anti-Aliasing from BambuStudio-ZAA (https://github.com/adob/BambuStudio-ZAA)
to OrcaSlicer. ZAA eliminates stair-stepping on curved and sloped top surfaces
by raycasting each extrusion point against the original 3D mesh and micro-adjusting
Z height to follow the actual surface geometry.

Key changes:
- Add ContourZ.cpp raycasting algorithm (~330 lines)
- Extend geometry with 3D support (Point3, Line3, Polyline3, MultiPoint3)
- Template arc fitting for 2D/3D compatibility
- Change ExtrusionPath::polyline from Polyline to Polyline3
- Add 5 ZAA config options (zaa_enabled, zaa_min_z, etc.)
- Add posContouring pipeline step in PrintObject
- Update GCode writer for 3D coordinate output
- Add ZAA settings UI in Print Settings > Quality
- Add docs/ZAA.md with usage and implementation details

ZAA is opt-in and disabled by default. When disabled, the slicing pipeline
is unchanged.
This commit is contained in:
Matthias Nott
2026-02-09 20:38:46 +01:00
parent cae1567726
commit 963f8d86b7
57 changed files with 1817 additions and 204 deletions

View File

@@ -224,17 +224,23 @@ using CurledLines = std::vector<CurledLine>;
class Line3
{
public:
Line3() : a(Vec3crd::Zero()), b(Vec3crd::Zero()) {}
Line3(const Vec3crd& _a, const Vec3crd& _b) : a(_a), b(_b) {}
Line3() : a(Point3()), b(Point3()) {}
Line3(const Point3& _a, const Point3& _b) : a(_a), b(_b) {}
// Backward compatibility with Vec3crd
Line3(const Vec3crd& _a, const Vec3crd& _b) : a(Point3(_a)), b(Point3(_b)) {}
double length() const { return (this->a - this->b).cast<double>().norm(); }
Vec3crd vector() const { return this->b - this->a; }
Point3 vector() const { Vec3crd v = this->b - this->a; return Point3(v.x(), v.y(), v.z()); }
Point3 midpoint() const { return Point3((this->a.x() + this->b.x()) / 2, (this->a.y() + this->b.y()) / 2, (this->a.z() + this->b.z()) / 2); }
Vec3crd a;
Vec3crd b;
// Convert to 2D line by dropping Z coordinate
Line to_line() const { return Line(this->a.to_point(), this->b.to_point()); }
Point3 a;
Point3 b;
static const constexpr int Dim = 3;
using Scalar = Vec3crd::Scalar;
using Scalar = coord_t;
};
class Linef
@@ -243,6 +249,10 @@ public:
Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {}
Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {}
Vec2d vector() const { return this->b - this->a; }
Vec2d unit_vector() const { return (length() == 0.0) ? Vec2d::Zero() : vector().normalized(); }
double length() const { return vector().norm(); }
Vec2d a;
Vec2d b;
@@ -263,6 +273,32 @@ public:
Vec3d unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); }
double length() const { return vector().norm(); }
double distance_to_infinite_squared(const Vec3d &point, Vec3d *closest_point) const {
const Vec3d v = this->b - this->a;
const Vec3d va = point - this->a;
const double l2 = v.squaredNorm();
if (l2 == 0.) {
// a == b case
*closest_point = this->a;
return va.squaredNorm();
}
// Consider the line extending the segment, parameterized as a + t (b - a).
// Find parameter value t of the projection of point onto the line.
const double t = va.dot(v) / l2;
*closest_point = this->a + t * v;
return (point - *closest_point).squaredNorm();
}
double distance_to_infinite_squared(const Vec3d &point) const {
Vec3d nearest_point;
return distance_to_infinite_squared(point, &nearest_point);
}
static inline double distance_to_infinite_squared(const Vec3d &point, const Vec3d &a, const Vec3d &b) {
Linef3 line{a, b};
return line.distance_to_infinite_squared(point);
}
Vec3d a;
Vec3d b;