/** * PrintabilityAnalyzer — FFF / SLA / SLS 3D-print pre-flight checker. * * Takes a triangle surface mesh (shared `SurfaceMesh` contract) plus optional * signed-distance field, and returns a `PrintabilityReport` with all fields * analytically computed — none are stubbed. * * ## Units * * The analyzer is **unit-agnostic**: it operates on raw coordinate values with * no built-in conversion. By STL convention coordinates are typically in * millimetres, but the caller controls interpretation. Use `scaleFactor` in * `PrintabilityOptions` if you need to normalise to a different unit before * analysis (vault rule G.GOLD.485: physical-unit assumptions are config, not * code). * * ## Algorithms * * ### Watertightness & Manifold check * * Build an undirected edge map: key = `min(a,b)_max(a,b)`. Each directed * half-edge (a→b) for triangle winding contributes one count per undirected * key. A closed, manifold mesh has every edge shared by exactly 2 triangles. * * watertight ⟺ ∀ edges: count == 2 * manifold ⟺ ∀ edges: count ≤ 2 AND no degenerate faces * * Degenerate face: any two vertex indices are equal, OR the cross-product * magnitude is < ε (zero-area face). * * ### Volume (divergence theorem) * * Signed volume via the divergence-theorem form of the surface integral: * * V = (1/6) Σ_i (v0 · (v1 × v2)) * * where v0,v1,v2 are the three vertices of each triangle in winding order. * A positive result means outward-facing normals (right-hand rule pointing * away from the interior); negative means inward / inverted winding. * * ### Surface area * * A = Σ_i ½ ‖(v1−v0) × (v2−v0)‖ * * ### Overhang detection * * Let N̂ be the outward face normal (unnormalised → normalised) and D̂ the * normalised build direction (default +Z). A face overhangs when: * * angle(N̂, −D̂) < (90° − threshold°) * * i.e. the face tilts toward the build plate more than `threshold` degrees * from the horizontal. Equivalently: * * dot(N̂, −D̂) > cos(90° − threshold°) = sin(threshold°) * * Faces whose centroid is within `bedEpsilon` of `aabb.min` along the build * direction are bed-contact faces and are excluded (they rest on the plate). * * ### Thin-wall heuristic (SDF sampling) * * Samples a uniform grid over the mesh AABB. For each interior sample * (evaluateSDFNode(p) < 0) within the narrow band |d| < minWallThickness, * records 2·|d| as the local wall-thickness estimate. Reports the minimum. * * This is a heuristic, not an exact medial-axis computation — it can miss * thin walls thinner than the grid spacing and may undercount on curved * surfaces. Accurate wall-thickness analysis requires medial-axis extraction * or morphological erosion. * * ## Build direction convention * * `buildDirection` is a convention parameter, NOT a physics-derived value. * The default [0,0,1] means "print layers stack along +Z" — the most common * slicer convention for STL files. Override this for machines that print * along a different axis, or when the part is oriented differently. * * @see SurfaceMesh — shared mesh contract (AutoMesher.ts) * @see SDFNode — signed-distance tree (SDFPointEvaluator.ts) * @see evaluateSDFNode — JS SDF evaluator */ import type { SurfaceMesh } from '../AutoMesher'; import type { SDFNode } from '../SDFPointEvaluator'; /** Three-component vector (no heap allocation in hot paths — use inline arrays). */ type Vec3 = readonly [number, number, number]; /** Axis-aligned bounding box. */ export interface AABB { min: Vec3; max: Vec3; size: Vec3; } /** Overhang summary returned in the report. */ export interface OverhangStats { /** Number of overhanging triangles. */ count: number; /** Total area of overhanging triangles (same units² as geometry). */ totalArea: number; /** Fraction of total surface area that overhangs: totalArea / surfaceArea. */ fraction: number; /** * Worst overhang angle in degrees — the smallest angle between the * face normal and –buildDirection (0° = perfectly horizontal underside). * NaN when count === 0. */ worstAngleDeg: number; } /** * Thin-wall sampling result. * * **Heuristic only** — this is a coarse grid-sampling estimate using the * signed-distance field. It is NOT an exact medial-axis computation. Thin * walls narrower than the grid spacing may not be detected, and curved * surfaces will yield conservative (under-)estimates. For production-grade * wall-thickness analysis, use morphological erosion or medial-axis * extraction on the full SDF. */ export interface ThinWallHeuristic { /** * Minimum 2·|sdf| measured over interior narrow-band samples. * Undefined when no interior narrow-band samples were found. */ minEstimatedThicknessMm: number | undefined; /** Number of interior narrow-band sample points queried. */ sampleCount: number; } /** Full printability analysis report. */ export interface PrintabilityReport { /** True iff every edge is shared by exactly 2 triangles. */ watertight: boolean; /** Number of edges shared by only 1 triangle (boundary edges). */ openEdgeCount: number; /** * True iff watertight AND no edge is shared by >2 triangles AND no * degenerate (zero-area or repeated-index) face exists. */ manifold: boolean; /** * Signed volume via the divergence theorem (same units³ as geometry). * Negative → winding is inverted (normals point inward). */ volume: number; /** Total surface area (same units² as geometry). */ surfaceArea: number; /** * True iff the computed volume is positive, meaning face normals are * consistently outward-facing. */ orientationOutward: boolean; /** Axis-aligned bounding box of the mesh vertices. */ aabb: AABB; /** * Whether the mesh AABB fits inside the given `buildVolume`. * Undefined when `buildVolume` was not provided. */ fitsBuildVolume: boolean | undefined; /** * Overhang statistics. Bed-contact faces (centroid within `bedEpsilon` of * aabb.min along buildDirection) are excluded. */ overhangs: OverhangStats; /** * Thin-wall heuristic result. Undefined when `sdf` and `minWallThickness` * were not both provided. */ wallThickness: ThinWallHeuristic | undefined; /** * - `'not-printable'` — mesh has topology errors or inverted winding. * - `'needs-supports'` — mesh is topologically sound but has overhangs. * - `'printable'` — no detected issues. */ recommendation: 'printable' | 'needs-supports' | 'not-printable'; } /** * Options for `analyzePrintability`. * * All fields are optional; documented defaults match common FFF-printer * conventions but are NOT physics laws — override as needed. */ export interface PrintabilityOptions { /** * Build direction — the direction in which layers are stacked. * * **Convention, not physics**: [0,0,1] (+Z up) is the most common slicer * convention for STL files and is the default here. Override for machines * that print along a different axis, or when the part is placed on its side. * * The vector does not need to be normalised — it is normalised internally. * * @default [0, 0, 1] */ buildDirection?: Vec3; /** * Overhang threshold in degrees (0°–90°). * * Faces angled more than this many degrees from horizontal (away from the * build plate) are flagged as overhangs. FFF printers typically bridge * ≤45° without supports; SLA/DLP can sometimes handle steeper angles. * * @default 45 */ overhangThresholdDeg?: number; /** * Optional build-volume AABB. When provided, `fitsBuildVolume` is set in * the report. Coordinates must be in the same unit system as the mesh. */ buildVolume?: { min: Vec3; max: Vec3; }; /** * Optional minimum wall thickness (same units as geometry). * * Only evaluated when `sdf` is also provided. Triggers SDF grid sampling * to estimate the thinnest wall present; see `ThinWallHeuristic`. */ minWallThickness?: number; /** * Optional SDF tree for interior wall-thickness sampling. * * Must describe the same solid as the surface mesh. Interior is defined * as evaluateSDFNode(p) < 0. Only used when `minWallThickness` is also * given. */ sdf?: SDFNode; /** * Optional uniform scale factor applied to all vertex coordinates before * analysis. Use to convert units (e.g. inches → mm: scaleFactor = 25.4). * * All report distances/areas/volumes are in the scaled units. * * @default 1 */ scaleFactor?: number; /** * Grid resolution for the thin-wall SDF sampling pass along each axis. * * Higher values give finer resolution at the cost of O(n³) SDF evaluations. * * @default [20, 20, 20] */ sdfGridResolution?: readonly [number, number, number]; /** * Bed-contact epsilon: faces whose centroid is within this distance of * `aabb.min` along the build direction are treated as resting on the print * bed and excluded from overhang detection. * * @default 1e-6 */ bedEpsilon?: number; } /** * Analyse a triangle surface mesh for 3D-print feasibility. * * @param mesh Triangle surface mesh — `SurfaceMesh` from AutoMesher.ts. * @param opts Analysis options (all optional; see `PrintabilityOptions`). * @returns `PrintabilityReport` with all fields computed. */ export declare function analyzePrintability(mesh: SurfaceMesh, opts?: PrintabilityOptions): PrintabilityReport; export {}; //# sourceMappingURL=PrintabilityAnalyzer.d.ts.map