remesh-threejs 0.2.1 → 0.3.1
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/README.md +124 -5
- package/dist/index.d.ts +405 -0
- package/dist/remesh-threejs.cjs +1 -1
- package/dist/remesh-threejs.cjs.map +1 -1
- package/dist/remesh-threejs.js +851 -0
- package/dist/remesh-threejs.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://github.com/RossGraeber/remesh-threejs/actions)
|
|
7
7
|
|
|
8
|
-
TypeScript library for
|
|
8
|
+
TypeScript library for repair and remeshing of non-manifold surfaces using Three.js.
|
|
9
9
|
|
|
10
10
|
Based on the EUROGRAPHICS 2008 paper ["Adaptive Remeshing of Non-Manifold Surfaces"](https://doi.org/10.1111/j.1467-8659.2008.01285.x) by Zilske, Lamecker, and Zachow.
|
|
11
11
|
|
|
@@ -14,6 +14,7 @@ Based on the EUROGRAPHICS 2008 paper ["Adaptive Remeshing of Non-Manifold Surfac
|
|
|
14
14
|
- **Non-manifold mesh support**: Extended halfedge data structure supporting edges with more than 2 incident faces
|
|
15
15
|
- **Feature skeleton**: Unified treatment of non-manifold edges, feature lines, and boundary edges
|
|
16
16
|
- **Adaptive remeshing**: Edge splitting, contraction, flipping, and vertex smoothing
|
|
17
|
+
- **Fast mesh repair**: Targeted repair operations 10-100x faster than full remeshing
|
|
17
18
|
- **Analysis tools**: Detect and classify non-manifold vertices and edges
|
|
18
19
|
- **Spatial acceleration**: SpatialHash and BVH for efficient queries on large meshes (500K+ triangles)
|
|
19
20
|
- **Three.js integration**: Import/export BufferGeometry with visualization helpers
|
|
@@ -42,6 +43,24 @@ console.log(`Remeshed in ${result.stats.iterations} iterations`);
|
|
|
42
43
|
const outputGeometry = result.geometry;
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
### Fast Mesh Repair
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { repairMesh, removeIsolatedVertices } from 'remesh-threejs';
|
|
50
|
+
|
|
51
|
+
// Quick repair (removes all common defects in optimal order)
|
|
52
|
+
const result = repairMesh(geometry);
|
|
53
|
+
console.log(`Fixed ${result.stats.totalDefectsFixed} defects in ${result.stats.totalTimeMs}ms`);
|
|
54
|
+
|
|
55
|
+
// Targeted repairs (10-100x faster than full remeshing)
|
|
56
|
+
const result2 = removeIsolatedVertices(geometry);
|
|
57
|
+
const result3 = removeDegenerateFaces(geometry, { areaThreshold: 1e-10 });
|
|
58
|
+
const result4 = removeDuplicateFaces(geometry);
|
|
59
|
+
const result5 = removeNonManifoldEdges(geometry, { strategy: 'auto' });
|
|
60
|
+
const result6 = fillHoles(geometry, { maxHoleSize: 10 });
|
|
61
|
+
const result7 = unifyNormals(geometry);
|
|
62
|
+
```
|
|
63
|
+
|
|
45
64
|
### Analyze Mesh for Non-Manifold Issues
|
|
46
65
|
|
|
47
66
|
```typescript
|
|
@@ -105,6 +124,13 @@ const outputGeometry = exportBufferGeometry(mesh);
|
|
|
105
124
|
| Function | Description |
|
|
106
125
|
|----------|-------------|
|
|
107
126
|
| `remesh(geometry, options?)` | One-shot remeshing of a BufferGeometry |
|
|
127
|
+
| `repairMesh(geometry, options?)` | Fast repair for common defects |
|
|
128
|
+
| `removeIsolatedVertices(geometry)` | Remove orphaned vertices with no faces |
|
|
129
|
+
| `removeDegenerateFaces(geometry, options?)` | Remove zero-area triangles |
|
|
130
|
+
| `removeDuplicateFaces(geometry)` | Remove faces with identical vertices |
|
|
131
|
+
| `removeNonManifoldEdges(geometry, options?)` | Fix edges with >2 incident faces |
|
|
132
|
+
| `fillHoles(geometry, options?)` | Fill boundary holes via triangulation |
|
|
133
|
+
| `unifyNormals(geometry, options?)` | Make face orientations consistent |
|
|
108
134
|
| `analyzeManifold(geometry)` | Analyze mesh for non-manifold features |
|
|
109
135
|
| `isManifold(geometry)` | Quick check if mesh is manifold |
|
|
110
136
|
| `validateTopology(mesh)` | Validate mesh topology integrity |
|
|
@@ -115,6 +141,7 @@ const outputGeometry = exportBufferGeometry(mesh);
|
|
|
115
141
|
|-------|-------------|
|
|
116
142
|
| `NonManifoldMesh` | Main mesh data structure with halfedge connectivity |
|
|
117
143
|
| `AdaptiveRemesher` | Iterative remeshing algorithm |
|
|
144
|
+
| `MeshRepairer` | Composable mesh repair operations |
|
|
118
145
|
| `ManifoldAnalyzer` | Analysis with caching support |
|
|
119
146
|
| `VertexClassifier` | Classify vertices by skeleton topology |
|
|
120
147
|
| `TopologyValidator` | Validate mesh topology invariants |
|
|
@@ -166,6 +193,76 @@ const bvh = createBVHFromMesh(mesh);
|
|
|
166
193
|
const result = bvh.closestPoint(queryPoint);
|
|
167
194
|
```
|
|
168
195
|
|
|
196
|
+
### Mesh Repair API
|
|
197
|
+
|
|
198
|
+
Fast, targeted repairs for common mesh defects. These operations are **10-100x faster** than full remeshing when you only need to fix specific issues.
|
|
199
|
+
|
|
200
|
+
#### Functional API (Simple)
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import {
|
|
204
|
+
repairMesh,
|
|
205
|
+
removeIsolatedVertices,
|
|
206
|
+
removeDegenerateFaces,
|
|
207
|
+
removeDuplicateFaces,
|
|
208
|
+
removeNonManifoldEdges,
|
|
209
|
+
fillHoles,
|
|
210
|
+
unifyNormals,
|
|
211
|
+
} from 'remesh-threejs';
|
|
212
|
+
|
|
213
|
+
// Run all repairs in optimal order
|
|
214
|
+
const result = repairMesh(geometry);
|
|
215
|
+
console.log(`Fixed ${result.stats.totalDefectsFixed} defects`);
|
|
216
|
+
|
|
217
|
+
// Or use targeted repairs
|
|
218
|
+
const result2 = removeIsolatedVertices(geometry); // 100x+ faster
|
|
219
|
+
const result3 = removeDegenerateFaces(geometry); // 50-100x faster
|
|
220
|
+
const result4 = removeDuplicateFaces(geometry); // 30-60x faster
|
|
221
|
+
const result5 = removeNonManifoldEdges(geometry, { strategy: 'split' }); // 10-30x faster
|
|
222
|
+
const result6 = fillHoles(geometry, { maxHoleSize: 10 }); // 20-50x faster
|
|
223
|
+
const result7 = unifyNormals(geometry); // 40-80x faster
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### Class-Based API (Advanced)
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { MeshRepairer } from 'remesh-threejs';
|
|
230
|
+
|
|
231
|
+
// Compose multiple repairs with chaining
|
|
232
|
+
const repairer = new MeshRepairer(geometry, {
|
|
233
|
+
verbose: true, // Enable logging
|
|
234
|
+
validateAfterEach: true, // Validate topology after each operation
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const stats = repairer
|
|
238
|
+
.removeIsolatedVertices()
|
|
239
|
+
.removeDegenerateFaces()
|
|
240
|
+
.removeDuplicateFaces()
|
|
241
|
+
.removeNonManifoldEdges('auto')
|
|
242
|
+
.fillHoles(10)
|
|
243
|
+
.unifyNormals()
|
|
244
|
+
.execute();
|
|
245
|
+
|
|
246
|
+
const repairedGeometry = repairer.toBufferGeometry();
|
|
247
|
+
|
|
248
|
+
// Validate results
|
|
249
|
+
const validation = repairer.validate();
|
|
250
|
+
if (!validation.isValid) {
|
|
251
|
+
console.error('Topology errors:', validation.errors);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### Common Defects Repaired
|
|
256
|
+
|
|
257
|
+
| Defect | Operation | Speedup vs Remesh |
|
|
258
|
+
|--------|-----------|-------------------|
|
|
259
|
+
| Orphaned vertices | `removeIsolatedVertices()` | 100x+ |
|
|
260
|
+
| Zero-area triangles | `removeDegenerateFaces()` | 50-100x |
|
|
261
|
+
| Duplicate faces | `removeDuplicateFaces()` | 30-60x |
|
|
262
|
+
| Edges with >2 faces | `removeNonManifoldEdges()` | 10-30x |
|
|
263
|
+
| Boundary holes | `fillHoles()` | 20-50x |
|
|
264
|
+
| Inconsistent normals | `unifyNormals()` | 40-80x |
|
|
265
|
+
|
|
169
266
|
### Visualization Helpers
|
|
170
267
|
|
|
171
268
|
```typescript
|
|
@@ -187,6 +284,8 @@ const qualityMesh = exportQualityGeometry(mesh);
|
|
|
187
284
|
|
|
188
285
|
## Options
|
|
189
286
|
|
|
287
|
+
### Remesh Options
|
|
288
|
+
|
|
190
289
|
```typescript
|
|
191
290
|
interface RemeshOptions {
|
|
192
291
|
// Target edge length (default: auto-computed)
|
|
@@ -210,6 +309,30 @@ interface RemeshOptions {
|
|
|
210
309
|
}
|
|
211
310
|
```
|
|
212
311
|
|
|
312
|
+
### Repair Options
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
interface RepairOptions {
|
|
316
|
+
// Use Web Workers for parallel processing (default: auto for large meshes)
|
|
317
|
+
useWorkers?: boolean;
|
|
318
|
+
|
|
319
|
+
// Number of worker threads (default: navigator.hardwareConcurrency || 4)
|
|
320
|
+
workerCount?: number;
|
|
321
|
+
|
|
322
|
+
// Use spatial acceleration structures (default: true)
|
|
323
|
+
useAcceleration?: boolean;
|
|
324
|
+
|
|
325
|
+
// Minimum mesh size to trigger parallelization (default: 10000 faces)
|
|
326
|
+
parallelThreshold?: number;
|
|
327
|
+
|
|
328
|
+
// Enable verbose logging (default: false)
|
|
329
|
+
verbose?: boolean;
|
|
330
|
+
|
|
331
|
+
// Validate topology after each operation (default: false)
|
|
332
|
+
validateAfterEach?: boolean;
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
213
336
|
## Development
|
|
214
337
|
|
|
215
338
|
```bash
|
|
@@ -265,7 +388,3 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
265
388
|
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
266
389
|
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
267
390
|
5. Open a Pull Request
|
|
268
|
-
|
|
269
|
-
## License
|
|
270
|
-
|
|
271
|
-
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -432,6 +432,32 @@ export declare function cross(a: Vec3, b: Vec3): Vec3;
|
|
|
432
432
|
*/
|
|
433
433
|
export declare const DEFAULT_REMESH_OPTIONS: Required<Omit<RemeshOptions, 'targetEdgeLength' | 'featureEdges'>>;
|
|
434
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Defect information for analysis.
|
|
437
|
+
*/
|
|
438
|
+
export declare interface DefectInfo {
|
|
439
|
+
type: 'non-manifold' | 'hole' | 'degenerate' | 'intersection' | 'isolated' | 'duplicate' | 'normal';
|
|
440
|
+
count: number;
|
|
441
|
+
locations: {
|
|
442
|
+
faceIndex?: number;
|
|
443
|
+
vertexIndex?: number;
|
|
444
|
+
edgeIndex?: number;
|
|
445
|
+
}[];
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Repairs degenerate faces (zero-area triangles, duplicate vertices).
|
|
450
|
+
*/
|
|
451
|
+
export declare class DegenerateFaceRepair extends RepairOperation {
|
|
452
|
+
private degenerateFaces;
|
|
453
|
+
private areaThreshold;
|
|
454
|
+
constructor(mesh: NonManifoldMesh, verbose?: boolean, areaThreshold?: number);
|
|
455
|
+
detect(): number;
|
|
456
|
+
repair(): number;
|
|
457
|
+
getName(): string;
|
|
458
|
+
canParallelize(): boolean;
|
|
459
|
+
}
|
|
460
|
+
|
|
435
461
|
/**
|
|
436
462
|
* Computes the Euclidean distance between two points.
|
|
437
463
|
*/
|
|
@@ -447,6 +473,21 @@ export declare function distanceSquared(a: Vec3, b: Vec3): number;
|
|
|
447
473
|
*/
|
|
448
474
|
export declare function dot(a: Vec3, b: Vec3): number;
|
|
449
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Repairs duplicate faces (faces with identical vertices).
|
|
478
|
+
*/
|
|
479
|
+
export declare class DuplicateFaceRepair extends RepairOperation {
|
|
480
|
+
private duplicates;
|
|
481
|
+
detect(): number;
|
|
482
|
+
repair(): number;
|
|
483
|
+
/**
|
|
484
|
+
* Create canonical key from sorted vertex IDs.
|
|
485
|
+
*/
|
|
486
|
+
private makeFaceKey;
|
|
487
|
+
getName(): string;
|
|
488
|
+
canParallelize(): boolean;
|
|
489
|
+
}
|
|
490
|
+
|
|
450
491
|
/**
|
|
451
492
|
* Represents an undirected edge in the mesh.
|
|
452
493
|
* For non-manifold meshes, an edge can have more than 2 halfedges.
|
|
@@ -985,6 +1026,17 @@ export declare class FeatureSkeleton {
|
|
|
985
1026
|
};
|
|
986
1027
|
}
|
|
987
1028
|
|
|
1029
|
+
/**
|
|
1030
|
+
* Fill holes in the mesh by triangulating boundary loops.
|
|
1031
|
+
*
|
|
1032
|
+
* @param geometry - Input BufferGeometry
|
|
1033
|
+
* @param options - Repair options with optional maxHoleSize
|
|
1034
|
+
* @returns Repaired geometry and statistics
|
|
1035
|
+
*/
|
|
1036
|
+
export declare function fillHoles(geometry: BufferGeometry, options?: RepairOptions & {
|
|
1037
|
+
maxHoleSize?: number;
|
|
1038
|
+
}): RepairResult;
|
|
1039
|
+
|
|
988
1040
|
/**
|
|
989
1041
|
* Flips an edge in the mesh.
|
|
990
1042
|
*
|
|
@@ -1165,6 +1217,36 @@ export declare type HalfedgeId = number & {
|
|
|
1165
1217
|
readonly __brand: 'HalfedgeId';
|
|
1166
1218
|
};
|
|
1167
1219
|
|
|
1220
|
+
/**
|
|
1221
|
+
* Fills holes in the mesh by triangulating boundary loops.
|
|
1222
|
+
*/
|
|
1223
|
+
export declare class HoleFiller extends RepairOperation {
|
|
1224
|
+
private holes;
|
|
1225
|
+
private maxHoleSize;
|
|
1226
|
+
private preserveBoundary;
|
|
1227
|
+
constructor(mesh: NonManifoldMesh, verbose?: boolean, maxHoleSize?: number, preserveBoundary?: boolean);
|
|
1228
|
+
detect(): number;
|
|
1229
|
+
repair(): number;
|
|
1230
|
+
/**
|
|
1231
|
+
* Extract boundary loops from a set of boundary edges.
|
|
1232
|
+
*/
|
|
1233
|
+
private extractBoundaryLoops;
|
|
1234
|
+
/**
|
|
1235
|
+
* Find the next boundary edge connected to a vertex.
|
|
1236
|
+
*/
|
|
1237
|
+
private findNextBoundaryEdge;
|
|
1238
|
+
/**
|
|
1239
|
+
* Triangulate a boundary loop using ear clipping algorithm.
|
|
1240
|
+
*/
|
|
1241
|
+
private triangulateBoundaryLoop;
|
|
1242
|
+
/**
|
|
1243
|
+
* Find an "ear" in the polygon (a triangle with no vertices inside).
|
|
1244
|
+
*/
|
|
1245
|
+
private findEar;
|
|
1246
|
+
getName(): string;
|
|
1247
|
+
canParallelize(): boolean;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1168
1250
|
/**
|
|
1169
1251
|
* Imports a Three.js BufferGeometry into a NonManifoldMesh.
|
|
1170
1252
|
*
|
|
@@ -1215,6 +1297,17 @@ export declare function isDelaunay(edge: Edge): boolean;
|
|
|
1215
1297
|
*/
|
|
1216
1298
|
export declare function isManifold(geometry: BufferGeometry): boolean;
|
|
1217
1299
|
|
|
1300
|
+
/**
|
|
1301
|
+
* Repairs isolated vertices (vertices with no incident halfedges).
|
|
1302
|
+
*/
|
|
1303
|
+
export declare class IsolatedVertexRepair extends RepairOperation {
|
|
1304
|
+
private isolatedVertices;
|
|
1305
|
+
detect(): number;
|
|
1306
|
+
repair(): number;
|
|
1307
|
+
getName(): string;
|
|
1308
|
+
canParallelize(): boolean;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1218
1311
|
/**
|
|
1219
1312
|
* Checks if a point lies inside a triangle (using barycentric coordinates).
|
|
1220
1313
|
*/
|
|
@@ -1379,6 +1472,80 @@ export declare interface MeshQualityStats {
|
|
|
1379
1472
|
totalArea: number;
|
|
1380
1473
|
}
|
|
1381
1474
|
|
|
1475
|
+
/**
|
|
1476
|
+
* Advanced mesh repair with fine-grained control and composition.
|
|
1477
|
+
*/
|
|
1478
|
+
export declare class MeshRepairer {
|
|
1479
|
+
private mesh;
|
|
1480
|
+
private options;
|
|
1481
|
+
private operations;
|
|
1482
|
+
private stats;
|
|
1483
|
+
constructor(meshOrGeometry: NonManifoldMesh | BufferGeometry, options?: RepairOptions);
|
|
1484
|
+
/**
|
|
1485
|
+
* Remove isolated vertices (vertices with no faces).
|
|
1486
|
+
* @returns this for chaining
|
|
1487
|
+
*/
|
|
1488
|
+
removeIsolatedVertices(): this;
|
|
1489
|
+
/**
|
|
1490
|
+
* Remove zero-area and degenerate triangles.
|
|
1491
|
+
* @param areaThreshold - Minimum area threshold (default: 1e-10)
|
|
1492
|
+
* @returns this for chaining
|
|
1493
|
+
*/
|
|
1494
|
+
removeDegenerateFaces(areaThreshold?: number): this;
|
|
1495
|
+
/**
|
|
1496
|
+
* Remove duplicate faces with identical vertices.
|
|
1497
|
+
* @returns this for chaining
|
|
1498
|
+
*/
|
|
1499
|
+
removeDuplicateFaces(): this;
|
|
1500
|
+
/**
|
|
1501
|
+
* Remove non-manifold edges by splitting or collapsing.
|
|
1502
|
+
* @param strategy - Repair strategy: 'split', 'collapse', or 'auto' (default: 'auto')
|
|
1503
|
+
* @returns this for chaining
|
|
1504
|
+
*/
|
|
1505
|
+
removeNonManifoldEdges(strategy?: NonManifoldRepairStrategy): this;
|
|
1506
|
+
/**
|
|
1507
|
+
* Fill boundary loops (holes) with triangulation.
|
|
1508
|
+
* @param maxHoleSize - Maximum number of edges in a hole to fill (default: 100)
|
|
1509
|
+
* @returns this for chaining
|
|
1510
|
+
*/
|
|
1511
|
+
fillHoles(maxHoleSize?: number): this;
|
|
1512
|
+
/**
|
|
1513
|
+
* Unify face orientations to make normals consistent.
|
|
1514
|
+
* @param seedFaceIndex - Index of the face to use as orientation reference (default: 0)
|
|
1515
|
+
* @returns this for chaining
|
|
1516
|
+
*/
|
|
1517
|
+
unifyNormals(seedFaceIndex?: number): this;
|
|
1518
|
+
/**
|
|
1519
|
+
* Run all common repairs in optimal order.
|
|
1520
|
+
* @returns this for chaining
|
|
1521
|
+
*/
|
|
1522
|
+
repairAll(): this;
|
|
1523
|
+
/**
|
|
1524
|
+
* Execute all queued operations.
|
|
1525
|
+
* @returns Repair statistics
|
|
1526
|
+
*/
|
|
1527
|
+
execute(): RepairStats;
|
|
1528
|
+
/**
|
|
1529
|
+
* Get current statistics.
|
|
1530
|
+
*/
|
|
1531
|
+
getStats(): RepairStats;
|
|
1532
|
+
/**
|
|
1533
|
+
* Get the repaired mesh.
|
|
1534
|
+
*/
|
|
1535
|
+
getMesh(): NonManifoldMesh;
|
|
1536
|
+
/**
|
|
1537
|
+
* Export to BufferGeometry.
|
|
1538
|
+
*/
|
|
1539
|
+
toBufferGeometry(): BufferGeometry;
|
|
1540
|
+
/**
|
|
1541
|
+
* Validate the mesh after repairs.
|
|
1542
|
+
*/
|
|
1543
|
+
validate(): {
|
|
1544
|
+
isValid: boolean;
|
|
1545
|
+
errors: string[];
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1382
1549
|
/**
|
|
1383
1550
|
* Computes the midpoint between two points.
|
|
1384
1551
|
*/
|
|
@@ -1406,6 +1573,35 @@ export declare interface NonManifoldEdgeInfo {
|
|
|
1406
1573
|
}];
|
|
1407
1574
|
}
|
|
1408
1575
|
|
|
1576
|
+
/**
|
|
1577
|
+
* Repairs non-manifold edges (edges with >2 incident faces).
|
|
1578
|
+
*/
|
|
1579
|
+
export declare class NonManifoldEdgeRepair extends RepairOperation {
|
|
1580
|
+
private nonManifoldEdges;
|
|
1581
|
+
private strategy;
|
|
1582
|
+
constructor(mesh: NonManifoldMesh, verbose?: boolean, strategy?: NonManifoldRepairStrategy);
|
|
1583
|
+
detect(): number;
|
|
1584
|
+
repair(): number;
|
|
1585
|
+
/**
|
|
1586
|
+
* Determine which strategy to use for a specific edge.
|
|
1587
|
+
*/
|
|
1588
|
+
private determineStrategy;
|
|
1589
|
+
/**
|
|
1590
|
+
* Compute average edge length in the mesh.
|
|
1591
|
+
*/
|
|
1592
|
+
private computeAverageEdgeLength;
|
|
1593
|
+
/**
|
|
1594
|
+
* Split a non-manifold edge by duplicating vertices.
|
|
1595
|
+
*/
|
|
1596
|
+
private splitNonManifoldEdge;
|
|
1597
|
+
/**
|
|
1598
|
+
* Collapse a non-manifold edge by removing excess faces.
|
|
1599
|
+
*/
|
|
1600
|
+
private collapseNonManifoldEdge;
|
|
1601
|
+
getName(): string;
|
|
1602
|
+
canParallelize(): boolean;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1409
1605
|
/**
|
|
1410
1606
|
* Represents a non-manifold mesh using an extended halfedge data structure.
|
|
1411
1607
|
* Supports edges with more than 2 incident faces (non-manifold seams).
|
|
@@ -1561,6 +1757,11 @@ export declare class NonManifoldMesh {
|
|
|
1561
1757
|
};
|
|
1562
1758
|
}
|
|
1563
1759
|
|
|
1760
|
+
/**
|
|
1761
|
+
* Strategy for repairing non-manifold edges.
|
|
1762
|
+
*/
|
|
1763
|
+
export declare type NonManifoldRepairStrategy = 'split' | 'collapse' | 'auto';
|
|
1764
|
+
|
|
1564
1765
|
/**
|
|
1565
1766
|
* Information about a non-manifold vertex.
|
|
1566
1767
|
*/
|
|
@@ -1585,6 +1786,61 @@ export declare interface NonManifoldVertexInfo {
|
|
|
1585
1786
|
*/
|
|
1586
1787
|
export declare function normalize(v: Vec3): Vec3;
|
|
1587
1788
|
|
|
1789
|
+
/**
|
|
1790
|
+
* Unifies face orientations to make normals consistent.
|
|
1791
|
+
*/
|
|
1792
|
+
export declare class NormalUnifier extends RepairOperation {
|
|
1793
|
+
private inconsistentFaces;
|
|
1794
|
+
private seedFaceIndex;
|
|
1795
|
+
constructor(mesh: NonManifoldMesh, verbose?: boolean, seedFaceIndex?: number);
|
|
1796
|
+
detect(): number;
|
|
1797
|
+
repair(): number;
|
|
1798
|
+
/**
|
|
1799
|
+
* Get faces that share an edge with the given face.
|
|
1800
|
+
*/
|
|
1801
|
+
private getNeighborFaces;
|
|
1802
|
+
/**
|
|
1803
|
+
* Find the edge shared between two faces.
|
|
1804
|
+
*/
|
|
1805
|
+
private getSharedEdge;
|
|
1806
|
+
/**
|
|
1807
|
+
* Check if two faces have consistent normal orientation across their shared edge.
|
|
1808
|
+
*/
|
|
1809
|
+
private areNormalsConsistent;
|
|
1810
|
+
/**
|
|
1811
|
+
* Get the halfedge in a face that corresponds to a given edge.
|
|
1812
|
+
*/
|
|
1813
|
+
private getHalfedgeInFace;
|
|
1814
|
+
/**
|
|
1815
|
+
* Get the start and end vertices of a halfedge.
|
|
1816
|
+
*/
|
|
1817
|
+
private getHalfedgeVertices;
|
|
1818
|
+
/**
|
|
1819
|
+
* Flip the orientation of a face by reversing its halfedge order.
|
|
1820
|
+
*/
|
|
1821
|
+
private flipFaceOrientation;
|
|
1822
|
+
getName(): string;
|
|
1823
|
+
canParallelize(): boolean;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* Statistics for a single repair operation.
|
|
1828
|
+
*/
|
|
1829
|
+
export declare interface OperationStats {
|
|
1830
|
+
/** Name of the operation */
|
|
1831
|
+
operation: string;
|
|
1832
|
+
/** Number of defects found */
|
|
1833
|
+
defectsFound: number;
|
|
1834
|
+
/** Number of defects fixed */
|
|
1835
|
+
defectsFixed: number;
|
|
1836
|
+
/** Processing time in milliseconds */
|
|
1837
|
+
timeMs: number;
|
|
1838
|
+
/** Whether the operation succeeded */
|
|
1839
|
+
success: boolean;
|
|
1840
|
+
/** Reason for failure (if any) */
|
|
1841
|
+
reason?: string;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1588
1844
|
/**
|
|
1589
1845
|
* Projects a point onto a line defined by two points.
|
|
1590
1846
|
* Returns the closest point on the line to the given point.
|
|
@@ -1783,6 +2039,144 @@ export declare interface RemeshStats {
|
|
|
1783
2039
|
processingTimeMs: number;
|
|
1784
2040
|
}
|
|
1785
2041
|
|
|
2042
|
+
/**
|
|
2043
|
+
* Remove degenerate faces (zero area, duplicate vertices).
|
|
2044
|
+
*
|
|
2045
|
+
* @param geometry - Input BufferGeometry
|
|
2046
|
+
* @param options - Repair options with optional areaThreshold
|
|
2047
|
+
* @returns Repaired geometry and statistics
|
|
2048
|
+
*/
|
|
2049
|
+
export declare function removeDegenerateFaces(geometry: BufferGeometry, options?: RepairOptions & {
|
|
2050
|
+
areaThreshold?: number;
|
|
2051
|
+
}): RepairResult;
|
|
2052
|
+
|
|
2053
|
+
/**
|
|
2054
|
+
* Remove duplicate faces with identical vertices.
|
|
2055
|
+
*
|
|
2056
|
+
* @param geometry - Input BufferGeometry
|
|
2057
|
+
* @param options - Repair options
|
|
2058
|
+
* @returns Repaired geometry and statistics
|
|
2059
|
+
*/
|
|
2060
|
+
export declare function removeDuplicateFaces(geometry: BufferGeometry, options?: RepairOptions): RepairResult;
|
|
2061
|
+
|
|
2062
|
+
/**
|
|
2063
|
+
* Remove isolated vertices (vertices with no incident faces).
|
|
2064
|
+
*
|
|
2065
|
+
* @param geometry - Input BufferGeometry
|
|
2066
|
+
* @param options - Repair options
|
|
2067
|
+
* @returns Repaired geometry and statistics
|
|
2068
|
+
*/
|
|
2069
|
+
export declare function removeIsolatedVertices(geometry: BufferGeometry, options?: RepairOptions): RepairResult;
|
|
2070
|
+
|
|
2071
|
+
/**
|
|
2072
|
+
* Remove non-manifold edges by splitting or collapsing.
|
|
2073
|
+
*
|
|
2074
|
+
* @param geometry - Input BufferGeometry
|
|
2075
|
+
* @param options - Repair options with optional strategy
|
|
2076
|
+
* @returns Repaired geometry and statistics
|
|
2077
|
+
*/
|
|
2078
|
+
export declare function removeNonManifoldEdges(geometry: BufferGeometry, options?: RepairOptions & {
|
|
2079
|
+
strategy?: NonManifoldRepairStrategy;
|
|
2080
|
+
}): RepairResult;
|
|
2081
|
+
|
|
2082
|
+
/**
|
|
2083
|
+
* Repair a mesh by applying all repair operations in optimal order.
|
|
2084
|
+
* Fast alternative to full remeshing for common defects.
|
|
2085
|
+
*
|
|
2086
|
+
* @param geometry - Input BufferGeometry
|
|
2087
|
+
* @param options - Repair options
|
|
2088
|
+
* @returns Repaired geometry and statistics
|
|
2089
|
+
*/
|
|
2090
|
+
export declare function repairMesh(geometry: BufferGeometry, options?: RepairOptions): RepairResult;
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* Base class for all repair operations.
|
|
2094
|
+
*/
|
|
2095
|
+
export declare abstract class RepairOperation {
|
|
2096
|
+
protected mesh: NonManifoldMesh;
|
|
2097
|
+
protected verbose: boolean;
|
|
2098
|
+
constructor(mesh: NonManifoldMesh, verbose?: boolean);
|
|
2099
|
+
/**
|
|
2100
|
+
* Detect defects in the mesh.
|
|
2101
|
+
* @returns Number of defects found
|
|
2102
|
+
*/
|
|
2103
|
+
abstract detect(): number;
|
|
2104
|
+
/**
|
|
2105
|
+
* Repair the detected defects.
|
|
2106
|
+
* @returns Number of defects fixed
|
|
2107
|
+
*/
|
|
2108
|
+
abstract repair(): number;
|
|
2109
|
+
/**
|
|
2110
|
+
* Execute the operation (detect + repair).
|
|
2111
|
+
* @returns Operation statistics
|
|
2112
|
+
*/
|
|
2113
|
+
execute(): OperationStats;
|
|
2114
|
+
/**
|
|
2115
|
+
* Get the name of this operation.
|
|
2116
|
+
*/
|
|
2117
|
+
abstract getName(): string;
|
|
2118
|
+
/**
|
|
2119
|
+
* Check if this operation can be parallelized.
|
|
2120
|
+
*/
|
|
2121
|
+
abstract canParallelize(): boolean;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
/**
|
|
2125
|
+
* Options for mesh repair operations.
|
|
2126
|
+
*/
|
|
2127
|
+
export declare interface RepairOptions {
|
|
2128
|
+
/** Use Web Workers for parallel processing (default: true for large meshes) */
|
|
2129
|
+
useWorkers?: boolean;
|
|
2130
|
+
/** Number of worker threads (default: navigator.hardwareConcurrency || 4) */
|
|
2131
|
+
workerCount?: number;
|
|
2132
|
+
/** Use spatial acceleration structures (default: true) */
|
|
2133
|
+
useAcceleration?: boolean;
|
|
2134
|
+
/** Minimum mesh size to trigger parallelization (default: 10000 faces) */
|
|
2135
|
+
parallelThreshold?: number;
|
|
2136
|
+
/** Enable verbose logging (default: false) */
|
|
2137
|
+
verbose?: boolean;
|
|
2138
|
+
/** Validate topology after each operation (default: false) */
|
|
2139
|
+
validateAfterEach?: boolean;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
/**
|
|
2143
|
+
* Result of a repair operation.
|
|
2144
|
+
*/
|
|
2145
|
+
export declare interface RepairResult {
|
|
2146
|
+
/** The repaired geometry */
|
|
2147
|
+
geometry: BufferGeometry;
|
|
2148
|
+
/** Repair statistics */
|
|
2149
|
+
stats: RepairStats;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
/**
|
|
2153
|
+
* Overall repair statistics.
|
|
2154
|
+
*/
|
|
2155
|
+
export declare interface RepairStats {
|
|
2156
|
+
/** Input mesh statistics */
|
|
2157
|
+
input: {
|
|
2158
|
+
vertices: number;
|
|
2159
|
+
faces: number;
|
|
2160
|
+
edges: number;
|
|
2161
|
+
};
|
|
2162
|
+
/** Output mesh statistics */
|
|
2163
|
+
output: {
|
|
2164
|
+
vertices: number;
|
|
2165
|
+
faces: number;
|
|
2166
|
+
edges: number;
|
|
2167
|
+
};
|
|
2168
|
+
/** Statistics for each operation performed */
|
|
2169
|
+
operations: OperationStats[];
|
|
2170
|
+
/** Total processing time in milliseconds */
|
|
2171
|
+
totalTimeMs: number;
|
|
2172
|
+
/** Whether all operations succeeded */
|
|
2173
|
+
success: boolean;
|
|
2174
|
+
/** Total defects found */
|
|
2175
|
+
totalDefectsFound: number;
|
|
2176
|
+
/** Total defects fixed */
|
|
2177
|
+
totalDefectsFixed: number;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
1786
2180
|
/**
|
|
1787
2181
|
* Multiplies a vector by a scalar.
|
|
1788
2182
|
*/
|
|
@@ -2252,6 +2646,17 @@ export declare function triangleNormal(v0: Vec3, v1: Vec3, v2: Vec3): Vec3;
|
|
|
2252
2646
|
*/
|
|
2253
2647
|
export declare function triangleQuality(v0: Vec3, v1: Vec3, v2: Vec3): number;
|
|
2254
2648
|
|
|
2649
|
+
/**
|
|
2650
|
+
* Unify face orientations to make normals consistent.
|
|
2651
|
+
*
|
|
2652
|
+
* @param geometry - Input BufferGeometry
|
|
2653
|
+
* @param options - Repair options with optional seedFaceIndex
|
|
2654
|
+
* @returns Repaired geometry and statistics
|
|
2655
|
+
*/
|
|
2656
|
+
export declare function unifyNormals(geometry: BufferGeometry, options?: RepairOptions & {
|
|
2657
|
+
seedFaceIndex?: number;
|
|
2658
|
+
}): RepairResult;
|
|
2659
|
+
|
|
2255
2660
|
/**
|
|
2256
2661
|
* Validates a BufferGeometry for import.
|
|
2257
2662
|
*
|