Skip to content

Commit 16c91ad

Browse files
Copilotjgphilpott
andcommitted
Add comprehensive documentation for near-parallel edge fix
Co-authored-by: jgphilpott <4128208+jgphilpott@users.noreply.github.com>
1 parent edb1960 commit 16c91ad

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

NEAR_PARALLEL_EDGE_FIX.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Near-Parallel Edge Detection Fix
2+
3+
## Problem
4+
5+
The `sliceIntoLayers` method was failing to generate segments for edges nearly parallel to the slice plane (< 1° angle). This caused gaps in layer slicing (0.60mm - 5.8mm) which prevented closed path formation in 3D printing applications.
6+
7+
## Root Cause
8+
9+
The original implementation used exact floating-point equality checks:
10+
```coffeescript
11+
continue if startDist is 0 and endDist is 0
12+
if startDist is 0
13+
if endDist is 0
14+
```
15+
16+
For edges nearly parallel to the plane, the distances to the plane (`startDist` and `endDist`) are extremely small but non-zero (e.g., 1e-15). These edges were incorrectly skipped, creating gaps in the generated segment chains.
17+
18+
## Solution
19+
20+
Implemented an **angle-aware adaptive epsilon** approach:
21+
22+
### 1. Calculate Edge Angle
23+
```coffeescript
24+
edgeDir = edgeVector.clone().divideScalar(edgeLength)
25+
dotWithNormal = Math.abs(edgeDir.dot(planeNormal))
26+
```
27+
28+
The dot product between the edge direction and plane normal indicates how parallel the edge is to the plane:
29+
- `dotWithNormal ≈ 0`: Edge is parallel to plane
30+
- `dotWithNormal ≈ 1`: Edge is perpendicular to plane
31+
32+
### 2. Adaptive Epsilon Calculation
33+
```coffeescript
34+
baseEpsilon = Math.max(1e-10, edgeLength * 1e-9)
35+
angleFactor = if dotWithNormal < 0.02 then 100.0 else 1.0
36+
epsilon = baseEpsilon * angleFactor
37+
```
38+
39+
- **Base epsilon**: Scales with edge length to handle floating-point precision errors
40+
- **Angle factor**: For near-parallel edges (< ~1° angle), increase epsilon by 100x
41+
- **Final epsilon**: Product of base and angle factor
42+
43+
### 3. Epsilon-Based Comparisons
44+
```coffeescript
45+
absStartDist = Math.abs(startDist)
46+
absEndDist = Math.abs(endDist)
47+
48+
# Skip edges entirely in plane
49+
continue if absStartDist < epsilon and absEndDist < epsilon
50+
51+
# Check if edge crosses or touches plane
52+
if absStartDist < epsilon
53+
# Start point on or very near plane
54+
if absEndDist < epsilon
55+
# End point on or very near plane
56+
```
57+
58+
## Test Coverage
59+
60+
Added 4 comprehensive test cases:
61+
62+
1. **Near-parallel edges**: Edges with vertices within 2e-7 of plane
63+
2. **Very small distances**: Tests 1e-10 precision floating-point errors
64+
3. **Duplicate detection**: Ensures epsilon tolerance doesn't create duplicates
65+
4. **Long edges**: Tests 200+ unit edges with scaled epsilon
66+
67+
All 507 tests pass (503 existing + 4 new).
68+
69+
## Impact
70+
71+
This fix ensures:
72+
- ✅ Edges nearly parallel to slice plane are correctly detected
73+
- ✅ Long edges with accumulated floating-point errors are handled
74+
- ✅ Backward compatible - existing functionality unchanged
75+
- ✅ Resolves gaps in layer slicing for complex geometries (e.g., Benchy model)
76+
77+
## Example
78+
79+
```javascript
80+
const Polytree = require('@jgphilpott/polytree');
81+
82+
// Create geometry with near-parallel edges
83+
const geometry = createGeometryWithNearParallelEdges();
84+
const mesh = new THREE.Mesh(geometry, material);
85+
86+
// Slice at Z=1.0 - now correctly handles near-parallel edges
87+
const layers = Polytree.sliceIntoLayers(mesh, 0.2, 0, 2);
88+
```
89+
90+
Before fix: Missing segments, gaps in paths
91+
After fix: Complete segment chains, closed paths
92+
93+
## References
94+
95+
- Issue analysis: [polyslice PR #69 comment](https://github.com/jgphilpott/polyslice/pull/69#issuecomment-3538692023)
96+
- Performance report: POLYTREE_PERFORMANCE_REPORT.md in polyslice PR #69
97+
- Benchmark analysis: BENCHMARK_SUMMARY.md in polyslice PR #69

0 commit comments

Comments
 (0)