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.
@@ -0,0 +1,2505 @@
1
+ /**
2
+ * remesh-threejs
3
+ *
4
+ * TypeScript library for adaptive remeshing of non-manifold surfaces using Three.js.
5
+ * Based on the EUROGRAPHICS 2008 paper "Adaptive Remeshing of Non-Manifold Surfaces"
6
+ * by Zilske, Lamecker, and Zachow.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+
11
+ import { BufferGeometry } from 'three';
12
+ import { Vector3 } from 'three';
13
+
14
+ /**
15
+ * Axis-Aligned Bounding Box.
16
+ */
17
+ export declare interface AABB {
18
+ min: Vec3;
19
+ max: Vec3;
20
+ }
21
+
22
+ /**
23
+ * Adaptive remeshing algorithm for non-manifold surfaces.
24
+ *
25
+ * Based on the EUROGRAPHICS 2008 paper "Adaptive Remeshing of Non-Manifold Surfaces"
26
+ * by Zilske, Lamecker, and Zachow.
27
+ */
28
+ export declare class AdaptiveRemesher {
29
+ private mesh;
30
+ private skeleton;
31
+ private constraints;
32
+ private options;
33
+ private state;
34
+ constructor(mesh: NonManifoldMesh, options?: RemeshOptions);
35
+ /**
36
+ * Runs one iteration of the remeshing algorithm.
37
+ *
38
+ * Each iteration performs:
39
+ * 1. Split long edges
40
+ * 2. Collapse short edges
41
+ * 3. Flip edges for Delaunay
42
+ * 4. Smooth vertex positions
43
+ */
44
+ iterate(): RemeshingState;
45
+ /**
46
+ * Runs multiple iterations until convergence or max iterations.
47
+ */
48
+ run(maxIterations?: number): RemeshStats;
49
+ /**
50
+ * Checks if the remeshing has converged.
51
+ */
52
+ hasConverged(): boolean;
53
+ /**
54
+ * Gets the current mesh.
55
+ */
56
+ getMesh(): NonManifoldMesh;
57
+ /**
58
+ * Gets the skeleton (if built).
59
+ */
60
+ getSkeleton(): FeatureSkeleton | null;
61
+ /**
62
+ * Gets the current quality stats.
63
+ */
64
+ getQuality(): MeshQualityStats;
65
+ /**
66
+ * Gets the current state.
67
+ */
68
+ getState(): RemeshingState;
69
+ /**
70
+ * Exports the mesh to BufferGeometry.
71
+ */
72
+ toBufferGeometry(): BufferGeometry;
73
+ }
74
+
75
+ /**
76
+ * Adds two vectors.
77
+ */
78
+ export declare function add(a: Vec3, b: Vec3): Vec3;
79
+
80
+ /**
81
+ * Analyzes a BufferGeometry for manifoldness.
82
+ *
83
+ * @param geometry - The geometry to analyze
84
+ * @returns Analysis result
85
+ */
86
+ export declare function analyzeManifold(geometry: BufferGeometry): ManifoldAnalysisResult;
87
+
88
+ /**
89
+ * Analyzes a NonManifoldMesh for manifoldness.
90
+ *
91
+ * @param mesh - The mesh to analyze
92
+ * @returns Analysis result
93
+ */
94
+ export declare function analyzeMesh(mesh: NonManifoldMesh): ManifoldAnalysisResult;
95
+
96
+ /**
97
+ * Computes the angle at a vertex in a triangle.
98
+ */
99
+ export declare function angleAtVertex(v0: Vec3, vertex: Vec3, v1: Vec3): number;
100
+
101
+ /**
102
+ * Computes the angle between two vectors in radians.
103
+ */
104
+ export declare function angleBetween(a: Vec3, b: Vec3): number;
105
+
106
+ /**
107
+ * Computes the barycentric coordinates of a point with respect to a triangle.
108
+ */
109
+ export declare function barycentricCoordinates(point: Vec3, v0: Vec3, v1: Vec3, v2: Vec3): {
110
+ u: number;
111
+ v: number;
112
+ w: number;
113
+ } | null;
114
+
115
+ /**
116
+ * Utility class for exporting meshes with various options.
117
+ */
118
+ export declare class BufferGeometryExporter {
119
+ private options;
120
+ constructor(options?: ExportOptions);
121
+ /**
122
+ * Exports a NonManifoldMesh to BufferGeometry.
123
+ */
124
+ export(mesh: NonManifoldMesh): BufferGeometry;
125
+ /**
126
+ * Exports skeleton edges as LineSegments geometry.
127
+ */
128
+ exportSkeleton(mesh: NonManifoldMesh): BufferGeometry;
129
+ /**
130
+ * Exports with vertex classification colors.
131
+ */
132
+ exportClassification(mesh: NonManifoldMesh): BufferGeometry;
133
+ /**
134
+ * Exports with quality visualization colors.
135
+ */
136
+ exportQuality(mesh: NonManifoldMesh): BufferGeometry;
137
+ /**
138
+ * Sets whether to compute normals.
139
+ */
140
+ setComputeNormals(enabled: boolean): this;
141
+ /**
142
+ * Sets whether to use smooth normals.
143
+ */
144
+ setSmoothNormals(enabled: boolean): this;
145
+ }
146
+
147
+ /**
148
+ * Utility class for importing BufferGeometry with additional features.
149
+ */
150
+ export declare class BufferGeometryImporter {
151
+ private options;
152
+ constructor(options?: ImportOptions);
153
+ /**
154
+ * Imports a BufferGeometry into a NonManifoldMesh.
155
+ */
156
+ import(geometry: BufferGeometry): NonManifoldMesh;
157
+ /**
158
+ * Validates a BufferGeometry without importing.
159
+ */
160
+ validate(geometry: BufferGeometry): ValidationResult;
161
+ /**
162
+ * Sets feature edges to preserve during remeshing.
163
+ */
164
+ setFeatureEdges(edges: FeatureEdge[]): this;
165
+ /**
166
+ * Enables or disables validation.
167
+ */
168
+ setValidation(enabled: boolean): this;
169
+ }
170
+
171
+ /**
172
+ * Builds the skeleton from a mesh.
173
+ */
174
+ export declare function buildSkeleton(mesh: NonManifoldMesh): SkeletonBuildResult;
175
+
176
+ /**
177
+ * Bounding Volume Hierarchy for fast spatial queries on triangle meshes.
178
+ */
179
+ export declare class BVH {
180
+ private root;
181
+ private triangles;
182
+ private maxLeafSize;
183
+ /**
184
+ * Creates a new BVH.
185
+ *
186
+ * @param maxLeafSize - Maximum number of triangles per leaf node
187
+ */
188
+ constructor(maxLeafSize?: number);
189
+ /**
190
+ * Builds the BVH from an array of triangles.
191
+ *
192
+ * @param triangles - Array of triangles to build from
193
+ */
194
+ build(triangles: Triangle[]): void;
195
+ /**
196
+ * Recursively builds a BVH node.
197
+ */
198
+ private buildNode;
199
+ /**
200
+ * Finds the closest point on the mesh to a query point.
201
+ *
202
+ * @param point - The query point
203
+ * @returns The closest point result, or null if no triangles
204
+ */
205
+ closestPoint(point: Vec3): ClosestPointResult | null;
206
+ /**
207
+ * Finds all triangles intersecting a sphere.
208
+ *
209
+ * @param center - Center of the sphere
210
+ * @param radius - Radius of the sphere
211
+ * @returns Array of triangle indices
212
+ */
213
+ queryRadius(center: Vec3, radius: number): number[];
214
+ /**
215
+ * Gets the total number of triangles.
216
+ */
217
+ get triangleCount(): number;
218
+ /**
219
+ * Gets a triangle by index.
220
+ */
221
+ getTriangle(index: number): Triangle | undefined;
222
+ }
223
+
224
+ /**
225
+ * Checks if an edge can be contracted.
226
+ *
227
+ * An edge can be contracted if:
228
+ * 1. Neither endpoint is a fixed vertex (branching or non-manifold other)
229
+ * 2. Contracting won't create invalid topology
230
+ * 3. The edge is not the only edge connecting two regions
231
+ */
232
+ export declare function canContractEdge(edge: Edge): boolean;
233
+
234
+ /**
235
+ * Determines if an edge can be flipped (only manifold edges can be flipped).
236
+ */
237
+ export declare function canFlipEdge(type: EdgeType): boolean;
238
+
239
+ /**
240
+ * Checks if an edge can be flipped.
241
+ *
242
+ * An edge can be flipped if:
243
+ * 1. It has exactly 2 adjacent faces (not boundary, not non-manifold)
244
+ * 2. It is not a skeleton edge
245
+ * 3. Both endpoint vertices have degree > 1
246
+ * 4. The quadrilateral formed is convex
247
+ */
248
+ export declare function canFlipEdgeGeometric(edge: Edge): boolean;
249
+
250
+ /**
251
+ * Determines if a vertex type allows free movement in 3D space.
252
+ */
253
+ export declare function canMoveFreely(type: VertexType): boolean;
254
+
255
+ /**
256
+ * Statistics about vertex classification.
257
+ */
258
+ export declare interface ClassificationStats {
259
+ /** Number of manifold vertices */
260
+ manifold: number;
261
+ /** Number of open-book vertices */
262
+ openBook: number;
263
+ /** Number of skeleton branching vertices */
264
+ skeletonBranching: number;
265
+ /** Number of other non-manifold vertices */
266
+ nonManifoldOther: number;
267
+ /** Total vertex count */
268
+ total: number;
269
+ }
270
+
271
+ /**
272
+ * Classifies all vertices in a mesh based on their neighborhood topology.
273
+ *
274
+ * @param mesh - The mesh to classify
275
+ * @returns Classification statistics
276
+ */
277
+ export declare function classifyAllVertices(mesh: NonManifoldMesh): ClassificationStats;
278
+
279
+ /**
280
+ * Classifies a single vertex based on its neighborhood.
281
+ *
282
+ * Vertex classification:
283
+ * - Manifold: Star homeomorphic to disk, can move freely in 3D
284
+ * - OpenBook: On exactly 2 skeleton edges (like pages of a book)
285
+ * - SkeletonBranching: On 1 or >2 skeleton edges, position is fixed
286
+ * - NonManifoldOther: Other non-manifold configurations
287
+ *
288
+ * @param vertex - The vertex to classify
289
+ * @returns The vertex type
290
+ */
291
+ export declare function classifyVertex(vertex: Vertex): VertexType;
292
+
293
+ /**
294
+ * Result of a closest point query.
295
+ */
296
+ export declare interface ClosestPointResult {
297
+ point: Vec3;
298
+ distance: number;
299
+ triangleIndex: number;
300
+ }
301
+
302
+ /**
303
+ * Computes quality statistics for a mesh.
304
+ */
305
+ export declare function computeMeshQuality(mesh: NonManifoldMesh, poorQualityThreshold?: number): MeshQualityStats;
306
+
307
+ /**
308
+ * Computes the target position for a vertex using tangential smoothing.
309
+ * This projects the barycenter of neighbors onto the tangent plane.
310
+ */
311
+ export declare function computeTangentialSmoothing(vertex: Vertex): Vec3 | null;
312
+
313
+ /**
314
+ * Computes the target edge length based on mesh bounding box.
315
+ */
316
+ export declare function computeTargetEdgeLength(mesh: NonManifoldMesh, numTargetVertices?: number): number;
317
+
318
+ /**
319
+ * Computes the aspect ratio of a triangle (longest / shortest edge).
320
+ */
321
+ export declare function computeTriangleAspectRatio(face: Face): number | null;
322
+
323
+ /**
324
+ * Result of constraining a vertex movement.
325
+ */
326
+ export declare interface ConstrainedPosition {
327
+ /** The constrained position */
328
+ position: Vec3;
329
+ /** Whether the movement was constrained */
330
+ wasConstrained: boolean;
331
+ /** The segment the vertex is constrained to (if applicable) */
332
+ segment?: SkeletonSegment;
333
+ /** Distance the position was moved during constraint */
334
+ constraintDistance: number;
335
+ }
336
+
337
+ /**
338
+ * Contracts an edge, merging its two endpoints into one vertex.
339
+ *
340
+ * The resulting vertex position depends on vertex types:
341
+ * - If one is fixed and one is movable: keep the fixed position
342
+ * - If both are movable: use midpoint
343
+ * - If one is on skeleton: use skeleton-constrained position
344
+ */
345
+ export declare function contractEdge(mesh: NonManifoldMesh, edge: Edge): EdgeContractionResult;
346
+
347
+ /**
348
+ * Contracts all edges shorter than a threshold.
349
+ */
350
+ export declare function contractShortEdges(mesh: NonManifoldMesh, minLength: number): {
351
+ contractCount: number;
352
+ removedVertices: number;
353
+ };
354
+
355
+ /**
356
+ * Computes the cotangent of the angle at a vertex in a triangle.
357
+ * Used for computing Laplacian weights.
358
+ */
359
+ export declare function cotangent(v0: Vec3, vertex: Vec3, v1: Vec3): number;
360
+
361
+ /**
362
+ * Creates a BVH from a NonManifoldMesh.
363
+ */
364
+ export declare function createBVHFromMesh(mesh: {
365
+ getFaces(): Array<{
366
+ getVertices(): [{
367
+ position: Vec3;
368
+ }, {
369
+ position: Vec3;
370
+ }, {
371
+ position: Vec3;
372
+ }] | null;
373
+ }>;
374
+ }): BVH;
375
+
376
+ /**
377
+ * Creates a branded EdgeId from a number.
378
+ */
379
+ export declare function createEdgeId(id: number): EdgeId;
380
+
381
+ /**
382
+ * Creates a branded FaceId from a number.
383
+ */
384
+ export declare function createFaceId(id: number): FaceId;
385
+
386
+ /**
387
+ * Creates a branded HalfedgeId from a number.
388
+ */
389
+ export declare function createHalfedgeId(id: number): HalfedgeId;
390
+
391
+ /**
392
+ * Creates a remesher from a BufferGeometry.
393
+ */
394
+ export declare function createRemesher(geometry: BufferGeometry, options?: RemeshOptions): AdaptiveRemesher;
395
+
396
+ /**
397
+ * Creates a branded SegmentId from a number.
398
+ */
399
+ export declare function createSegmentId(id: number): SegmentId;
400
+
401
+ /**
402
+ * Creates and builds a skeleton for a mesh.
403
+ */
404
+ export declare function createSkeleton(mesh: NonManifoldMesh): FeatureSkeleton;
405
+
406
+ /**
407
+ * Creates skeleton constraints for a mesh.
408
+ */
409
+ export declare function createSkeletonConstraints(skeleton: FeatureSkeleton): SkeletonConstraints;
410
+
411
+ /**
412
+ * Creates a spatial hash from an array of items with positions.
413
+ *
414
+ * @param items - Array of items with position getter
415
+ * @param getPosition - Function to get the position of an item
416
+ * @param cellSize - Optional cell size (auto-computed if not provided)
417
+ */
418
+ export declare function createSpatialHash<T>(items: T[], getPosition: (item: T) => Vec3, cellSize?: number): SpatialHash<T>;
419
+
420
+ /**
421
+ * Creates a branded VertexId from a number.
422
+ */
423
+ export declare function createVertexId(id: number): VertexId;
424
+
425
+ /**
426
+ * Computes the cross product of two vectors.
427
+ */
428
+ export declare function cross(a: Vec3, b: Vec3): Vec3;
429
+
430
+ /**
431
+ * Default remeshing options.
432
+ */
433
+ export declare const DEFAULT_REMESH_OPTIONS: Required<Omit<RemeshOptions, 'targetEdgeLength' | 'featureEdges'>>;
434
+
435
+ /**
436
+ * Computes the Euclidean distance between two points.
437
+ */
438
+ export declare function distance(a: Vec3, b: Vec3): number;
439
+
440
+ /**
441
+ * Computes the squared distance between two points.
442
+ */
443
+ export declare function distanceSquared(a: Vec3, b: Vec3): number;
444
+
445
+ /**
446
+ * Computes the dot product of two vectors.
447
+ */
448
+ export declare function dot(a: Vec3, b: Vec3): number;
449
+
450
+ /**
451
+ * Represents an undirected edge in the mesh.
452
+ * For non-manifold meshes, an edge can have more than 2 halfedges.
453
+ */
454
+ export declare class Edge {
455
+ /**
456
+ * Unique identifier for this edge.
457
+ */
458
+ readonly id: EdgeId;
459
+ /**
460
+ * One of the halfedges comprising this edge (used for traversal).
461
+ */
462
+ halfedge: Halfedge;
463
+ /**
464
+ * All halfedges associated with this edge.
465
+ * For manifold edges, this contains exactly 2 halfedges.
466
+ * For non-manifold edges, this contains more than 2 halfedges.
467
+ */
468
+ allHalfedges: Halfedge[];
469
+ /**
470
+ * The intrinsic length of this edge.
471
+ * This may differ from the Euclidean distance after edge operations.
472
+ */
473
+ length: number;
474
+ /**
475
+ * Classification of this edge.
476
+ */
477
+ type: EdgeType;
478
+ /**
479
+ * Whether this edge is part of any path in a network.
480
+ */
481
+ isInPath: boolean;
482
+ constructor(
483
+ /**
484
+ * Unique identifier for this edge.
485
+ */
486
+ id: EdgeId,
487
+ /**
488
+ * One of the halfedges.
489
+ */
490
+ halfedge: Halfedge,
491
+ /**
492
+ * Initial edge length.
493
+ */
494
+ length: number);
495
+ /**
496
+ * Adds a halfedge to this edge.
497
+ */
498
+ addHalfedge(halfedge: Halfedge): void;
499
+ /**
500
+ * Gets the number of halfedges (indicates non-manifoldness).
501
+ * 2 = manifold, >2 = non-manifold, 1 = boundary
502
+ */
503
+ getHalfedgeCount(): number;
504
+ /**
505
+ * Updates the edge type based on the number of incident faces.
506
+ */
507
+ updateType(): void;
508
+ /**
509
+ * Gets the number of faces incident to this edge.
510
+ */
511
+ getFaceCount(): number;
512
+ /**
513
+ * Gets both vertices of this edge.
514
+ * Returns [v0, v1] where v0 is the source of halfedge and v1 is the target.
515
+ */
516
+ getVertices(): [Vertex, Vertex] | [null, null];
517
+ /**
518
+ * Gets all faces adjacent to this edge.
519
+ * For manifold edges, returns up to 2 faces.
520
+ * For non-manifold edges, returns all incident faces.
521
+ */
522
+ getFaces(): Face[];
523
+ /**
524
+ * Gets both faces adjacent to this edge (for manifold edges).
525
+ * Returns [f0, f1] where f0 is the face of halfedge and f1 is the face of twin.
526
+ * Either face can be null for boundary edges.
527
+ */
528
+ getTwoFaces(): [Face | null, Face | null];
529
+ /**
530
+ * Checks if this edge is on the boundary (has only one adjacent face).
531
+ */
532
+ isBoundary(): boolean;
533
+ /**
534
+ * Checks if this edge is non-manifold (has more than 2 adjacent faces).
535
+ */
536
+ isNonManifold(): boolean;
537
+ /**
538
+ * Checks if this edge is part of the feature skeleton.
539
+ */
540
+ isSkeletonEdge(): boolean;
541
+ /**
542
+ * Checks if this edge can be flipped.
543
+ * An edge can be flipped if:
544
+ * 1. It has exactly two adjacent faces (manifold, not skeleton)
545
+ * 2. Both endpoints have degree > 1
546
+ * 3. The quadrilateral formed is convex (checked separately)
547
+ */
548
+ canFlip(): boolean;
549
+ /**
550
+ * Gets the other vertex of this edge (given one vertex).
551
+ */
552
+ getOtherVertex(v: Vertex): Vertex | null;
553
+ /**
554
+ * Marks this edge as a feature edge.
555
+ */
556
+ markAsFeature(): void;
557
+ }
558
+
559
+ /**
560
+ * Result of an edge contraction operation.
561
+ */
562
+ export declare interface EdgeContractionResult {
563
+ /** Whether the contraction was successful */
564
+ success: boolean;
565
+ /** Reason for failure (if any) */
566
+ reason?: string;
567
+ /** The remaining vertex after contraction */
568
+ remainingVertex?: Vertex;
569
+ /** Faces that were removed */
570
+ removedFaces?: Face[];
571
+ }
572
+
573
+ /**
574
+ * Edge contraction operation handler.
575
+ */
576
+ export declare class EdgeContractor {
577
+ private mesh;
578
+ constructor(mesh: NonManifoldMesh);
579
+ /**
580
+ * Contracts an edge.
581
+ */
582
+ contract(edge: Edge): EdgeContractionResult;
583
+ /**
584
+ * Checks if an edge can be contracted.
585
+ */
586
+ canContract(edge: Edge): boolean;
587
+ /**
588
+ * Contracts all edges shorter than a threshold.
589
+ */
590
+ contractShortEdges(minLength: number): {
591
+ contractCount: number;
592
+ removedVertices: number;
593
+ };
594
+ /**
595
+ * Checks if an edge should be contracted based on target length.
596
+ */
597
+ shouldContract(edge: Edge, targetLength: number, minRatio?: number): boolean;
598
+ }
599
+
600
+ /**
601
+ * Edge flip operation handler.
602
+ */
603
+ export declare class EdgeFlipper {
604
+ private mesh;
605
+ constructor(mesh: NonManifoldMesh);
606
+ /**
607
+ * Flips an edge.
608
+ */
609
+ flip(edge: Edge): EdgeFlipResult;
610
+ /**
611
+ * Checks if an edge can be flipped.
612
+ */
613
+ canFlip(edge: Edge): boolean;
614
+ /**
615
+ * Checks if an edge satisfies the Delaunay condition.
616
+ */
617
+ isDelaunay(edge: Edge): boolean;
618
+ /**
619
+ * Makes the mesh Delaunay by flipping non-Delaunay edges.
620
+ */
621
+ makeDelaunay(maxIterations?: number): number;
622
+ }
623
+
624
+ /**
625
+ * Result of an edge flip operation.
626
+ */
627
+ export declare interface EdgeFlipResult {
628
+ /** Whether the flip was successful */
629
+ success: boolean;
630
+ /** Reason for failure (if any) */
631
+ reason?: string;
632
+ /** The new edge length after flip */
633
+ newLength?: number;
634
+ }
635
+
636
+ /**
637
+ * Unique identifier for an edge in the mesh.
638
+ */
639
+ export declare type EdgeId = number & {
640
+ readonly __brand: 'EdgeId';
641
+ };
642
+
643
+ /**
644
+ * Result of an edge split operation.
645
+ */
646
+ export declare interface EdgeSplitResult {
647
+ /** Whether the split was successful */
648
+ success: boolean;
649
+ /** Reason for failure (if any) */
650
+ reason?: string;
651
+ /** The new vertex created at the midpoint */
652
+ newVertex?: Vertex;
653
+ /** The new edges created */
654
+ newEdges?: Edge[];
655
+ /** The new faces created */
656
+ newFaces?: Face[];
657
+ }
658
+
659
+ /**
660
+ * Edge split operation handler.
661
+ */
662
+ export declare class EdgeSplitter {
663
+ private mesh;
664
+ constructor(mesh: NonManifoldMesh);
665
+ /**
666
+ * Splits an edge at the midpoint.
667
+ */
668
+ split(edge: Edge, ratio?: number): EdgeSplitResult;
669
+ /**
670
+ * Splits all edges longer than a threshold.
671
+ */
672
+ splitLongEdges(maxLength: number): {
673
+ splitCount: number;
674
+ newVertices: Vertex[];
675
+ };
676
+ /**
677
+ * Checks if an edge should be split based on target length.
678
+ */
679
+ shouldSplit(edge: Edge, targetLength: number, maxRatio?: number): boolean;
680
+ }
681
+
682
+ /**
683
+ * Classification of an edge based on its incident faces.
684
+ *
685
+ * - Manifold: Exactly 2 incident faces
686
+ * - NonManifold: More than 2 incident faces (seam edge)
687
+ * - Feature: User-defined feature edge that should be preserved
688
+ * - Boundary: Only 1 incident face (mesh boundary)
689
+ */
690
+ export declare enum EdgeType {
691
+ /** Edge with exactly 2 incident faces - standard manifold edge */
692
+ Manifold = "manifold",
693
+ /** Edge with more than 2 incident faces - non-manifold seam */
694
+ NonManifold = "non_manifold",
695
+ /** User-defined feature edge that should be preserved */
696
+ Feature = "feature",
697
+ /** Edge with only 1 incident face - boundary edge */
698
+ Boundary = "boundary"
699
+ }
700
+
701
+ /**
702
+ * Exports a NonManifoldMesh to a Three.js BufferGeometry.
703
+ *
704
+ * @param mesh - The mesh to export
705
+ * @param options - Export options
706
+ * @returns The exported BufferGeometry
707
+ */
708
+ export declare function exportBufferGeometry(mesh: NonManifoldMesh, options?: ExportOptions): BufferGeometry;
709
+
710
+ /**
711
+ * Creates a colored mesh geometry for visualizing vertex classification.
712
+ *
713
+ * @param mesh - The mesh to visualize
714
+ * @returns BufferGeometry with vertex colors based on classification
715
+ */
716
+ export declare function exportClassificationGeometry(mesh: NonManifoldMesh): BufferGeometry;
717
+
718
+ /**
719
+ * Options for exporting a mesh to BufferGeometry.
720
+ */
721
+ export declare interface ExportOptions {
722
+ /**
723
+ * Whether to compute vertex normals.
724
+ * @default true
725
+ */
726
+ computeNormals?: boolean;
727
+ /**
728
+ * Whether to use smooth (averaged) normals.
729
+ * If false, uses flat (per-face) normals.
730
+ * @default true
731
+ */
732
+ smoothNormals?: boolean;
733
+ /**
734
+ * Angle threshold (in radians) for smooth normals.
735
+ * Edges with angles greater than this will have split normals.
736
+ * @default Math.PI / 3 (60 degrees)
737
+ */
738
+ smoothAngle?: number;
739
+ /**
740
+ * Whether to include UV coordinates if available.
741
+ * @default false
742
+ */
743
+ includeUVs?: boolean;
744
+ }
745
+
746
+ /**
747
+ * Creates a mesh geometry with face colors based on triangle quality.
748
+ *
749
+ * @param mesh - The mesh to visualize
750
+ * @returns BufferGeometry with vertex colors representing quality
751
+ */
752
+ export declare function exportQualityGeometry(mesh: NonManifoldMesh): BufferGeometry;
753
+
754
+ /**
755
+ * Exports only skeleton edges as a LineSegments geometry.
756
+ *
757
+ * @param mesh - The mesh to export skeleton from
758
+ * @returns BufferGeometry suitable for THREE.LineSegments
759
+ */
760
+ export declare function exportSkeletonGeometry(mesh: NonManifoldMesh): BufferGeometry;
761
+
762
+ /**
763
+ * Represents a triangular face in the mesh.
764
+ * A face is defined by three halfedges forming a loop.
765
+ */
766
+ export declare class Face {
767
+ /**
768
+ * Unique identifier for this face.
769
+ */
770
+ readonly id: FaceId;
771
+ /**
772
+ * One of the three halfedges bounding this face.
773
+ * The other two can be found by following next pointers.
774
+ */
775
+ halfedge: Halfedge;
776
+ /**
777
+ * Whether this face is marked (e.g., for selection or processing).
778
+ */
779
+ isMarked: boolean;
780
+ constructor(
781
+ /**
782
+ * Unique identifier for this face.
783
+ */
784
+ id: FaceId,
785
+ /**
786
+ * One of the bounding halfedges.
787
+ */
788
+ halfedge: Halfedge);
789
+ /**
790
+ * Gets all three vertices of this face.
791
+ * Returns vertices in counter-clockwise order.
792
+ */
793
+ getVertices(): [Vertex, Vertex, Vertex] | null;
794
+ /**
795
+ * Gets all three halfedges of this face.
796
+ * Returns halfedges in counter-clockwise order.
797
+ */
798
+ getHalfedges(): [Halfedge, Halfedge, Halfedge] | null;
799
+ /**
800
+ * Iterates over the three halfedges of this face.
801
+ *
802
+ * @param callback - Function called for each halfedge
803
+ */
804
+ forEachHalfedge(callback: (halfedge: Halfedge) => void): void;
805
+ /**
806
+ * Iterates over the three vertices of this face.
807
+ *
808
+ * @param callback - Function called for each vertex
809
+ */
810
+ forEachVertex(callback: (vertex: Vertex) => void): void;
811
+ /**
812
+ * Computes the centroid (center of mass) of this face.
813
+ * Returns null if vertices cannot be retrieved.
814
+ */
815
+ getCentroid(): {
816
+ x: number;
817
+ y: number;
818
+ z: number;
819
+ } | null;
820
+ /**
821
+ * Computes the normal vector of this face.
822
+ * Uses the cross product of two edges.
823
+ * Returns null if vertices cannot be retrieved.
824
+ */
825
+ getNormal(): {
826
+ x: number;
827
+ y: number;
828
+ z: number;
829
+ } | null;
830
+ /**
831
+ * Computes the area of this face.
832
+ * Returns null if vertices cannot be retrieved.
833
+ */
834
+ getArea(): number | null;
835
+ /**
836
+ * Computes the quality of this triangle.
837
+ * Quality is measured as 2 * inradius / circumradius (ranges from 0 to 1).
838
+ * A value of 1 indicates an equilateral triangle.
839
+ * Returns null if vertices cannot be retrieved.
840
+ */
841
+ getQuality(): number | null;
842
+ /**
843
+ * Checks if this face contains a given vertex.
844
+ */
845
+ containsVertex(vertex: Vertex): boolean;
846
+ /**
847
+ * Gets the halfedge opposite to a given vertex.
848
+ * Returns null if the vertex is not part of this face.
849
+ */
850
+ getOppositeHalfedge(vertex: Vertex): Halfedge | null;
851
+ /**
852
+ * Checks if this face is degenerate (has zero or near-zero area).
853
+ */
854
+ isDegenerate(epsilon?: number): boolean;
855
+ }
856
+
857
+ /**
858
+ * Unique identifier for a face in the mesh.
859
+ */
860
+ export declare type FaceId = number & {
861
+ readonly __brand: 'FaceId';
862
+ };
863
+
864
+ /**
865
+ * Configuration options for the adaptive remeshing algorithm.
866
+ */
867
+ /**
868
+ * Feature edge specification as a pair of vertex indices.
869
+ */
870
+ export declare type FeatureEdge = [number, number];
871
+
872
+ /**
873
+ * Represents the feature skeleton of a mesh.
874
+ * The skeleton consists of non-manifold edges, boundary edges, and feature edges.
875
+ */
876
+ export declare class FeatureSkeleton {
877
+ /** The mesh this skeleton belongs to */
878
+ readonly mesh: NonManifoldMesh;
879
+ /** All segments in the skeleton */
880
+ segments: Map<SegmentId, SkeletonSegment>;
881
+ /** All skeleton edges */
882
+ private skeletonEdges;
883
+ /** All branching vertices */
884
+ private branchingVertices;
885
+ /** All open-book vertices */
886
+ private openBookVertices;
887
+ /** Map from vertex to its segment (for open-book vertices) */
888
+ private vertexToSegment;
889
+ /** Whether the skeleton has been built */
890
+ private isBuilt;
891
+ constructor(mesh: NonManifoldMesh);
892
+ /**
893
+ * Builds the skeleton from the mesh.
894
+ */
895
+ build(): void;
896
+ /**
897
+ * Applies a build result to this skeleton.
898
+ */
899
+ private applyBuildResult;
900
+ /**
901
+ * Rebuilds the skeleton. Call after topology changes.
902
+ */
903
+ rebuild(): void;
904
+ /**
905
+ * Gets all segments.
906
+ */
907
+ getSegments(): SkeletonSegment[];
908
+ /**
909
+ * Gets a segment by ID.
910
+ */
911
+ getSegment(id: SegmentId): SkeletonSegment | undefined;
912
+ /**
913
+ * Gets the segment containing a vertex.
914
+ * Only works for open-book vertices.
915
+ */
916
+ getSegmentForVertex(vertex: Vertex): SkeletonSegment | undefined;
917
+ /**
918
+ * Gets all skeleton edges.
919
+ */
920
+ getSkeletonEdges(): Edge[];
921
+ /**
922
+ * Gets all branching vertices.
923
+ */
924
+ getBranchingVertices(): Vertex[];
925
+ /**
926
+ * Gets all open-book vertices.
927
+ */
928
+ getOpenBookVertices(): Vertex[];
929
+ /**
930
+ * Gets the number of segments.
931
+ */
932
+ get segmentCount(): number;
933
+ /**
934
+ * Gets the number of skeleton edges.
935
+ */
936
+ get skeletonEdgeCount(): number;
937
+ /**
938
+ * Gets the number of branching vertices.
939
+ */
940
+ get branchingVertexCount(): number;
941
+ /**
942
+ * Gets the number of open-book vertices.
943
+ */
944
+ get openBookVertexCount(): number;
945
+ /**
946
+ * Checks if the skeleton has been built.
947
+ */
948
+ get built(): boolean;
949
+ /**
950
+ * Projects a point onto the skeleton.
951
+ * Returns the closest point on any segment.
952
+ */
953
+ projectPoint(point: Vec3): {
954
+ point: Vec3;
955
+ segment: SkeletonSegment;
956
+ parameter: number;
957
+ distance: number;
958
+ } | null;
959
+ /**
960
+ * Checks if a vertex is on the skeleton.
961
+ */
962
+ isVertexOnSkeleton(vertex: Vertex): boolean;
963
+ /**
964
+ * Checks if an edge is on the skeleton.
965
+ */
966
+ isEdgeOnSkeleton(edge: Edge): boolean;
967
+ /**
968
+ * Gets all vertices on the skeleton.
969
+ */
970
+ getAllSkeletonVertices(): Vertex[];
971
+ /**
972
+ * Computes the total length of the skeleton.
973
+ */
974
+ getTotalLength(): number;
975
+ /**
976
+ * Gets statistics about the skeleton.
977
+ */
978
+ getStats(): {
979
+ segmentCount: number;
980
+ skeletonEdgeCount: number;
981
+ branchingVertexCount: number;
982
+ openBookVertexCount: number;
983
+ totalLength: number;
984
+ closedLoopCount: number;
985
+ };
986
+ }
987
+
988
+ /**
989
+ * Flips an edge in the mesh.
990
+ *
991
+ * Before flip (edge connects vA to vB):
992
+ *
993
+ * vC
994
+ * /|\
995
+ * / | \
996
+ * / | \
997
+ * / f0| \
998
+ * vA----|----vB
999
+ * \ f1| /
1000
+ * \ | /
1001
+ * \ | /
1002
+ * \|/
1003
+ * vD
1004
+ *
1005
+ * After flip (edge connects vC to vD):
1006
+ *
1007
+ * vC
1008
+ * / \
1009
+ * / f0\
1010
+ * / \
1011
+ * / \
1012
+ * vA---------vB
1013
+ * \ /
1014
+ * \ f1 /
1015
+ * \ /
1016
+ * \ /
1017
+ * vD
1018
+ */
1019
+ export declare function flipEdge(_mesh: NonManifoldMesh, edge: Edge): EdgeFlipResult;
1020
+
1021
+ /**
1022
+ * Converts a Three.js Vector3 to a Vec3 interface.
1023
+ */
1024
+ export declare function fromVector3(v: Vector3): Vec3;
1025
+
1026
+ /**
1027
+ * Gets vertices with high valence (many incident edges).
1028
+ */
1029
+ export declare function getHighValenceVertices(mesh: NonManifoldMesh, maxValence?: number): Vertex[];
1030
+
1031
+ /**
1032
+ * Gets edges that are too long (should be split).
1033
+ */
1034
+ export declare function getLongEdges(mesh: NonManifoldMesh, targetLength: number, maxRatio?: number): Edge[];
1035
+
1036
+ /**
1037
+ * Gets vertices with low valence (few incident edges).
1038
+ */
1039
+ export declare function getLowValenceVertices(mesh: NonManifoldMesh, minValence?: number): Vertex[];
1040
+
1041
+ /**
1042
+ * Gets all manifold vertices.
1043
+ */
1044
+ export declare function getManifoldVertices(mesh: NonManifoldMesh): Vertex[];
1045
+
1046
+ /**
1047
+ * Gets all non-manifold vertices (open-book + branching + other).
1048
+ */
1049
+ export declare function getNonManifoldVertices(mesh: NonManifoldMesh): Vertex[];
1050
+
1051
+ /**
1052
+ * Gets all open-book vertices.
1053
+ */
1054
+ export declare function getOpenBookVertices(mesh: NonManifoldMesh): Vertex[];
1055
+
1056
+ /**
1057
+ * Gets faces with quality below a threshold.
1058
+ */
1059
+ export declare function getPoorQualityFaces(mesh: NonManifoldMesh, threshold?: number): Face[];
1060
+
1061
+ /**
1062
+ * Gets edges that are too short (should be collapsed).
1063
+ */
1064
+ export declare function getShortEdges(mesh: NonManifoldMesh, targetLength: number, minRatio?: number): Edge[];
1065
+
1066
+ /**
1067
+ * Gets all skeleton branching vertices.
1068
+ */
1069
+ export declare function getSkeletonBranchingVertices(mesh: NonManifoldMesh): Vertex[];
1070
+
1071
+ /**
1072
+ * Gets all vertices of a specific type.
1073
+ *
1074
+ * @param mesh - The mesh to search
1075
+ * @param type - The vertex type to find
1076
+ * @returns Array of vertices matching the type
1077
+ */
1078
+ export declare function getVerticesByType(mesh: NonManifoldMesh, type: VertexType): Vertex[];
1079
+
1080
+ /**
1081
+ * Represents a halfedge in the mesh.
1082
+ * A halfedge is a directed edge from one vertex to another.
1083
+ */
1084
+ export declare class Halfedge {
1085
+ /**
1086
+ * Unique identifier for this halfedge.
1087
+ */
1088
+ readonly id: HalfedgeId;
1089
+ /**
1090
+ * The vertex this halfedge points to (target vertex).
1091
+ */
1092
+ vertex: Vertex;
1093
+ /**
1094
+ * The opposite halfedge (same edge, opposite direction).
1095
+ * For non-manifold edges, this points to one of potentially many twins.
1096
+ */
1097
+ twin: Halfedge | null;
1098
+ /**
1099
+ * The next halfedge in the face loop (counter-clockwise).
1100
+ */
1101
+ next: Halfedge | null;
1102
+ /**
1103
+ * The previous halfedge in the face loop.
1104
+ */
1105
+ prev: Halfedge | null;
1106
+ /**
1107
+ * The face this halfedge belongs to (null for boundary halfedges).
1108
+ */
1109
+ face: Face | null;
1110
+ /**
1111
+ * The parent undirected edge.
1112
+ */
1113
+ edge: Edge;
1114
+ constructor(
1115
+ /**
1116
+ * Unique identifier for this halfedge.
1117
+ */
1118
+ id: HalfedgeId,
1119
+ /**
1120
+ * The vertex this halfedge points to.
1121
+ */
1122
+ vertex: Vertex,
1123
+ /**
1124
+ * The parent edge.
1125
+ */
1126
+ edge: Edge);
1127
+ /**
1128
+ * Gets the source vertex of this halfedge (the vertex it starts from).
1129
+ * This is the target vertex of the twin halfedge.
1130
+ */
1131
+ getSourceVertex(): Vertex | null;
1132
+ /**
1133
+ * Gets the target vertex of this halfedge.
1134
+ */
1135
+ getTargetVertex(): Vertex;
1136
+ /**
1137
+ * Checks if this halfedge is on the boundary (has no face).
1138
+ */
1139
+ isBoundary(): boolean;
1140
+ /**
1141
+ * Gets the opposite halfedge in the same face (two edges away).
1142
+ * For a triangle, this is the edge opposite to this halfedge's source vertex.
1143
+ */
1144
+ getOppositeHalfedge(): Halfedge | null;
1145
+ /**
1146
+ * Gets the vertex opposite to this halfedge in its face.
1147
+ * For a triangle, this is the vertex not on this halfedge.
1148
+ */
1149
+ getOppositeVertex(): Vertex | null;
1150
+ /**
1151
+ * Computes the vector along this halfedge (from source to target).
1152
+ * Returns null if source vertex is not available.
1153
+ */
1154
+ getVector(): {
1155
+ x: number;
1156
+ y: number;
1157
+ z: number;
1158
+ } | null;
1159
+ }
1160
+
1161
+ /**
1162
+ * Unique identifier for a halfedge in the mesh.
1163
+ */
1164
+ export declare type HalfedgeId = number & {
1165
+ readonly __brand: 'HalfedgeId';
1166
+ };
1167
+
1168
+ /**
1169
+ * Imports a Three.js BufferGeometry into a NonManifoldMesh.
1170
+ *
1171
+ * @param geometry - The input geometry
1172
+ * @param options - Import options
1173
+ * @returns The imported mesh
1174
+ * @throws Error if geometry is invalid and validation is enabled
1175
+ */
1176
+ export declare function importBufferGeometry(geometry: BufferGeometry, options?: ImportOptions): NonManifoldMesh;
1177
+
1178
+ /**
1179
+ * Options for importing a BufferGeometry.
1180
+ */
1181
+ export declare interface ImportOptions {
1182
+ /**
1183
+ * User-defined feature edges to preserve.
1184
+ * Each edge is specified as a pair of vertex indices.
1185
+ */
1186
+ featureEdges?: FeatureEdge[];
1187
+ /**
1188
+ * Whether to validate the geometry before importing.
1189
+ * @default true
1190
+ */
1191
+ validate?: boolean;
1192
+ /**
1193
+ * Whether to merge duplicate vertices.
1194
+ * @default false
1195
+ */
1196
+ mergeVertices?: boolean;
1197
+ /**
1198
+ * Tolerance for merging vertices.
1199
+ * @default 1e-6
1200
+ */
1201
+ mergeTolerance?: number;
1202
+ }
1203
+
1204
+ /**
1205
+ * Checks if an edge satisfies the Delaunay condition.
1206
+ * An edge is Delaunay if the sum of opposite angles is <= 180 degrees.
1207
+ */
1208
+ export declare function isDelaunay(edge: Edge): boolean;
1209
+
1210
+ /**
1211
+ * Quick check if a geometry is manifold.
1212
+ *
1213
+ * @param geometry - The geometry to check
1214
+ * @returns True if the geometry is manifold
1215
+ */
1216
+ export declare function isManifold(geometry: BufferGeometry): boolean;
1217
+
1218
+ /**
1219
+ * Checks if a point lies inside a triangle (using barycentric coordinates).
1220
+ */
1221
+ export declare function isPointInTriangle(point: Vec3, v0: Vec3, v1: Vec3, v2: Vec3): boolean;
1222
+
1223
+ /**
1224
+ * Determines if a vertex type has a fixed position.
1225
+ */
1226
+ export declare function isPositionFixed(type: VertexType): boolean;
1227
+
1228
+ /**
1229
+ * Checks if the quadrilateral formed by two adjacent triangles is convex.
1230
+ * Used to determine if an edge can be flipped.
1231
+ *
1232
+ * @param v0 - First vertex of the shared edge
1233
+ * @param v1 - Second vertex of the shared edge
1234
+ * @param v2 - Opposite vertex in first triangle
1235
+ * @param v3 - Opposite vertex in second triangle
1236
+ */
1237
+ export declare function isQuadConvex(v0: Vec3, v1: Vec3, v2: Vec3, v3: Vec3): boolean;
1238
+
1239
+ /**
1240
+ * Determines if a vertex type is constrained to a skeleton segment.
1241
+ */
1242
+ export declare function isSkeletonConstrained(type: VertexType): boolean;
1243
+
1244
+ /**
1245
+ * Determines if an edge type is part of the feature skeleton.
1246
+ */
1247
+ export declare function isSkeletonEdge(type: EdgeType): boolean;
1248
+
1249
+ /**
1250
+ * Quick check if mesh topology is valid.
1251
+ */
1252
+ export declare function isTopologyValid(mesh: NonManifoldMesh): boolean;
1253
+
1254
+ /**
1255
+ * Computes the length of a vector.
1256
+ */
1257
+ declare function length_2(v: Vec3): number;
1258
+ export { length_2 as length }
1259
+
1260
+ /**
1261
+ * Computes the squared length of a vector.
1262
+ */
1263
+ export declare function lengthSquared(v: Vec3): number;
1264
+
1265
+ /**
1266
+ * Linearly interpolates between two vectors.
1267
+ */
1268
+ export declare function lerp(a: Vec3, b: Vec3, t: number): Vec3;
1269
+
1270
+ /**
1271
+ * Performs Delaunay flips on the mesh.
1272
+ * Returns the number of flips performed.
1273
+ */
1274
+ export declare function makeDelaunay(mesh: NonManifoldMesh, maxIterations?: number): number;
1275
+
1276
+ /**
1277
+ * Result of manifold analysis.
1278
+ */
1279
+ export declare interface ManifoldAnalysisResult {
1280
+ /** Whether the mesh is manifold */
1281
+ isManifold: boolean;
1282
+ /** Whether the mesh has boundary edges */
1283
+ hasBoundary: boolean;
1284
+ /** Total number of vertices */
1285
+ vertexCount: number;
1286
+ /** Total number of edges */
1287
+ edgeCount: number;
1288
+ /** Total number of faces */
1289
+ faceCount: number;
1290
+ /** Number of manifold edges */
1291
+ manifoldEdgeCount: number;
1292
+ /** Number of non-manifold edges */
1293
+ nonManifoldEdgeCount: number;
1294
+ /** Number of boundary edges */
1295
+ boundaryEdgeCount: number;
1296
+ /** Number of manifold vertices */
1297
+ manifoldVertexCount: number;
1298
+ /** Number of non-manifold vertices */
1299
+ nonManifoldVertexCount: number;
1300
+ /** Detailed info about non-manifold edges */
1301
+ nonManifoldEdges: NonManifoldEdgeInfo[];
1302
+ /** Detailed info about non-manifold vertices */
1303
+ nonManifoldVertices: NonManifoldVertexInfo[];
1304
+ /** Euler characteristic (V - E + F) */
1305
+ eulerCharacteristic: number;
1306
+ /** Average vertex degree */
1307
+ averageVertexDegree: number;
1308
+ }
1309
+
1310
+ /**
1311
+ * Class for analyzing mesh manifoldness with caching.
1312
+ */
1313
+ export declare class ManifoldAnalyzer {
1314
+ private mesh;
1315
+ private cachedResult;
1316
+ /**
1317
+ * Loads a geometry for analysis.
1318
+ */
1319
+ load(geometry: BufferGeometry): this;
1320
+ /**
1321
+ * Loads an existing mesh for analysis.
1322
+ */
1323
+ loadMesh(mesh: NonManifoldMesh): this;
1324
+ /**
1325
+ * Gets the analysis result (cached).
1326
+ */
1327
+ analyze(): ManifoldAnalysisResult;
1328
+ /**
1329
+ * Checks if the mesh is manifold.
1330
+ */
1331
+ isManifold(): boolean;
1332
+ /**
1333
+ * Checks if the mesh has boundary.
1334
+ */
1335
+ hasBoundary(): boolean;
1336
+ /**
1337
+ * Gets non-manifold edges.
1338
+ */
1339
+ getNonManifoldEdges(): NonManifoldEdgeInfo[];
1340
+ /**
1341
+ * Gets non-manifold vertices.
1342
+ */
1343
+ getNonManifoldVertices(): NonManifoldVertexInfo[];
1344
+ /**
1345
+ * Gets the underlying mesh.
1346
+ */
1347
+ getMesh(): NonManifoldMesh | null;
1348
+ /**
1349
+ * Clears cached results.
1350
+ */
1351
+ clearCache(): this;
1352
+ }
1353
+
1354
+ /**
1355
+ * Quality statistics for a mesh.
1356
+ */
1357
+ export declare interface MeshQualityStats {
1358
+ /** Minimum triangle quality (0 to 1) */
1359
+ minQuality: number;
1360
+ /** Maximum triangle quality (0 to 1) */
1361
+ maxQuality: number;
1362
+ /** Average triangle quality (0 to 1) */
1363
+ averageQuality: number;
1364
+ /** Standard deviation of triangle quality */
1365
+ stdDevQuality: number;
1366
+ /** Number of triangles with quality below threshold */
1367
+ poorQualityCount: number;
1368
+ /** Minimum edge length */
1369
+ minEdgeLength: number;
1370
+ /** Maximum edge length */
1371
+ maxEdgeLength: number;
1372
+ /** Average edge length */
1373
+ averageEdgeLength: number;
1374
+ /** Minimum triangle area */
1375
+ minArea: number;
1376
+ /** Maximum triangle area */
1377
+ maxArea: number;
1378
+ /** Total surface area */
1379
+ totalArea: number;
1380
+ }
1381
+
1382
+ /**
1383
+ * Computes the midpoint between two points.
1384
+ */
1385
+ export declare function midpoint(a: Vec3, b: Vec3): Vec3;
1386
+
1387
+ /**
1388
+ * Information about a non-manifold edge.
1389
+ */
1390
+ export declare interface NonManifoldEdgeInfo {
1391
+ /** Index of the edge */
1392
+ edgeId: number;
1393
+ /** Indices of the two vertices */
1394
+ vertexIndices: [number, number];
1395
+ /** Number of incident faces */
1396
+ faceCount: number;
1397
+ /** Positions of the edge endpoints */
1398
+ positions: [{
1399
+ x: number;
1400
+ y: number;
1401
+ z: number;
1402
+ }, {
1403
+ x: number;
1404
+ y: number;
1405
+ z: number;
1406
+ }];
1407
+ }
1408
+
1409
+ /**
1410
+ * Represents a non-manifold mesh using an extended halfedge data structure.
1411
+ * Supports edges with more than 2 incident faces (non-manifold seams).
1412
+ */
1413
+ export declare class NonManifoldMesh {
1414
+ vertices: Map<VertexId, Vertex>;
1415
+ edges: Map<EdgeId, Edge>;
1416
+ halfedges: Map<HalfedgeId, Halfedge>;
1417
+ faces: Map<FaceId, Face>;
1418
+ private nextVertexId;
1419
+ private nextEdgeId;
1420
+ private nextHalfedgeId;
1421
+ private nextFaceId;
1422
+ /** Map from vertex pair key to edge for fast lookup */
1423
+ private edgeMap;
1424
+ /**
1425
+ * Creates a non-manifold mesh from a Three.js BufferGeometry.
1426
+ *
1427
+ * @param geometry - The input geometry (must be indexed triangles)
1428
+ * @param featureEdges - Optional user-defined feature edges to preserve
1429
+ */
1430
+ static fromBufferGeometry(geometry: BufferGeometry, featureEdges?: FeatureEdge[]): NonManifoldMesh;
1431
+ /**
1432
+ * Gets or creates an edge between two vertices.
1433
+ */
1434
+ private getOrCreateEdge;
1435
+ /**
1436
+ * Creates a canonical key for an edge between two vertices.
1437
+ */
1438
+ private makeEdgeKey;
1439
+ /**
1440
+ * Sets up twin halfedge relationships.
1441
+ * For non-manifold edges (>2 halfedges), creates a circular twin chain.
1442
+ */
1443
+ private setupTwinHalfedges;
1444
+ /**
1445
+ * Sets up twin relationships for non-manifold edges.
1446
+ * Groups halfedges by direction and pairs them appropriately.
1447
+ */
1448
+ private setupNonManifoldTwins;
1449
+ /**
1450
+ * Marks user-defined feature edges.
1451
+ */
1452
+ markFeatureEdges(featureEdges: FeatureEdge[]): void;
1453
+ /**
1454
+ * Classifies all vertices based on their neighborhood topology.
1455
+ */
1456
+ classifyVertices(): void;
1457
+ /**
1458
+ * Classifies a single vertex based on its neighborhood.
1459
+ */
1460
+ private classifyVertex;
1461
+ /**
1462
+ * Exports the mesh to a Three.js BufferGeometry.
1463
+ */
1464
+ toBufferGeometry(): BufferGeometry;
1465
+ /**
1466
+ * Gets all vertices in the mesh.
1467
+ */
1468
+ getVertices(): Vertex[];
1469
+ /**
1470
+ * Gets all edges in the mesh.
1471
+ */
1472
+ getEdges(): Edge[];
1473
+ /**
1474
+ * Gets all faces in the mesh.
1475
+ */
1476
+ getFaces(): Face[];
1477
+ /**
1478
+ * Gets all halfedges in the mesh.
1479
+ */
1480
+ getHalfedges(): Halfedge[];
1481
+ /**
1482
+ * Gets the vertex count.
1483
+ */
1484
+ get vertexCount(): number;
1485
+ /**
1486
+ * Gets the edge count.
1487
+ */
1488
+ get edgeCount(): number;
1489
+ /**
1490
+ * Gets the face count.
1491
+ */
1492
+ get faceCount(): number;
1493
+ /**
1494
+ * Gets the halfedge count.
1495
+ */
1496
+ get halfedgeCount(): number;
1497
+ /**
1498
+ * Gets all non-manifold edges.
1499
+ */
1500
+ getNonManifoldEdges(): Edge[];
1501
+ /**
1502
+ * Gets all boundary edges.
1503
+ */
1504
+ getBoundaryEdges(): Edge[];
1505
+ /**
1506
+ * Gets all feature edges.
1507
+ */
1508
+ getFeatureEdges(): Edge[];
1509
+ /**
1510
+ * Gets all skeleton edges (non-manifold + boundary + feature).
1511
+ */
1512
+ getSkeletonEdges(): Edge[];
1513
+ /**
1514
+ * Checks if the mesh is manifold (no non-manifold edges).
1515
+ */
1516
+ isManifold(): boolean;
1517
+ /**
1518
+ * Checks if the mesh has boundaries.
1519
+ */
1520
+ hasBoundary(): boolean;
1521
+ /**
1522
+ * Gets a vertex by ID.
1523
+ */
1524
+ getVertex(id: VertexId): Vertex | undefined;
1525
+ /**
1526
+ * Gets an edge by ID.
1527
+ */
1528
+ getEdge(id: EdgeId): Edge | undefined;
1529
+ /**
1530
+ * Gets a face by ID.
1531
+ */
1532
+ getFace(id: FaceId): Face | undefined;
1533
+ /**
1534
+ * Gets a halfedge by ID.
1535
+ */
1536
+ getHalfedge(id: HalfedgeId): Halfedge | undefined;
1537
+ /**
1538
+ * Gets the edge between two vertices (if it exists).
1539
+ */
1540
+ getEdgeBetween(v0: Vertex, v1: Vertex): Edge | undefined;
1541
+ /**
1542
+ * Creates a new vertex and adds it to the mesh.
1543
+ */
1544
+ createVertex(position: Vector3): Vertex;
1545
+ /**
1546
+ * Creates a new face from three vertices.
1547
+ * Also creates the necessary halfedges and edges.
1548
+ */
1549
+ createFace(v0: Vertex, v1: Vertex, v2: Vertex): Face;
1550
+ /**
1551
+ * Computes mesh statistics.
1552
+ */
1553
+ getStats(): {
1554
+ vertexCount: number;
1555
+ edgeCount: number;
1556
+ faceCount: number;
1557
+ nonManifoldEdgeCount: number;
1558
+ boundaryEdgeCount: number;
1559
+ featureEdgeCount: number;
1560
+ eulerCharacteristic: number;
1561
+ };
1562
+ }
1563
+
1564
+ /**
1565
+ * Information about a non-manifold vertex.
1566
+ */
1567
+ export declare interface NonManifoldVertexInfo {
1568
+ /** Index of the vertex */
1569
+ vertexId: number;
1570
+ /** Position of the vertex */
1571
+ position: {
1572
+ x: number;
1573
+ y: number;
1574
+ z: number;
1575
+ };
1576
+ /** Classification type */
1577
+ type: VertexType;
1578
+ /** Number of incident skeleton edges */
1579
+ skeletonEdgeCount: number;
1580
+ }
1581
+
1582
+ /**
1583
+ * Normalizes a vector to unit length.
1584
+ * Returns a zero vector if the input has zero length.
1585
+ */
1586
+ export declare function normalize(v: Vec3): Vec3;
1587
+
1588
+ /**
1589
+ * Projects a point onto a line defined by two points.
1590
+ * Returns the closest point on the line to the given point.
1591
+ */
1592
+ export declare function projectPointOnLine(point: Vec3, lineStart: Vec3, lineEnd: Vec3): Vec3;
1593
+
1594
+ /**
1595
+ * Projects a point onto a line segment defined by two endpoints.
1596
+ * Returns the closest point on the segment to the given point.
1597
+ */
1598
+ export declare function projectPointOnSegment(point: Vec3, segStart: Vec3, segEnd: Vec3): Vec3;
1599
+
1600
+ /**
1601
+ * Quality metrics utility class.
1602
+ */
1603
+ export declare class QualityMetrics {
1604
+ private mesh;
1605
+ constructor(mesh: NonManifoldMesh);
1606
+ /**
1607
+ * Computes overall mesh quality statistics.
1608
+ */
1609
+ computeStats(poorQualityThreshold?: number): MeshQualityStats;
1610
+ /**
1611
+ * Gets poor quality faces.
1612
+ */
1613
+ getPoorQualityFaces(threshold?: number): Face[];
1614
+ /**
1615
+ * Gets long edges that should be split.
1616
+ */
1617
+ getLongEdges(targetLength: number, maxRatio?: number): Edge[];
1618
+ /**
1619
+ * Gets short edges that should be collapsed.
1620
+ */
1621
+ getShortEdges(targetLength: number, minRatio?: number): Edge[];
1622
+ /**
1623
+ * Computes target edge length.
1624
+ */
1625
+ computeTargetEdgeLength(numTargetVertices?: number): number;
1626
+ /**
1627
+ * Gets high valence vertices.
1628
+ */
1629
+ getHighValenceVertices(maxValence?: number): Vertex[];
1630
+ /**
1631
+ * Gets low valence vertices.
1632
+ */
1633
+ getLowValenceVertices(minValence?: number): Vertex[];
1634
+ }
1635
+
1636
+ /**
1637
+ * Reclassifies all vertices in a mesh.
1638
+ * Call this after topology changes.
1639
+ */
1640
+ export declare function reclassifyVertices(mesh: NonManifoldMesh): void;
1641
+
1642
+ /**
1643
+ * Relocates a vertex to a target position, respecting constraints.
1644
+ */
1645
+ export declare function relocateVertex(_mesh: NonManifoldMesh, vertex: Vertex, targetPosition: Vec3, constraints?: SkeletonConstraints): VertexRelocationResult;
1646
+
1647
+ /**
1648
+ * Simple function to remesh a BufferGeometry.
1649
+ */
1650
+ export declare function remesh(geometry: BufferGeometry, options?: RemeshOptions): {
1651
+ geometry: BufferGeometry;
1652
+ stats: RemeshStats;
1653
+ };
1654
+
1655
+ /**
1656
+ * State during remeshing iteration.
1657
+ */
1658
+ declare interface RemeshingState {
1659
+ iteration: number;
1660
+ edgeSplits: number;
1661
+ edgeContractions: number;
1662
+ edgeFlips: number;
1663
+ vertexRelocations: number;
1664
+ quality: MeshQualityStats;
1665
+ }
1666
+
1667
+ /**
1668
+ * Options for the adaptive remeshing algorithm.
1669
+ */
1670
+ export declare interface RemeshOptions {
1671
+ /**
1672
+ * Number of remeshing iterations to perform.
1673
+ * More iterations generally produce higher quality results.
1674
+ * @default 5
1675
+ */
1676
+ iterations?: number;
1677
+ /**
1678
+ * Target edge length for the remeshed surface.
1679
+ * If not specified, computed automatically based on mesh bounding box.
1680
+ */
1681
+ targetEdgeLength?: number;
1682
+ /**
1683
+ * User-defined feature edges that should be preserved.
1684
+ * Each edge is specified as a pair of vertex indices from the input geometry.
1685
+ * These edges will be included in the feature skeleton.
1686
+ */
1687
+ featureEdges?: FeatureEdge[];
1688
+ /**
1689
+ * Whether to preserve boundary edges.
1690
+ * When true, boundary edges are included in the skeleton and preserved.
1691
+ * @default true
1692
+ */
1693
+ preserveBoundary?: boolean;
1694
+ /**
1695
+ * Minimum allowed edge length as a fraction of targetEdgeLength.
1696
+ * Edges shorter than this will be collapsed.
1697
+ * @default 0.4
1698
+ */
1699
+ minEdgeLengthRatio?: number;
1700
+ /**
1701
+ * Maximum allowed edge length as a fraction of targetEdgeLength.
1702
+ * Edges longer than this will be split.
1703
+ * @default 1.333
1704
+ */
1705
+ maxEdgeLengthRatio?: number;
1706
+ /**
1707
+ * Minimum allowed triangle quality (0 to 1).
1708
+ * Triangles with quality below this threshold are prioritized for improvement.
1709
+ * Quality is measured as the ratio of inscribed to circumscribed circle radii.
1710
+ * @default 0.3
1711
+ */
1712
+ minTriangleQuality?: number;
1713
+ /**
1714
+ * Maximum angle deviation from original surface (in radians).
1715
+ * Vertices are not relocated if it would cause normals to deviate more than this.
1716
+ * @default Math.PI / 6 (30 degrees)
1717
+ */
1718
+ maxNormalDeviation?: number;
1719
+ /**
1720
+ * Use spatial acceleration structures for large meshes.
1721
+ * Recommended for meshes with more than 50K triangles.
1722
+ * @default true
1723
+ */
1724
+ useAcceleration?: boolean;
1725
+ /**
1726
+ * Process mesh in chunks of this size.
1727
+ * Set to 0 to disable chunking.
1728
+ * Useful for very large meshes to manage memory usage.
1729
+ * @default 0
1730
+ */
1731
+ chunkSize?: number;
1732
+ /**
1733
+ * Maximum memory budget in MB.
1734
+ * Set to 0 for unlimited.
1735
+ * When exceeded, algorithm will attempt to reduce memory usage.
1736
+ * @default 0
1737
+ */
1738
+ memoryBudget?: number;
1739
+ /**
1740
+ * Enable verbose logging during remeshing.
1741
+ * @default false
1742
+ */
1743
+ verbose?: boolean;
1744
+ }
1745
+
1746
+ /**
1747
+ * Result of the remeshing operation.
1748
+ */
1749
+ export declare interface RemeshResult {
1750
+ /** Statistics about the remeshing operation */
1751
+ stats: RemeshStats;
1752
+ }
1753
+
1754
+ /**
1755
+ * Statistics returned after remeshing completes.
1756
+ */
1757
+ export declare interface RemeshStats {
1758
+ /** Number of vertices in the input mesh */
1759
+ inputVertices: number;
1760
+ /** Number of faces in the input mesh */
1761
+ inputFaces: number;
1762
+ /** Number of vertices in the output mesh */
1763
+ outputVertices: number;
1764
+ /** Number of faces in the output mesh */
1765
+ outputFaces: number;
1766
+ /** Number of iterations performed */
1767
+ iterations: number;
1768
+ /** Final average triangle quality (0 to 1) */
1769
+ finalQuality: number;
1770
+ /** Number of non-manifold edges detected */
1771
+ nonManifoldEdges: number;
1772
+ /** Number of skeleton edges (non-manifold + feature + boundary) */
1773
+ skeletonEdges: number;
1774
+ /** Number of edge flips performed */
1775
+ edgeFlips: number;
1776
+ /** Number of edge splits performed */
1777
+ edgeSplits: number;
1778
+ /** Number of edge contractions performed */
1779
+ edgeContractions: number;
1780
+ /** Number of vertex relocations performed */
1781
+ vertexRelocations: number;
1782
+ /** Total processing time in milliseconds */
1783
+ processingTimeMs: number;
1784
+ }
1785
+
1786
+ /**
1787
+ * Multiplies a vector by a scalar.
1788
+ */
1789
+ export declare function scale(v: Vec3, s: number): Vec3;
1790
+
1791
+ /**
1792
+ * Unique identifier for a skeleton segment.
1793
+ */
1794
+ export declare type SegmentId = number & {
1795
+ readonly __brand: 'SegmentId';
1796
+ };
1797
+
1798
+ /**
1799
+ * Builds the feature skeleton from a mesh.
1800
+ * The skeleton consists of non-manifold edges, boundary edges, and feature edges.
1801
+ */
1802
+ export declare class SkeletonBuilder {
1803
+ private mesh;
1804
+ private nextSegmentId;
1805
+ constructor(mesh: NonManifoldMesh);
1806
+ /**
1807
+ * Builds the skeleton and returns the result.
1808
+ */
1809
+ build(): SkeletonBuildResult;
1810
+ /**
1811
+ * Builds segments from skeleton edges.
1812
+ * A segment is a path between two branching vertices.
1813
+ */
1814
+ private buildSegments;
1815
+ /**
1816
+ * Gets skeleton edges incident to a vertex.
1817
+ */
1818
+ private getIncidentSkeletonEdges;
1819
+ /**
1820
+ * Traces a segment from a starting vertex and edge.
1821
+ */
1822
+ private traceSegment;
1823
+ /**
1824
+ * Traces a closed loop starting from an edge.
1825
+ */
1826
+ private traceClosedLoop;
1827
+ /**
1828
+ * Gets the next skeleton edge from a vertex, excluding the current edge.
1829
+ */
1830
+ private getNextSkeletonEdge;
1831
+ /**
1832
+ * Creates a new segment ID.
1833
+ */
1834
+ private createSegmentId;
1835
+ }
1836
+
1837
+ /**
1838
+ * Result of skeleton building.
1839
+ */
1840
+ export declare interface SkeletonBuildResult {
1841
+ /** All segments in the skeleton */
1842
+ segments: SkeletonSegment[];
1843
+ /** All skeleton edges */
1844
+ skeletonEdges: Edge[];
1845
+ /** All branching vertices (endpoints of segments) */
1846
+ branchingVertices: Vertex[];
1847
+ /** All open-book vertices (interior of segments) */
1848
+ openBookVertices: Vertex[];
1849
+ }
1850
+
1851
+ /**
1852
+ * Determines movement constraints for vertices based on their type.
1853
+ */
1854
+ export declare class SkeletonConstraints {
1855
+ private skeleton;
1856
+ constructor(skeleton: FeatureSkeleton);
1857
+ /**
1858
+ * Constrains a target position based on vertex type.
1859
+ *
1860
+ * - Manifold vertices: Can move freely (no constraint)
1861
+ * - Open-book vertices: Constrained to their skeleton segment
1862
+ * - Branching vertices: Fixed (cannot move)
1863
+ *
1864
+ * @param vertex - The vertex to constrain
1865
+ * @param targetPosition - The desired target position
1866
+ * @returns The constrained position
1867
+ */
1868
+ constrainPosition(vertex: Vertex, targetPosition: Vec3): ConstrainedPosition;
1869
+ /**
1870
+ * Constrains a position to a skeleton segment.
1871
+ */
1872
+ private constrainToSegment;
1873
+ /**
1874
+ * Checks if a vertex can move freely.
1875
+ */
1876
+ canMoveFreely(vertex: Vertex): boolean;
1877
+ /**
1878
+ * Checks if a vertex is fixed (cannot move).
1879
+ */
1880
+ isFixed(vertex: Vertex): boolean;
1881
+ /**
1882
+ * Checks if a vertex is constrained to a segment.
1883
+ */
1884
+ isConstrainedToSegment(vertex: Vertex): boolean;
1885
+ /**
1886
+ * Gets the segment a vertex is constrained to.
1887
+ */
1888
+ getConstraintSegment(vertex: Vertex): SkeletonSegment | undefined;
1889
+ /**
1890
+ * Computes the allowed movement direction for a vertex.
1891
+ * For open-book vertices, this is the tangent direction of the segment.
1892
+ */
1893
+ getAllowedDirection(vertex: Vertex): Vec3 | null;
1894
+ }
1895
+
1896
+ /**
1897
+ * Represents a segment of the feature skeleton.
1898
+ * A segment is a path of skeleton edges between two branching vertices.
1899
+ */
1900
+ export declare class SkeletonSegment {
1901
+ /**
1902
+ * Unique identifier for this segment.
1903
+ */
1904
+ readonly id: SegmentId;
1905
+ /**
1906
+ * Vertices along this segment, in order from start to end.
1907
+ * Includes the endpoint branching vertices.
1908
+ */
1909
+ vertices: Vertex[];
1910
+ /**
1911
+ * Edges along this segment, in order.
1912
+ */
1913
+ edges: Edge[];
1914
+ /**
1915
+ * Whether this segment forms a closed loop.
1916
+ */
1917
+ isClosed: boolean;
1918
+ /**
1919
+ * Total arc length of this segment.
1920
+ */
1921
+ private _totalLength;
1922
+ /**
1923
+ * Cumulative lengths at each vertex (for parameterization).
1924
+ */
1925
+ private _cumulativeLengths;
1926
+ constructor(
1927
+ /**
1928
+ * Unique identifier for this segment.
1929
+ */
1930
+ id: SegmentId);
1931
+ /**
1932
+ * Gets the start vertex of this segment.
1933
+ */
1934
+ get startVertex(): Vertex | undefined;
1935
+ /**
1936
+ * Gets the end vertex of this segment.
1937
+ */
1938
+ get endVertex(): Vertex | undefined;
1939
+ /**
1940
+ * Gets the total arc length of this segment.
1941
+ */
1942
+ get totalLength(): number;
1943
+ /**
1944
+ * Gets the number of vertices in this segment.
1945
+ */
1946
+ get vertexCount(): number;
1947
+ /**
1948
+ * Gets the number of edges in this segment.
1949
+ */
1950
+ get edgeCount(): number;
1951
+ /**
1952
+ * Adds a vertex to the end of the segment.
1953
+ */
1954
+ addVertex(vertex: Vertex): void;
1955
+ /**
1956
+ * Adds an edge to the segment.
1957
+ */
1958
+ addEdge(edge: Edge): void;
1959
+ /**
1960
+ * Recomputes the total length and cumulative lengths.
1961
+ */
1962
+ recomputeLengths(): void;
1963
+ /**
1964
+ * Gets the parameter t (0 to 1) for a vertex index.
1965
+ */
1966
+ getParameterAtVertex(index: number): number;
1967
+ /**
1968
+ * Gets the position at a parameter t along the segment.
1969
+ *
1970
+ * @param t - Parameter from 0 (start) to 1 (end)
1971
+ * @returns The interpolated position
1972
+ */
1973
+ getPositionAt(t: number): Vec3 | null;
1974
+ /**
1975
+ * Projects a point onto this segment.
1976
+ * Returns the closest point on the segment and its parameter.
1977
+ */
1978
+ projectPoint(point: Vec3): {
1979
+ point: Vec3;
1980
+ parameter: number;
1981
+ distance: number;
1982
+ } | null;
1983
+ /**
1984
+ * Gets the vertex at a specific index.
1985
+ */
1986
+ getVertex(index: number): Vertex | undefined;
1987
+ /**
1988
+ * Gets the edge at a specific index.
1989
+ */
1990
+ getEdge(index: number): Edge | undefined;
1991
+ /**
1992
+ * Checks if a vertex is part of this segment.
1993
+ */
1994
+ containsVertex(vertex: Vertex): boolean;
1995
+ /**
1996
+ * Checks if an edge is part of this segment.
1997
+ */
1998
+ containsEdge(edge: Edge): boolean;
1999
+ /**
2000
+ * Gets the index of a vertex in this segment.
2001
+ */
2002
+ indexOfVertex(vertex: Vertex): number;
2003
+ /**
2004
+ * Iterates over vertices in this segment.
2005
+ */
2006
+ forEachVertex(callback: (vertex: Vertex, index: number) => void): void;
2007
+ /**
2008
+ * Iterates over edges in this segment.
2009
+ */
2010
+ forEachEdge(callback: (edge: Edge, index: number) => void): void;
2011
+ /**
2012
+ * Creates a copy of this segment.
2013
+ */
2014
+ clone(newId: SegmentId): SkeletonSegment;
2015
+ }
2016
+
2017
+ /**
2018
+ * Applies tangential smoothing to all relocatable vertices.
2019
+ */
2020
+ export declare function smoothAllVertices(mesh: NonManifoldMesh, constraints?: SkeletonConstraints, dampingFactor?: number): {
2021
+ smoothedCount: number;
2022
+ totalDistance: number;
2023
+ };
2024
+
2025
+ /**
2026
+ * Applies tangential smoothing to a vertex.
2027
+ */
2028
+ export declare function smoothVertex(mesh: NonManifoldMesh, vertex: Vertex, constraints?: SkeletonConstraints, dampingFactor?: number): VertexRelocationResult;
2029
+
2030
+ /**
2031
+ * A spatial hash grid for fast neighbor queries.
2032
+ * Uses a 3D hash grid to accelerate proximity searches.
2033
+ *
2034
+ * @template T - The type of items stored in the hash
2035
+ */
2036
+ export declare class SpatialHash<T> {
2037
+ private cells;
2038
+ private cellSize;
2039
+ private itemPositions;
2040
+ /**
2041
+ * Creates a new spatial hash with the specified cell size.
2042
+ *
2043
+ * @param cellSize - The size of each cell in the grid
2044
+ */
2045
+ constructor(cellSize: number);
2046
+ /**
2047
+ * Computes the cell key for a position.
2048
+ */
2049
+ private getCellKey;
2050
+ /**
2051
+ * Computes the cell indices for a position.
2052
+ */
2053
+ private getCellIndices;
2054
+ /**
2055
+ * Inserts an item at the specified position.
2056
+ *
2057
+ * @param item - The item to insert
2058
+ * @param position - The 3D position of the item
2059
+ */
2060
+ insert(item: T, position: Vec3): void;
2061
+ /**
2062
+ * Removes an item from the hash.
2063
+ *
2064
+ * @param item - The item to remove
2065
+ * @returns True if the item was found and removed
2066
+ */
2067
+ remove(item: T): boolean;
2068
+ /**
2069
+ * Updates an item's position in the hash.
2070
+ *
2071
+ * @param item - The item to update
2072
+ * @param newPosition - The new position
2073
+ */
2074
+ update(item: T, newPosition: Vec3): void;
2075
+ /**
2076
+ * Queries all items within a radius of a point.
2077
+ *
2078
+ * @param center - The center point of the query
2079
+ * @param radius - The search radius
2080
+ * @returns Array of items within the radius
2081
+ */
2082
+ queryRadius(center: Vec3, radius: number): T[];
2083
+ /**
2084
+ * Queries the k nearest neighbors to a point.
2085
+ *
2086
+ * @param center - The center point of the query
2087
+ * @param k - The number of neighbors to find
2088
+ * @param maxRadius - Optional maximum search radius
2089
+ * @returns Array of the k nearest items, sorted by distance
2090
+ */
2091
+ queryKNearest(center: Vec3, k: number, maxRadius?: number): T[];
2092
+ /**
2093
+ * Clears all items from the hash.
2094
+ */
2095
+ clear(): void;
2096
+ /**
2097
+ * Gets the number of items in the hash.
2098
+ */
2099
+ get size(): number;
2100
+ /**
2101
+ * Gets the number of non-empty cells.
2102
+ */
2103
+ get cellCount(): number;
2104
+ /**
2105
+ * Gets the position of an item.
2106
+ */
2107
+ getPosition(item: T): Vec3 | undefined;
2108
+ /**
2109
+ * Checks if an item is in the hash.
2110
+ */
2111
+ has(item: T): boolean;
2112
+ /**
2113
+ * Iterates over all items in the hash.
2114
+ */
2115
+ [Symbol.iterator](): Iterator<T>;
2116
+ /**
2117
+ * Gets all items in the hash.
2118
+ */
2119
+ getAll(): T[];
2120
+ }
2121
+
2122
+ /**
2123
+ * Splits an edge at its midpoint.
2124
+ *
2125
+ * Before split:
2126
+ * vC
2127
+ * /|\
2128
+ * / | \
2129
+ * / | \
2130
+ * / f0| \
2131
+ * vA---e---vB
2132
+ * \ f1| /
2133
+ * \ | /
2134
+ * \ | /
2135
+ * \|/
2136
+ * vD
2137
+ *
2138
+ * After split (new vertex vM at midpoint):
2139
+ * vC
2140
+ * /|\
2141
+ * / | \
2142
+ * / | \
2143
+ * / f0|f2 \
2144
+ * vA--vM---vB
2145
+ * \ f1|f3 /
2146
+ * \ | /
2147
+ * \ | /
2148
+ * \|/
2149
+ * vD
2150
+ */
2151
+ export declare function splitEdge(mesh: NonManifoldMesh, edge: Edge, splitRatio?: number): EdgeSplitResult;
2152
+
2153
+ /**
2154
+ * Splits all edges longer than a threshold.
2155
+ */
2156
+ export declare function splitLongEdges(mesh: NonManifoldMesh, maxLength: number): {
2157
+ splitCount: number;
2158
+ newVertices: Vertex[];
2159
+ };
2160
+
2161
+ /**
2162
+ * Subtracts vector b from vector a.
2163
+ */
2164
+ export declare function subtract(a: Vec3, b: Vec3): Vec3;
2165
+
2166
+ /**
2167
+ * Extracts the numeric value from a branded ID.
2168
+ */
2169
+ export declare function toNumber(id: VertexId | EdgeId | HalfedgeId | FaceId | SegmentId): number;
2170
+
2171
+ /**
2172
+ * Result of topology validation.
2173
+ */
2174
+ export declare interface TopologyValidationResult {
2175
+ /** Whether the mesh topology is valid */
2176
+ isValid: boolean;
2177
+ /** List of errors found */
2178
+ errors: ValidationError[];
2179
+ /** List of warnings */
2180
+ warnings: ValidationError[];
2181
+ }
2182
+
2183
+ /**
2184
+ * Class for topology validation.
2185
+ */
2186
+ export declare class TopologyValidator {
2187
+ private mesh;
2188
+ constructor(mesh: NonManifoldMesh);
2189
+ /**
2190
+ * Validates the mesh topology.
2191
+ */
2192
+ validate(): TopologyValidationResult;
2193
+ /**
2194
+ * Quick check if topology is valid.
2195
+ */
2196
+ isValid(): boolean;
2197
+ /**
2198
+ * Gets all errors.
2199
+ */
2200
+ getErrors(): ValidationError[];
2201
+ /**
2202
+ * Gets all warnings.
2203
+ */
2204
+ getWarnings(): ValidationError[];
2205
+ }
2206
+
2207
+ /**
2208
+ * A triangle primitive for BVH.
2209
+ */
2210
+ export declare interface Triangle {
2211
+ v0: Vec3;
2212
+ v1: Vec3;
2213
+ v2: Vec3;
2214
+ data?: unknown;
2215
+ }
2216
+
2217
+ /**
2218
+ * Computes the area of a triangle given three vertices.
2219
+ */
2220
+ export declare function triangleArea(v0: Vec3, v1: Vec3, v2: Vec3): number;
2221
+
2222
+ /**
2223
+ * Computes the centroid of a triangle.
2224
+ */
2225
+ export declare function triangleCentroid(v0: Vec3, v1: Vec3, v2: Vec3): Vec3;
2226
+
2227
+ /**
2228
+ * Computes the circumcenter of a triangle.
2229
+ * Returns the center of the circumscribed circle.
2230
+ */
2231
+ export declare function triangleCircumcenter(v0: Vec3, v1: Vec3, v2: Vec3): Vec3 | null;
2232
+
2233
+ /**
2234
+ * Computes the circumradius of a triangle.
2235
+ */
2236
+ export declare function triangleCircumradius(v0: Vec3, v1: Vec3, v2: Vec3): number | null;
2237
+
2238
+ /**
2239
+ * Computes the inradius of a triangle.
2240
+ */
2241
+ export declare function triangleInradius(v0: Vec3, v1: Vec3, v2: Vec3): number | null;
2242
+
2243
+ /**
2244
+ * Computes the normal of a triangle given three vertices.
2245
+ * Returns a normalized vector perpendicular to the triangle.
2246
+ */
2247
+ export declare function triangleNormal(v0: Vec3, v1: Vec3, v2: Vec3): Vec3;
2248
+
2249
+ /**
2250
+ * Computes the quality of a triangle (2 * inradius / circumradius).
2251
+ * Returns a value between 0 and 1, where 1 is an equilateral triangle.
2252
+ */
2253
+ export declare function triangleQuality(v0: Vec3, v1: Vec3, v2: Vec3): number;
2254
+
2255
+ /**
2256
+ * Validates a BufferGeometry for import.
2257
+ *
2258
+ * @param geometry - The geometry to validate
2259
+ * @returns Validation result with errors and warnings
2260
+ */
2261
+ export declare function validateGeometry(geometry: BufferGeometry): ValidationResult;
2262
+
2263
+ /**
2264
+ * Validates the topology of a mesh.
2265
+ *
2266
+ * @param mesh - The mesh to validate
2267
+ * @returns Validation result
2268
+ */
2269
+ export declare function validateTopology(mesh: NonManifoldMesh): TopologyValidationResult;
2270
+
2271
+ /**
2272
+ * A validation error.
2273
+ */
2274
+ export declare interface ValidationError {
2275
+ /** Type of the error */
2276
+ type: string;
2277
+ /** Human-readable message */
2278
+ message: string;
2279
+ /** Related element IDs */
2280
+ elementIds?: number[];
2281
+ }
2282
+
2283
+ /**
2284
+ * Result of geometry validation.
2285
+ */
2286
+ export declare interface ValidationResult {
2287
+ /** Whether the geometry is valid */
2288
+ isValid: boolean;
2289
+ /** List of validation errors */
2290
+ errors: string[];
2291
+ /** List of validation warnings */
2292
+ warnings: string[];
2293
+ }
2294
+
2295
+ /**
2296
+ * A simple 3D vector interface for internal computations.
2297
+ */
2298
+ export declare interface Vec3 {
2299
+ x: number;
2300
+ y: number;
2301
+ z: number;
2302
+ }
2303
+
2304
+ /**
2305
+ * Represents a vertex in the mesh.
2306
+ * Stores position, classification, and a reference to one outgoing halfedge.
2307
+ */
2308
+ export declare class Vertex {
2309
+ /**
2310
+ * Unique identifier for this vertex.
2311
+ */
2312
+ readonly id: VertexId;
2313
+ /**
2314
+ * 3D position of this vertex.
2315
+ */
2316
+ readonly position: Vector3;
2317
+ /**
2318
+ * One outgoing halfedge from this vertex.
2319
+ * All outgoing halfedges can be found by following next/twin pointers.
2320
+ */
2321
+ halfedge: Halfedge | null;
2322
+ /**
2323
+ * Classification of this vertex based on neighborhood topology.
2324
+ * Determines movement constraints during remeshing.
2325
+ */
2326
+ type: VertexType;
2327
+ /**
2328
+ * Whether this vertex is marked (e.g., for selection or processing).
2329
+ */
2330
+ isMarked: boolean;
2331
+ constructor(
2332
+ /**
2333
+ * Unique identifier for this vertex.
2334
+ */
2335
+ id: VertexId,
2336
+ /**
2337
+ * 3D position of this vertex.
2338
+ */
2339
+ position: Vector3);
2340
+ /**
2341
+ * Gets the degree of this vertex (number of incident edges).
2342
+ * Returns null if the vertex has no incident halfedge.
2343
+ */
2344
+ degree(): number | null;
2345
+ /**
2346
+ * Iterates over all outgoing halfedges from this vertex.
2347
+ *
2348
+ * @param callback - Function called for each outgoing halfedge
2349
+ */
2350
+ forEachOutgoingHalfedge(callback: (halfedge: Halfedge) => void): void;
2351
+ /**
2352
+ * Collects all outgoing halfedges from this vertex into an array.
2353
+ *
2354
+ * @returns Array of outgoing halfedges
2355
+ */
2356
+ getOutgoingHalfedges(): Halfedge[];
2357
+ /**
2358
+ * Iterates over all neighboring vertices.
2359
+ *
2360
+ * @param callback - Function called for each neighboring vertex
2361
+ */
2362
+ forEachNeighbor(callback: (vertex: Vertex) => void): void;
2363
+ /**
2364
+ * Collects all neighboring vertices into an array.
2365
+ *
2366
+ * @returns Array of neighboring vertices
2367
+ */
2368
+ getNeighbors(): Vertex[];
2369
+ /**
2370
+ * Checks if this vertex is on the boundary of the mesh.
2371
+ * A vertex is on the boundary if any of its incident halfedges has no face.
2372
+ */
2373
+ isBoundary(): boolean;
2374
+ /**
2375
+ * Checks if this vertex can move freely during remeshing.
2376
+ * Only manifold vertices can move freely in 3D space.
2377
+ */
2378
+ canMoveFreely(): boolean;
2379
+ /**
2380
+ * Checks if this vertex is constrained to a skeleton segment.
2381
+ * OpenBook vertices can only move along their skeleton segment.
2382
+ */
2383
+ isSkeletonConstrained(): boolean;
2384
+ /**
2385
+ * Checks if this vertex has a fixed position.
2386
+ * Branching and other non-manifold vertices cannot move.
2387
+ */
2388
+ isPositionFixed(): boolean;
2389
+ /**
2390
+ * Checks if this vertex is part of the feature skeleton.
2391
+ */
2392
+ isOnSkeleton(): boolean;
2393
+ }
2394
+
2395
+ /**
2396
+ * Class for vertex classification operations.
2397
+ */
2398
+ export declare class VertexClassifier {
2399
+ private mesh;
2400
+ constructor(mesh: NonManifoldMesh);
2401
+ /**
2402
+ * Classifies all vertices and returns statistics.
2403
+ */
2404
+ classifyAll(): ClassificationStats;
2405
+ /**
2406
+ * Gets vertices of a specific type.
2407
+ */
2408
+ getByType(type: VertexType): Vertex[];
2409
+ /**
2410
+ * Gets all manifold vertices.
2411
+ */
2412
+ getManifold(): Vertex[];
2413
+ /**
2414
+ * Gets all non-manifold vertices.
2415
+ */
2416
+ getNonManifold(): Vertex[];
2417
+ /**
2418
+ * Reclassifies all vertices.
2419
+ */
2420
+ reclassify(): void;
2421
+ }
2422
+
2423
+ /**
2424
+ * Branded types for mesh elements to ensure type safety.
2425
+ * These prevent accidentally mixing up different ID types.
2426
+ */
2427
+ /**
2428
+ * Unique identifier for a vertex in the mesh.
2429
+ */
2430
+ export declare type VertexId = number & {
2431
+ readonly __brand: 'VertexId';
2432
+ };
2433
+
2434
+ /**
2435
+ * Result of a vertex relocation operation.
2436
+ */
2437
+ export declare interface VertexRelocationResult {
2438
+ /** Whether the relocation was successful */
2439
+ success: boolean;
2440
+ /** Reason for failure (if any) */
2441
+ reason?: string;
2442
+ /** The new position */
2443
+ newPosition?: Vec3;
2444
+ /** Whether the position was constrained */
2445
+ wasConstrained?: boolean;
2446
+ /** Distance moved */
2447
+ distanceMoved?: number;
2448
+ }
2449
+
2450
+ /**
2451
+ * Vertex relocation operation handler.
2452
+ */
2453
+ export declare class VertexRelocator {
2454
+ private mesh;
2455
+ private constraints;
2456
+ constructor(mesh: NonManifoldMesh, constraints?: SkeletonConstraints);
2457
+ /**
2458
+ * Sets the skeleton constraints.
2459
+ */
2460
+ setConstraints(constraints: SkeletonConstraints): void;
2461
+ /**
2462
+ * Relocates a vertex to a target position.
2463
+ */
2464
+ relocate(vertex: Vertex, targetPosition: Vec3): VertexRelocationResult;
2465
+ /**
2466
+ * Applies tangential smoothing to a vertex.
2467
+ */
2468
+ smooth(vertex: Vertex, dampingFactor?: number): VertexRelocationResult;
2469
+ /**
2470
+ * Applies tangential smoothing to all relocatable vertices.
2471
+ */
2472
+ smoothAll(dampingFactor?: number): {
2473
+ smoothedCount: number;
2474
+ totalDistance: number;
2475
+ };
2476
+ /**
2477
+ * Checks if a vertex can be relocated.
2478
+ */
2479
+ canRelocate(vertex: Vertex): boolean;
2480
+ }
2481
+
2482
+ /**
2483
+ * Classification types for vertices and edges in non-manifold meshes.
2484
+ * Based on the EUROGRAPHICS 2008 paper "Adaptive Remeshing of Non-Manifold Surfaces".
2485
+ */
2486
+ /**
2487
+ * Classification of a vertex based on its neighborhood topology.
2488
+ *
2489
+ * - Manifold: Star homeomorphic to disk, can move freely in 3D
2490
+ * - OpenBook: On exactly 2 skeleton edges (like pages of a book), constrained to skeleton
2491
+ * - SkeletonBranching: On 1 or >2 skeleton edges, position is fixed
2492
+ * - NonManifoldOther: Other non-manifold configurations, position is fixed
2493
+ */
2494
+ export declare enum VertexType {
2495
+ /** Vertex with manifold neighborhood - can move freely in 3D */
2496
+ Manifold = "manifold",
2497
+ /** Vertex on exactly 2 skeleton edges (open-book) - constrained to skeleton segment */
2498
+ OpenBook = "open_book",
2499
+ /** Vertex on 1 or >2 skeleton edges - position is fixed */
2500
+ SkeletonBranching = "skeleton_branching",
2501
+ /** Other non-manifold vertex type - position is fixed */
2502
+ NonManifoldOther = "non_manifold_other"
2503
+ }
2504
+
2505
+ export { }