import * as THREE from "three"; import type { TopoType, ComponentInfo } from "../../rendering/id-picking.js"; import type { ToolType } from "./tools.js"; /** * A measurement response. Carries both `subtype` (so the viewer's * `handleBackendResponse` routes it like a Python response) and `tool_type` (so * `Tools.handleResponse` dispatches to the right measurement). The remaining fields * (`result`, `refpoint*`, `shape_type`, `geom_type`, …) mirror the Python backend. */ export interface MeasureResponse { type: "backend_response"; subtype: "tool_response"; tool_type: ToolType; [key: string]: unknown; } /** * TypeScript mesh-based measurement backend. * * Computes meaningful measurements (area, length, volume, bounding box, min/center * distance, angle) from the tessellated mesh, so the measure tools work WITHOUT the * external Python (`ocp_vscode`) backend — the default when developing three-cad-viewer * standalone. Selected via the `externalMeasurementBackend` option (default `false` = * this backend; `ocp_vscode` sets `true` to use Python). See MeshBackend.md. * * Accuracy: `shape_type` / `geom_type` are EXACT (carried per-component in the * tessellation `face_types` / `edge_types`). Numeric values are mesh-accurate — exact * for planar faces / straight edges, within tessellation deflection for curved geometry. * * This module is the FROZEN contract (APPROACH.md "contracts-first"): the GeomAbs name * tables, the {@link MeshComponentGeometry} shape the provider yields, the * {@link MeshGeometryProvider} interface, and the pure geometry math operate on * world-space coordinates (the provider applies each node's transform). */ /** GeomAbs_SurfaceType ordinals → name (face_types). */ export declare const SURFACE_TYPE_NAMES: readonly ["Plane", "Cylinder", "Cone", "Sphere", "Torus", "BezierSurface", "BSplineSurface", "SurfaceOfRevolution", "SurfaceOfExtrusion", "OffsetSurface", "OtherSurface"]; /** GeomAbs_CurveType ordinals → name (edge_types). */ export declare const CURVE_TYPE_NAMES: readonly ["Line", "Circle", "Ellipse", "Hyperbola", "Parabola", "BezierCurve", "BSplineCurve", "OffsetCurve", "OtherCurve"]; /** Resolve a face's `face_types` code to its geom_type name (`"Other"` if unknown). */ export declare function faceGeomType(code: number): string; /** Resolve an edge's `edge_types` code to its geom_type name (`"Other"` if unknown). */ export declare function edgeGeomType(code: number): string; /** * Short, lowercase geom_type for a status-line readout. Drops the trailing * `Curve`/`Surface` suffix (`BSplineSurface`/`BSplineCurve` → `bspline`, * `Plane` → `plane`, `Line` → `line`) and spaces the remaining CamelCase words * for readability (`SurfaceOfExtrusion` → `surface of extrusion`, * `SurfaceOfRevolution` → `surface of revolution`). The lowercase→uppercase * split leaves single words and the leading-caps `BSpline` untouched. Topo * selects the surface vs curve table. */ export declare function displayGeomType(topo: TopoType, code: number): string; /** * Mesh geometry for one resolved component, in WORLD space (the provider has already * applied the owning node's transform). Discriminated by {@link topo}: * - `face` / `solid`: {@link positions} is a vertex pool, {@link indices} are triangle * index triples into it (a solid merges all its faces). * - `edge`: {@link positions} is a flat list of segment endpoint pairs (6 floats per * segment: `x0,y0,z0, x1,y1,z1`); {@link indices} is undefined. * - `vertex`: {@link positions} is exactly one point (3 floats); {@link indices} undefined. */ export interface MeshComponentGeometry { topo: TopoType; /** Raw GeomAbs code (`face_types`/`edge_types` entry); `-1` for vertex/solid. */ geomType: number; /** World-space coordinates (layout depends on {@link topo}; see interface doc). */ positions: Float32Array; /** Triangle index triples into {@link positions} (face/solid only). */ indices?: Uint32Array; } /** * Resolves a backend component path (e.g. `"/box/faces/faces_3"`, `"/box/edges/edges_1"`, * `"/box/vertices/vertices_0"`, or a bare solid path `"/box"`) to its world-space mesh * geometry. Returns `null` for unknown paths or components with no captured geometry. * Populated at tessellation time (see Phase task: render-shape / nestedgroup). */ export interface MeshGeometryProvider { resolve(path: string): MeshComponentGeometry | null; } /** * Decomposition of a component into closest-distance primitives. The minimum distance * between two triangle meshes is always realized by a vertex-vs-triangle or an * edge-vs-edge pair, so these three lists are sufficient (and exact for the mesh). */ export interface MeshFeatures { /** All vertices (world space). */ points: THREE.Vector3[]; /** Triangles as [a, b, c] vertex triples (face/solid). */ tris: [THREE.Vector3, THREE.Vector3, THREE.Vector3][]; /** Line segments as [a, b] endpoint pairs (edges, and triangle edges of faces). */ segs: [THREE.Vector3, THREE.Vector3][]; } /** Build the {@link MeshFeatures} primitive sets from a component's geometry. */ export declare function buildFeatures(geom: MeshComponentGeometry): MeshFeatures; /** Total surface area of a triangulated face/solid (Σ ½·|(b−a)×(c−a)|). */ export declare function triangulatedArea(geom: MeshComponentGeometry): number; /** Total length of an edge polyline (Σ segment lengths). */ export declare function polylineLength(geom: MeshComponentGeometry): number; /** * Signed volume of a closed triangulated solid via the divergence theorem * (Σ (1/6)·a·(b×c) over triangles). The tessellation winds triangles CCW outward, so * the sum is positive; returned as an absolute value for robustness. */ export declare function meshVolume(geom: MeshComponentGeometry): number; /** * Exact circle (center + radius) through three well-separated points of a circular * edge's tessellation polyline. The tessellation vertices lie ON the true curve, so * the circumcircle of any three is exact (up to float precision). `positions` is the * flat segment-endpoint list (works for both arcs and closed circles). Returns `null` * if the three points are degenerate/collinear. */ export declare function circleFromPolyline(positions: Float32Array): { center: number[]; radius: number; } | null; /** * Status-line text for a hovered component — FIXED attributes only, no backend, no * live cursor coord, NO path (the object is identified via the tree on double-click). * Mesh-estimated length/area/volume are shown with `≈` (BRep-grade values come from * the measurement tool). face: `geom: area ≈ A`; edge: `geom: len ≈ L, start/end`; * vertex: coords; solid: `solid: N faces, M edges, vol ≈ V`. */ export declare function hoverStatusText(info: ComponentInfo, fromSolid: boolean, provider: MeshGeometrySource): string; /** Axis-aligned bounding box of a component's vertices. */ export declare function boundingBox(geom: MeshComponentGeometry): { min: number[]; center: number[]; max: number[]; size: number[]; }; /** * Representative center point of a component (mesh approximation of `refpoint`): * - vertex → the point; * - edge → length-weighted midpoint of its segments; * - face → area-weighted centroid of its triangles; * - solid → volume-weighted centroid of its tetrahedra (apex at origin). */ export declare function centroid(geom: MeshComponentGeometry): THREE.Vector3; /** Area-weighted average triangle normal of a face (unit length), or `null`. */ export declare function averageNormal(geom: MeshComponentGeometry): THREE.Vector3 | null; /** Overall direction of an edge (first → last endpoint, unit length), or `null`. */ export declare function edgeDirection(geom: MeshComponentGeometry): THREE.Vector3 | null; /** Closest point on segment [a,b] to point p, written into `out`. */ export declare function closestPointOnSegment(p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, out: THREE.Vector3): THREE.Vector3; /** Closest point on triangle (a,b,c) to point p, written into `out` (Ericson §5.1.5). */ export declare function closestPointOnTriangle(p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, c: THREE.Vector3, out: THREE.Vector3): THREE.Vector3; /** * Closest points between segments [p1,q1] and [p2,q2], written into `outA`/`outB`; * returns the squared distance (Ericson §5.1.9). */ export declare function closestSegmentSegment(p1: THREE.Vector3, q1: THREE.Vector3, p2: THREE.Vector3, q2: THREE.Vector3, outA: THREE.Vector3, outB: THREE.Vector3): number; /** * Brute-force minimum distance between two components and the realizing points. * Evaluates every closest-feature pair, in BOTH argument orders, over the feature sets: * point-vs-triangle, point-vs-segment, segment-vs-segment, and point-vs-point. This is * the complete set of closest-feature pairs for triangle meshes and their lower-dim * degenerations (edges = segments, vertices = points), so the result is exact for the * mesh and independent of which component is passed first. * * O(Ta·Tb) — quadratic. {@link minDistance} is the production entry: it uses this * directly for small components and the BVH branch-and-bound above the pair threshold. * Kept exported as the reference oracle the BVH path is property-tested against. */ export declare function minDistanceBrute(ga: MeshComponentGeometry, gb: MeshComponentGeometry): { distance: number; point1: THREE.Vector3; point2: THREE.Vector3; }; /** * Minimum squared distance between triangle (ta,tb,tc) and segment (sa,sb), with the * realizing points (on the triangle → `outTri`, on the segment → `outSeg`). Complete * set: each segment endpoint vs the triangle (covers face interior + edges + vertices) * and each triangle edge vs the segment. */ export declare function triSegDistance(ta: THREE.Vector3, tb: THREE.Vector3, tc: THREE.Vector3, sa: THREE.Vector3, sb: THREE.Vector3, outTri: THREE.Vector3, outSeg: THREE.Vector3): number; /** * Minimum squared distance between triangles (a0,a1,a2) and (b0,b1,b2), with the * realizing points (`outA` on the first, `outB` on the second). Complete set for * disjoint triangles: each vertex vs the other triangle, plus all 9 edge-edge pairs. * (Interpenetrating triangles can report a small positive value rather than 0 — the * same limitation the brute oracle has, and irrelevant for distance between surfaces.) */ export declare function triTriDistance(a0: THREE.Vector3, a1: THREE.Vector3, a2: THREE.Vector3, b0: THREE.Vector3, b1: THREE.Vector3, b2: THREE.Vector3, outA: THREE.Vector3, outB: THREE.Vector3): number; /** * Minimum distance between two components and the realizing points — the production * entry. Exact and sub-quadratic via a per-component AABB tree + branch-and-bound * (see {@link minDistanceBrute} for the O(Ta·Tb) reference it is property-tested * against, and which it delegates to for small inputs). Result is identical to the * brute force and independent of argument order. */ export declare function minDistance(ga: MeshComponentGeometry, gb: MeshComponentGeometry): { distance: number; point1: THREE.Vector3; point2: THREE.Vector3; }; /** Angle (degrees) between two unit directions. */ export declare function angleBetween(d1: THREE.Vector3, d2: THREE.Vector3): number; /** * Angle (degrees) of a face normal or edge tangent to the world XY plane (+Z up), * mirroring `measure.py` `angle to XY`: for a face normal, the angle to +Z; for an edge * direction `abs(90 − angle(dir, +Z))`. */ export declare function angleToXY(dir: THREE.Vector3, isEdge: boolean): number; /** Raw per-node tessellation arrays the source needs (subset of `Shape`). */ export interface RawNodeShape { vertices?: number[] | number[][] | Float32Array | undefined; triangles?: number[] | number[][] | Uint32Array | undefined; triangles_per_face?: number[] | Uint32Array | undefined; edges?: number[] | number[][] | Float32Array | undefined; segments_per_edge?: number[] | Uint32Array | undefined; obj_vertices?: number[] | Float32Array | undefined; face_types?: number[] | Uint32Array | undefined; edge_types?: number[] | Uint8Array | Uint32Array | undefined; } /** * Populated as the compact `NestedGroup` tessellates each node (faces/edges/vertices), * keyed by the node's `/`-path — the SAME paths the `ComponentRegistry` uses, so a * backend component id resolves directly. Mode-independent: it stores the raw per-node * arrays + the owning group (for `matrixWorld`) and slices/transforms on demand. */ export declare class MeshGeometrySource implements MeshGeometryProvider { private nodes; constructor(); /** Record a node's raw tessellation arrays. `object` provides the world transform. */ register(path: string, shape: RawNodeShape, object: THREE.Object3D, subtype: string | null): void; /** Drop all entries (called from `NestedGroup.clear`/`dispose`). */ clear(): void; /** * Drop nodes whose path is `prefix` or lies under it (`prefix + "/"`), for * {@link Viewer.removePart} — keeps the provider from growing across remove/add * cycles. */ removeByPathPrefix(prefix: string): void; /** * Static face/edge counts of a node from its tessellation type arrays * (`len(face_types)` / `len(edge_types)`). For a solid node these are the solid's * total face/edge counts. `null` for an unknown node. */ nodeCounts(path: string): { faces: number; edges: number; } | null; resolve(path: string): MeshComponentGeometry | null; private _typeAt; /** Index triples for face `i` into the vertex pool (flat-with-counts or nested). */ private _faceTriangleIndices; /** All triangle index triples (every face) for a solid. */ private _allTriangleIndices; /** World-local segment endpoint pairs (6 floats/segment) for edge `i`. */ private _edgeSegments; } /** * Computes measurement responses from the mesh (no external Python backend). The * default measurement backend when `externalMeasurementBackend === false`. Returns a * `ToolResponse` ready for `viewer.handleBackendResponse`, or `null` if a component * can't be resolved (caller leaves the panel unanswered, same as a backend timeout). */ export declare class MeshMeasureBackend { private getProvider; constructor(getProvider: () => MeshGeometryProvider | null); /** PropertiesMeasurement response for a single component. */ properties(path: string): MeasureResponse | null; /** DistanceMeasurement response between two components. */ distance(path1: string, path2: string, center: boolean): MeasureResponse | null; }