remesh-threejs 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +271 -0
- package/dist/index.d.ts +2505 -0
- package/dist/remesh-threejs.cjs +2 -0
- package/dist/remesh-threejs.cjs.map +1 -0
- package/dist/remesh-threejs.js +4338 -0
- package/dist/remesh-threejs.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remesh-threejs.js","sources":["../src/types/MeshData.ts","../src/types/SkeletonData.ts","../src/types/RemeshOptions.ts","../src/core/Vertex.ts","../src/core/Edge.ts","../src/core/Face.ts","../src/core/NonManifoldMesh.ts","../src/geometry/GeometricUtils.ts","../src/skeleton/SkeletonSegment.ts","../src/skeleton/SkeletonBuilder.ts","../src/core/FeatureSkeleton.ts","../src/skeleton/SkeletonConstraints.ts","../src/io/BufferGeometryImporter.ts","../src/io/BufferGeometryExporter.ts","../src/spatial/SpatialHash.ts","../src/spatial/BVH.ts","../src/analysis/ManifoldAnalyzer.ts","../src/analysis/VertexClassifier.ts","../src/analysis/TopologyValidator.ts","../src/operations/EdgeFlip.ts","../src/operations/EdgeSplit.ts","../src/operations/EdgeContraction.ts","../src/operations/VertexRelocation.ts","../src/algorithms/QualityMetrics.ts","../src/algorithms/AdaptiveRemesher.ts"],"sourcesContent":["/**\n * Branded types for mesh elements to ensure type safety.\n * These prevent accidentally mixing up different ID types.\n */\n\n/**\n * Unique identifier for a vertex in the mesh.\n */\nexport type VertexId = number & { readonly __brand: 'VertexId' };\n\n/**\n * Unique identifier for an edge in the mesh.\n */\nexport type EdgeId = number & { readonly __brand: 'EdgeId' };\n\n/**\n * Unique identifier for a halfedge in the mesh.\n */\nexport type HalfedgeId = number & { readonly __brand: 'HalfedgeId' };\n\n/**\n * Unique identifier for a face in the mesh.\n */\nexport type FaceId = number & { readonly __brand: 'FaceId' };\n\n/**\n * Unique identifier for a skeleton segment.\n */\nexport type SegmentId = number & { readonly __brand: 'SegmentId' };\n\n/**\n * Creates a branded VertexId from a number.\n */\nexport function createVertexId(id: number): VertexId {\n return id as VertexId;\n}\n\n/**\n * Creates a branded EdgeId from a number.\n */\nexport function createEdgeId(id: number): EdgeId {\n return id as EdgeId;\n}\n\n/**\n * Creates a branded HalfedgeId from a number.\n */\nexport function createHalfedgeId(id: number): HalfedgeId {\n return id as HalfedgeId;\n}\n\n/**\n * Creates a branded FaceId from a number.\n */\nexport function createFaceId(id: number): FaceId {\n return id as FaceId;\n}\n\n/**\n * Creates a branded SegmentId from a number.\n */\nexport function createSegmentId(id: number): SegmentId {\n return id as SegmentId;\n}\n\n/**\n * Extracts the numeric value from a branded ID.\n */\nexport function toNumber(id: VertexId | EdgeId | HalfedgeId | FaceId | SegmentId): number {\n return id as number;\n}\n","/**\n * Classification types for vertices and edges in non-manifold meshes.\n * Based on the EUROGRAPHICS 2008 paper \"Adaptive Remeshing of Non-Manifold Surfaces\".\n */\n\n/**\n * Classification of a vertex based on its neighborhood topology.\n *\n * - Manifold: Star homeomorphic to disk, can move freely in 3D\n * - OpenBook: On exactly 2 skeleton edges (like pages of a book), constrained to skeleton\n * - SkeletonBranching: On 1 or >2 skeleton edges, position is fixed\n * - NonManifoldOther: Other non-manifold configurations, position is fixed\n */\nexport enum VertexType {\n /** Vertex with manifold neighborhood - can move freely in 3D */\n Manifold = 'manifold',\n\n /** Vertex on exactly 2 skeleton edges (open-book) - constrained to skeleton segment */\n OpenBook = 'open_book',\n\n /** Vertex on 1 or >2 skeleton edges - position is fixed */\n SkeletonBranching = 'skeleton_branching',\n\n /** Other non-manifold vertex type - position is fixed */\n NonManifoldOther = 'non_manifold_other',\n}\n\n/**\n * Classification of an edge based on its incident faces.\n *\n * - Manifold: Exactly 2 incident faces\n * - NonManifold: More than 2 incident faces (seam edge)\n * - Feature: User-defined feature edge that should be preserved\n * - Boundary: Only 1 incident face (mesh boundary)\n */\nexport enum EdgeType {\n /** Edge with exactly 2 incident faces - standard manifold edge */\n Manifold = 'manifold',\n\n /** Edge with more than 2 incident faces - non-manifold seam */\n NonManifold = 'non_manifold',\n\n /** User-defined feature edge that should be preserved */\n Feature = 'feature',\n\n /** Edge with only 1 incident face - boundary edge */\n Boundary = 'boundary',\n}\n\n/**\n * Determines if a vertex type allows free movement in 3D space.\n */\nexport function canMoveFreely(type: VertexType): boolean {\n return type === VertexType.Manifold;\n}\n\n/**\n * Determines if a vertex type is constrained to a skeleton segment.\n */\nexport function isSkeletonConstrained(type: VertexType): boolean {\n return type === VertexType.OpenBook;\n}\n\n/**\n * Determines if a vertex type has a fixed position.\n */\nexport function isPositionFixed(type: VertexType): boolean {\n return type === VertexType.SkeletonBranching || type === VertexType.NonManifoldOther;\n}\n\n/**\n * Determines if an edge type is part of the feature skeleton.\n */\nexport function isSkeletonEdge(type: EdgeType): boolean {\n return type === EdgeType.NonManifold || type === EdgeType.Feature || type === EdgeType.Boundary;\n}\n\n/**\n * Determines if an edge can be flipped (only manifold edges can be flipped).\n */\nexport function canFlipEdge(type: EdgeType): boolean {\n return type === EdgeType.Manifold;\n}\n","/**\n * Configuration options for the adaptive remeshing algorithm.\n */\n\n/**\n * Feature edge specification as a pair of vertex indices.\n */\nexport type FeatureEdge = [number, number];\n\n/**\n * Options for the adaptive remeshing algorithm.\n */\nexport interface RemeshOptions {\n /**\n * Number of remeshing iterations to perform.\n * More iterations generally produce higher quality results.\n * @default 5\n */\n iterations?: number;\n\n /**\n * Target edge length for the remeshed surface.\n * If not specified, computed automatically based on mesh bounding box.\n */\n targetEdgeLength?: number;\n\n /**\n * User-defined feature edges that should be preserved.\n * Each edge is specified as a pair of vertex indices from the input geometry.\n * These edges will be included in the feature skeleton.\n */\n featureEdges?: FeatureEdge[];\n\n /**\n * Whether to preserve boundary edges.\n * When true, boundary edges are included in the skeleton and preserved.\n * @default true\n */\n preserveBoundary?: boolean;\n\n /**\n * Minimum allowed edge length as a fraction of targetEdgeLength.\n * Edges shorter than this will be collapsed.\n * @default 0.4\n */\n minEdgeLengthRatio?: number;\n\n /**\n * Maximum allowed edge length as a fraction of targetEdgeLength.\n * Edges longer than this will be split.\n * @default 1.333\n */\n maxEdgeLengthRatio?: number;\n\n /**\n * Minimum allowed triangle quality (0 to 1).\n * Triangles with quality below this threshold are prioritized for improvement.\n * Quality is measured as the ratio of inscribed to circumscribed circle radii.\n * @default 0.3\n */\n minTriangleQuality?: number;\n\n /**\n * Maximum angle deviation from original surface (in radians).\n * Vertices are not relocated if it would cause normals to deviate more than this.\n * @default Math.PI / 6 (30 degrees)\n */\n maxNormalDeviation?: number;\n\n /**\n * Use spatial acceleration structures for large meshes.\n * Recommended for meshes with more than 50K triangles.\n * @default true\n */\n useAcceleration?: boolean;\n\n /**\n * Process mesh in chunks of this size.\n * Set to 0 to disable chunking.\n * Useful for very large meshes to manage memory usage.\n * @default 0\n */\n chunkSize?: number;\n\n /**\n * Maximum memory budget in MB.\n * Set to 0 for unlimited.\n * When exceeded, algorithm will attempt to reduce memory usage.\n * @default 0\n */\n memoryBudget?: number;\n\n /**\n * Enable verbose logging during remeshing.\n * @default false\n */\n verbose?: boolean;\n}\n\n/**\n * Statistics returned after remeshing completes.\n */\nexport interface RemeshStats {\n /** Number of vertices in the input mesh */\n inputVertices: number;\n\n /** Number of faces in the input mesh */\n inputFaces: number;\n\n /** Number of vertices in the output mesh */\n outputVertices: number;\n\n /** Number of faces in the output mesh */\n outputFaces: number;\n\n /** Number of iterations performed */\n iterations: number;\n\n /** Final average triangle quality (0 to 1) */\n finalQuality: number;\n\n /** Number of non-manifold edges detected */\n nonManifoldEdges: number;\n\n /** Number of skeleton edges (non-manifold + feature + boundary) */\n skeletonEdges: number;\n\n /** Number of edge flips performed */\n edgeFlips: number;\n\n /** Number of edge splits performed */\n edgeSplits: number;\n\n /** Number of edge contractions performed */\n edgeContractions: number;\n\n /** Number of vertex relocations performed */\n vertexRelocations: number;\n\n /** Total processing time in milliseconds */\n processingTimeMs: number;\n}\n\n/**\n * Result of the remeshing operation.\n */\nexport interface RemeshResult {\n /** Statistics about the remeshing operation */\n stats: RemeshStats;\n}\n\n/**\n * Default remeshing options.\n */\nexport const DEFAULT_REMESH_OPTIONS: Required<\n Omit<RemeshOptions, 'targetEdgeLength' | 'featureEdges'>\n> = {\n iterations: 5,\n preserveBoundary: true,\n minEdgeLengthRatio: 0.4,\n maxEdgeLengthRatio: 1.333,\n minTriangleQuality: 0.3,\n maxNormalDeviation: Math.PI / 6,\n useAcceleration: true,\n chunkSize: 0,\n memoryBudget: 0,\n verbose: false,\n};\n","import type { Vector3 } from 'three';\nimport type { VertexId } from '../types/MeshData';\nimport type { Halfedge } from './Edge';\nimport { VertexType } from '../types/SkeletonData';\n\n/**\n * Maximum iterations for vertex traversal to prevent infinite loops.\n */\nconst MAX_ITERATIONS = 10000;\n\n/**\n * Represents a vertex in the mesh.\n * Stores position, classification, and a reference to one outgoing halfedge.\n */\nexport class Vertex {\n /**\n * One outgoing halfedge from this vertex.\n * All outgoing halfedges can be found by following next/twin pointers.\n */\n public halfedge: Halfedge | null = null;\n\n /**\n * Classification of this vertex based on neighborhood topology.\n * Determines movement constraints during remeshing.\n */\n public type: VertexType = VertexType.Manifold;\n\n /**\n * Whether this vertex is marked (e.g., for selection or processing).\n */\n public isMarked: boolean = false;\n\n constructor(\n /**\n * Unique identifier for this vertex.\n */\n public readonly id: VertexId,\n\n /**\n * 3D position of this vertex.\n */\n public readonly position: Vector3\n ) {}\n\n /**\n * Gets the degree of this vertex (number of incident edges).\n * Returns null if the vertex has no incident halfedge.\n */\n degree(): number | null {\n if (!this.halfedge) {\n return null;\n }\n\n let count = 0;\n let current = this.halfedge;\n\n do {\n count++;\n // Move to next outgoing halfedge by going to twin's next\n if (!current.twin || !current.twin.next) {\n // Boundary vertex or invalid structure - count remaining edges manually\n break;\n }\n current = current.twin.next;\n\n // Safety check to prevent infinite loops\n if (count > MAX_ITERATIONS) {\n throw new Error(`Vertex ${this.id}: degree calculation exceeded maximum iterations`);\n }\n } while (current !== this.halfedge);\n\n return count;\n }\n\n /**\n * Iterates over all outgoing halfedges from this vertex.\n *\n * @param callback - Function called for each outgoing halfedge\n */\n forEachOutgoingHalfedge(callback: (halfedge: Halfedge) => void): void {\n if (!this.halfedge) {\n return;\n }\n\n let current = this.halfedge;\n let iterationCount = 0;\n\n do {\n callback(current);\n\n // Move to next outgoing halfedge\n if (!current.twin || !current.twin.next) {\n break;\n }\n current = current.twin.next;\n\n // Safety check\n iterationCount++;\n if (iterationCount > MAX_ITERATIONS) {\n throw new Error(`Vertex ${this.id}: halfedge iteration exceeded maximum iterations`);\n }\n } while (current !== this.halfedge);\n }\n\n /**\n * Collects all outgoing halfedges from this vertex into an array.\n *\n * @returns Array of outgoing halfedges\n */\n getOutgoingHalfedges(): Halfedge[] {\n const halfedges: Halfedge[] = [];\n this.forEachOutgoingHalfedge((he) => halfedges.push(he));\n return halfedges;\n }\n\n /**\n * Iterates over all neighboring vertices.\n *\n * @param callback - Function called for each neighboring vertex\n */\n forEachNeighbor(callback: (vertex: Vertex) => void): void {\n this.forEachOutgoingHalfedge((he) => {\n callback(he.vertex);\n });\n }\n\n /**\n * Collects all neighboring vertices into an array.\n *\n * @returns Array of neighboring vertices\n */\n getNeighbors(): Vertex[] {\n const neighbors: Vertex[] = [];\n this.forEachNeighbor((v) => neighbors.push(v));\n return neighbors;\n }\n\n /**\n * Checks if this vertex is on the boundary of the mesh.\n * A vertex is on the boundary if any of its incident halfedges has no face.\n */\n isBoundary(): boolean {\n if (!this.halfedge) {\n return true;\n }\n\n let hasBoundaryHalfedge = false;\n this.forEachOutgoingHalfedge((he) => {\n if (!he.face) {\n hasBoundaryHalfedge = true;\n }\n });\n\n return hasBoundaryHalfedge;\n }\n\n /**\n * Checks if this vertex can move freely during remeshing.\n * Only manifold vertices can move freely in 3D space.\n */\n canMoveFreely(): boolean {\n return this.type === VertexType.Manifold;\n }\n\n /**\n * Checks if this vertex is constrained to a skeleton segment.\n * OpenBook vertices can only move along their skeleton segment.\n */\n isSkeletonConstrained(): boolean {\n return this.type === VertexType.OpenBook;\n }\n\n /**\n * Checks if this vertex has a fixed position.\n * Branching and other non-manifold vertices cannot move.\n */\n isPositionFixed(): boolean {\n return this.type === VertexType.SkeletonBranching || this.type === VertexType.NonManifoldOther;\n }\n\n /**\n * Checks if this vertex is part of the feature skeleton.\n */\n isOnSkeleton(): boolean {\n return this.type !== VertexType.Manifold;\n }\n}\n","import type { EdgeId, HalfedgeId } from '../types/MeshData';\nimport type { Vertex } from './Vertex';\nimport type { Face } from './Face';\nimport { EdgeType } from '../types/SkeletonData';\n\n/**\n * Represents a halfedge in the mesh.\n * A halfedge is a directed edge from one vertex to another.\n */\nexport class Halfedge {\n /**\n * The vertex this halfedge points to (target vertex).\n */\n public vertex: Vertex;\n\n /**\n * The opposite halfedge (same edge, opposite direction).\n * For non-manifold edges, this points to one of potentially many twins.\n */\n public twin: Halfedge | null = null;\n\n /**\n * The next halfedge in the face loop (counter-clockwise).\n */\n public next: Halfedge | null = null;\n\n /**\n * The previous halfedge in the face loop.\n */\n public prev: Halfedge | null = null;\n\n /**\n * The face this halfedge belongs to (null for boundary halfedges).\n */\n public face: Face | null = null;\n\n /**\n * The parent undirected edge.\n */\n public edge: Edge;\n\n constructor(\n /**\n * Unique identifier for this halfedge.\n */\n public readonly id: HalfedgeId,\n\n /**\n * The vertex this halfedge points to.\n */\n vertex: Vertex,\n\n /**\n * The parent edge.\n */\n edge: Edge\n ) {\n this.vertex = vertex;\n this.edge = edge;\n }\n\n /**\n * Gets the source vertex of this halfedge (the vertex it starts from).\n * This is the target vertex of the twin halfedge.\n */\n getSourceVertex(): Vertex | null {\n return this.twin?.vertex ?? null;\n }\n\n /**\n * Gets the target vertex of this halfedge.\n */\n getTargetVertex(): Vertex {\n return this.vertex;\n }\n\n /**\n * Checks if this halfedge is on the boundary (has no face).\n */\n isBoundary(): boolean {\n return this.face === null;\n }\n\n /**\n * Gets the opposite halfedge in the same face (two edges away).\n * For a triangle, this is the edge opposite to this halfedge's source vertex.\n */\n getOppositeHalfedge(): Halfedge | null {\n return this.next?.next ?? null;\n }\n\n /**\n * Gets the vertex opposite to this halfedge in its face.\n * For a triangle, this is the vertex not on this halfedge.\n */\n getOppositeVertex(): Vertex | null {\n return this.next?.vertex ?? null;\n }\n\n /**\n * Computes the vector along this halfedge (from source to target).\n * Returns null if source vertex is not available.\n */\n getVector(): { x: number; y: number; z: number } | null {\n const source = this.getSourceVertex();\n if (!source) {\n return null;\n }\n\n return {\n x: this.vertex.position.x - source.position.x,\n y: this.vertex.position.y - source.position.y,\n z: this.vertex.position.z - source.position.z,\n };\n }\n}\n\n/**\n * Represents an undirected edge in the mesh.\n * For non-manifold meshes, an edge can have more than 2 halfedges.\n */\nexport class Edge {\n /**\n * One of the halfedges comprising this edge (used for traversal).\n */\n public halfedge: Halfedge;\n\n /**\n * All halfedges associated with this edge.\n * For manifold edges, this contains exactly 2 halfedges.\n * For non-manifold edges, this contains more than 2 halfedges.\n */\n public allHalfedges: Halfedge[] = [];\n\n /**\n * The intrinsic length of this edge.\n * This may differ from the Euclidean distance after edge operations.\n */\n public length: number;\n\n /**\n * Classification of this edge.\n */\n public type: EdgeType = EdgeType.Manifold;\n\n /**\n * Whether this edge is part of any path in a network.\n */\n public isInPath: boolean = false;\n\n constructor(\n /**\n * Unique identifier for this edge.\n */\n public readonly id: EdgeId,\n\n /**\n * One of the halfedges.\n */\n halfedge: Halfedge,\n\n /**\n * Initial edge length.\n */\n length: number\n ) {\n this.halfedge = halfedge;\n this.length = length;\n this.allHalfedges.push(halfedge);\n }\n\n /**\n * Adds a halfedge to this edge.\n */\n addHalfedge(halfedge: Halfedge): void {\n this.allHalfedges.push(halfedge);\n this.updateType();\n }\n\n /**\n * Gets the number of halfedges (indicates non-manifoldness).\n * 2 = manifold, >2 = non-manifold, 1 = boundary\n */\n getHalfedgeCount(): number {\n return this.allHalfedges.length;\n }\n\n /**\n * Updates the edge type based on the number of incident faces.\n */\n updateType(): void {\n const faceCount = this.getFaceCount();\n\n if (faceCount === 0) {\n // Isolated edge (shouldn't normally happen)\n this.type = EdgeType.Boundary;\n } else if (faceCount === 1) {\n this.type = EdgeType.Boundary;\n } else if (faceCount === 2) {\n // Could still be a feature edge - don't override if already set\n if (this.type !== EdgeType.Feature) {\n this.type = EdgeType.Manifold;\n }\n } else {\n // More than 2 faces = non-manifold\n this.type = EdgeType.NonManifold;\n }\n }\n\n /**\n * Gets the number of faces incident to this edge.\n */\n getFaceCount(): number {\n let count = 0;\n for (const he of this.allHalfedges) {\n if (he.face !== null) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Gets both vertices of this edge.\n * Returns [v0, v1] where v0 is the source of halfedge and v1 is the target.\n */\n getVertices(): [Vertex, Vertex] | [null, null] {\n const v0 = this.halfedge.getSourceVertex();\n const v1 = this.halfedge.getTargetVertex();\n\n if (!v0) {\n return [null, null];\n }\n\n return [v0, v1];\n }\n\n /**\n * Gets all faces adjacent to this edge.\n * For manifold edges, returns up to 2 faces.\n * For non-manifold edges, returns all incident faces.\n */\n getFaces(): Face[] {\n const faces: Face[] = [];\n for (const he of this.allHalfedges) {\n if (he.face !== null) {\n faces.push(he.face);\n }\n }\n return faces;\n }\n\n /**\n * Gets both faces adjacent to this edge (for manifold edges).\n * Returns [f0, f1] where f0 is the face of halfedge and f1 is the face of twin.\n * Either face can be null for boundary edges.\n */\n getTwoFaces(): [Face | null, Face | null] {\n const f0 = this.halfedge.face;\n const f1 = this.halfedge.twin?.face ?? null;\n return [f0, f1];\n }\n\n /**\n * Checks if this edge is on the boundary (has only one adjacent face).\n */\n isBoundary(): boolean {\n return this.type === EdgeType.Boundary;\n }\n\n /**\n * Checks if this edge is non-manifold (has more than 2 adjacent faces).\n */\n isNonManifold(): boolean {\n return this.type === EdgeType.NonManifold;\n }\n\n /**\n * Checks if this edge is part of the feature skeleton.\n */\n isSkeletonEdge(): boolean {\n return (\n this.type === EdgeType.NonManifold ||\n this.type === EdgeType.Feature ||\n this.type === EdgeType.Boundary\n );\n }\n\n /**\n * Checks if this edge can be flipped.\n * An edge can be flipped if:\n * 1. It has exactly two adjacent faces (manifold, not skeleton)\n * 2. Both endpoints have degree > 1\n * 3. The quadrilateral formed is convex (checked separately)\n */\n canFlip(): boolean {\n // Only manifold edges can be flipped\n if (this.type !== EdgeType.Manifold) {\n return false;\n }\n\n // Check if edge has exactly two faces\n if (this.getFaceCount() !== 2) {\n return false;\n }\n\n // Check vertex degrees\n const [v0, v1] = this.getVertices();\n if (!v0 || !v1) {\n return false;\n }\n\n const degree0 = v0.degree();\n const degree1 = v1.degree();\n\n if (degree0 === null || degree1 === null || degree0 <= 1 || degree1 <= 1) {\n return false;\n }\n\n // Convexity check would require geometric information (done in EdgeFlip algorithm)\n return true;\n }\n\n /**\n * Gets the other vertex of this edge (given one vertex).\n */\n getOtherVertex(v: Vertex): Vertex | null {\n const [v0, v1] = this.getVertices();\n if (!v0 || !v1) {\n return null;\n }\n\n if (v.id === v0.id) {\n return v1;\n } else if (v.id === v1.id) {\n return v0;\n }\n\n return null;\n }\n\n /**\n * Marks this edge as a feature edge.\n */\n markAsFeature(): void {\n if (this.type === EdgeType.Manifold) {\n this.type = EdgeType.Feature;\n }\n }\n}\n","import type { FaceId } from '../types/MeshData';\nimport type { Halfedge } from './Edge';\nimport type { Vertex } from './Vertex';\n\n/**\n * Represents a triangular face in the mesh.\n * A face is defined by three halfedges forming a loop.\n */\nexport class Face {\n /**\n * One of the three halfedges bounding this face.\n * The other two can be found by following next pointers.\n */\n public halfedge: Halfedge;\n\n /**\n * Whether this face is marked (e.g., for selection or processing).\n */\n public isMarked: boolean = false;\n\n constructor(\n /**\n * Unique identifier for this face.\n */\n public readonly id: FaceId,\n\n /**\n * One of the bounding halfedges.\n */\n halfedge: Halfedge\n ) {\n this.halfedge = halfedge;\n }\n\n /**\n * Gets all three vertices of this face.\n * Returns vertices in counter-clockwise order.\n */\n getVertices(): [Vertex, Vertex, Vertex] | null {\n const he0 = this.halfedge;\n const he1 = he0.next;\n const he2 = he1?.next;\n\n if (!he1 || !he2) {\n return null;\n }\n\n return [he0.vertex, he1.vertex, he2.vertex];\n }\n\n /**\n * Gets all three halfedges of this face.\n * Returns halfedges in counter-clockwise order.\n */\n getHalfedges(): [Halfedge, Halfedge, Halfedge] | null {\n const he0 = this.halfedge;\n const he1 = he0.next;\n const he2 = he1?.next;\n\n if (!he1 || !he2) {\n return null;\n }\n\n return [he0, he1, he2];\n }\n\n /**\n * Iterates over the three halfedges of this face.\n *\n * @param callback - Function called for each halfedge\n */\n forEachHalfedge(callback: (halfedge: Halfedge) => void): void {\n const halfedges = this.getHalfedges();\n if (!halfedges) {\n return;\n }\n\n for (const he of halfedges) {\n callback(he);\n }\n }\n\n /**\n * Iterates over the three vertices of this face.\n *\n * @param callback - Function called for each vertex\n */\n forEachVertex(callback: (vertex: Vertex) => void): void {\n const vertices = this.getVertices();\n if (!vertices) {\n return;\n }\n\n for (const v of vertices) {\n callback(v);\n }\n }\n\n /**\n * Computes the centroid (center of mass) of this face.\n * Returns null if vertices cannot be retrieved.\n */\n getCentroid(): { x: number; y: number; z: number } | null {\n const vertices = this.getVertices();\n if (!vertices) {\n return null;\n }\n\n const [v0, v1, v2] = vertices;\n return {\n x: (v0.position.x + v1.position.x + v2.position.x) / 3,\n y: (v0.position.y + v1.position.y + v2.position.y) / 3,\n z: (v0.position.z + v1.position.z + v2.position.z) / 3,\n };\n }\n\n /**\n * Computes the normal vector of this face.\n * Uses the cross product of two edges.\n * Returns null if vertices cannot be retrieved.\n */\n getNormal(): { x: number; y: number; z: number } | null {\n const vertices = this.getVertices();\n if (!vertices) {\n return null;\n }\n\n const [v0, v1, v2] = vertices;\n\n // Edge vectors\n const e1x = v1.position.x - v0.position.x;\n const e1y = v1.position.y - v0.position.y;\n const e1z = v1.position.z - v0.position.z;\n\n const e2x = v2.position.x - v0.position.x;\n const e2y = v2.position.y - v0.position.y;\n const e2z = v2.position.z - v0.position.z;\n\n // Cross product\n const nx = e1y * e2z - e1z * e2y;\n const ny = e1z * e2x - e1x * e2z;\n const nz = e1x * e2y - e1y * e2x;\n\n // Normalize\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\n if (len < 1e-10) {\n return { x: 0, y: 0, z: 1 }; // Degenerate face\n }\n\n return {\n x: nx / len,\n y: ny / len,\n z: nz / len,\n };\n }\n\n /**\n * Computes the area of this face.\n * Returns null if vertices cannot be retrieved.\n */\n getArea(): number | null {\n const vertices = this.getVertices();\n if (!vertices) {\n return null;\n }\n\n const [v0, v1, v2] = vertices;\n\n // Edge vectors\n const e1x = v1.position.x - v0.position.x;\n const e1y = v1.position.y - v0.position.y;\n const e1z = v1.position.z - v0.position.z;\n\n const e2x = v2.position.x - v0.position.x;\n const e2y = v2.position.y - v0.position.y;\n const e2z = v2.position.z - v0.position.z;\n\n // Cross product magnitude / 2\n const cx = e1y * e2z - e1z * e2y;\n const cy = e1z * e2x - e1x * e2z;\n const cz = e1x * e2y - e1y * e2x;\n\n return Math.sqrt(cx * cx + cy * cy + cz * cz) / 2;\n }\n\n /**\n * Computes the quality of this triangle.\n * Quality is measured as 2 * inradius / circumradius (ranges from 0 to 1).\n * A value of 1 indicates an equilateral triangle.\n * Returns null if vertices cannot be retrieved.\n */\n getQuality(): number | null {\n const vertices = this.getVertices();\n if (!vertices) {\n return null;\n }\n\n const [v0, v1, v2] = vertices;\n\n // Compute edge lengths\n const a = Math.sqrt(\n Math.pow(v1.position.x - v2.position.x, 2) +\n Math.pow(v1.position.y - v2.position.y, 2) +\n Math.pow(v1.position.z - v2.position.z, 2)\n );\n const b = Math.sqrt(\n Math.pow(v0.position.x - v2.position.x, 2) +\n Math.pow(v0.position.y - v2.position.y, 2) +\n Math.pow(v0.position.z - v2.position.z, 2)\n );\n const c = Math.sqrt(\n Math.pow(v0.position.x - v1.position.x, 2) +\n Math.pow(v0.position.y - v1.position.y, 2) +\n Math.pow(v0.position.z - v1.position.z, 2)\n );\n\n // Semi-perimeter\n const s = (a + b + c) / 2;\n\n // Area via Heron's formula\n const areaSquared = s * (s - a) * (s - b) * (s - c);\n if (areaSquared <= 0) {\n return 0; // Degenerate triangle\n }\n const area = Math.sqrt(areaSquared);\n\n // Inradius: r = area / s\n const inradius = area / s;\n\n // Circumradius: R = (a * b * c) / (4 * area)\n const circumradius = (a * b * c) / (4 * area);\n\n if (circumradius < 1e-10) {\n return 0;\n }\n\n // Quality: 2 * r / R (normalized to [0, 1])\n const quality = (2 * inradius) / circumradius;\n\n return Math.max(0, Math.min(1, quality));\n }\n\n /**\n * Checks if this face contains a given vertex.\n */\n containsVertex(vertex: Vertex): boolean {\n const vertices = this.getVertices();\n if (!vertices) {\n return false;\n }\n\n return vertices.some((v) => v.id === vertex.id);\n }\n\n /**\n * Gets the halfedge opposite to a given vertex.\n * Returns null if the vertex is not part of this face.\n */\n getOppositeHalfedge(vertex: Vertex): Halfedge | null {\n const halfedges = this.getHalfedges();\n if (!halfedges) {\n return null;\n }\n\n for (const he of halfedges) {\n const source = he.getSourceVertex();\n if (source && source.id !== vertex.id && he.vertex.id !== vertex.id) {\n return he;\n }\n }\n\n return null;\n }\n\n /**\n * Checks if this face is degenerate (has zero or near-zero area).\n */\n isDegenerate(epsilon: number = 1e-10): boolean {\n const area = this.getArea();\n return area === null || area < epsilon;\n }\n}\n","import { Vector3, type BufferGeometry } from 'three';\nimport { Vertex } from './Vertex';\nimport { Edge, Halfedge } from './Edge';\nimport { Face } from './Face';\nimport {\n createVertexId,\n createEdgeId,\n createHalfedgeId,\n createFaceId,\n type VertexId,\n type EdgeId,\n type HalfedgeId,\n type FaceId,\n} from '../types/MeshData';\nimport { EdgeType, VertexType } from '../types/SkeletonData';\nimport type { FeatureEdge } from '../types/RemeshOptions';\n\n/**\n * Represents a non-manifold mesh using an extended halfedge data structure.\n * Supports edges with more than 2 incident faces (non-manifold seams).\n */\nexport class NonManifoldMesh {\n public vertices: Map<VertexId, Vertex> = new Map();\n public edges: Map<EdgeId, Edge> = new Map();\n public halfedges: Map<HalfedgeId, Halfedge> = new Map();\n public faces: Map<FaceId, Face> = new Map();\n\n private nextVertexId = 0;\n private nextEdgeId = 0;\n private nextHalfedgeId = 0;\n private nextFaceId = 0;\n\n /** Map from vertex pair key to edge for fast lookup */\n private edgeMap: Map<string, Edge> = new Map();\n\n /**\n * Creates a non-manifold mesh from a Three.js BufferGeometry.\n *\n * @param geometry - The input geometry (must be indexed triangles)\n * @param featureEdges - Optional user-defined feature edges to preserve\n */\n static fromBufferGeometry(\n geometry: BufferGeometry,\n featureEdges?: FeatureEdge[]\n ): NonManifoldMesh {\n const mesh = new NonManifoldMesh();\n\n // Get position attribute\n const positions = geometry.attributes['position'];\n if (!positions) {\n throw new Error('Geometry must have a position attribute');\n }\n\n // Get index attribute\n const indices = geometry.index;\n if (!indices) {\n throw new Error('Geometry must be indexed');\n }\n\n const numVertices = positions.count;\n const numFaces = indices.count / 3;\n\n if (indices.count % 3 !== 0) {\n throw new Error('Geometry must be triangulated (indices count must be divisible by 3)');\n }\n\n // Create vertices\n for (let i = 0; i < numVertices; i++) {\n const x = positions.getX(i);\n const y = positions.getY(i);\n const z = positions.getZ(i);\n const vertex = new Vertex(createVertexId(mesh.nextVertexId++), new Vector3(x, y, z));\n mesh.vertices.set(vertex.id, vertex);\n }\n\n // Create faces and halfedges\n for (let i = 0; i < numFaces; i++) {\n const i0 = indices.getX(i * 3 + 0);\n const i1 = indices.getX(i * 3 + 1);\n const i2 = indices.getX(i * 3 + 2);\n\n const v0 = mesh.vertices.get(createVertexId(i0));\n const v1 = mesh.vertices.get(createVertexId(i1));\n const v2 = mesh.vertices.get(createVertexId(i2));\n\n if (!v0 || !v1 || !v2) {\n throw new Error(`Vertex not found in face ${i}: ${i0}, ${i1}, ${i2}`);\n }\n\n // Get or create edges\n const edge01 = mesh.getOrCreateEdge(i0, i1);\n const edge12 = mesh.getOrCreateEdge(i1, i2);\n const edge20 = mesh.getOrCreateEdge(i2, i0);\n\n // Create face\n const face = new Face(createFaceId(mesh.nextFaceId++), null as unknown as Halfedge);\n mesh.faces.set(face.id, face);\n\n // Create halfedges\n const he01 = new Halfedge(createHalfedgeId(mesh.nextHalfedgeId++), v1, edge01);\n const he12 = new Halfedge(createHalfedgeId(mesh.nextHalfedgeId++), v2, edge12);\n const he20 = new Halfedge(createHalfedgeId(mesh.nextHalfedgeId++), v0, edge20);\n\n mesh.halfedges.set(he01.id, he01);\n mesh.halfedges.set(he12.id, he12);\n mesh.halfedges.set(he20.id, he20);\n\n // Add halfedges to their edges\n edge01.addHalfedge(he01);\n edge12.addHalfedge(he12);\n edge20.addHalfedge(he20);\n\n // Set up halfedge connectivity for this face\n he01.next = he12;\n he12.next = he20;\n he20.next = he01;\n\n he01.prev = he20;\n he12.prev = he01;\n he20.prev = he12;\n\n he01.face = face;\n he12.face = face;\n he20.face = face;\n\n // Set face's halfedge\n face.halfedge = he01;\n\n // Set vertex outgoing halfedge (if not already set)\n if (!v0.halfedge) v0.halfedge = he01;\n if (!v1.halfedge) v1.halfedge = he12;\n if (!v2.halfedge) v2.halfedge = he20;\n\n // Update edge's primary halfedge to the most recently created one\n edge01.halfedge = he01;\n edge12.halfedge = he12;\n edge20.halfedge = he20;\n }\n\n // Set up twin halfedges (handles non-manifold edges)\n mesh.setupTwinHalfedges();\n\n // Mark feature edges\n if (featureEdges && featureEdges.length > 0) {\n mesh.markFeatureEdges(featureEdges);\n }\n\n // Classify vertices based on neighborhood topology\n mesh.classifyVertices();\n\n return mesh;\n }\n\n /**\n * Gets or creates an edge between two vertices.\n */\n private getOrCreateEdge(v0Id: number, v1Id: number): Edge {\n const key = this.makeEdgeKey(v0Id, v1Id);\n let edge = this.edgeMap.get(key);\n\n if (!edge) {\n const v0 = this.vertices.get(createVertexId(v0Id));\n const v1 = this.vertices.get(createVertexId(v1Id));\n if (!v0 || !v1) {\n throw new Error(`Vertex not found: ${v0Id} or ${v1Id}`);\n }\n\n // Calculate edge length from 3D positions\n const dx = v1.position.x - v0.position.x;\n const dy = v1.position.y - v0.position.y;\n const dz = v1.position.z - v0.position.z;\n const length = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n // Create edge with placeholder halfedge\n edge = new Edge(createEdgeId(this.nextEdgeId++), null as unknown as Halfedge, length);\n // Clear allHalfedges since it was initialized with the placeholder\n edge.allHalfedges = [];\n this.edgeMap.set(key, edge);\n this.edges.set(edge.id, edge);\n }\n\n return edge;\n }\n\n /**\n * Creates a canonical key for an edge between two vertices.\n */\n private makeEdgeKey(v0Id: number, v1Id: number): string {\n return v0Id < v1Id ? `${v0Id},${v1Id}` : `${v1Id},${v0Id}`;\n }\n\n /**\n * Sets up twin halfedge relationships.\n * For non-manifold edges (>2 halfedges), creates a circular twin chain.\n */\n private setupTwinHalfedges(): void {\n for (const edge of this.edges.values()) {\n const halfedges = edge.allHalfedges;\n const count = halfedges.length;\n\n if (count === 0) {\n continue;\n }\n\n if (count === 1) {\n // Boundary edge - no twin\n halfedges[0]!.twin = null;\n edge.type = EdgeType.Boundary;\n } else if (count === 2) {\n // Standard manifold edge\n halfedges[0]!.twin = halfedges[1]!;\n halfedges[1]!.twin = halfedges[0]!;\n edge.type = EdgeType.Manifold;\n } else {\n // Non-manifold edge (>2 halfedges)\n // Group by direction and set up twins for opposite pairs\n this.setupNonManifoldTwins(edge, halfedges);\n edge.type = EdgeType.NonManifold;\n }\n }\n\n // Update vertex halfedges to prefer interior edges\n for (const he of this.halfedges.values()) {\n if (he.twin !== null) {\n const vertex = he.prev?.vertex;\n if (vertex) {\n vertex.halfedge = he;\n }\n }\n }\n }\n\n /**\n * Sets up twin relationships for non-manifold edges.\n * Groups halfedges by direction and pairs them appropriately.\n */\n private setupNonManifoldTwins(edge: Edge, halfedges: Halfedge[]): void {\n // Group halfedges by their direction (which vertex they point to)\n const [v0, v1] = edge.getVertices();\n if (!v0 || !v1) return;\n\n const toV0: Halfedge[] = [];\n const toV1: Halfedge[] = [];\n\n for (const he of halfedges) {\n if (he.vertex.id === v0.id) {\n toV0.push(he);\n } else {\n toV1.push(he);\n }\n }\n\n // Pair halfedges in opposite directions\n // If counts are unequal, some will not have twins\n const minCount = Math.min(toV0.length, toV1.length);\n\n for (let i = 0; i < minCount; i++) {\n toV0[i]!.twin = toV1[i]!;\n toV1[i]!.twin = toV0[i]!;\n }\n\n // Remaining unpaired halfedges have null twins (like boundary)\n for (let i = minCount; i < toV0.length; i++) {\n toV0[i]!.twin = null;\n }\n for (let i = minCount; i < toV1.length; i++) {\n toV1[i]!.twin = null;\n }\n }\n\n /**\n * Marks user-defined feature edges.\n */\n markFeatureEdges(featureEdges: FeatureEdge[]): void {\n for (const [v0, v1] of featureEdges) {\n const key = this.makeEdgeKey(v0, v1);\n const edge = this.edgeMap.get(key);\n if (edge && edge.type === EdgeType.Manifold) {\n edge.markAsFeature();\n }\n }\n }\n\n /**\n * Classifies all vertices based on their neighborhood topology.\n */\n classifyVertices(): void {\n for (const vertex of this.vertices.values()) {\n vertex.type = this.classifyVertex(vertex);\n }\n }\n\n /**\n * Classifies a single vertex based on its neighborhood.\n */\n private classifyVertex(vertex: Vertex): VertexType {\n // Count skeleton edges incident to this vertex\n let skeletonEdgeCount = 0;\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (he.edge.isSkeletonEdge()) {\n skeletonEdgeCount++;\n }\n });\n\n if (skeletonEdgeCount === 0) {\n // No skeleton edges - manifold vertex\n return VertexType.Manifold;\n } else if (skeletonEdgeCount === 2) {\n // Exactly 2 skeleton edges - open-book vertex\n return VertexType.OpenBook;\n } else {\n // 1 or >2 skeleton edges - branching vertex\n return VertexType.SkeletonBranching;\n }\n }\n\n /**\n * Exports the mesh to a Three.js BufferGeometry.\n */\n toBufferGeometry(): BufferGeometry {\n const geometry = new (Vector3.constructor as unknown as typeof BufferGeometry)();\n\n // This will be implemented in BufferGeometryExporter\n // For now, just return an empty geometry\n return geometry;\n }\n\n /**\n * Gets all vertices in the mesh.\n */\n getVertices(): Vertex[] {\n return Array.from(this.vertices.values());\n }\n\n /**\n * Gets all edges in the mesh.\n */\n getEdges(): Edge[] {\n return Array.from(this.edges.values());\n }\n\n /**\n * Gets all faces in the mesh.\n */\n getFaces(): Face[] {\n return Array.from(this.faces.values());\n }\n\n /**\n * Gets all halfedges in the mesh.\n */\n getHalfedges(): Halfedge[] {\n return Array.from(this.halfedges.values());\n }\n\n /**\n * Gets the vertex count.\n */\n get vertexCount(): number {\n return this.vertices.size;\n }\n\n /**\n * Gets the edge count.\n */\n get edgeCount(): number {\n return this.edges.size;\n }\n\n /**\n * Gets the face count.\n */\n get faceCount(): number {\n return this.faces.size;\n }\n\n /**\n * Gets the halfedge count.\n */\n get halfedgeCount(): number {\n return this.halfedges.size;\n }\n\n /**\n * Gets all non-manifold edges.\n */\n getNonManifoldEdges(): Edge[] {\n return this.getEdges().filter((e) => e.type === EdgeType.NonManifold);\n }\n\n /**\n * Gets all boundary edges.\n */\n getBoundaryEdges(): Edge[] {\n return this.getEdges().filter((e) => e.type === EdgeType.Boundary);\n }\n\n /**\n * Gets all feature edges.\n */\n getFeatureEdges(): Edge[] {\n return this.getEdges().filter((e) => e.type === EdgeType.Feature);\n }\n\n /**\n * Gets all skeleton edges (non-manifold + boundary + feature).\n */\n getSkeletonEdges(): Edge[] {\n return this.getEdges().filter((e) => e.isSkeletonEdge());\n }\n\n /**\n * Checks if the mesh is manifold (no non-manifold edges).\n */\n isManifold(): boolean {\n return this.getNonManifoldEdges().length === 0;\n }\n\n /**\n * Checks if the mesh has boundaries.\n */\n hasBoundary(): boolean {\n return this.getBoundaryEdges().length > 0;\n }\n\n /**\n * Gets a vertex by ID.\n */\n getVertex(id: VertexId): Vertex | undefined {\n return this.vertices.get(id);\n }\n\n /**\n * Gets an edge by ID.\n */\n getEdge(id: EdgeId): Edge | undefined {\n return this.edges.get(id);\n }\n\n /**\n * Gets a face by ID.\n */\n getFace(id: FaceId): Face | undefined {\n return this.faces.get(id);\n }\n\n /**\n * Gets a halfedge by ID.\n */\n getHalfedge(id: HalfedgeId): Halfedge | undefined {\n return this.halfedges.get(id);\n }\n\n /**\n * Gets the edge between two vertices (if it exists).\n */\n getEdgeBetween(v0: Vertex, v1: Vertex): Edge | undefined {\n const key = this.makeEdgeKey(v0.id as number, v1.id as number);\n return this.edgeMap.get(key);\n }\n\n /**\n * Creates a new vertex and adds it to the mesh.\n */\n createVertex(position: Vector3): Vertex {\n const vertex = new Vertex(createVertexId(this.nextVertexId++), position);\n this.vertices.set(vertex.id, vertex);\n return vertex;\n }\n\n /**\n * Creates a new face from three vertices.\n * Also creates the necessary halfedges and edges.\n */\n createFace(v0: Vertex, v1: Vertex, v2: Vertex): Face {\n // Get or create edges\n const edge01 = this.getOrCreateEdge(v0.id as number, v1.id as number);\n const edge12 = this.getOrCreateEdge(v1.id as number, v2.id as number);\n const edge20 = this.getOrCreateEdge(v2.id as number, v0.id as number);\n\n // Create face\n const face = new Face(createFaceId(this.nextFaceId++), null as unknown as Halfedge);\n this.faces.set(face.id, face);\n\n // Create halfedges\n const he01 = new Halfedge(createHalfedgeId(this.nextHalfedgeId++), v1, edge01);\n const he12 = new Halfedge(createHalfedgeId(this.nextHalfedgeId++), v2, edge12);\n const he20 = new Halfedge(createHalfedgeId(this.nextHalfedgeId++), v0, edge20);\n\n this.halfedges.set(he01.id, he01);\n this.halfedges.set(he12.id, he12);\n this.halfedges.set(he20.id, he20);\n\n // Add to edges\n edge01.addHalfedge(he01);\n edge12.addHalfedge(he12);\n edge20.addHalfedge(he20);\n\n // Set up halfedge connectivity\n he01.next = he12;\n he12.next = he20;\n he20.next = he01;\n\n he01.prev = he20;\n he12.prev = he01;\n he20.prev = he12;\n\n he01.face = face;\n he12.face = face;\n he20.face = face;\n\n face.halfedge = he01;\n\n // Update vertex halfedges\n if (!v0.halfedge) v0.halfedge = he01;\n if (!v1.halfedge) v1.halfedge = he12;\n if (!v2.halfedge) v2.halfedge = he20;\n\n // Update edge primary halfedges\n edge01.halfedge = he01;\n edge12.halfedge = he12;\n edge20.halfedge = he20;\n\n return face;\n }\n\n /**\n * Computes mesh statistics.\n */\n getStats(): {\n vertexCount: number;\n edgeCount: number;\n faceCount: number;\n nonManifoldEdgeCount: number;\n boundaryEdgeCount: number;\n featureEdgeCount: number;\n eulerCharacteristic: number;\n } {\n const nonManifoldEdgeCount = this.getNonManifoldEdges().length;\n const boundaryEdgeCount = this.getBoundaryEdges().length;\n const featureEdgeCount = this.getFeatureEdges().length;\n\n // Euler characteristic: V - E + F\n const eulerCharacteristic = this.vertexCount - this.edgeCount + this.faceCount;\n\n return {\n vertexCount: this.vertexCount,\n edgeCount: this.edgeCount,\n faceCount: this.faceCount,\n nonManifoldEdgeCount,\n boundaryEdgeCount,\n featureEdgeCount,\n eulerCharacteristic,\n };\n }\n}\n","import type { Vector3 } from 'three';\n\n/**\n * A simple 3D vector interface for internal computations.\n */\nexport interface Vec3 {\n x: number;\n y: number;\n z: number;\n}\n\n/**\n * Computes the squared distance between two points.\n */\nexport function distanceSquared(a: Vec3, b: Vec3): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const dz = b.z - a.z;\n return dx * dx + dy * dy + dz * dz;\n}\n\n/**\n * Computes the Euclidean distance between two points.\n */\nexport function distance(a: Vec3, b: Vec3): number {\n return Math.sqrt(distanceSquared(a, b));\n}\n\n/**\n * Computes the dot product of two vectors.\n */\nexport function dot(a: Vec3, b: Vec3): number {\n return a.x * b.x + a.y * b.y + a.z * b.z;\n}\n\n/**\n * Computes the cross product of two vectors.\n */\nexport function cross(a: Vec3, b: Vec3): Vec3 {\n return {\n x: a.y * b.z - a.z * b.y,\n y: a.z * b.x - a.x * b.z,\n z: a.x * b.y - a.y * b.x,\n };\n}\n\n/**\n * Computes the length of a vector.\n */\nexport function length(v: Vec3): number {\n return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);\n}\n\n/**\n * Computes the squared length of a vector.\n */\nexport function lengthSquared(v: Vec3): number {\n return v.x * v.x + v.y * v.y + v.z * v.z;\n}\n\n/**\n * Normalizes a vector to unit length.\n * Returns a zero vector if the input has zero length.\n */\nexport function normalize(v: Vec3): Vec3 {\n const len = length(v);\n if (len < 1e-10) {\n return { x: 0, y: 0, z: 0 };\n }\n return {\n x: v.x / len,\n y: v.y / len,\n z: v.z / len,\n };\n}\n\n/**\n * Adds two vectors.\n */\nexport function add(a: Vec3, b: Vec3): Vec3 {\n return {\n x: a.x + b.x,\n y: a.y + b.y,\n z: a.z + b.z,\n };\n}\n\n/**\n * Subtracts vector b from vector a.\n */\nexport function subtract(a: Vec3, b: Vec3): Vec3 {\n return {\n x: a.x - b.x,\n y: a.y - b.y,\n z: a.z - b.z,\n };\n}\n\n/**\n * Multiplies a vector by a scalar.\n */\nexport function scale(v: Vec3, s: number): Vec3 {\n return {\n x: v.x * s,\n y: v.y * s,\n z: v.z * s,\n };\n}\n\n/**\n * Linearly interpolates between two vectors.\n */\nexport function lerp(a: Vec3, b: Vec3, t: number): Vec3 {\n return {\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n z: a.z + (b.z - a.z) * t,\n };\n}\n\n/**\n * Computes the midpoint between two points.\n */\nexport function midpoint(a: Vec3, b: Vec3): Vec3 {\n return {\n x: (a.x + b.x) / 2,\n y: (a.y + b.y) / 2,\n z: (a.z + b.z) / 2,\n };\n}\n\n/**\n * Computes the angle between two vectors in radians.\n */\nexport function angleBetween(a: Vec3, b: Vec3): number {\n const lenA = length(a);\n const lenB = length(b);\n if (lenA < 1e-10 || lenB < 1e-10) {\n return 0;\n }\n const cosAngle = dot(a, b) / (lenA * lenB);\n // Clamp to [-1, 1] to handle numerical errors\n return Math.acos(Math.max(-1, Math.min(1, cosAngle)));\n}\n\n/**\n * Projects a point onto a line defined by two points.\n * Returns the closest point on the line to the given point.\n */\nexport function projectPointOnLine(point: Vec3, lineStart: Vec3, lineEnd: Vec3): Vec3 {\n const lineDir = subtract(lineEnd, lineStart);\n const lineLengthSq = lengthSquared(lineDir);\n\n if (lineLengthSq < 1e-10) {\n return { ...lineStart };\n }\n\n const t = dot(subtract(point, lineStart), lineDir) / lineLengthSq;\n\n return add(lineStart, scale(lineDir, t));\n}\n\n/**\n * Projects a point onto a line segment defined by two endpoints.\n * Returns the closest point on the segment to the given point.\n */\nexport function projectPointOnSegment(point: Vec3, segStart: Vec3, segEnd: Vec3): Vec3 {\n const lineDir = subtract(segEnd, segStart);\n const lineLengthSq = lengthSquared(lineDir);\n\n if (lineLengthSq < 1e-10) {\n return { ...segStart };\n }\n\n const t = Math.max(0, Math.min(1, dot(subtract(point, segStart), lineDir) / lineLengthSq));\n\n return add(segStart, scale(lineDir, t));\n}\n\n/**\n * Computes the area of a triangle given three vertices.\n */\nexport function triangleArea(v0: Vec3, v1: Vec3, v2: Vec3): number {\n const e1 = subtract(v1, v0);\n const e2 = subtract(v2, v0);\n const crossProduct = cross(e1, e2);\n return length(crossProduct) / 2;\n}\n\n/**\n * Computes the normal of a triangle given three vertices.\n * Returns a normalized vector perpendicular to the triangle.\n */\nexport function triangleNormal(v0: Vec3, v1: Vec3, v2: Vec3): Vec3 {\n const e1 = subtract(v1, v0);\n const e2 = subtract(v2, v0);\n return normalize(cross(e1, e2));\n}\n\n/**\n * Computes the centroid of a triangle.\n */\nexport function triangleCentroid(v0: Vec3, v1: Vec3, v2: Vec3): Vec3 {\n return {\n x: (v0.x + v1.x + v2.x) / 3,\n y: (v0.y + v1.y + v2.y) / 3,\n z: (v0.z + v1.z + v2.z) / 3,\n };\n}\n\n/**\n * Computes the circumcenter of a triangle.\n * Returns the center of the circumscribed circle.\n */\nexport function triangleCircumcenter(v0: Vec3, v1: Vec3, v2: Vec3): Vec3 | null {\n const a = subtract(v1, v0);\n const b = subtract(v2, v0);\n const crossAB = cross(a, b);\n const denom = 2 * lengthSquared(crossAB);\n\n if (denom < 1e-10) {\n return null; // Degenerate triangle\n }\n\n const aLenSq = lengthSquared(a);\n const bLenSq = lengthSquared(b);\n\n const term1 = scale(cross(crossAB, a), bLenSq);\n const term2 = scale(cross(b, crossAB), aLenSq);\n const circumcenterOffset = scale(add(term1, term2), 1 / denom);\n\n return add(v0, circumcenterOffset);\n}\n\n/**\n * Computes the circumradius of a triangle.\n */\nexport function triangleCircumradius(v0: Vec3, v1: Vec3, v2: Vec3): number | null {\n const a = distance(v1, v2);\n const b = distance(v0, v2);\n const c = distance(v0, v1);\n\n const area = triangleArea(v0, v1, v2);\n if (area < 1e-10) {\n return null; // Degenerate triangle\n }\n\n return (a * b * c) / (4 * area);\n}\n\n/**\n * Computes the inradius of a triangle.\n */\nexport function triangleInradius(v0: Vec3, v1: Vec3, v2: Vec3): number | null {\n const a = distance(v1, v2);\n const b = distance(v0, v2);\n const c = distance(v0, v1);\n\n const s = (a + b + c) / 2; // Semi-perimeter\n const area = triangleArea(v0, v1, v2);\n\n if (s < 1e-10) {\n return null; // Degenerate triangle\n }\n\n return area / s;\n}\n\n/**\n * Computes the quality of a triangle (2 * inradius / circumradius).\n * Returns a value between 0 and 1, where 1 is an equilateral triangle.\n */\nexport function triangleQuality(v0: Vec3, v1: Vec3, v2: Vec3): number {\n const inr = triangleInradius(v0, v1, v2);\n const circumr = triangleCircumradius(v0, v1, v2);\n\n if (inr === null || circumr === null || circumr < 1e-10) {\n return 0;\n }\n\n return Math.max(0, Math.min(1, (2 * inr) / circumr));\n}\n\n/**\n * Checks if a point lies inside a triangle (using barycentric coordinates).\n */\nexport function isPointInTriangle(point: Vec3, v0: Vec3, v1: Vec3, v2: Vec3): boolean {\n const e0 = subtract(v1, v0);\n const e1 = subtract(v2, v0);\n const e2 = subtract(point, v0);\n\n const d00 = dot(e0, e0);\n const d01 = dot(e0, e1);\n const d11 = dot(e1, e1);\n const d20 = dot(e2, e0);\n const d21 = dot(e2, e1);\n\n const denom = d00 * d11 - d01 * d01;\n if (Math.abs(denom) < 1e-10) {\n return false; // Degenerate triangle\n }\n\n const v = (d11 * d20 - d01 * d21) / denom;\n const w = (d00 * d21 - d01 * d20) / denom;\n const u = 1 - v - w;\n\n return u >= 0 && v >= 0 && w >= 0;\n}\n\n/**\n * Computes the barycentric coordinates of a point with respect to a triangle.\n */\nexport function barycentricCoordinates(\n point: Vec3,\n v0: Vec3,\n v1: Vec3,\n v2: Vec3\n): { u: number; v: number; w: number } | null {\n const e0 = subtract(v1, v0);\n const e1 = subtract(v2, v0);\n const e2 = subtract(point, v0);\n\n const d00 = dot(e0, e0);\n const d01 = dot(e0, e1);\n const d11 = dot(e1, e1);\n const d20 = dot(e2, e0);\n const d21 = dot(e2, e1);\n\n const denom = d00 * d11 - d01 * d01;\n if (Math.abs(denom) < 1e-10) {\n return null; // Degenerate triangle\n }\n\n const v = (d11 * d20 - d01 * d21) / denom;\n const w = (d00 * d21 - d01 * d20) / denom;\n const u = 1 - v - w;\n\n return { u, v, w };\n}\n\n/**\n * Checks if the quadrilateral formed by two adjacent triangles is convex.\n * Used to determine if an edge can be flipped.\n *\n * @param v0 - First vertex of the shared edge\n * @param v1 - Second vertex of the shared edge\n * @param v2 - Opposite vertex in first triangle\n * @param v3 - Opposite vertex in second triangle\n */\nexport function isQuadConvex(v0: Vec3, v1: Vec3, v2: Vec3, v3: Vec3): boolean {\n // Project to 2D using the average normal of the two triangles\n const n1 = triangleNormal(v0, v1, v2);\n const n2 = triangleNormal(v0, v3, v1);\n const normal = normalize(add(n1, n2));\n\n // Choose a coordinate system on the plane\n let tangent: Vec3;\n if (Math.abs(normal.x) < 0.9) {\n tangent = normalize(cross(normal, { x: 1, y: 0, z: 0 }));\n } else {\n tangent = normalize(cross(normal, { x: 0, y: 1, z: 0 }));\n }\n const bitangent = cross(normal, tangent);\n\n // Project vertices to 2D\n const project = (v: Vec3): { x: number; y: number } => ({\n x: dot(v, tangent),\n y: dot(v, bitangent),\n });\n\n const p0 = project(v0);\n const p1 = project(v1);\n const p2 = project(v2);\n const p3 = project(v3);\n\n // Check if the diagonal v2-v3 lies inside the quadrilateral\n // by checking if v2 and v3 are on opposite sides of v0-v1\n const cross2D = (a: { x: number; y: number }, b: { x: number; y: number }): number =>\n a.x * b.y - a.y * b.x;\n\n const d01 = { x: p1.x - p0.x, y: p1.y - p0.y };\n const d02 = { x: p2.x - p0.x, y: p2.y - p0.y };\n const d03 = { x: p3.x - p0.x, y: p3.y - p0.y };\n\n const sign2 = cross2D(d01, d02);\n const sign3 = cross2D(d01, d03);\n\n // v2 and v3 should be on opposite sides of the edge v0-v1\n if (sign2 * sign3 >= 0) {\n return false;\n }\n\n // Also check that v0 and v1 are on opposite sides of v2-v3\n const d23 = { x: p3.x - p2.x, y: p3.y - p2.y };\n const d20 = { x: p0.x - p2.x, y: p0.y - p2.y };\n const d21 = { x: p1.x - p2.x, y: p1.y - p2.y };\n\n const sign0 = cross2D(d23, d20);\n const sign1 = cross2D(d23, d21);\n\n return sign0 * sign1 < 0;\n}\n\n/**\n * Converts a Three.js Vector3 to a Vec3 interface.\n */\nexport function fromVector3(v: Vector3): Vec3 {\n return { x: v.x, y: v.y, z: v.z };\n}\n\n/**\n * Computes the cotangent of the angle at a vertex in a triangle.\n * Used for computing Laplacian weights.\n */\nexport function cotangent(v0: Vec3, vertex: Vec3, v1: Vec3): number {\n const e0 = subtract(v0, vertex);\n const e1 = subtract(v1, vertex);\n\n const cosAngle = dot(e0, e1);\n const sinAngle = length(cross(e0, e1));\n\n if (Math.abs(sinAngle) < 1e-10) {\n return 0; // Degenerate case\n }\n\n return cosAngle / sinAngle;\n}\n\n/**\n * Computes the angle at a vertex in a triangle.\n */\nexport function angleAtVertex(v0: Vec3, vertex: Vec3, v1: Vec3): number {\n const e0 = subtract(v0, vertex);\n const e1 = subtract(v1, vertex);\n return angleBetween(e0, e1);\n}\n","import type { SegmentId } from '../types/MeshData';\nimport type { Vertex } from '../core/Vertex';\nimport type { Edge } from '../core/Edge';\nimport type { Vec3 } from '../geometry/GeometricUtils';\nimport { distance, projectPointOnSegment, lerp } from '../geometry/GeometricUtils';\n\n/**\n * Represents a segment of the feature skeleton.\n * A segment is a path of skeleton edges between two branching vertices.\n */\nexport class SkeletonSegment {\n /**\n * Vertices along this segment, in order from start to end.\n * Includes the endpoint branching vertices.\n */\n public vertices: Vertex[] = [];\n\n /**\n * Edges along this segment, in order.\n */\n public edges: Edge[] = [];\n\n /**\n * Whether this segment forms a closed loop.\n */\n public isClosed: boolean = false;\n\n /**\n * Total arc length of this segment.\n */\n private _totalLength: number = 0;\n\n /**\n * Cumulative lengths at each vertex (for parameterization).\n */\n private _cumulativeLengths: number[] = [];\n\n constructor(\n /**\n * Unique identifier for this segment.\n */\n public readonly id: SegmentId\n ) {}\n\n /**\n * Gets the start vertex of this segment.\n */\n get startVertex(): Vertex | undefined {\n return this.vertices[0];\n }\n\n /**\n * Gets the end vertex of this segment.\n */\n get endVertex(): Vertex | undefined {\n return this.vertices[this.vertices.length - 1];\n }\n\n /**\n * Gets the total arc length of this segment.\n */\n get totalLength(): number {\n return this._totalLength;\n }\n\n /**\n * Gets the number of vertices in this segment.\n */\n get vertexCount(): number {\n return this.vertices.length;\n }\n\n /**\n * Gets the number of edges in this segment.\n */\n get edgeCount(): number {\n return this.edges.length;\n }\n\n /**\n * Adds a vertex to the end of the segment.\n */\n addVertex(vertex: Vertex): void {\n if (this.vertices.length > 0) {\n const lastVertex = this.vertices[this.vertices.length - 1]!;\n const edgeLength = distance(\n { x: lastVertex.position.x, y: lastVertex.position.y, z: lastVertex.position.z },\n { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z }\n );\n this._totalLength += edgeLength;\n }\n\n this._cumulativeLengths.push(this._totalLength);\n this.vertices.push(vertex);\n }\n\n /**\n * Adds an edge to the segment.\n */\n addEdge(edge: Edge): void {\n this.edges.push(edge);\n }\n\n /**\n * Recomputes the total length and cumulative lengths.\n */\n recomputeLengths(): void {\n this._totalLength = 0;\n this._cumulativeLengths = [0];\n\n for (let i = 1; i < this.vertices.length; i++) {\n const v0 = this.vertices[i - 1]!;\n const v1 = this.vertices[i]!;\n const len = distance(\n { x: v0.position.x, y: v0.position.y, z: v0.position.z },\n { x: v1.position.x, y: v1.position.y, z: v1.position.z }\n );\n this._totalLength += len;\n this._cumulativeLengths.push(this._totalLength);\n }\n }\n\n /**\n * Gets the parameter t (0 to 1) for a vertex index.\n */\n getParameterAtVertex(index: number): number {\n if (this._totalLength === 0 || index < 0 || index >= this.vertices.length) {\n return 0;\n }\n return (this._cumulativeLengths[index] ?? 0) / this._totalLength;\n }\n\n /**\n * Gets the position at a parameter t along the segment.\n *\n * @param t - Parameter from 0 (start) to 1 (end)\n * @returns The interpolated position\n */\n getPositionAt(t: number): Vec3 | null {\n if (this.vertices.length === 0) {\n return null;\n }\n\n if (this.vertices.length === 1) {\n const v = this.vertices[0]!;\n return { x: v.position.x, y: v.position.y, z: v.position.z };\n }\n\n // Clamp t to [0, 1]\n t = Math.max(0, Math.min(1, t));\n\n const targetLength = t * this._totalLength;\n\n // Find the edge containing this parameter\n for (let i = 1; i < this.vertices.length; i++) {\n const prevLen = this._cumulativeLengths[i - 1] ?? 0;\n const currLen = this._cumulativeLengths[i] ?? 0;\n\n if (targetLength <= currLen) {\n const v0 = this.vertices[i - 1]!;\n const v1 = this.vertices[i]!;\n const edgeLength = currLen - prevLen;\n\n if (edgeLength < 1e-10) {\n return { x: v0.position.x, y: v0.position.y, z: v0.position.z };\n }\n\n const localT = (targetLength - prevLen) / edgeLength;\n return lerp(\n { x: v0.position.x, y: v0.position.y, z: v0.position.z },\n { x: v1.position.x, y: v1.position.y, z: v1.position.z },\n localT\n );\n }\n }\n\n // Return end position\n const lastV = this.vertices[this.vertices.length - 1]!;\n return { x: lastV.position.x, y: lastV.position.y, z: lastV.position.z };\n }\n\n /**\n * Projects a point onto this segment.\n * Returns the closest point on the segment and its parameter.\n */\n projectPoint(point: Vec3): { point: Vec3; parameter: number; distance: number } | null {\n if (this.vertices.length === 0) {\n return null;\n }\n\n if (this.vertices.length === 1) {\n const v = this.vertices[0]!;\n const pos = { x: v.position.x, y: v.position.y, z: v.position.z };\n return {\n point: pos,\n parameter: 0,\n distance: distance(point, pos),\n };\n }\n\n let bestPoint: Vec3 | null = null;\n let bestParam = 0;\n let bestDist = Infinity;\n\n for (let i = 1; i < this.vertices.length; i++) {\n const v0 = this.vertices[i - 1]!;\n const v1 = this.vertices[i]!;\n const p0 = { x: v0.position.x, y: v0.position.y, z: v0.position.z };\n const p1 = { x: v1.position.x, y: v1.position.y, z: v1.position.z };\n\n const projected = projectPointOnSegment(point, p0, p1);\n const dist = distance(point, projected);\n\n if (dist < bestDist) {\n bestDist = dist;\n bestPoint = projected;\n\n // Compute parameter\n const prevLen = this._cumulativeLengths[i - 1] ?? 0;\n const currLen = this._cumulativeLengths[i] ?? 0;\n const edgeLength = currLen - prevLen;\n\n if (edgeLength < 1e-10) {\n bestParam = prevLen / this._totalLength;\n } else {\n const localDist = distance(p0, projected);\n bestParam = (prevLen + localDist) / this._totalLength;\n }\n }\n }\n\n if (!bestPoint) {\n return null;\n }\n\n return {\n point: bestPoint,\n parameter: bestParam,\n distance: bestDist,\n };\n }\n\n /**\n * Gets the vertex at a specific index.\n */\n getVertex(index: number): Vertex | undefined {\n return this.vertices[index];\n }\n\n /**\n * Gets the edge at a specific index.\n */\n getEdge(index: number): Edge | undefined {\n return this.edges[index];\n }\n\n /**\n * Checks if a vertex is part of this segment.\n */\n containsVertex(vertex: Vertex): boolean {\n return this.vertices.some((v) => v.id === vertex.id);\n }\n\n /**\n * Checks if an edge is part of this segment.\n */\n containsEdge(edge: Edge): boolean {\n return this.edges.some((e) => e.id === edge.id);\n }\n\n /**\n * Gets the index of a vertex in this segment.\n */\n indexOfVertex(vertex: Vertex): number {\n return this.vertices.findIndex((v) => v.id === vertex.id);\n }\n\n /**\n * Iterates over vertices in this segment.\n */\n forEachVertex(callback: (vertex: Vertex, index: number) => void): void {\n this.vertices.forEach(callback);\n }\n\n /**\n * Iterates over edges in this segment.\n */\n forEachEdge(callback: (edge: Edge, index: number) => void): void {\n this.edges.forEach(callback);\n }\n\n /**\n * Creates a copy of this segment.\n */\n clone(newId: SegmentId): SkeletonSegment {\n const segment = new SkeletonSegment(newId);\n segment.vertices = [...this.vertices];\n segment.edges = [...this.edges];\n segment.isClosed = this.isClosed;\n segment._totalLength = this._totalLength;\n segment._cumulativeLengths = [...this._cumulativeLengths];\n return segment;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Vertex } from '../core/Vertex';\nimport type { Edge } from '../core/Edge';\nimport { SkeletonSegment } from './SkeletonSegment';\nimport { VertexType } from '../types/SkeletonData';\nimport { createSegmentId, type SegmentId } from '../types/MeshData';\n\n/**\n * Result of skeleton building.\n */\nexport interface SkeletonBuildResult {\n /** All segments in the skeleton */\n segments: SkeletonSegment[];\n\n /** All skeleton edges */\n skeletonEdges: Edge[];\n\n /** All branching vertices (endpoints of segments) */\n branchingVertices: Vertex[];\n\n /** All open-book vertices (interior of segments) */\n openBookVertices: Vertex[];\n}\n\n/**\n * Builds the feature skeleton from a mesh.\n * The skeleton consists of non-manifold edges, boundary edges, and feature edges.\n */\nexport class SkeletonBuilder {\n private mesh: NonManifoldMesh;\n private nextSegmentId: number = 0;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Builds the skeleton and returns the result.\n */\n build(): SkeletonBuildResult {\n const skeletonEdges = this.mesh.getSkeletonEdges();\n const branchingVertices: Vertex[] = [];\n const openBookVertices: Vertex[] = [];\n\n // Classify vertices\n for (const vertex of this.mesh.getVertices()) {\n if (vertex.type === VertexType.SkeletonBranching) {\n branchingVertices.push(vertex);\n } else if (vertex.type === VertexType.OpenBook) {\n openBookVertices.push(vertex);\n }\n }\n\n // Build segments\n const segments = this.buildSegments(skeletonEdges, branchingVertices);\n\n return {\n segments,\n skeletonEdges,\n branchingVertices,\n openBookVertices,\n };\n }\n\n /**\n * Builds segments from skeleton edges.\n * A segment is a path between two branching vertices.\n */\n private buildSegments(skeletonEdges: Edge[], branchingVertices: Vertex[]): SkeletonSegment[] {\n const segments: SkeletonSegment[] = [];\n const visitedEdges = new Set<number>();\n const branchingIds = new Set(branchingVertices.map((v) => v.id as number));\n\n // Start from each branching vertex and trace segments\n for (const startVertex of branchingVertices) {\n // Get all skeleton edges incident to this vertex\n const incidentEdges = this.getIncidentSkeletonEdges(startVertex, skeletonEdges);\n\n for (const startEdge of incidentEdges) {\n if (visitedEdges.has(startEdge.id as number)) {\n continue;\n }\n\n const segment = this.traceSegment(startVertex, startEdge, branchingIds, visitedEdges);\n\n if (segment) {\n segments.push(segment);\n }\n }\n }\n\n // Handle closed loops that don't contain branching vertices\n for (const edge of skeletonEdges) {\n if (visitedEdges.has(edge.id as number)) {\n continue;\n }\n\n const segment = this.traceClosedLoop(edge, visitedEdges);\n if (segment) {\n segments.push(segment);\n }\n }\n\n return segments;\n }\n\n /**\n * Gets skeleton edges incident to a vertex.\n */\n private getIncidentSkeletonEdges(vertex: Vertex, skeletonEdges: Edge[]): Edge[] {\n const skeletonEdgeSet = new Set(skeletonEdges.map((e) => e.id as number));\n const result: Edge[] = [];\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (skeletonEdgeSet.has(he.edge.id as number)) {\n // Avoid duplicates\n if (!result.some((e) => e.id === he.edge.id)) {\n result.push(he.edge);\n }\n }\n });\n\n return result;\n }\n\n /**\n * Traces a segment from a starting vertex and edge.\n */\n private traceSegment(\n startVertex: Vertex,\n startEdge: Edge,\n branchingIds: Set<number>,\n visitedEdges: Set<number>\n ): SkeletonSegment | null {\n const segment = new SkeletonSegment(this.createSegmentId());\n segment.addVertex(startVertex);\n\n let currentVertex = startVertex;\n let currentEdge: Edge | null = startEdge;\n\n while (currentEdge && !visitedEdges.has(currentEdge.id as number)) {\n visitedEdges.add(currentEdge.id as number);\n segment.addEdge(currentEdge);\n\n // Get the other vertex of this edge\n const nextVertex = currentEdge.getOtherVertex(currentVertex);\n if (!nextVertex) {\n break;\n }\n\n segment.addVertex(nextVertex);\n currentVertex = nextVertex;\n\n // If we reached a branching vertex, stop\n if (branchingIds.has(currentVertex.id as number)) {\n break;\n }\n\n // Find the next skeleton edge (there should be exactly one for open-book vertices)\n currentEdge = this.getNextSkeletonEdge(currentVertex, currentEdge, visitedEdges);\n }\n\n // Check if segment forms a closed loop\n if (segment.vertices.length > 2 && segment.startVertex?.id === segment.endVertex?.id) {\n segment.isClosed = true;\n // Remove duplicate end vertex\n segment.vertices.pop();\n }\n\n segment.recomputeLengths();\n return segment;\n }\n\n /**\n * Traces a closed loop starting from an edge.\n */\n private traceClosedLoop(startEdge: Edge, visitedEdges: Set<number>): SkeletonSegment | null {\n const [v0, v1] = startEdge.getVertices();\n if (!v0 || !v1) {\n return null;\n }\n\n const segment = new SkeletonSegment(this.createSegmentId());\n segment.addVertex(v0);\n segment.addEdge(startEdge);\n segment.addVertex(v1);\n visitedEdges.add(startEdge.id as number);\n\n let currentVertex = v1;\n let currentEdge = this.getNextSkeletonEdge(currentVertex, startEdge, visitedEdges);\n\n while (currentEdge && !visitedEdges.has(currentEdge.id as number)) {\n visitedEdges.add(currentEdge.id as number);\n segment.addEdge(currentEdge);\n\n const nextVertex = currentEdge.getOtherVertex(currentVertex);\n if (!nextVertex) {\n break;\n }\n\n // Check if we've closed the loop\n if (nextVertex.id === v0.id) {\n segment.isClosed = true;\n break;\n }\n\n segment.addVertex(nextVertex);\n currentVertex = nextVertex;\n currentEdge = this.getNextSkeletonEdge(currentVertex, currentEdge, visitedEdges);\n }\n\n segment.recomputeLengths();\n return segment;\n }\n\n /**\n * Gets the next skeleton edge from a vertex, excluding the current edge.\n */\n private getNextSkeletonEdge(\n vertex: Vertex,\n currentEdge: Edge,\n visitedEdges: Set<number>\n ): Edge | null {\n let result: Edge | null = null;\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (\n he.edge.id !== currentEdge.id &&\n he.edge.isSkeletonEdge() &&\n !visitedEdges.has(he.edge.id as number)\n ) {\n result = he.edge;\n }\n });\n\n return result;\n }\n\n /**\n * Creates a new segment ID.\n */\n private createSegmentId(): SegmentId {\n return createSegmentId(this.nextSegmentId++);\n }\n}\n\n/**\n * Builds the skeleton from a mesh.\n */\nexport function buildSkeleton(mesh: NonManifoldMesh): SkeletonBuildResult {\n const builder = new SkeletonBuilder(mesh);\n return builder.build();\n}\n","import type { NonManifoldMesh } from './NonManifoldMesh';\nimport type { Vertex } from './Vertex';\nimport type { Edge } from './Edge';\nimport type { SkeletonBuildResult } from '../skeleton/SkeletonBuilder';\nimport type { SkeletonSegment } from '../skeleton/SkeletonSegment';\nimport { SkeletonBuilder } from '../skeleton/SkeletonBuilder';\nimport type { SegmentId } from '../types/MeshData';\nimport type { Vec3 } from '../geometry/GeometricUtils';\n\n/**\n * Represents the feature skeleton of a mesh.\n * The skeleton consists of non-manifold edges, boundary edges, and feature edges.\n */\nexport class FeatureSkeleton {\n /** The mesh this skeleton belongs to */\n public readonly mesh: NonManifoldMesh;\n\n /** All segments in the skeleton */\n public segments: Map<SegmentId, SkeletonSegment> = new Map();\n\n /** All skeleton edges */\n private skeletonEdges: Edge[] = [];\n\n /** All branching vertices */\n private branchingVertices: Vertex[] = [];\n\n /** All open-book vertices */\n private openBookVertices: Vertex[] = [];\n\n /** Map from vertex to its segment (for open-book vertices) */\n private vertexToSegment: Map<number, SkeletonSegment> = new Map();\n\n /** Whether the skeleton has been built */\n private isBuilt: boolean = false;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Builds the skeleton from the mesh.\n */\n build(): void {\n const builder = new SkeletonBuilder(this.mesh);\n const result = builder.build();\n\n this.applyBuildResult(result);\n this.isBuilt = true;\n }\n\n /**\n * Applies a build result to this skeleton.\n */\n private applyBuildResult(result: SkeletonBuildResult): void {\n this.segments.clear();\n this.vertexToSegment.clear();\n\n for (const segment of result.segments) {\n this.segments.set(segment.id, segment);\n\n // Map vertices to segments (excluding branching vertices at endpoints)\n for (let i = 1; i < segment.vertices.length - 1; i++) {\n const vertex = segment.vertices[i];\n if (vertex) {\n this.vertexToSegment.set(vertex.id as number, segment);\n }\n }\n }\n\n this.skeletonEdges = result.skeletonEdges;\n this.branchingVertices = result.branchingVertices;\n this.openBookVertices = result.openBookVertices;\n }\n\n /**\n * Rebuilds the skeleton. Call after topology changes.\n */\n rebuild(): void {\n this.build();\n }\n\n /**\n * Gets all segments.\n */\n getSegments(): SkeletonSegment[] {\n return Array.from(this.segments.values());\n }\n\n /**\n * Gets a segment by ID.\n */\n getSegment(id: SegmentId): SkeletonSegment | undefined {\n return this.segments.get(id);\n }\n\n /**\n * Gets the segment containing a vertex.\n * Only works for open-book vertices.\n */\n getSegmentForVertex(vertex: Vertex): SkeletonSegment | undefined {\n return this.vertexToSegment.get(vertex.id as number);\n }\n\n /**\n * Gets all skeleton edges.\n */\n getSkeletonEdges(): Edge[] {\n return this.skeletonEdges;\n }\n\n /**\n * Gets all branching vertices.\n */\n getBranchingVertices(): Vertex[] {\n return this.branchingVertices;\n }\n\n /**\n * Gets all open-book vertices.\n */\n getOpenBookVertices(): Vertex[] {\n return this.openBookVertices;\n }\n\n /**\n * Gets the number of segments.\n */\n get segmentCount(): number {\n return this.segments.size;\n }\n\n /**\n * Gets the number of skeleton edges.\n */\n get skeletonEdgeCount(): number {\n return this.skeletonEdges.length;\n }\n\n /**\n * Gets the number of branching vertices.\n */\n get branchingVertexCount(): number {\n return this.branchingVertices.length;\n }\n\n /**\n * Gets the number of open-book vertices.\n */\n get openBookVertexCount(): number {\n return this.openBookVertices.length;\n }\n\n /**\n * Checks if the skeleton has been built.\n */\n get built(): boolean {\n return this.isBuilt;\n }\n\n /**\n * Projects a point onto the skeleton.\n * Returns the closest point on any segment.\n */\n projectPoint(point: Vec3): {\n point: Vec3;\n segment: SkeletonSegment;\n parameter: number;\n distance: number;\n } | null {\n let bestResult: {\n point: Vec3;\n segment: SkeletonSegment;\n parameter: number;\n distance: number;\n } | null = null;\n\n for (const segment of this.segments.values()) {\n const projection = segment.projectPoint(point);\n if (projection && (!bestResult || projection.distance < bestResult.distance)) {\n bestResult = {\n point: projection.point,\n segment,\n parameter: projection.parameter,\n distance: projection.distance,\n };\n }\n }\n\n return bestResult;\n }\n\n /**\n * Checks if a vertex is on the skeleton.\n */\n isVertexOnSkeleton(vertex: Vertex): boolean {\n return vertex.isOnSkeleton();\n }\n\n /**\n * Checks if an edge is on the skeleton.\n */\n isEdgeOnSkeleton(edge: Edge): boolean {\n return edge.isSkeletonEdge();\n }\n\n /**\n * Gets all vertices on the skeleton.\n */\n getAllSkeletonVertices(): Vertex[] {\n return [...this.branchingVertices, ...this.openBookVertices];\n }\n\n /**\n * Computes the total length of the skeleton.\n */\n getTotalLength(): number {\n let total = 0;\n for (const segment of this.segments.values()) {\n total += segment.totalLength;\n }\n return total;\n }\n\n /**\n * Gets statistics about the skeleton.\n */\n getStats(): {\n segmentCount: number;\n skeletonEdgeCount: number;\n branchingVertexCount: number;\n openBookVertexCount: number;\n totalLength: number;\n closedLoopCount: number;\n } {\n let closedLoopCount = 0;\n for (const segment of this.segments.values()) {\n if (segment.isClosed) {\n closedLoopCount++;\n }\n }\n\n return {\n segmentCount: this.segmentCount,\n skeletonEdgeCount: this.skeletonEdgeCount,\n branchingVertexCount: this.branchingVertexCount,\n openBookVertexCount: this.openBookVertexCount,\n totalLength: this.getTotalLength(),\n closedLoopCount,\n };\n }\n}\n\n/**\n * Creates and builds a skeleton for a mesh.\n */\nexport function createSkeleton(mesh: NonManifoldMesh): FeatureSkeleton {\n const skeleton = new FeatureSkeleton(mesh);\n skeleton.build();\n return skeleton;\n}\n","import type { Vertex } from '../core/Vertex';\nimport type { FeatureSkeleton } from '../core/FeatureSkeleton';\nimport type { SkeletonSegment } from './SkeletonSegment';\nimport type { Vec3 } from '../geometry/GeometricUtils';\nimport { VertexType } from '../types/SkeletonData';\nimport { distance } from '../geometry/GeometricUtils';\n\n/**\n * Result of constraining a vertex movement.\n */\nexport interface ConstrainedPosition {\n /** The constrained position */\n position: Vec3;\n\n /** Whether the movement was constrained */\n wasConstrained: boolean;\n\n /** The segment the vertex is constrained to (if applicable) */\n segment?: SkeletonSegment;\n\n /** Distance the position was moved during constraint */\n constraintDistance: number;\n}\n\n/**\n * Determines movement constraints for vertices based on their type.\n */\nexport class SkeletonConstraints {\n private skeleton: FeatureSkeleton;\n\n constructor(skeleton: FeatureSkeleton) {\n this.skeleton = skeleton;\n }\n\n /**\n * Constrains a target position based on vertex type.\n *\n * - Manifold vertices: Can move freely (no constraint)\n * - Open-book vertices: Constrained to their skeleton segment\n * - Branching vertices: Fixed (cannot move)\n *\n * @param vertex - The vertex to constrain\n * @param targetPosition - The desired target position\n * @returns The constrained position\n */\n constrainPosition(vertex: Vertex, targetPosition: Vec3): ConstrainedPosition {\n switch (vertex.type) {\n case VertexType.Manifold:\n // Manifold vertices can move freely\n return {\n position: targetPosition,\n wasConstrained: false,\n constraintDistance: 0,\n };\n\n case VertexType.OpenBook:\n // Open-book vertices are constrained to their skeleton segment\n return this.constrainToSegment(vertex, targetPosition);\n\n case VertexType.SkeletonBranching:\n case VertexType.NonManifoldOther:\n // Branching and other non-manifold vertices are fixed\n return {\n position: {\n x: vertex.position.x,\n y: vertex.position.y,\n z: vertex.position.z,\n },\n wasConstrained: true,\n constraintDistance: distance(targetPosition, {\n x: vertex.position.x,\n y: vertex.position.y,\n z: vertex.position.z,\n }),\n };\n\n default:\n return {\n position: targetPosition,\n wasConstrained: false,\n constraintDistance: 0,\n };\n }\n }\n\n /**\n * Constrains a position to a skeleton segment.\n */\n private constrainToSegment(vertex: Vertex, targetPosition: Vec3): ConstrainedPosition {\n const segment = this.skeleton.getSegmentForVertex(vertex);\n\n if (!segment) {\n // No segment found - project onto nearest segment\n const projection = this.skeleton.projectPoint(targetPosition);\n if (projection) {\n return {\n position: projection.point,\n wasConstrained: true,\n segment: projection.segment,\n constraintDistance: projection.distance,\n };\n }\n\n // Fallback: don't move\n return {\n position: {\n x: vertex.position.x,\n y: vertex.position.y,\n z: vertex.position.z,\n },\n wasConstrained: true,\n constraintDistance: distance(targetPosition, {\n x: vertex.position.x,\n y: vertex.position.y,\n z: vertex.position.z,\n }),\n };\n }\n\n // Project onto the segment\n const projection = segment.projectPoint(targetPosition);\n if (!projection) {\n return {\n position: {\n x: vertex.position.x,\n y: vertex.position.y,\n z: vertex.position.z,\n },\n wasConstrained: true,\n segment,\n constraintDistance: 0,\n };\n }\n\n return {\n position: projection.point,\n wasConstrained: true,\n segment,\n constraintDistance: projection.distance,\n };\n }\n\n /**\n * Checks if a vertex can move freely.\n */\n canMoveFreely(vertex: Vertex): boolean {\n return vertex.type === VertexType.Manifold;\n }\n\n /**\n * Checks if a vertex is fixed (cannot move).\n */\n isFixed(vertex: Vertex): boolean {\n return (\n vertex.type === VertexType.SkeletonBranching || vertex.type === VertexType.NonManifoldOther\n );\n }\n\n /**\n * Checks if a vertex is constrained to a segment.\n */\n isConstrainedToSegment(vertex: Vertex): boolean {\n return vertex.type === VertexType.OpenBook;\n }\n\n /**\n * Gets the segment a vertex is constrained to.\n */\n getConstraintSegment(vertex: Vertex): SkeletonSegment | undefined {\n if (vertex.type !== VertexType.OpenBook) {\n return undefined;\n }\n return this.skeleton.getSegmentForVertex(vertex);\n }\n\n /**\n * Computes the allowed movement direction for a vertex.\n * For open-book vertices, this is the tangent direction of the segment.\n */\n getAllowedDirection(vertex: Vertex): Vec3 | null {\n if (vertex.type !== VertexType.OpenBook) {\n return null; // Free movement or fixed\n }\n\n const segment = this.skeleton.getSegmentForVertex(vertex);\n if (!segment || segment.vertices.length < 2) {\n return null;\n }\n\n // Find vertex in segment\n const idx = segment.indexOfVertex(vertex);\n if (idx < 0) {\n return null;\n }\n\n // Compute tangent direction\n let p0: Vec3;\n let p1: Vec3;\n\n if (idx === 0) {\n const v0 = segment.vertices[0]!;\n const v1 = segment.vertices[1]!;\n p0 = { x: v0.position.x, y: v0.position.y, z: v0.position.z };\n p1 = { x: v1.position.x, y: v1.position.y, z: v1.position.z };\n } else if (idx === segment.vertices.length - 1) {\n const v0 = segment.vertices[idx - 1]!;\n const v1 = segment.vertices[idx]!;\n p0 = { x: v0.position.x, y: v0.position.y, z: v0.position.z };\n p1 = { x: v1.position.x, y: v1.position.y, z: v1.position.z };\n } else {\n // Average of adjacent edges\n const vPrev = segment.vertices[idx - 1]!;\n const vNext = segment.vertices[idx + 1]!;\n p0 = { x: vPrev.position.x, y: vPrev.position.y, z: vPrev.position.z };\n p1 = { x: vNext.position.x, y: vNext.position.y, z: vNext.position.z };\n }\n\n const dx = p1.x - p0.x;\n const dy = p1.y - p0.y;\n const dz = p1.z - p0.z;\n const len = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n if (len < 1e-10) {\n return null;\n }\n\n return {\n x: dx / len,\n y: dy / len,\n z: dz / len,\n };\n }\n}\n\n/**\n * Creates skeleton constraints for a mesh.\n */\nexport function createSkeletonConstraints(skeleton: FeatureSkeleton): SkeletonConstraints {\n return new SkeletonConstraints(skeleton);\n}\n","import type { BufferGeometry } from 'three';\nimport { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { FeatureEdge } from '../types/RemeshOptions';\n\n/**\n * Options for importing a BufferGeometry.\n */\nexport interface ImportOptions {\n /**\n * User-defined feature edges to preserve.\n * Each edge is specified as a pair of vertex indices.\n */\n featureEdges?: FeatureEdge[];\n\n /**\n * Whether to validate the geometry before importing.\n * @default true\n */\n validate?: boolean;\n\n /**\n * Whether to merge duplicate vertices.\n * @default false\n */\n mergeVertices?: boolean;\n\n /**\n * Tolerance for merging vertices.\n * @default 1e-6\n */\n mergeTolerance?: number;\n}\n\n/**\n * Result of geometry validation.\n */\nexport interface ValidationResult {\n /** Whether the geometry is valid */\n isValid: boolean;\n\n /** List of validation errors */\n errors: string[];\n\n /** List of validation warnings */\n warnings: string[];\n}\n\n/**\n * Validates a BufferGeometry for import.\n *\n * @param geometry - The geometry to validate\n * @returns Validation result with errors and warnings\n */\nexport function validateGeometry(geometry: BufferGeometry): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check for position attribute\n const positions = geometry.attributes['position'];\n if (!positions) {\n errors.push('Geometry must have a position attribute');\n return { isValid: false, errors, warnings };\n }\n\n // Check for index\n const indices = geometry.index;\n if (!indices) {\n errors.push('Geometry must be indexed');\n return { isValid: false, errors, warnings };\n }\n\n // Check that indices form triangles\n if (indices.count % 3 !== 0) {\n errors.push(`Index count (${indices.count}) must be divisible by 3 for triangle mesh`);\n }\n\n // Check for invalid indices\n const numVertices = positions.count;\n for (let i = 0; i < indices.count; i++) {\n const index = indices.getX(i);\n if (index < 0 || index >= numVertices) {\n errors.push(`Invalid index ${index} at position ${i} (vertex count: ${numVertices})`);\n break; // Only report first invalid index\n }\n }\n\n // Check for degenerate triangles\n let degenerateCount = 0;\n const numFaces = indices.count / 3;\n for (let i = 0; i < numFaces; i++) {\n const i0 = indices.getX(i * 3);\n const i1 = indices.getX(i * 3 + 1);\n const i2 = indices.getX(i * 3 + 2);\n\n if (i0 === i1 || i1 === i2 || i2 === i0) {\n degenerateCount++;\n }\n }\n if (degenerateCount > 0) {\n warnings.push(`Found ${degenerateCount} degenerate triangle(s) with repeated vertices`);\n }\n\n // Check for NaN/Infinity in positions\n let invalidPositionCount = 0;\n for (let i = 0; i < numVertices; i++) {\n const x = positions.getX(i);\n const y = positions.getY(i);\n const z = positions.getZ(i);\n if (!isFinite(x) || !isFinite(y) || !isFinite(z)) {\n invalidPositionCount++;\n }\n }\n if (invalidPositionCount > 0) {\n errors.push(`Found ${invalidPositionCount} vertex position(s) with NaN or Infinity values`);\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Imports a Three.js BufferGeometry into a NonManifoldMesh.\n *\n * @param geometry - The input geometry\n * @param options - Import options\n * @returns The imported mesh\n * @throws Error if geometry is invalid and validation is enabled\n */\nexport function importBufferGeometry(\n geometry: BufferGeometry,\n options: ImportOptions = {}\n): NonManifoldMesh {\n const { featureEdges, validate = true } = options;\n\n // Validate geometry\n if (validate) {\n const validation = validateGeometry(geometry);\n if (!validation.isValid) {\n throw new Error(`Invalid geometry: ${validation.errors.join('; ')}`);\n }\n }\n\n // Import using NonManifoldMesh factory method\n return NonManifoldMesh.fromBufferGeometry(geometry, featureEdges);\n}\n\n/**\n * Utility class for importing BufferGeometry with additional features.\n */\nexport class BufferGeometryImporter {\n private options: ImportOptions;\n\n constructor(options: ImportOptions = {}) {\n this.options = options;\n }\n\n /**\n * Imports a BufferGeometry into a NonManifoldMesh.\n */\n import(geometry: BufferGeometry): NonManifoldMesh {\n return importBufferGeometry(geometry, this.options);\n }\n\n /**\n * Validates a BufferGeometry without importing.\n */\n validate(geometry: BufferGeometry): ValidationResult {\n return validateGeometry(geometry);\n }\n\n /**\n * Sets feature edges to preserve during remeshing.\n */\n setFeatureEdges(edges: FeatureEdge[]): this {\n this.options.featureEdges = edges;\n return this;\n }\n\n /**\n * Enables or disables validation.\n */\n setValidation(enabled: boolean): this {\n this.options.validate = enabled;\n return this;\n }\n}\n","import { BufferGeometry, BufferAttribute } from 'three';\nimport type { NonManifoldMesh } from '../core/NonManifoldMesh';\n\n/**\n * Options for exporting a mesh to BufferGeometry.\n */\nexport interface ExportOptions {\n /**\n * Whether to compute vertex normals.\n * @default true\n */\n computeNormals?: boolean;\n\n /**\n * Whether to use smooth (averaged) normals.\n * If false, uses flat (per-face) normals.\n * @default true\n */\n smoothNormals?: boolean;\n\n /**\n * Angle threshold (in radians) for smooth normals.\n * Edges with angles greater than this will have split normals.\n * @default Math.PI / 3 (60 degrees)\n */\n smoothAngle?: number;\n\n /**\n * Whether to include UV coordinates if available.\n * @default false\n */\n includeUVs?: boolean;\n}\n\n/**\n * Exports a NonManifoldMesh to a Three.js BufferGeometry.\n *\n * @param mesh - The mesh to export\n * @param options - Export options\n * @returns The exported BufferGeometry\n */\nexport function exportBufferGeometry(\n mesh: NonManifoldMesh,\n options: ExportOptions = {}\n): BufferGeometry {\n const { computeNormals = true, smoothNormals = true } = options;\n\n const geometry = new BufferGeometry();\n\n // Get all faces\n const faces = mesh.getFaces();\n if (faces.length === 0) {\n return geometry;\n }\n\n // Build vertex index map (vertex ID -> array index)\n const vertices = mesh.getVertices();\n const vertexIndexMap = new Map<number, number>();\n vertices.forEach((v, i) => {\n vertexIndexMap.set(v.id as number, i);\n });\n\n // Create position array\n const positions = new Float32Array(vertices.length * 3);\n vertices.forEach((v, i) => {\n positions[i * 3] = v.position.x;\n positions[i * 3 + 1] = v.position.y;\n positions[i * 3 + 2] = v.position.z;\n });\n\n // Create index array\n const indices: number[] = [];\n for (const face of faces) {\n const verts = face.getVertices();\n if (!verts) continue;\n\n const [v0, v1, v2] = verts;\n const i0 = vertexIndexMap.get(v0.id as number);\n const i1 = vertexIndexMap.get(v1.id as number);\n const i2 = vertexIndexMap.get(v2.id as number);\n\n if (i0 !== undefined && i1 !== undefined && i2 !== undefined) {\n indices.push(i0, i1, i2);\n }\n }\n\n // Set attributes\n geometry.setAttribute('position', new BufferAttribute(positions, 3));\n geometry.setIndex(indices);\n\n // Compute normals\n if (computeNormals) {\n if (smoothNormals) {\n computeSmoothNormals(geometry, mesh, vertexIndexMap);\n } else {\n geometry.computeVertexNormals();\n }\n }\n\n return geometry;\n}\n\n/**\n * Computes smooth vertex normals by averaging face normals.\n */\nfunction computeSmoothNormals(\n geometry: BufferGeometry,\n mesh: NonManifoldMesh,\n vertexIndexMap: Map<number, number>\n): void {\n const vertices = mesh.getVertices();\n const normals = new Float32Array(vertices.length * 3);\n const normalCounts = new Uint32Array(vertices.length);\n\n // Accumulate face normals at each vertex\n for (const face of mesh.getFaces()) {\n const faceNormal = face.getNormal();\n if (!faceNormal) continue;\n\n const verts = face.getVertices();\n if (!verts) continue;\n\n for (const v of verts) {\n const idx = vertexIndexMap.get(v.id as number);\n if (idx === undefined) continue;\n\n const baseIdx = idx * 3;\n normals[baseIdx] = (normals[baseIdx] ?? 0) + faceNormal.x;\n normals[baseIdx + 1] = (normals[baseIdx + 1] ?? 0) + faceNormal.y;\n normals[baseIdx + 2] = (normals[baseIdx + 2] ?? 0) + faceNormal.z;\n normalCounts[idx] = (normalCounts[idx] ?? 0) + 1;\n }\n }\n\n // Normalize\n for (let i = 0; i < vertices.length; i++) {\n const count = normalCounts[i] ?? 0;\n if (count === 0) continue;\n\n const baseIdx = i * 3;\n const nx = (normals[baseIdx] ?? 0) / count;\n const ny = (normals[baseIdx + 1] ?? 0) / count;\n const nz = (normals[baseIdx + 2] ?? 0) / count;\n\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\n if (len > 1e-10) {\n normals[i * 3] = nx / len;\n normals[i * 3 + 1] = ny / len;\n normals[i * 3 + 2] = nz / len;\n } else {\n normals[i * 3] = 0;\n normals[i * 3 + 1] = 1;\n normals[i * 3 + 2] = 0;\n }\n }\n\n geometry.setAttribute('normal', new BufferAttribute(normals, 3));\n}\n\n/**\n * Exports only skeleton edges as a LineSegments geometry.\n *\n * @param mesh - The mesh to export skeleton from\n * @returns BufferGeometry suitable for THREE.LineSegments\n */\nexport function exportSkeletonGeometry(mesh: NonManifoldMesh): BufferGeometry {\n const geometry = new BufferGeometry();\n const skeletonEdges = mesh.getSkeletonEdges();\n\n if (skeletonEdges.length === 0) {\n return geometry;\n }\n\n // Each edge needs 2 vertices (6 floats)\n const positions = new Float32Array(skeletonEdges.length * 6);\n\n let offset = 0;\n for (const edge of skeletonEdges) {\n const [v0, v1] = edge.getVertices();\n if (!v0 || !v1) continue;\n\n positions[offset++] = v0.position.x;\n positions[offset++] = v0.position.y;\n positions[offset++] = v0.position.z;\n\n positions[offset++] = v1.position.x;\n positions[offset++] = v1.position.y;\n positions[offset++] = v1.position.z;\n }\n\n geometry.setAttribute('position', new BufferAttribute(positions.slice(0, offset), 3));\n\n return geometry;\n}\n\n/**\n * Creates a colored mesh geometry for visualizing vertex classification.\n *\n * @param mesh - The mesh to visualize\n * @returns BufferGeometry with vertex colors based on classification\n */\nexport function exportClassificationGeometry(mesh: NonManifoldMesh): BufferGeometry {\n const baseGeometry = exportBufferGeometry(mesh, { computeNormals: true });\n\n const vertices = mesh.getVertices();\n const colors = new Float32Array(vertices.length * 3);\n\n // Build vertex index map\n const vertexIndexMap = new Map<number, number>();\n vertices.forEach((v, i) => {\n vertexIndexMap.set(v.id as number, i);\n });\n\n // Color by vertex type\n // Manifold: green, OpenBook: blue, SkeletonBranching: red, NonManifoldOther: magenta\n for (const vertex of vertices) {\n const idx = vertexIndexMap.get(vertex.id as number);\n if (idx === undefined) continue;\n\n let r = 0,\n g = 0,\n b = 0;\n\n switch (vertex.type) {\n case 'manifold':\n r = 0.2;\n g = 0.8;\n b = 0.2;\n break;\n case 'open_book':\n r = 0.2;\n g = 0.4;\n b = 0.9;\n break;\n case 'skeleton_branching':\n r = 0.9;\n g = 0.2;\n b = 0.2;\n break;\n case 'non_manifold_other':\n r = 0.9;\n g = 0.2;\n b = 0.9;\n break;\n }\n\n colors[idx * 3] = r;\n colors[idx * 3 + 1] = g;\n colors[idx * 3 + 2] = b;\n }\n\n baseGeometry.setAttribute('color', new BufferAttribute(colors, 3));\n\n return baseGeometry;\n}\n\n/**\n * Creates a mesh geometry with face colors based on triangle quality.\n *\n * @param mesh - The mesh to visualize\n * @returns BufferGeometry with vertex colors representing quality\n */\nexport function exportQualityGeometry(mesh: NonManifoldMesh): BufferGeometry {\n const faces = mesh.getFaces();\n if (faces.length === 0) {\n return new BufferGeometry();\n }\n\n // For quality visualization, we need per-face colors, so we use non-indexed geometry\n const positions = new Float32Array(faces.length * 9); // 3 vertices * 3 coords\n const colors = new Float32Array(faces.length * 9); // 3 vertices * 3 color components\n const normals = new Float32Array(faces.length * 9);\n\n let offset = 0;\n for (const face of faces) {\n const verts = face.getVertices();\n const normal = face.getNormal();\n const quality = face.getQuality() ?? 0;\n\n if (!verts || !normal) continue;\n\n // Color mapping: red (bad quality) -> yellow -> green (good quality)\n const r = quality < 0.5 ? 1.0 : 2.0 - quality * 2.0;\n const g = quality < 0.5 ? quality * 2.0 : 1.0;\n const b = 0.1;\n\n for (const v of verts) {\n // Position\n positions[offset] = v.position.x;\n positions[offset + 1] = v.position.y;\n positions[offset + 2] = v.position.z;\n\n // Color\n colors[offset] = r;\n colors[offset + 1] = g;\n colors[offset + 2] = b;\n\n // Normal\n normals[offset] = normal.x;\n normals[offset + 1] = normal.y;\n normals[offset + 2] = normal.z;\n\n offset += 3;\n }\n }\n\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(positions.slice(0, offset), 3));\n geometry.setAttribute('color', new BufferAttribute(colors.slice(0, offset), 3));\n geometry.setAttribute('normal', new BufferAttribute(normals.slice(0, offset), 3));\n\n return geometry;\n}\n\n/**\n * Utility class for exporting meshes with various options.\n */\nexport class BufferGeometryExporter {\n private options: ExportOptions;\n\n constructor(options: ExportOptions = {}) {\n this.options = options;\n }\n\n /**\n * Exports a NonManifoldMesh to BufferGeometry.\n */\n export(mesh: NonManifoldMesh): BufferGeometry {\n return exportBufferGeometry(mesh, this.options);\n }\n\n /**\n * Exports skeleton edges as LineSegments geometry.\n */\n exportSkeleton(mesh: NonManifoldMesh): BufferGeometry {\n return exportSkeletonGeometry(mesh);\n }\n\n /**\n * Exports with vertex classification colors.\n */\n exportClassification(mesh: NonManifoldMesh): BufferGeometry {\n return exportClassificationGeometry(mesh);\n }\n\n /**\n * Exports with quality visualization colors.\n */\n exportQuality(mesh: NonManifoldMesh): BufferGeometry {\n return exportQualityGeometry(mesh);\n }\n\n /**\n * Sets whether to compute normals.\n */\n setComputeNormals(enabled: boolean): this {\n this.options.computeNormals = enabled;\n return this;\n }\n\n /**\n * Sets whether to use smooth normals.\n */\n setSmoothNormals(enabled: boolean): this {\n this.options.smoothNormals = enabled;\n return this;\n }\n}\n","import type { Vec3 } from '../geometry/GeometricUtils';\n\n/**\n * A spatial hash grid for fast neighbor queries.\n * Uses a 3D hash grid to accelerate proximity searches.\n *\n * @template T - The type of items stored in the hash\n */\nexport class SpatialHash<T> {\n private cells: Map<string, T[]> = new Map();\n private cellSize: number;\n private itemPositions: Map<T, Vec3> = new Map();\n\n /**\n * Creates a new spatial hash with the specified cell size.\n *\n * @param cellSize - The size of each cell in the grid\n */\n constructor(cellSize: number) {\n if (cellSize <= 0) {\n throw new Error('Cell size must be positive');\n }\n this.cellSize = cellSize;\n }\n\n /**\n * Computes the cell key for a position.\n */\n private getCellKey(x: number, y: number, z: number): string {\n const ix = Math.floor(x / this.cellSize);\n const iy = Math.floor(y / this.cellSize);\n const iz = Math.floor(z / this.cellSize);\n return `${ix},${iy},${iz}`;\n }\n\n /**\n * Computes the cell indices for a position.\n */\n private getCellIndices(x: number, y: number, z: number): [number, number, number] {\n return [\n Math.floor(x / this.cellSize),\n Math.floor(y / this.cellSize),\n Math.floor(z / this.cellSize),\n ];\n }\n\n /**\n * Inserts an item at the specified position.\n *\n * @param item - The item to insert\n * @param position - The 3D position of the item\n */\n insert(item: T, position: Vec3): void {\n const key = this.getCellKey(position.x, position.y, position.z);\n\n let cell = this.cells.get(key);\n if (!cell) {\n cell = [];\n this.cells.set(key, cell);\n }\n\n cell.push(item);\n this.itemPositions.set(item, position);\n }\n\n /**\n * Removes an item from the hash.\n *\n * @param item - The item to remove\n * @returns True if the item was found and removed\n */\n remove(item: T): boolean {\n const position = this.itemPositions.get(item);\n if (!position) {\n return false;\n }\n\n const key = this.getCellKey(position.x, position.y, position.z);\n const cell = this.cells.get(key);\n\n if (cell) {\n const index = cell.indexOf(item);\n if (index !== -1) {\n cell.splice(index, 1);\n if (cell.length === 0) {\n this.cells.delete(key);\n }\n }\n }\n\n this.itemPositions.delete(item);\n return true;\n }\n\n /**\n * Updates an item's position in the hash.\n *\n * @param item - The item to update\n * @param newPosition - The new position\n */\n update(item: T, newPosition: Vec3): void {\n this.remove(item);\n this.insert(item, newPosition);\n }\n\n /**\n * Queries all items within a radius of a point.\n *\n * @param center - The center point of the query\n * @param radius - The search radius\n * @returns Array of items within the radius\n */\n queryRadius(center: Vec3, radius: number): T[] {\n const results: T[] = [];\n const radiusSquared = radius * radius;\n\n // Calculate the range of cells to check\n const minCell = this.getCellIndices(center.x - radius, center.y - radius, center.z - radius);\n const maxCell = this.getCellIndices(center.x + radius, center.y + radius, center.z + radius);\n\n // Check all cells in range\n for (let ix = minCell[0]; ix <= maxCell[0]; ix++) {\n for (let iy = minCell[1]; iy <= maxCell[1]; iy++) {\n for (let iz = minCell[2]; iz <= maxCell[2]; iz++) {\n const key = `${ix},${iy},${iz}`;\n const cell = this.cells.get(key);\n\n if (cell) {\n for (const item of cell) {\n const pos = this.itemPositions.get(item);\n if (pos) {\n const dx = pos.x - center.x;\n const dy = pos.y - center.y;\n const dz = pos.z - center.z;\n const distSq = dx * dx + dy * dy + dz * dz;\n\n if (distSq <= radiusSquared) {\n results.push(item);\n }\n }\n }\n }\n }\n }\n }\n\n return results;\n }\n\n /**\n * Queries the k nearest neighbors to a point.\n *\n * @param center - The center point of the query\n * @param k - The number of neighbors to find\n * @param maxRadius - Optional maximum search radius\n * @returns Array of the k nearest items, sorted by distance\n */\n queryKNearest(center: Vec3, k: number, maxRadius?: number): T[] {\n // Start with a small radius and expand if needed\n let radius = this.cellSize;\n let results: Array<{ item: T; distSq: number }> = [];\n\n while (results.length < k) {\n if (maxRadius !== undefined && radius > maxRadius) {\n break;\n }\n\n results = [];\n const candidates = this.queryRadius(center, radius);\n\n for (const item of candidates) {\n const pos = this.itemPositions.get(item);\n if (pos) {\n const dx = pos.x - center.x;\n const dy = pos.y - center.y;\n const dz = pos.z - center.z;\n results.push({ item, distSq: dx * dx + dy * dy + dz * dz });\n }\n }\n\n radius *= 2;\n }\n\n // Sort by distance and return top k\n results.sort((a, b) => a.distSq - b.distSq);\n return results.slice(0, k).map((r) => r.item);\n }\n\n /**\n * Clears all items from the hash.\n */\n clear(): void {\n this.cells.clear();\n this.itemPositions.clear();\n }\n\n /**\n * Gets the number of items in the hash.\n */\n get size(): number {\n return this.itemPositions.size;\n }\n\n /**\n * Gets the number of non-empty cells.\n */\n get cellCount(): number {\n return this.cells.size;\n }\n\n /**\n * Gets the position of an item.\n */\n getPosition(item: T): Vec3 | undefined {\n return this.itemPositions.get(item);\n }\n\n /**\n * Checks if an item is in the hash.\n */\n has(item: T): boolean {\n return this.itemPositions.has(item);\n }\n\n /**\n * Iterates over all items in the hash.\n */\n *[Symbol.iterator](): Iterator<T> {\n for (const item of this.itemPositions.keys()) {\n yield item;\n }\n }\n\n /**\n * Gets all items in the hash.\n */\n getAll(): T[] {\n return Array.from(this.itemPositions.keys());\n }\n}\n\n/**\n * Creates a spatial hash from an array of items with positions.\n *\n * @param items - Array of items with position getter\n * @param getPosition - Function to get the position of an item\n * @param cellSize - Optional cell size (auto-computed if not provided)\n */\nexport function createSpatialHash<T>(\n items: T[],\n getPosition: (item: T) => Vec3,\n cellSize?: number\n): SpatialHash<T> {\n // Auto-compute cell size based on item spread if not provided\n let computedCellSize = cellSize;\n\n if (computedCellSize === undefined && items.length > 1) {\n // Compute bounding box\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n\n for (const item of items) {\n const pos = getPosition(item);\n minX = Math.min(minX, pos.x);\n minY = Math.min(minY, pos.y);\n minZ = Math.min(minZ, pos.z);\n maxX = Math.max(maxX, pos.x);\n maxY = Math.max(maxY, pos.y);\n maxZ = Math.max(maxZ, pos.z);\n }\n\n const diagonal = Math.sqrt((maxX - minX) ** 2 + (maxY - minY) ** 2 + (maxZ - minZ) ** 2);\n\n // Cell size is diagonal / sqrt(n) for roughly uniform distribution\n computedCellSize = diagonal / Math.sqrt(items.length);\n }\n\n const hash = new SpatialHash<T>(computedCellSize ?? 1.0);\n\n for (const item of items) {\n hash.insert(item, getPosition(item));\n }\n\n return hash;\n}\n","import type { Vec3 } from '../geometry/GeometricUtils';\nimport { distanceSquared } from '../geometry/GeometricUtils';\n\n/**\n * Axis-Aligned Bounding Box.\n */\nexport interface AABB {\n min: Vec3;\n max: Vec3;\n}\n\n/**\n * A triangle primitive for BVH.\n */\nexport interface Triangle {\n v0: Vec3;\n v1: Vec3;\n v2: Vec3;\n data?: unknown;\n}\n\n/**\n * Result of a closest point query.\n */\nexport interface ClosestPointResult {\n point: Vec3;\n distance: number;\n triangleIndex: number;\n}\n\n/**\n * BVH node for the tree structure.\n */\ninterface BVHNode {\n bounds: AABB;\n left?: BVHNode;\n right?: BVHNode;\n triangleIndices?: number[];\n}\n\n/**\n * Computes the AABB of a triangle.\n */\nfunction triangleBounds(tri: Triangle): AABB {\n return {\n min: {\n x: Math.min(tri.v0.x, tri.v1.x, tri.v2.x),\n y: Math.min(tri.v0.y, tri.v1.y, tri.v2.y),\n z: Math.min(tri.v0.z, tri.v1.z, tri.v2.z),\n },\n max: {\n x: Math.max(tri.v0.x, tri.v1.x, tri.v2.x),\n y: Math.max(tri.v0.y, tri.v1.y, tri.v2.y),\n z: Math.max(tri.v0.z, tri.v1.z, tri.v2.z),\n },\n };\n}\n\n/**\n * Merges two AABBs.\n */\nfunction mergeBounds(a: AABB, b: AABB): AABB {\n return {\n min: {\n x: Math.min(a.min.x, b.min.x),\n y: Math.min(a.min.y, b.min.y),\n z: Math.min(a.min.z, b.min.z),\n },\n max: {\n x: Math.max(a.max.x, b.max.x),\n y: Math.max(a.max.y, b.max.y),\n z: Math.max(a.max.z, b.max.z),\n },\n };\n}\n\n/**\n * Computes the centroid of a triangle.\n */\nfunction triangleCentroid(tri: Triangle): Vec3 {\n return {\n x: (tri.v0.x + tri.v1.x + tri.v2.x) / 3,\n y: (tri.v0.y + tri.v1.y + tri.v2.y) / 3,\n z: (tri.v0.z + tri.v1.z + tri.v2.z) / 3,\n };\n}\n\n/**\n * Computes the squared distance from a point to an AABB.\n */\nfunction pointToAABBDistanceSquared(point: Vec3, box: AABB): number {\n let distSq = 0;\n\n if (point.x < box.min.x) {\n distSq += (box.min.x - point.x) ** 2;\n } else if (point.x > box.max.x) {\n distSq += (point.x - box.max.x) ** 2;\n }\n\n if (point.y < box.min.y) {\n distSq += (box.min.y - point.y) ** 2;\n } else if (point.y > box.max.y) {\n distSq += (point.y - box.max.y) ** 2;\n }\n\n if (point.z < box.min.z) {\n distSq += (box.min.z - point.z) ** 2;\n } else if (point.z > box.max.z) {\n distSq += (point.z - box.max.z) ** 2;\n }\n\n return distSq;\n}\n\n/**\n * Computes the closest point on a triangle to a query point.\n */\nfunction closestPointOnTriangle(point: Vec3, tri: Triangle): Vec3 {\n // Based on Real-Time Collision Detection by Christer Ericson\n\n const a = tri.v0;\n const b = tri.v1;\n const c = tri.v2;\n\n // Check if P in vertex region outside A\n const ab = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z };\n const ac = { x: c.x - a.x, y: c.y - a.y, z: c.z - a.z };\n const ap = { x: point.x - a.x, y: point.y - a.y, z: point.z - a.z };\n\n const d1 = ab.x * ap.x + ab.y * ap.y + ab.z * ap.z;\n const d2 = ac.x * ap.x + ac.y * ap.y + ac.z * ap.z;\n\n if (d1 <= 0 && d2 <= 0) return a; // Barycentric coordinates (1,0,0)\n\n // Check if P in vertex region outside B\n const bp = { x: point.x - b.x, y: point.y - b.y, z: point.z - b.z };\n const d3 = ab.x * bp.x + ab.y * bp.y + ab.z * bp.z;\n const d4 = ac.x * bp.x + ac.y * bp.y + ac.z * bp.z;\n\n if (d3 >= 0 && d4 <= d3) return b; // Barycentric coordinates (0,1,0)\n\n // Check if P in edge region of AB\n const vc = d1 * d4 - d3 * d2;\n if (vc <= 0 && d1 >= 0 && d3 <= 0) {\n const v = d1 / (d1 - d3);\n return { x: a.x + v * ab.x, y: a.y + v * ab.y, z: a.z + v * ab.z };\n }\n\n // Check if P in vertex region outside C\n const cp = { x: point.x - c.x, y: point.y - c.y, z: point.z - c.z };\n const d5 = ab.x * cp.x + ab.y * cp.y + ab.z * cp.z;\n const d6 = ac.x * cp.x + ac.y * cp.y + ac.z * cp.z;\n\n if (d6 >= 0 && d5 <= d6) return c; // Barycentric coordinates (0,0,1)\n\n // Check if P in edge region of AC\n const vb = d5 * d2 - d1 * d6;\n if (vb <= 0 && d2 >= 0 && d6 <= 0) {\n const w = d2 / (d2 - d6);\n return { x: a.x + w * ac.x, y: a.y + w * ac.y, z: a.z + w * ac.z };\n }\n\n // Check if P in edge region of BC\n const va = d3 * d6 - d5 * d4;\n if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0) {\n const w = (d4 - d3) / (d4 - d3 + (d5 - d6));\n return {\n x: b.x + w * (c.x - b.x),\n y: b.y + w * (c.y - b.y),\n z: b.z + w * (c.z - b.z),\n };\n }\n\n // P inside face region\n const denom = 1 / (va + vb + vc);\n const v = vb * denom;\n const w = vc * denom;\n return {\n x: a.x + ab.x * v + ac.x * w,\n y: a.y + ab.y * v + ac.y * w,\n z: a.z + ab.z * v + ac.z * w,\n };\n}\n\n/**\n * Bounding Volume Hierarchy for fast spatial queries on triangle meshes.\n */\nexport class BVH {\n private root: BVHNode | null = null;\n private triangles: Triangle[] = [];\n private maxLeafSize: number;\n\n /**\n * Creates a new BVH.\n *\n * @param maxLeafSize - Maximum number of triangles per leaf node\n */\n constructor(maxLeafSize: number = 4) {\n this.maxLeafSize = maxLeafSize;\n }\n\n /**\n * Builds the BVH from an array of triangles.\n *\n * @param triangles - Array of triangles to build from\n */\n build(triangles: Triangle[]): void {\n this.triangles = triangles;\n\n if (triangles.length === 0) {\n this.root = null;\n return;\n }\n\n const indices = triangles.map((_, i) => i);\n this.root = this.buildNode(indices);\n }\n\n /**\n * Recursively builds a BVH node.\n */\n private buildNode(indices: number[]): BVHNode {\n // Compute bounds\n let bounds = triangleBounds(this.triangles[indices[0]!]!);\n for (let i = 1; i < indices.length; i++) {\n bounds = mergeBounds(bounds, triangleBounds(this.triangles[indices[i]!]!));\n }\n\n // Leaf node if small enough\n if (indices.length <= this.maxLeafSize) {\n return { bounds, triangleIndices: indices };\n }\n\n // Choose split axis (longest axis)\n const extents = {\n x: bounds.max.x - bounds.min.x,\n y: bounds.max.y - bounds.min.y,\n z: bounds.max.z - bounds.min.z,\n };\n\n let axis: 'x' | 'y' | 'z' = 'x';\n if (extents.y > extents.x && extents.y > extents.z) axis = 'y';\n else if (extents.z > extents.x && extents.z > extents.y) axis = 'z';\n\n // Sort by centroid along axis\n const centroids = indices.map((i) => ({\n index: i,\n centroid: triangleCentroid(this.triangles[i]!),\n }));\n\n centroids.sort((a, b) => a.centroid[axis] - b.centroid[axis]);\n\n // Split at median\n const mid = Math.floor(centroids.length / 2);\n const leftIndices = centroids.slice(0, mid).map((c) => c.index);\n const rightIndices = centroids.slice(mid).map((c) => c.index);\n\n // Handle degenerate case where all triangles have same centroid\n if (leftIndices.length === 0 || rightIndices.length === 0) {\n return { bounds, triangleIndices: indices };\n }\n\n return {\n bounds,\n left: this.buildNode(leftIndices),\n right: this.buildNode(rightIndices),\n };\n }\n\n /**\n * Finds the closest point on the mesh to a query point.\n *\n * @param point - The query point\n * @returns The closest point result, or null if no triangles\n */\n closestPoint(point: Vec3): ClosestPointResult | null {\n if (!this.root || this.triangles.length === 0) {\n return null;\n }\n\n let bestResult: ClosestPointResult | null = null;\n let bestDistSq = Infinity;\n\n const stack: BVHNode[] = [this.root];\n\n while (stack.length > 0) {\n const node = stack.pop()!;\n\n // Check if this node could contain a closer point\n const boxDistSq = pointToAABBDistanceSquared(point, node.bounds);\n if (boxDistSq >= bestDistSq) {\n continue;\n }\n\n if (node.triangleIndices) {\n // Leaf node - check triangles\n for (const idx of node.triangleIndices) {\n const tri = this.triangles[idx]!;\n const closest = closestPointOnTriangle(point, tri);\n const distSq = distanceSquared(point, closest);\n\n if (distSq < bestDistSq) {\n bestDistSq = distSq;\n bestResult = {\n point: closest,\n distance: Math.sqrt(distSq),\n triangleIndex: idx,\n };\n }\n }\n } else {\n // Internal node - add children to stack\n // Add farther child first so closer child is processed first\n if (node.left && node.right) {\n const leftDist = pointToAABBDistanceSquared(point, node.left.bounds);\n const rightDist = pointToAABBDistanceSquared(point, node.right.bounds);\n\n if (leftDist < rightDist) {\n stack.push(node.right);\n stack.push(node.left);\n } else {\n stack.push(node.left);\n stack.push(node.right);\n }\n } else if (node.left) {\n stack.push(node.left);\n } else if (node.right) {\n stack.push(node.right);\n }\n }\n }\n\n return bestResult;\n }\n\n /**\n * Finds all triangles intersecting a sphere.\n *\n * @param center - Center of the sphere\n * @param radius - Radius of the sphere\n * @returns Array of triangle indices\n */\n queryRadius(center: Vec3, radius: number): number[] {\n const results: number[] = [];\n const radiusSq = radius * radius;\n\n if (!this.root) {\n return results;\n }\n\n const stack: BVHNode[] = [this.root];\n\n while (stack.length > 0) {\n const node = stack.pop()!;\n\n // Check if sphere could intersect this node\n const boxDistSq = pointToAABBDistanceSquared(center, node.bounds);\n if (boxDistSq > radiusSq) {\n continue;\n }\n\n if (node.triangleIndices) {\n // Leaf node - check triangles\n for (const idx of node.triangleIndices) {\n const tri = this.triangles[idx]!;\n const closest = closestPointOnTriangle(center, tri);\n const distSq = distanceSquared(center, closest);\n\n if (distSq <= radiusSq) {\n results.push(idx);\n }\n }\n } else {\n // Internal node - add children\n if (node.left) stack.push(node.left);\n if (node.right) stack.push(node.right);\n }\n }\n\n return results;\n }\n\n /**\n * Gets the total number of triangles.\n */\n get triangleCount(): number {\n return this.triangles.length;\n }\n\n /**\n * Gets a triangle by index.\n */\n getTriangle(index: number): Triangle | undefined {\n return this.triangles[index];\n }\n}\n\n/**\n * Creates a BVH from a NonManifoldMesh.\n */\nexport function createBVHFromMesh(mesh: {\n getFaces(): Array<{\n getVertices(): [{ position: Vec3 }, { position: Vec3 }, { position: Vec3 }] | null;\n }>;\n}): BVH {\n const triangles: Triangle[] = [];\n\n for (const face of mesh.getFaces()) {\n const verts = face.getVertices();\n if (!verts) continue;\n\n triangles.push({\n v0: { x: verts[0].position.x, y: verts[0].position.y, z: verts[0].position.z },\n v1: { x: verts[1].position.x, y: verts[1].position.y, z: verts[1].position.z },\n v2: { x: verts[2].position.x, y: verts[2].position.y, z: verts[2].position.z },\n });\n }\n\n const bvh = new BVH();\n bvh.build(triangles);\n return bvh;\n}\n","import type { BufferGeometry } from 'three';\nimport { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport { EdgeType, VertexType } from '../types/SkeletonData';\nimport type { Edge } from '../core/Edge';\nimport type { Vertex } from '../core/Vertex';\n\n/**\n * Information about a non-manifold edge.\n */\nexport interface NonManifoldEdgeInfo {\n /** Index of the edge */\n edgeId: number;\n\n /** Indices of the two vertices */\n vertexIndices: [number, number];\n\n /** Number of incident faces */\n faceCount: number;\n\n /** Positions of the edge endpoints */\n positions: [{ x: number; y: number; z: number }, { x: number; y: number; z: number }];\n}\n\n/**\n * Information about a non-manifold vertex.\n */\nexport interface NonManifoldVertexInfo {\n /** Index of the vertex */\n vertexId: number;\n\n /** Position of the vertex */\n position: { x: number; y: number; z: number };\n\n /** Classification type */\n type: VertexType;\n\n /** Number of incident skeleton edges */\n skeletonEdgeCount: number;\n}\n\n/**\n * Result of manifold analysis.\n */\nexport interface ManifoldAnalysisResult {\n /** Whether the mesh is manifold */\n isManifold: boolean;\n\n /** Whether the mesh has boundary edges */\n hasBoundary: boolean;\n\n /** Total number of vertices */\n vertexCount: number;\n\n /** Total number of edges */\n edgeCount: number;\n\n /** Total number of faces */\n faceCount: number;\n\n /** Number of manifold edges */\n manifoldEdgeCount: number;\n\n /** Number of non-manifold edges */\n nonManifoldEdgeCount: number;\n\n /** Number of boundary edges */\n boundaryEdgeCount: number;\n\n /** Number of manifold vertices */\n manifoldVertexCount: number;\n\n /** Number of non-manifold vertices */\n nonManifoldVertexCount: number;\n\n /** Detailed info about non-manifold edges */\n nonManifoldEdges: NonManifoldEdgeInfo[];\n\n /** Detailed info about non-manifold vertices */\n nonManifoldVertices: NonManifoldVertexInfo[];\n\n /** Euler characteristic (V - E + F) */\n eulerCharacteristic: number;\n\n /** Average vertex degree */\n averageVertexDegree: number;\n}\n\n/**\n * Analyzes a BufferGeometry for manifoldness.\n *\n * @param geometry - The geometry to analyze\n * @returns Analysis result\n */\nexport function analyzeManifold(geometry: BufferGeometry): ManifoldAnalysisResult {\n const mesh = NonManifoldMesh.fromBufferGeometry(geometry);\n return analyzeMesh(mesh);\n}\n\n/**\n * Analyzes a NonManifoldMesh for manifoldness.\n *\n * @param mesh - The mesh to analyze\n * @returns Analysis result\n */\nexport function analyzeMesh(mesh: NonManifoldMesh): ManifoldAnalysisResult {\n const edges = mesh.getEdges();\n const vertices = mesh.getVertices();\n\n // Count edge types\n let manifoldEdgeCount = 0;\n let nonManifoldEdgeCount = 0;\n let boundaryEdgeCount = 0;\n\n const nonManifoldEdges: NonManifoldEdgeInfo[] = [];\n\n for (const edge of edges) {\n switch (edge.type) {\n case EdgeType.Manifold:\n case EdgeType.Feature:\n manifoldEdgeCount++;\n break;\n case EdgeType.NonManifold:\n nonManifoldEdgeCount++;\n nonManifoldEdges.push(extractEdgeInfo(edge));\n break;\n case EdgeType.Boundary:\n boundaryEdgeCount++;\n break;\n }\n }\n\n // Count vertex types\n let manifoldVertexCount = 0;\n let nonManifoldVertexCount = 0;\n let totalDegree = 0;\n\n const nonManifoldVertices: NonManifoldVertexInfo[] = [];\n\n for (const vertex of vertices) {\n const degree = vertex.degree() ?? 0;\n totalDegree += degree;\n\n if (vertex.type === VertexType.Manifold) {\n manifoldVertexCount++;\n } else {\n nonManifoldVertexCount++;\n nonManifoldVertices.push(extractVertexInfo(vertex));\n }\n }\n\n const averageVertexDegree = vertices.length > 0 ? totalDegree / vertices.length : 0;\n const eulerCharacteristic = mesh.vertexCount - mesh.edgeCount + mesh.faceCount;\n\n return {\n isManifold: nonManifoldEdgeCount === 0,\n hasBoundary: boundaryEdgeCount > 0,\n vertexCount: mesh.vertexCount,\n edgeCount: mesh.edgeCount,\n faceCount: mesh.faceCount,\n manifoldEdgeCount,\n nonManifoldEdgeCount,\n boundaryEdgeCount,\n manifoldVertexCount,\n nonManifoldVertexCount,\n nonManifoldEdges,\n nonManifoldVertices,\n eulerCharacteristic,\n averageVertexDegree,\n };\n}\n\n/**\n * Extracts info about a non-manifold edge.\n */\nfunction extractEdgeInfo(edge: Edge): NonManifoldEdgeInfo {\n const [v0, v1] = edge.getVertices();\n\n return {\n edgeId: edge.id as number,\n vertexIndices: [v0 ? (v0.id as number) : -1, v1 ? (v1.id as number) : -1],\n faceCount: edge.getFaceCount(),\n positions: [\n v0 ? { x: v0.position.x, y: v0.position.y, z: v0.position.z } : { x: 0, y: 0, z: 0 },\n v1 ? { x: v1.position.x, y: v1.position.y, z: v1.position.z } : { x: 0, y: 0, z: 0 },\n ],\n };\n}\n\n/**\n * Extracts info about a non-manifold vertex.\n */\nfunction extractVertexInfo(vertex: Vertex): NonManifoldVertexInfo {\n let skeletonEdgeCount = 0;\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (he.edge.isSkeletonEdge()) {\n skeletonEdgeCount++;\n }\n });\n\n return {\n vertexId: vertex.id as number,\n position: { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z },\n type: vertex.type,\n skeletonEdgeCount,\n };\n}\n\n/**\n * Quick check if a geometry is manifold.\n *\n * @param geometry - The geometry to check\n * @returns True if the geometry is manifold\n */\nexport function isManifold(geometry: BufferGeometry): boolean {\n const mesh = NonManifoldMesh.fromBufferGeometry(geometry);\n return mesh.isManifold();\n}\n\n/**\n * Class for analyzing mesh manifoldness with caching.\n */\nexport class ManifoldAnalyzer {\n private mesh: NonManifoldMesh | null = null;\n private cachedResult: ManifoldAnalysisResult | null = null;\n\n /**\n * Loads a geometry for analysis.\n */\n load(geometry: BufferGeometry): this {\n this.mesh = NonManifoldMesh.fromBufferGeometry(geometry);\n this.cachedResult = null;\n return this;\n }\n\n /**\n * Loads an existing mesh for analysis.\n */\n loadMesh(mesh: NonManifoldMesh): this {\n this.mesh = mesh;\n this.cachedResult = null;\n return this;\n }\n\n /**\n * Gets the analysis result (cached).\n */\n analyze(): ManifoldAnalysisResult {\n if (!this.mesh) {\n throw new Error('No mesh loaded. Call load() first.');\n }\n\n if (!this.cachedResult) {\n this.cachedResult = analyzeMesh(this.mesh);\n }\n\n return this.cachedResult;\n }\n\n /**\n * Checks if the mesh is manifold.\n */\n isManifold(): boolean {\n return this.analyze().isManifold;\n }\n\n /**\n * Checks if the mesh has boundary.\n */\n hasBoundary(): boolean {\n return this.analyze().hasBoundary;\n }\n\n /**\n * Gets non-manifold edges.\n */\n getNonManifoldEdges(): NonManifoldEdgeInfo[] {\n return this.analyze().nonManifoldEdges;\n }\n\n /**\n * Gets non-manifold vertices.\n */\n getNonManifoldVertices(): NonManifoldVertexInfo[] {\n return this.analyze().nonManifoldVertices;\n }\n\n /**\n * Gets the underlying mesh.\n */\n getMesh(): NonManifoldMesh | null {\n return this.mesh;\n }\n\n /**\n * Clears cached results.\n */\n clearCache(): this {\n this.cachedResult = null;\n return this;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Vertex } from '../core/Vertex';\nimport { VertexType } from '../types/SkeletonData';\n\n/**\n * Statistics about vertex classification.\n */\nexport interface ClassificationStats {\n /** Number of manifold vertices */\n manifold: number;\n\n /** Number of open-book vertices */\n openBook: number;\n\n /** Number of skeleton branching vertices */\n skeletonBranching: number;\n\n /** Number of other non-manifold vertices */\n nonManifoldOther: number;\n\n /** Total vertex count */\n total: number;\n}\n\n/**\n * Classifies all vertices in a mesh based on their neighborhood topology.\n *\n * @param mesh - The mesh to classify\n * @returns Classification statistics\n */\nexport function classifyAllVertices(mesh: NonManifoldMesh): ClassificationStats {\n const stats: ClassificationStats = {\n manifold: 0,\n openBook: 0,\n skeletonBranching: 0,\n nonManifoldOther: 0,\n total: 0,\n };\n\n for (const vertex of mesh.getVertices()) {\n vertex.type = classifyVertex(vertex);\n stats.total++;\n\n switch (vertex.type) {\n case VertexType.Manifold:\n stats.manifold++;\n break;\n case VertexType.OpenBook:\n stats.openBook++;\n break;\n case VertexType.SkeletonBranching:\n stats.skeletonBranching++;\n break;\n case VertexType.NonManifoldOther:\n stats.nonManifoldOther++;\n break;\n }\n }\n\n return stats;\n}\n\n/**\n * Classifies a single vertex based on its neighborhood.\n *\n * Vertex classification:\n * - Manifold: Star homeomorphic to disk, can move freely in 3D\n * - OpenBook: On exactly 2 skeleton edges (like pages of a book)\n * - SkeletonBranching: On 1 or >2 skeleton edges, position is fixed\n * - NonManifoldOther: Other non-manifold configurations\n *\n * @param vertex - The vertex to classify\n * @returns The vertex type\n */\nexport function classifyVertex(vertex: Vertex): VertexType {\n // Count skeleton edges incident to this vertex\n let skeletonEdgeCount = 0;\n let totalEdgeCount = 0;\n let hasBoundary = false;\n let hasNonManifold = false;\n\n vertex.forEachOutgoingHalfedge((he) => {\n totalEdgeCount++;\n\n if (he.edge.isSkeletonEdge()) {\n skeletonEdgeCount++;\n }\n\n if (he.edge.isBoundary()) {\n hasBoundary = true;\n }\n\n if (he.edge.isNonManifold()) {\n hasNonManifold = true;\n }\n });\n\n // If no edges, treat as manifold (isolated vertex)\n if (totalEdgeCount === 0) {\n return VertexType.Manifold;\n }\n\n // Check for non-manifold configurations\n if (hasNonManifold) {\n if (skeletonEdgeCount === 2) {\n return VertexType.OpenBook;\n } else if (skeletonEdgeCount === 1 || skeletonEdgeCount > 2) {\n return VertexType.SkeletonBranching;\n }\n return VertexType.NonManifoldOther;\n }\n\n // Check for boundary configurations\n if (hasBoundary) {\n if (skeletonEdgeCount === 2) {\n return VertexType.OpenBook;\n } else if (skeletonEdgeCount === 1 || skeletonEdgeCount > 2) {\n return VertexType.SkeletonBranching;\n }\n }\n\n // No skeleton edges - manifold vertex\n if (skeletonEdgeCount === 0) {\n return VertexType.Manifold;\n }\n\n // Exactly 2 skeleton edges - open-book\n if (skeletonEdgeCount === 2) {\n return VertexType.OpenBook;\n }\n\n // 1 or >2 skeleton edges - branching\n return VertexType.SkeletonBranching;\n}\n\n/**\n * Gets all vertices of a specific type.\n *\n * @param mesh - The mesh to search\n * @param type - The vertex type to find\n * @returns Array of vertices matching the type\n */\nexport function getVerticesByType(mesh: NonManifoldMesh, type: VertexType): Vertex[] {\n return mesh.getVertices().filter((v) => v.type === type);\n}\n\n/**\n * Gets all manifold vertices.\n */\nexport function getManifoldVertices(mesh: NonManifoldMesh): Vertex[] {\n return getVerticesByType(mesh, VertexType.Manifold);\n}\n\n/**\n * Gets all open-book vertices.\n */\nexport function getOpenBookVertices(mesh: NonManifoldMesh): Vertex[] {\n return getVerticesByType(mesh, VertexType.OpenBook);\n}\n\n/**\n * Gets all skeleton branching vertices.\n */\nexport function getSkeletonBranchingVertices(mesh: NonManifoldMesh): Vertex[] {\n return getVerticesByType(mesh, VertexType.SkeletonBranching);\n}\n\n/**\n * Gets all non-manifold vertices (open-book + branching + other).\n */\nexport function getNonManifoldVertices(mesh: NonManifoldMesh): Vertex[] {\n return mesh.getVertices().filter((v) => v.type !== VertexType.Manifold);\n}\n\n/**\n * Reclassifies all vertices in a mesh.\n * Call this after topology changes.\n */\nexport function reclassifyVertices(mesh: NonManifoldMesh): void {\n mesh.classifyVertices();\n}\n\n/**\n * Class for vertex classification operations.\n */\nexport class VertexClassifier {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Classifies all vertices and returns statistics.\n */\n classifyAll(): ClassificationStats {\n return classifyAllVertices(this.mesh);\n }\n\n /**\n * Gets vertices of a specific type.\n */\n getByType(type: VertexType): Vertex[] {\n return getVerticesByType(this.mesh, type);\n }\n\n /**\n * Gets all manifold vertices.\n */\n getManifold(): Vertex[] {\n return getManifoldVertices(this.mesh);\n }\n\n /**\n * Gets all non-manifold vertices.\n */\n getNonManifold(): Vertex[] {\n return getNonManifoldVertices(this.mesh);\n }\n\n /**\n * Reclassifies all vertices.\n */\n reclassify(): void {\n reclassifyVertices(this.mesh);\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\n\n/**\n * A validation error.\n */\nexport interface ValidationError {\n /** Type of the error */\n type: string;\n\n /** Human-readable message */\n message: string;\n\n /** Related element IDs */\n elementIds?: number[];\n}\n\n/**\n * Result of topology validation.\n */\nexport interface TopologyValidationResult {\n /** Whether the mesh topology is valid */\n isValid: boolean;\n\n /** List of errors found */\n errors: ValidationError[];\n\n /** List of warnings */\n warnings: ValidationError[];\n}\n\n/**\n * Validates the topology of a mesh.\n *\n * @param mesh - The mesh to validate\n * @returns Validation result\n */\nexport function validateTopology(mesh: NonManifoldMesh): TopologyValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationError[] = [];\n\n // Validate vertices\n validateVertices(mesh, errors, warnings);\n\n // Validate edges\n validateEdges(mesh, errors, warnings);\n\n // Validate faces\n validateFaces(mesh, errors, warnings);\n\n // Validate halfedge connectivity\n validateHalfedgeConnectivity(mesh, errors, warnings);\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validates vertex references.\n */\nfunction validateVertices(\n mesh: NonManifoldMesh,\n errors: ValidationError[],\n _warnings: ValidationError[]\n): void {\n for (const vertex of mesh.getVertices()) {\n // Check halfedge reference\n if (vertex.halfedge) {\n if (!mesh.getHalfedge(vertex.halfedge.id)) {\n errors.push({\n type: 'invalid_vertex_halfedge',\n message: `Vertex ${vertex.id} references non-existent halfedge ${vertex.halfedge.id}`,\n elementIds: [vertex.id as number],\n });\n }\n }\n\n // Check for valid position\n if (\n !isFinite(vertex.position.x) ||\n !isFinite(vertex.position.y) ||\n !isFinite(vertex.position.z)\n ) {\n errors.push({\n type: 'invalid_vertex_position',\n message: `Vertex ${vertex.id} has invalid position`,\n elementIds: [vertex.id as number],\n });\n }\n }\n}\n\n/**\n * Validates edge references.\n */\nfunction validateEdges(\n mesh: NonManifoldMesh,\n errors: ValidationError[],\n warnings: ValidationError[]\n): void {\n for (const edge of mesh.getEdges()) {\n // Check that edge has at least one halfedge\n if (edge.allHalfedges.length === 0) {\n errors.push({\n type: 'edge_no_halfedges',\n message: `Edge ${edge.id} has no halfedges`,\n elementIds: [edge.id as number],\n });\n continue;\n }\n\n // Check primary halfedge reference\n if (!mesh.getHalfedge(edge.halfedge.id)) {\n errors.push({\n type: 'invalid_edge_halfedge',\n message: `Edge ${edge.id} references non-existent halfedge`,\n elementIds: [edge.id as number],\n });\n }\n\n // Check edge length\n if (edge.length <= 0 || !isFinite(edge.length)) {\n warnings.push({\n type: 'invalid_edge_length',\n message: `Edge ${edge.id} has invalid length: ${edge.length}`,\n elementIds: [edge.id as number],\n });\n }\n\n // Validate all halfedges reference this edge\n for (const he of edge.allHalfedges) {\n if (he.edge.id !== edge.id) {\n errors.push({\n type: 'halfedge_edge_mismatch',\n message: `Halfedge ${he.id} in edge ${edge.id} references different edge ${he.edge.id}`,\n elementIds: [edge.id as number, he.id as number],\n });\n }\n }\n }\n}\n\n/**\n * Validates face references.\n */\nfunction validateFaces(\n mesh: NonManifoldMesh,\n errors: ValidationError[],\n warnings: ValidationError[]\n): void {\n for (const face of mesh.getFaces()) {\n // Check halfedge reference\n if (!face.halfedge) {\n errors.push({\n type: 'face_no_halfedge',\n message: `Face ${face.id} has no halfedge`,\n elementIds: [face.id as number],\n });\n continue;\n }\n\n if (!mesh.getHalfedge(face.halfedge.id)) {\n errors.push({\n type: 'invalid_face_halfedge',\n message: `Face ${face.id} references non-existent halfedge`,\n elementIds: [face.id as number],\n });\n continue;\n }\n\n // Check that face has exactly 3 halfedges (triangle)\n const halfedges = face.getHalfedges();\n if (!halfedges) {\n errors.push({\n type: 'face_invalid_loop',\n message: `Face ${face.id} has invalid halfedge loop`,\n elementIds: [face.id as number],\n });\n continue;\n }\n\n // Check that all halfedges reference this face\n for (const he of halfedges) {\n if (he.face?.id !== face.id) {\n errors.push({\n type: 'halfedge_face_mismatch',\n message: `Halfedge ${he.id} in face ${face.id} references different face`,\n elementIds: [face.id as number, he.id as number],\n });\n }\n }\n\n // Check for degenerate triangles\n if (face.isDegenerate()) {\n warnings.push({\n type: 'degenerate_face',\n message: `Face ${face.id} is degenerate (near-zero area)`,\n elementIds: [face.id as number],\n });\n }\n }\n}\n\n/**\n * Validates halfedge connectivity.\n */\nfunction validateHalfedgeConnectivity(\n mesh: NonManifoldMesh,\n errors: ValidationError[],\n _warnings: ValidationError[]\n): void {\n for (const he of mesh.getHalfedges()) {\n // Check next pointer\n if (!he.next) {\n errors.push({\n type: 'halfedge_no_next',\n message: `Halfedge ${he.id} has no next pointer`,\n elementIds: [he.id as number],\n });\n } else if (!mesh.getHalfedge(he.next.id)) {\n errors.push({\n type: 'halfedge_invalid_next',\n message: `Halfedge ${he.id} has invalid next pointer`,\n elementIds: [he.id as number],\n });\n }\n\n // Check prev pointer\n if (!he.prev) {\n errors.push({\n type: 'halfedge_no_prev',\n message: `Halfedge ${he.id} has no prev pointer`,\n elementIds: [he.id as number],\n });\n } else if (!mesh.getHalfedge(he.prev.id)) {\n errors.push({\n type: 'halfedge_invalid_prev',\n message: `Halfedge ${he.id} has invalid prev pointer`,\n elementIds: [he.id as number],\n });\n }\n\n // Check next/prev consistency\n if (he.next && he.next.prev !== he) {\n errors.push({\n type: 'halfedge_next_prev_mismatch',\n message: `Halfedge ${he.id}: next.prev does not point back`,\n elementIds: [he.id as number],\n });\n }\n\n if (he.prev && he.prev.next !== he) {\n errors.push({\n type: 'halfedge_prev_next_mismatch',\n message: `Halfedge ${he.id}: prev.next does not point back`,\n elementIds: [he.id as number],\n });\n }\n\n // Check twin consistency (if exists)\n if (he.twin) {\n if (!mesh.getHalfedge(he.twin.id)) {\n errors.push({\n type: 'halfedge_invalid_twin',\n message: `Halfedge ${he.id} has invalid twin pointer`,\n elementIds: [he.id as number],\n });\n } else if (he.twin.twin !== he) {\n errors.push({\n type: 'halfedge_twin_mismatch',\n message: `Halfedge ${he.id}: twin.twin does not point back`,\n elementIds: [he.id as number],\n });\n }\n }\n\n // Check vertex reference\n if (!mesh.getVertex(he.vertex.id)) {\n errors.push({\n type: 'halfedge_invalid_vertex',\n message: `Halfedge ${he.id} references non-existent vertex`,\n elementIds: [he.id as number],\n });\n }\n\n // Check edge reference\n if (!mesh.getEdge(he.edge.id)) {\n errors.push({\n type: 'halfedge_invalid_edge',\n message: `Halfedge ${he.id} references non-existent edge`,\n elementIds: [he.id as number],\n });\n }\n }\n}\n\n/**\n * Quick check if mesh topology is valid.\n */\nexport function isTopologyValid(mesh: NonManifoldMesh): boolean {\n return validateTopology(mesh).isValid;\n}\n\n/**\n * Class for topology validation.\n */\nexport class TopologyValidator {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Validates the mesh topology.\n */\n validate(): TopologyValidationResult {\n return validateTopology(this.mesh);\n }\n\n /**\n * Quick check if topology is valid.\n */\n isValid(): boolean {\n return isTopologyValid(this.mesh);\n }\n\n /**\n * Gets all errors.\n */\n getErrors(): ValidationError[] {\n return this.validate().errors;\n }\n\n /**\n * Gets all warnings.\n */\n getWarnings(): ValidationError[] {\n return this.validate().warnings;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Edge } from '../core/Edge';\nimport type { Vec3 } from '../geometry/GeometricUtils';\nimport { isQuadConvex, distance } from '../geometry/GeometricUtils';\n\n/**\n * Result of an edge flip operation.\n */\nexport interface EdgeFlipResult {\n /** Whether the flip was successful */\n success: boolean;\n\n /** Reason for failure (if any) */\n reason?: string;\n\n /** The new edge length after flip */\n newLength?: number;\n}\n\n/**\n * Checks if an edge can be flipped.\n *\n * An edge can be flipped if:\n * 1. It has exactly 2 adjacent faces (not boundary, not non-manifold)\n * 2. It is not a skeleton edge\n * 3. Both endpoint vertices have degree > 1\n * 4. The quadrilateral formed is convex\n */\nexport function canFlipEdge(edge: Edge): boolean {\n // Must not be a skeleton edge\n if (edge.isSkeletonEdge()) {\n return false;\n }\n\n // Basic flip check\n if (!edge.canFlip()) {\n return false;\n }\n\n // Get the quadrilateral vertices\n const quad = getQuadVertices(edge);\n if (!quad) {\n return false;\n }\n\n // Check convexity\n return isQuadConvex(quad.v0, quad.v1, quad.v2, quad.v3);\n}\n\n/**\n * Gets the four vertices forming the quadrilateral around an edge.\n *\n * Returns vertices in order: v0, v1 (edge endpoints), v2, v3 (opposite vertices)\n */\nfunction getQuadVertices(edge: Edge): { v0: Vec3; v1: Vec3; v2: Vec3; v3: Vec3 } | null {\n const h = edge.halfedge;\n const hTwin = h.twin;\n\n if (!hTwin || !h.face || !hTwin.face) {\n return null;\n }\n\n const hNext = h.next;\n const hTwinNext = hTwin.next;\n\n if (!hNext || !hTwinNext) {\n return null;\n }\n\n const v0 = hTwin.vertex; // Edge start\n const v1 = h.vertex; // Edge end\n const v2 = hNext.vertex; // Opposite in face 0\n const v3 = hTwinNext.vertex; // Opposite in face 1\n\n return {\n v0: { x: v0.position.x, y: v0.position.y, z: v0.position.z },\n v1: { x: v1.position.x, y: v1.position.y, z: v1.position.z },\n v2: { x: v2.position.x, y: v2.position.y, z: v2.position.z },\n v3: { x: v3.position.x, y: v3.position.y, z: v3.position.z },\n };\n}\n\n/**\n * Flips an edge in the mesh.\n *\n * Before flip (edge connects vA to vB):\n *\n * vC\n * /|\\\n * / | \\\n * / | \\\n * / f0| \\\n * vA----|----vB\n * \\ f1| /\n * \\ | /\n * \\ | /\n * \\|/\n * vD\n *\n * After flip (edge connects vC to vD):\n *\n * vC\n * / \\\n * / f0\\\n * / \\\n * / \\\n * vA---------vB\n * \\ /\n * \\ f1 /\n * \\ /\n * \\ /\n * vD\n */\nexport function flipEdge(_mesh: NonManifoldMesh, edge: Edge): EdgeFlipResult {\n // Check if edge can be flipped\n if (!canFlipEdge(edge)) {\n return { success: false, reason: 'Edge cannot be flipped' };\n }\n\n const h = edge.halfedge;\n const hTwin = h.twin;\n\n if (!hTwin) {\n return { success: false, reason: 'Edge has no twin' };\n }\n\n // Get the 4 surrounding halfedges\n const hNext = h.next!;\n const hPrev = h.prev!;\n const hTwinNext = hTwin.next!;\n const hTwinPrev = hTwin.prev!;\n\n // Get the 4 vertices\n const vA = hTwin.vertex;\n const vB = h.vertex;\n const vC = hNext.vertex;\n const vD = hTwinNext.vertex;\n\n // Get faces\n const f0 = h.face;\n const f1 = hTwin.face;\n\n if (!f0 || !f1) {\n return { success: false, reason: 'Missing faces' };\n }\n\n // Update edge length (new edge connects vC to vD)\n const newLength = distance(\n { x: vC.position.x, y: vC.position.y, z: vC.position.z },\n { x: vD.position.x, y: vD.position.y, z: vD.position.z }\n );\n edge.length = newLength;\n\n // Update halfedge targets\n h.vertex = vD;\n hTwin.vertex = vC;\n\n // Set up face f0 cycle: h -> hTwinPrev -> hNext -> h\n h.next = hTwinPrev;\n h.prev = hNext;\n hTwinPrev.next = hNext;\n hTwinPrev.prev = h;\n hNext.next = h;\n hNext.prev = hTwinPrev;\n\n // Set up face f1 cycle: hTwin -> hPrev -> hTwinNext -> hTwin\n hTwin.next = hPrev;\n hTwin.prev = hTwinNext;\n hPrev.next = hTwinNext;\n hPrev.prev = hTwin;\n hTwinNext.next = hTwin;\n hTwinNext.prev = hPrev;\n\n // Update face assignments\n h.face = f0;\n hTwinPrev.face = f0;\n hNext.face = f0;\n\n hTwin.face = f1;\n hPrev.face = f1;\n hTwinNext.face = f1;\n\n // Update face halfedges\n f0.halfedge = h;\n f1.halfedge = hTwin;\n\n // Update vertex halfedges if they pointed to the flipped edge\n if (vA.halfedge === h) {\n vA.halfedge = hTwinNext;\n }\n if (vB.halfedge === hTwin) {\n vB.halfedge = hNext;\n }\n\n return { success: true, newLength };\n}\n\n/**\n * Checks if an edge satisfies the Delaunay condition.\n * An edge is Delaunay if the sum of opposite angles is <= 180 degrees.\n */\nexport function isDelaunay(edge: Edge): boolean {\n const h = edge.halfedge;\n const hTwin = h.twin;\n\n if (!hTwin || !h.face || !hTwin.face) {\n return true; // Boundary edges are always Delaunay\n }\n\n // Get the quadrilateral vertices\n const quad = getQuadVertices(edge);\n if (!quad) {\n return true;\n }\n\n // Compute opposite angles using law of cosines\n const angle0 = computeAngle(quad.v2, quad.v0, quad.v1);\n const angle1 = computeAngle(quad.v3, quad.v0, quad.v1);\n\n // Delaunay condition: sum of opposite angles <= π\n return angle0 + angle1 <= Math.PI + 1e-10;\n}\n\n/**\n * Computes the angle at vertex v0 in triangle (v0, v1, v2).\n */\nfunction computeAngle(v0: Vec3, v1: Vec3, v2: Vec3): number {\n const dx1 = v1.x - v0.x;\n const dy1 = v1.y - v0.y;\n const dz1 = v1.z - v0.z;\n\n const dx2 = v2.x - v0.x;\n const dy2 = v2.y - v0.y;\n const dz2 = v2.z - v0.z;\n\n const dot = dx1 * dx2 + dy1 * dy2 + dz1 * dz2;\n const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);\n const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);\n\n if (len1 < 1e-10 || len2 < 1e-10) {\n return 0;\n }\n\n const cosAngle = Math.max(-1, Math.min(1, dot / (len1 * len2)));\n return Math.acos(cosAngle);\n}\n\n/**\n * Performs Delaunay flips on the mesh.\n * Returns the number of flips performed.\n */\nexport function makeDelaunay(mesh: NonManifoldMesh, maxIterations?: number): number {\n const edges = mesh.getEdges();\n const maxIter = maxIterations ?? edges.length * 10;\n\n let flipCount = 0;\n let iteration = 0;\n\n while (iteration < maxIter) {\n iteration++;\n let flippedAny = false;\n\n for (const edge of edges) {\n if (!isDelaunay(edge) && canFlipEdge(edge)) {\n const result = flipEdge(mesh, edge);\n if (result.success) {\n flipCount++;\n flippedAny = true;\n }\n }\n }\n\n if (!flippedAny) {\n break;\n }\n }\n\n return flipCount;\n}\n\n/**\n * Edge flip operation handler.\n */\nexport class EdgeFlipper {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Flips an edge.\n */\n flip(edge: Edge): EdgeFlipResult {\n return flipEdge(this.mesh, edge);\n }\n\n /**\n * Checks if an edge can be flipped.\n */\n canFlip(edge: Edge): boolean {\n return canFlipEdge(edge);\n }\n\n /**\n * Checks if an edge satisfies the Delaunay condition.\n */\n isDelaunay(edge: Edge): boolean {\n return isDelaunay(edge);\n }\n\n /**\n * Makes the mesh Delaunay by flipping non-Delaunay edges.\n */\n makeDelaunay(maxIterations?: number): number {\n return makeDelaunay(this.mesh, maxIterations);\n }\n}\n","import { Vector3 } from 'three';\nimport type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Edge } from '../core/Edge';\nimport type { Vertex } from '../core/Vertex';\nimport type { Face } from '../core/Face';\nimport type { Halfedge } from '../core/Edge';\n\n/**\n * Result of an edge split operation.\n */\nexport interface EdgeSplitResult {\n /** Whether the split was successful */\n success: boolean;\n\n /** Reason for failure (if any) */\n reason?: string;\n\n /** The new vertex created at the midpoint */\n newVertex?: Vertex;\n\n /** The new edges created */\n newEdges?: Edge[];\n\n /** The new faces created */\n newFaces?: Face[];\n}\n\n/**\n * Splits an edge at its midpoint.\n *\n * Before split:\n * vC\n * /|\\\n * / | \\\n * / | \\\n * / f0| \\\n * vA---e---vB\n * \\ f1| /\n * \\ | /\n * \\ | /\n * \\|/\n * vD\n *\n * After split (new vertex vM at midpoint):\n * vC\n * /|\\\n * / | \\\n * / | \\\n * / f0|f2 \\\n * vA--vM---vB\n * \\ f1|f3 /\n * \\ | /\n * \\ | /\n * \\|/\n * vD\n */\nexport function splitEdge(\n mesh: NonManifoldMesh,\n edge: Edge,\n splitRatio: number = 0.5\n): EdgeSplitResult {\n const [v0, v1] = edge.getVertices();\n if (!v0 || !v1) {\n return { success: false, reason: 'Edge has no vertices' };\n }\n\n // Compute the split point\n const p0 = { x: v0.position.x, y: v0.position.y, z: v0.position.z };\n const p1 = { x: v1.position.x, y: v1.position.y, z: v1.position.z };\n const mid = {\n x: p0.x + (p1.x - p0.x) * splitRatio,\n y: p0.y + (p1.y - p0.y) * splitRatio,\n z: p0.z + (p1.z - p0.z) * splitRatio,\n };\n\n // Create new vertex at the split point\n const newVertex = mesh.createVertex(new Vector3(mid.x, mid.y, mid.z));\n\n // Inherit type from edge for skeleton edges\n if (edge.isSkeletonEdge()) {\n // The new vertex will be classified later\n }\n\n const newEdges: Edge[] = [];\n const newFaces: Face[] = [];\n\n // Get faces incident to this edge\n const faces = edge.getFaces();\n\n if (faces.length === 0) {\n // Isolated edge - just update the connectivity\n return { success: true, newVertex, newEdges: [], newFaces: [] };\n }\n\n // For each face, we need to split it into two triangles\n for (const face of faces) {\n if (!face) continue;\n\n const halfedges = face.getHalfedges();\n if (!halfedges) continue;\n\n // Find the halfedge corresponding to this edge in this face\n let edgeHe: Halfedge | null = null;\n for (const he of halfedges) {\n if (he.edge.id === edge.id) {\n edgeHe = he;\n break;\n }\n }\n\n if (!edgeHe) continue;\n\n // Split this face\n splitFaceAtEdge(mesh, face, edgeHe, newVertex, newEdges, newFaces);\n }\n\n // Update edge length\n edge.length = edge.length * splitRatio;\n\n // Reclassify the new vertex\n mesh.classifyVertices();\n\n return { success: true, newVertex, newEdges, newFaces };\n}\n\n/**\n * Splits a face at an edge by inserting a new vertex.\n */\nfunction splitFaceAtEdge(\n mesh: NonManifoldMesh,\n _face: Face,\n edgeHe: Halfedge,\n newVertex: Vertex,\n _newEdges: Edge[],\n newFaces: Face[]\n): void {\n // This is a complex operation that involves:\n // 1. Creating new halfedges\n // 2. Creating a new edge from the opposite vertex to the new vertex\n // 3. Updating all connectivity\n\n const heNext = edgeHe.next!;\n\n const vOpposite = heNext.vertex; // The vertex opposite to the edge\n const vTarget = edgeHe.vertex; // Original target of the halfedge\n\n // For now, create a simple split by creating two new faces\n // This is a simplified version - full implementation would update in-place\n\n // Create new face with vertices: newVertex, vTarget, vOpposite\n const newFace = mesh.createFace(newVertex, vTarget, vOpposite);\n newFaces.push(newFace);\n\n // Update the original face to use newVertex instead of vTarget\n // This requires updating halfedge connectivity\n edgeHe.vertex = newVertex;\n\n // Set the new vertex's halfedge\n if (!newVertex.halfedge) {\n newVertex.halfedge = edgeHe;\n }\n}\n\n/**\n * Splits all edges longer than a threshold.\n */\nexport function splitLongEdges(\n mesh: NonManifoldMesh,\n maxLength: number\n): { splitCount: number; newVertices: Vertex[] } {\n const newVertices: Vertex[] = [];\n let splitCount = 0;\n\n // Collect edges to split (iterate over a copy since we're modifying)\n const edgesToSplit: Edge[] = [];\n for (const edge of mesh.getEdges()) {\n if (edge.length > maxLength) {\n edgesToSplit.push(edge);\n }\n }\n\n // Split edges\n for (const edge of edgesToSplit) {\n const result = splitEdge(mesh, edge);\n if (result.success && result.newVertex) {\n splitCount++;\n newVertices.push(result.newVertex);\n }\n }\n\n return { splitCount, newVertices };\n}\n\n/**\n * Edge split operation handler.\n */\nexport class EdgeSplitter {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Splits an edge at the midpoint.\n */\n split(edge: Edge, ratio: number = 0.5): EdgeSplitResult {\n return splitEdge(this.mesh, edge, ratio);\n }\n\n /**\n * Splits all edges longer than a threshold.\n */\n splitLongEdges(maxLength: number): { splitCount: number; newVertices: Vertex[] } {\n return splitLongEdges(this.mesh, maxLength);\n }\n\n /**\n * Checks if an edge should be split based on target length.\n */\n shouldSplit(edge: Edge, targetLength: number, maxRatio: number = 1.333): boolean {\n return edge.length > targetLength * maxRatio;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Edge } from '../core/Edge';\nimport type { Vertex } from '../core/Vertex';\nimport type { Face } from '../core/Face';\nimport { VertexType } from '../types/SkeletonData';\nimport { midpoint } from '../geometry/GeometricUtils';\n\n/**\n * Result of an edge contraction operation.\n */\nexport interface EdgeContractionResult {\n /** Whether the contraction was successful */\n success: boolean;\n\n /** Reason for failure (if any) */\n reason?: string;\n\n /** The remaining vertex after contraction */\n remainingVertex?: Vertex;\n\n /** Faces that were removed */\n removedFaces?: Face[];\n}\n\n/**\n * Checks if an edge can be contracted.\n *\n * An edge can be contracted if:\n * 1. Neither endpoint is a fixed vertex (branching or non-manifold other)\n * 2. Contracting won't create invalid topology\n * 3. The edge is not the only edge connecting two regions\n */\nexport function canContractEdge(edge: Edge): boolean {\n const [v0, v1] = edge.getVertices();\n if (!v0 || !v1) {\n return false;\n }\n\n // Check vertex types\n if (v0.type === VertexType.SkeletonBranching || v0.type === VertexType.NonManifoldOther) {\n // Can only contract if v1 is also not fixed\n if (v1.type === VertexType.SkeletonBranching || v1.type === VertexType.NonManifoldOther) {\n return false; // Both fixed\n }\n }\n\n if (v1.type === VertexType.SkeletonBranching || v1.type === VertexType.NonManifoldOther) {\n // v0 must not be fixed (already checked)\n }\n\n // Check if contraction would create invalid topology\n // (Link condition: intersection of vertex links should only contain the edge vertices)\n if (!checkLinkCondition(v0, v1)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks the link condition for edge contraction.\n * The link of a vertex is the set of vertices connected to it.\n * For valid contraction, link(v0) ∩ link(v1) should equal the edge endpoints.\n */\nfunction checkLinkCondition(v0: Vertex, v1: Vertex): boolean {\n const link0 = new Set<number>();\n const link1 = new Set<number>();\n\n v0.forEachNeighbor((v) => {\n link0.add(v.id as number);\n });\n\n v1.forEachNeighbor((v) => {\n link1.add(v.id as number);\n });\n\n // Count common neighbors (excluding v0 and v1 themselves)\n let commonCount = 0;\n for (const id of link0) {\n if (id !== (v0.id as number) && id !== (v1.id as number) && link1.has(id)) {\n commonCount++;\n }\n }\n\n // For a valid edge contraction in a triangle mesh:\n // - Interior edge: common neighbors should be exactly 2 (the opposite vertices of the two triangles)\n // - Boundary edge: common neighbors should be exactly 1\n\n const faces = getSharedFaces(v0, v1);\n const expectedCommon = faces.length;\n\n return commonCount <= expectedCommon;\n}\n\n/**\n * Gets faces shared by two vertices.\n */\nfunction getSharedFaces(v0: Vertex, v1: Vertex): Face[] {\n const faces0 = new Set<number>();\n const sharedFaces: Face[] = [];\n\n v0.forEachOutgoingHalfedge((he) => {\n if (he.face) {\n faces0.add(he.face.id as number);\n }\n });\n\n v1.forEachOutgoingHalfedge((he) => {\n if (he.face && faces0.has(he.face.id as number)) {\n sharedFaces.push(he.face);\n }\n });\n\n return sharedFaces;\n}\n\n/**\n * Contracts an edge, merging its two endpoints into one vertex.\n *\n * The resulting vertex position depends on vertex types:\n * - If one is fixed and one is movable: keep the fixed position\n * - If both are movable: use midpoint\n * - If one is on skeleton: use skeleton-constrained position\n */\nexport function contractEdge(mesh: NonManifoldMesh, edge: Edge): EdgeContractionResult {\n if (!canContractEdge(edge)) {\n return { success: false, reason: 'Edge cannot be contracted' };\n }\n\n const [v0, v1] = edge.getVertices();\n if (!v0 || !v1) {\n return { success: false, reason: 'Edge has no vertices' };\n }\n\n // Determine which vertex to keep and what position to use\n const { keepVertex, removeVertex, newPosition } = determineContractionResult(v0, v1);\n\n // Update the kept vertex position\n keepVertex.position.set(newPosition.x, newPosition.y, newPosition.z);\n\n // Get faces that will be removed (the triangles incident to the edge)\n const removedFaces = getSharedFaces(v0, v1);\n\n // Redirect all halfedges from removeVertex to keepVertex\n redirectHalfedges(removeVertex, keepVertex);\n\n // Remove the collapsed faces from the mesh\n for (const face of removedFaces) {\n mesh.faces.delete(face.id);\n }\n\n // Remove the contracted edge\n mesh.edges.delete(edge.id);\n\n // Remove halfedges associated with the edge\n for (const he of edge.allHalfedges) {\n mesh.halfedges.delete(he.id);\n }\n\n // Remove the vertex\n mesh.vertices.delete(removeVertex.id);\n\n // Update keepVertex's halfedge if needed\n if (keepVertex.halfedge && !mesh.halfedges.has(keepVertex.halfedge.id)) {\n // Find a valid halfedge\n for (const he of mesh.halfedges.values()) {\n if (he.getSourceVertex()?.id === keepVertex.id) {\n keepVertex.halfedge = he;\n break;\n }\n }\n }\n\n // Reclassify vertices\n mesh.classifyVertices();\n\n return { success: true, remainingVertex: keepVertex, removedFaces };\n}\n\n/**\n * Determines which vertex to keep and the new position after contraction.\n */\nfunction determineContractionResult(\n v0: Vertex,\n v1: Vertex\n): { keepVertex: Vertex; removeVertex: Vertex; newPosition: { x: number; y: number; z: number } } {\n // Priority: Fixed > OpenBook > Manifold\n const priority = (v: Vertex): number => {\n switch (v.type) {\n case VertexType.SkeletonBranching:\n case VertexType.NonManifoldOther:\n return 3;\n case VertexType.OpenBook:\n return 2;\n case VertexType.Manifold:\n return 1;\n default:\n return 0;\n }\n };\n\n const p0 = priority(v0);\n const p1 = priority(v1);\n\n let keepVertex: Vertex;\n let removeVertex: Vertex;\n let newPosition: { x: number; y: number; z: number };\n\n if (p0 >= p1) {\n keepVertex = v0;\n removeVertex = v1;\n } else {\n keepVertex = v1;\n removeVertex = v0;\n }\n\n // Determine position\n if (\n keepVertex.type === VertexType.SkeletonBranching ||\n keepVertex.type === VertexType.NonManifoldOther\n ) {\n // Fixed vertex: keep its position\n newPosition = {\n x: keepVertex.position.x,\n y: keepVertex.position.y,\n z: keepVertex.position.z,\n };\n } else if (keepVertex.type === VertexType.OpenBook && removeVertex.type === VertexType.Manifold) {\n // Keep the skeleton vertex position\n newPosition = {\n x: keepVertex.position.x,\n y: keepVertex.position.y,\n z: keepVertex.position.z,\n };\n } else {\n // Use midpoint\n newPosition = midpoint(\n { x: v0.position.x, y: v0.position.y, z: v0.position.z },\n { x: v1.position.x, y: v1.position.y, z: v1.position.z }\n );\n }\n\n return { keepVertex, removeVertex, newPosition };\n}\n\n/**\n * Redirects all halfedges from one vertex to another.\n */\nfunction redirectHalfedges(fromVertex: Vertex, toVertex: Vertex): void {\n fromVertex.forEachOutgoingHalfedge((he) => {\n // Update the twin's vertex (since outgoing halfedge's source is fromVertex)\n if (he.twin) {\n he.twin.vertex = toVertex;\n }\n });\n}\n\n/**\n * Contracts all edges shorter than a threshold.\n */\nexport function contractShortEdges(\n mesh: NonManifoldMesh,\n minLength: number\n): { contractCount: number; removedVertices: number } {\n let contractCount = 0;\n let removedVertices = 0;\n\n // Collect edges to contract (iterate over a copy since we're modifying)\n let edgesToContract: Edge[] = [];\n for (const edge of mesh.getEdges()) {\n if (edge.length < minLength && canContractEdge(edge)) {\n edgesToContract.push(edge);\n }\n }\n\n // Contract edges one at a time (order matters since contractions affect neighbors)\n while (edgesToContract.length > 0) {\n const edge = edgesToContract.pop()!;\n\n // Check if edge still exists and can be contracted\n if (!mesh.edges.has(edge.id) || !canContractEdge(edge)) {\n continue;\n }\n\n const result = contractEdge(mesh, edge);\n if (result.success) {\n contractCount++;\n removedVertices++;\n }\n }\n\n return { contractCount, removedVertices };\n}\n\n/**\n * Edge contraction operation handler.\n */\nexport class EdgeContractor {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Contracts an edge.\n */\n contract(edge: Edge): EdgeContractionResult {\n return contractEdge(this.mesh, edge);\n }\n\n /**\n * Checks if an edge can be contracted.\n */\n canContract(edge: Edge): boolean {\n return canContractEdge(edge);\n }\n\n /**\n * Contracts all edges shorter than a threshold.\n */\n contractShortEdges(minLength: number): { contractCount: number; removedVertices: number } {\n return contractShortEdges(this.mesh, minLength);\n }\n\n /**\n * Checks if an edge should be contracted based on target length.\n */\n shouldContract(edge: Edge, targetLength: number, minRatio: number = 0.4): boolean {\n return edge.length < targetLength * minRatio;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Vertex } from '../core/Vertex';\nimport type { SkeletonConstraints } from '../skeleton/SkeletonConstraints';\nimport type { Vec3 } from '../geometry/GeometricUtils';\nimport { VertexType } from '../types/SkeletonData';\nimport { add, subtract, scale, normalize, dot, distance } from '../geometry/GeometricUtils';\n\n/**\n * Result of a vertex relocation operation.\n */\nexport interface VertexRelocationResult {\n /** Whether the relocation was successful */\n success: boolean;\n\n /** Reason for failure (if any) */\n reason?: string;\n\n /** The new position */\n newPosition?: Vec3;\n\n /** Whether the position was constrained */\n wasConstrained?: boolean;\n\n /** Distance moved */\n distanceMoved?: number;\n}\n\n/**\n * Computes the target position for a vertex using tangential smoothing.\n * This projects the barycenter of neighbors onto the tangent plane.\n */\nexport function computeTangentialSmoothing(vertex: Vertex): Vec3 | null {\n const neighbors = vertex.getNeighbors();\n if (neighbors.length === 0) {\n return null;\n }\n\n // Compute barycenter of neighbors\n let cx = 0,\n cy = 0,\n cz = 0;\n for (const n of neighbors) {\n cx += n.position.x;\n cy += n.position.y;\n cz += n.position.z;\n }\n cx /= neighbors.length;\n cy /= neighbors.length;\n cz /= neighbors.length;\n\n const barycenter = { x: cx, y: cy, z: cz };\n\n // Compute vertex normal (average of incident face normals)\n const normal = computeVertexNormal(vertex);\n if (!normal) {\n return barycenter;\n }\n\n // Project barycenter onto tangent plane\n const vertexPos = { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z };\n const toBarycenter = subtract(barycenter, vertexPos);\n const normalComponent = scale(normal, dot(toBarycenter, normal));\n const tangentComponent = subtract(toBarycenter, normalComponent);\n\n return add(vertexPos, tangentComponent);\n}\n\n/**\n * Computes the vertex normal by averaging incident face normals.\n */\nfunction computeVertexNormal(vertex: Vertex): Vec3 | null {\n let nx = 0,\n ny = 0,\n nz = 0;\n let count = 0;\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (he.face) {\n const faceNormal = he.face.getNormal();\n if (faceNormal) {\n nx += faceNormal.x;\n ny += faceNormal.y;\n nz += faceNormal.z;\n count++;\n }\n }\n });\n\n if (count === 0) {\n return null;\n }\n\n return normalize({ x: nx / count, y: ny / count, z: nz / count });\n}\n\n/**\n * Relocates a vertex to a target position, respecting constraints.\n */\nexport function relocateVertex(\n _mesh: NonManifoldMesh,\n vertex: Vertex,\n targetPosition: Vec3,\n constraints?: SkeletonConstraints\n): VertexRelocationResult {\n // Check if vertex can move\n if (vertex.type === VertexType.SkeletonBranching || vertex.type === VertexType.NonManifoldOther) {\n return { success: false, reason: 'Vertex is fixed' };\n }\n\n const currentPos = { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z };\n let finalPosition = targetPosition;\n let wasConstrained = false;\n\n // Apply skeleton constraints if available\n if (constraints) {\n const constrained = constraints.constrainPosition(vertex, targetPosition);\n finalPosition = constrained.position;\n wasConstrained = constrained.wasConstrained;\n }\n\n // Check if the move would create invalid geometry\n if (!isValidRelocation(vertex, finalPosition)) {\n return { success: false, reason: 'Relocation would create invalid geometry' };\n }\n\n // Apply the relocation\n vertex.position.set(finalPosition.x, finalPosition.y, finalPosition.z);\n\n // Update incident edge lengths\n updateIncidentEdgeLengths(vertex);\n\n const distanceMoved = distance(currentPos, finalPosition);\n\n return {\n success: true,\n newPosition: finalPosition,\n wasConstrained,\n distanceMoved,\n };\n}\n\n/**\n * Checks if a vertex relocation would create invalid geometry.\n */\nfunction isValidRelocation(vertex: Vertex, newPosition: Vec3): boolean {\n // Check for face inversions (normals flipping)\n const originalPos = { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z };\n\n // Temporarily move vertex\n vertex.position.set(newPosition.x, newPosition.y, newPosition.z);\n\n let isValid = true;\n\n vertex.forEachOutgoingHalfedge((he) => {\n if (he.face) {\n const area = he.face.getArea();\n if (area !== null && area < 1e-10) {\n isValid = false; // Degenerate triangle\n }\n }\n });\n\n // Restore original position\n vertex.position.set(originalPos.x, originalPos.y, originalPos.z);\n\n return isValid;\n}\n\n/**\n * Updates the lengths of all edges incident to a vertex.\n */\nfunction updateIncidentEdgeLengths(vertex: Vertex): void {\n vertex.forEachOutgoingHalfedge((he) => {\n const source = he.getSourceVertex();\n if (source) {\n he.edge.length = distance(\n { x: source.position.x, y: source.position.y, z: source.position.z },\n { x: he.vertex.position.x, y: he.vertex.position.y, z: he.vertex.position.z }\n );\n }\n });\n}\n\n/**\n * Applies tangential smoothing to a vertex.\n */\nexport function smoothVertex(\n mesh: NonManifoldMesh,\n vertex: Vertex,\n constraints?: SkeletonConstraints,\n dampingFactor: number = 0.5\n): VertexRelocationResult {\n const target = computeTangentialSmoothing(vertex);\n if (!target) {\n return { success: false, reason: 'Cannot compute smoothing target' };\n }\n\n // Apply damping\n const currentPos = { x: vertex.position.x, y: vertex.position.y, z: vertex.position.z };\n const dampedTarget = {\n x: currentPos.x + (target.x - currentPos.x) * dampingFactor,\n y: currentPos.y + (target.y - currentPos.y) * dampingFactor,\n z: currentPos.z + (target.z - currentPos.z) * dampingFactor,\n };\n\n return relocateVertex(mesh, vertex, dampedTarget, constraints);\n}\n\n/**\n * Applies tangential smoothing to all relocatable vertices.\n */\nexport function smoothAllVertices(\n mesh: NonManifoldMesh,\n constraints?: SkeletonConstraints,\n dampingFactor: number = 0.5\n): { smoothedCount: number; totalDistance: number } {\n let smoothedCount = 0;\n let totalDistance = 0;\n\n for (const vertex of mesh.getVertices()) {\n if (vertex.type === VertexType.Manifold || vertex.type === VertexType.OpenBook) {\n const result = smoothVertex(mesh, vertex, constraints, dampingFactor);\n if (result.success) {\n smoothedCount++;\n totalDistance += result.distanceMoved ?? 0;\n }\n }\n }\n\n return { smoothedCount, totalDistance };\n}\n\n/**\n * Vertex relocation operation handler.\n */\nexport class VertexRelocator {\n private mesh: NonManifoldMesh;\n private constraints: SkeletonConstraints | null = null;\n\n constructor(mesh: NonManifoldMesh, constraints?: SkeletonConstraints) {\n this.mesh = mesh;\n this.constraints = constraints ?? null;\n }\n\n /**\n * Sets the skeleton constraints.\n */\n setConstraints(constraints: SkeletonConstraints): void {\n this.constraints = constraints;\n }\n\n /**\n * Relocates a vertex to a target position.\n */\n relocate(vertex: Vertex, targetPosition: Vec3): VertexRelocationResult {\n return relocateVertex(this.mesh, vertex, targetPosition, this.constraints ?? undefined);\n }\n\n /**\n * Applies tangential smoothing to a vertex.\n */\n smooth(vertex: Vertex, dampingFactor: number = 0.5): VertexRelocationResult {\n return smoothVertex(this.mesh, vertex, this.constraints ?? undefined, dampingFactor);\n }\n\n /**\n * Applies tangential smoothing to all relocatable vertices.\n */\n smoothAll(dampingFactor: number = 0.5): { smoothedCount: number; totalDistance: number } {\n return smoothAllVertices(this.mesh, this.constraints ?? undefined, dampingFactor);\n }\n\n /**\n * Checks if a vertex can be relocated.\n */\n canRelocate(vertex: Vertex): boolean {\n return vertex.type === VertexType.Manifold || vertex.type === VertexType.OpenBook;\n }\n}\n","import type { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport type { Face } from '../core/Face';\nimport type { Edge } from '../core/Edge';\nimport type { Vertex } from '../core/Vertex';\n\n/**\n * Quality statistics for a mesh.\n */\nexport interface MeshQualityStats {\n /** Minimum triangle quality (0 to 1) */\n minQuality: number;\n\n /** Maximum triangle quality (0 to 1) */\n maxQuality: number;\n\n /** Average triangle quality (0 to 1) */\n averageQuality: number;\n\n /** Standard deviation of triangle quality */\n stdDevQuality: number;\n\n /** Number of triangles with quality below threshold */\n poorQualityCount: number;\n\n /** Minimum edge length */\n minEdgeLength: number;\n\n /** Maximum edge length */\n maxEdgeLength: number;\n\n /** Average edge length */\n averageEdgeLength: number;\n\n /** Minimum triangle area */\n minArea: number;\n\n /** Maximum triangle area */\n maxArea: number;\n\n /** Total surface area */\n totalArea: number;\n}\n\n/**\n * Computes quality statistics for a mesh.\n */\nexport function computeMeshQuality(\n mesh: NonManifoldMesh,\n poorQualityThreshold: number = 0.3\n): MeshQualityStats {\n const faces = mesh.getFaces();\n const edges = mesh.getEdges();\n\n // Triangle quality\n const qualities: number[] = [];\n const areas: number[] = [];\n\n for (const face of faces) {\n const quality = face.getQuality();\n if (quality !== null) {\n qualities.push(quality);\n }\n\n const area = face.getArea();\n if (area !== null) {\n areas.push(area);\n }\n }\n\n // Edge lengths\n const edgeLengths = edges.map((e) => e.length);\n\n // Compute stats\n const minQuality = qualities.length > 0 ? Math.min(...qualities) : 0;\n const maxQuality = qualities.length > 0 ? Math.max(...qualities) : 0;\n const averageQuality =\n qualities.length > 0 ? qualities.reduce((a, b) => a + b, 0) / qualities.length : 0;\n\n const variance =\n qualities.length > 0\n ? qualities.reduce((sum, q) => sum + Math.pow(q - averageQuality, 2), 0) / qualities.length\n : 0;\n const stdDevQuality = Math.sqrt(variance);\n\n const poorQualityCount = qualities.filter((q) => q < poorQualityThreshold).length;\n\n const minEdgeLength = edgeLengths.length > 0 ? Math.min(...edgeLengths) : 0;\n const maxEdgeLength = edgeLengths.length > 0 ? Math.max(...edgeLengths) : 0;\n const averageEdgeLength =\n edgeLengths.length > 0 ? edgeLengths.reduce((a, b) => a + b, 0) / edgeLengths.length : 0;\n\n const minArea = areas.length > 0 ? Math.min(...areas) : 0;\n const maxArea = areas.length > 0 ? Math.max(...areas) : 0;\n const totalArea = areas.reduce((a, b) => a + b, 0);\n\n return {\n minQuality,\n maxQuality,\n averageQuality,\n stdDevQuality,\n poorQualityCount,\n minEdgeLength,\n maxEdgeLength,\n averageEdgeLength,\n minArea,\n maxArea,\n totalArea,\n };\n}\n\n/**\n * Gets faces with quality below a threshold.\n */\nexport function getPoorQualityFaces(mesh: NonManifoldMesh, threshold: number = 0.3): Face[] {\n return mesh.getFaces().filter((face) => {\n const quality = face.getQuality();\n return quality !== null && quality < threshold;\n });\n}\n\n/**\n * Gets edges that are too long (should be split).\n */\nexport function getLongEdges(\n mesh: NonManifoldMesh,\n targetLength: number,\n maxRatio: number = 1.333\n): Edge[] {\n const maxLength = targetLength * maxRatio;\n return mesh.getEdges().filter((e) => e.length > maxLength);\n}\n\n/**\n * Gets edges that are too short (should be collapsed).\n */\nexport function getShortEdges(\n mesh: NonManifoldMesh,\n targetLength: number,\n minRatio: number = 0.4\n): Edge[] {\n const minLength = targetLength * minRatio;\n return mesh.getEdges().filter((e) => e.length < minLength);\n}\n\n/**\n * Computes the target edge length based on mesh bounding box.\n */\nexport function computeTargetEdgeLength(mesh: NonManifoldMesh, numTargetVertices?: number): number {\n const vertices = mesh.getVertices();\n if (vertices.length === 0) {\n return 1.0;\n }\n\n // Compute bounding box\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n\n for (const v of vertices) {\n minX = Math.min(minX, v.position.x);\n minY = Math.min(minY, v.position.y);\n minZ = Math.min(minZ, v.position.z);\n maxX = Math.max(maxX, v.position.x);\n maxY = Math.max(maxY, v.position.y);\n maxZ = Math.max(maxZ, v.position.z);\n }\n\n const diagonal = Math.sqrt(\n Math.pow(maxX - minX, 2) + Math.pow(maxY - minY, 2) + Math.pow(maxZ - minZ, 2)\n );\n\n if (numTargetVertices !== undefined && numTargetVertices > 0) {\n // Estimate edge length from target vertex count\n // For a closed manifold surface: F ≈ 2V, E ≈ 3V\n // Average edge length ≈ sqrt(surface area / (2 * V))\n const stats = computeMeshQuality(mesh);\n if (stats.totalArea > 0) {\n return Math.sqrt(stats.totalArea / (2 * numTargetVertices));\n }\n }\n\n // Default: diagonal / sqrt(vertex count)\n return diagonal / Math.sqrt(vertices.length);\n}\n\n/**\n * Computes the aspect ratio of a triangle (longest / shortest edge).\n */\nexport function computeTriangleAspectRatio(face: Face): number | null {\n const halfedges = face.getHalfedges();\n if (!halfedges) {\n return null;\n }\n\n const lengths = halfedges.map((he) => he.edge.length);\n const minLen = Math.min(...lengths);\n const maxLen = Math.max(...lengths);\n\n if (minLen < 1e-10) {\n return Infinity;\n }\n\n return maxLen / minLen;\n}\n\n/**\n * Gets vertices with high valence (many incident edges).\n */\nexport function getHighValenceVertices(mesh: NonManifoldMesh, maxValence: number = 8): Vertex[] {\n return mesh.getVertices().filter((v) => {\n const degree = v.degree();\n return degree !== null && degree > maxValence;\n });\n}\n\n/**\n * Gets vertices with low valence (few incident edges).\n */\nexport function getLowValenceVertices(mesh: NonManifoldMesh, minValence: number = 4): Vertex[] {\n return mesh.getVertices().filter((v) => {\n const degree = v.degree();\n return degree !== null && degree < minValence;\n });\n}\n\n/**\n * Quality metrics utility class.\n */\nexport class QualityMetrics {\n private mesh: NonManifoldMesh;\n\n constructor(mesh: NonManifoldMesh) {\n this.mesh = mesh;\n }\n\n /**\n * Computes overall mesh quality statistics.\n */\n computeStats(poorQualityThreshold: number = 0.3): MeshQualityStats {\n return computeMeshQuality(this.mesh, poorQualityThreshold);\n }\n\n /**\n * Gets poor quality faces.\n */\n getPoorQualityFaces(threshold: number = 0.3): Face[] {\n return getPoorQualityFaces(this.mesh, threshold);\n }\n\n /**\n * Gets long edges that should be split.\n */\n getLongEdges(targetLength: number, maxRatio: number = 1.333): Edge[] {\n return getLongEdges(this.mesh, targetLength, maxRatio);\n }\n\n /**\n * Gets short edges that should be collapsed.\n */\n getShortEdges(targetLength: number, minRatio: number = 0.4): Edge[] {\n return getShortEdges(this.mesh, targetLength, minRatio);\n }\n\n /**\n * Computes target edge length.\n */\n computeTargetEdgeLength(numTargetVertices?: number): number {\n return computeTargetEdgeLength(this.mesh, numTargetVertices);\n }\n\n /**\n * Gets high valence vertices.\n */\n getHighValenceVertices(maxValence: number = 8): Vertex[] {\n return getHighValenceVertices(this.mesh, maxValence);\n }\n\n /**\n * Gets low valence vertices.\n */\n getLowValenceVertices(minValence: number = 4): Vertex[] {\n return getLowValenceVertices(this.mesh, minValence);\n }\n}\n","import type { BufferGeometry } from 'three';\nimport { NonManifoldMesh } from '../core/NonManifoldMesh';\nimport { type FeatureSkeleton, createSkeleton } from '../core/FeatureSkeleton';\nimport {\n createSkeletonConstraints,\n type SkeletonConstraints,\n} from '../skeleton/SkeletonConstraints';\nimport { exportBufferGeometry } from '../io/BufferGeometryExporter';\nimport { splitLongEdges } from '../operations/EdgeSplit';\nimport { contractShortEdges } from '../operations/EdgeContraction';\nimport { makeDelaunay } from '../operations/EdgeFlip';\nimport { smoothAllVertices } from '../operations/VertexRelocation';\nimport {\n computeMeshQuality,\n computeTargetEdgeLength,\n type MeshQualityStats,\n} from './QualityMetrics';\nimport type { RemeshOptions, RemeshStats } from '../types/RemeshOptions';\nimport { DEFAULT_REMESH_OPTIONS } from '../types/RemeshOptions';\n\n/**\n * State during remeshing iteration.\n */\ninterface RemeshingState {\n iteration: number;\n edgeSplits: number;\n edgeContractions: number;\n edgeFlips: number;\n vertexRelocations: number;\n quality: MeshQualityStats;\n}\n\n/**\n * Adaptive remeshing algorithm for non-manifold surfaces.\n *\n * Based on the EUROGRAPHICS 2008 paper \"Adaptive Remeshing of Non-Manifold Surfaces\"\n * by Zilske, Lamecker, and Zachow.\n */\nexport class AdaptiveRemesher {\n private mesh: NonManifoldMesh;\n private skeleton: FeatureSkeleton | null = null;\n private constraints: SkeletonConstraints | null = null;\n private options: Required<Omit<RemeshOptions, 'targetEdgeLength' | 'featureEdges'>> & {\n targetEdgeLength: number;\n };\n private state: RemeshingState;\n\n constructor(mesh: NonManifoldMesh, options: RemeshOptions = {}) {\n this.mesh = mesh;\n\n // Merge with defaults\n const targetEdgeLength = options.targetEdgeLength ?? computeTargetEdgeLength(mesh);\n this.options = {\n ...DEFAULT_REMESH_OPTIONS,\n ...options,\n targetEdgeLength,\n };\n\n // Initialize state\n this.state = {\n iteration: 0,\n edgeSplits: 0,\n edgeContractions: 0,\n edgeFlips: 0,\n vertexRelocations: 0,\n quality: computeMeshQuality(mesh),\n };\n\n // Build skeleton if mesh has non-manifold edges\n if (!mesh.isManifold()) {\n this.skeleton = createSkeleton(mesh);\n this.constraints = createSkeletonConstraints(this.skeleton);\n }\n }\n\n /**\n * Runs one iteration of the remeshing algorithm.\n *\n * Each iteration performs:\n * 1. Split long edges\n * 2. Collapse short edges\n * 3. Flip edges for Delaunay\n * 4. Smooth vertex positions\n */\n iterate(): RemeshingState {\n this.state.iteration++;\n\n const targetLength = this.options.targetEdgeLength;\n const minLength = targetLength * this.options.minEdgeLengthRatio;\n const maxLength = targetLength * this.options.maxEdgeLengthRatio;\n\n // 1. Split long edges\n const splitResult = splitLongEdges(this.mesh, maxLength);\n this.state.edgeSplits += splitResult.splitCount;\n\n // 2. Collapse short edges\n const contractResult = contractShortEdges(this.mesh, minLength);\n this.state.edgeContractions += contractResult.contractCount;\n\n // 3. Flip edges for Delaunay\n const flipCount = makeDelaunay(this.mesh);\n this.state.edgeFlips += flipCount;\n\n // 4. Smooth vertex positions\n const smoothResult = smoothAllVertices(this.mesh, this.constraints ?? undefined, 0.5);\n this.state.vertexRelocations += smoothResult.smoothedCount;\n\n // Rebuild skeleton if needed\n if (this.skeleton && (splitResult.splitCount > 0 || contractResult.contractCount > 0)) {\n this.skeleton.rebuild();\n }\n\n // Update quality stats\n this.state.quality = computeMeshQuality(this.mesh, this.options.minTriangleQuality);\n\n if (this.options.verbose) {\n console.warn(\n `Iteration ${this.state.iteration}: splits=${splitResult.splitCount}, ` +\n `contractions=${contractResult.contractCount}, flips=${flipCount}, ` +\n `smoothed=${smoothResult.smoothedCount}, avgQuality=${this.state.quality.averageQuality.toFixed(3)}`\n );\n }\n\n return { ...this.state };\n }\n\n /**\n * Runs multiple iterations until convergence or max iterations.\n */\n run(maxIterations?: number): RemeshStats {\n const iterations = maxIterations ?? this.options.iterations;\n const startTime = Date.now();\n const inputStats = {\n vertices: this.mesh.vertexCount,\n faces: this.mesh.faceCount,\n };\n\n for (let i = 0; i < iterations; i++) {\n const prevQuality = this.state.quality.averageQuality;\n this.iterate();\n\n // Check for convergence\n const qualityImprovement = this.state.quality.averageQuality - prevQuality;\n if (Math.abs(qualityImprovement) < 0.001 && i > 0) {\n if (this.options.verbose) {\n console.warn(`Converged after ${i + 1} iterations`);\n }\n break;\n }\n }\n\n const processingTimeMs = Date.now() - startTime;\n\n return {\n inputVertices: inputStats.vertices,\n inputFaces: inputStats.faces,\n outputVertices: this.mesh.vertexCount,\n outputFaces: this.mesh.faceCount,\n iterations: this.state.iteration,\n finalQuality: this.state.quality.averageQuality,\n nonManifoldEdges: this.mesh.getNonManifoldEdges().length,\n skeletonEdges: this.mesh.getSkeletonEdges().length,\n edgeFlips: this.state.edgeFlips,\n edgeSplits: this.state.edgeSplits,\n edgeContractions: this.state.edgeContractions,\n vertexRelocations: this.state.vertexRelocations,\n processingTimeMs,\n };\n }\n\n /**\n * Checks if the remeshing has converged.\n */\n hasConverged(): boolean {\n return this.state.quality.averageQuality > 0.9 || this.state.quality.poorQualityCount === 0;\n }\n\n /**\n * Gets the current mesh.\n */\n getMesh(): NonManifoldMesh {\n return this.mesh;\n }\n\n /**\n * Gets the skeleton (if built).\n */\n getSkeleton(): FeatureSkeleton | null {\n return this.skeleton;\n }\n\n /**\n * Gets the current quality stats.\n */\n getQuality(): MeshQualityStats {\n return this.state.quality;\n }\n\n /**\n * Gets the current state.\n */\n getState(): RemeshingState {\n return { ...this.state };\n }\n\n /**\n * Exports the mesh to BufferGeometry.\n */\n toBufferGeometry(): BufferGeometry {\n return exportBufferGeometry(this.mesh);\n }\n}\n\n/**\n * Simple function to remesh a BufferGeometry.\n */\nexport function remesh(\n geometry: BufferGeometry,\n options: RemeshOptions = {}\n): { geometry: BufferGeometry; stats: RemeshStats } {\n const mesh = NonManifoldMesh.fromBufferGeometry(geometry, options.featureEdges);\n const remesher = new AdaptiveRemesher(mesh, options);\n const stats = remesher.run();\n const outputGeometry = remesher.toBufferGeometry();\n\n return { geometry: outputGeometry, stats };\n}\n\n/**\n * Creates a remesher from a BufferGeometry.\n */\nexport function createRemesher(\n geometry: BufferGeometry,\n options: RemeshOptions = {}\n): AdaptiveRemesher {\n const mesh = NonManifoldMesh.fromBufferGeometry(geometry, options.featureEdges);\n return new AdaptiveRemesher(mesh, options);\n}\n"],"names":["VertexType","EdgeType","canFlipEdge","length","triangleCentroid","projection","v","w","dot"],"mappings":"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"}
|