-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDcel.js
78 lines (69 loc) · 2.53 KB
/
Dcel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import * as THREE from 'three';
import { Face } from './libs/ConvexHull.js'; // TODO after r145 import from three instead
/**
* Doubly Connected Edge List - DCEL
* For each face in the geometry, contains its half-edges.
* A half-edge has two vertices and its twin half-edge on the adjacent face.
*/
export class Dcel {
constructor(geometry, options) {
const num = geometry.attributes.position.count;
this.vertices = Array.from({ length: num }, (_, i) => {
return {
point: new THREE.Vector3().fromBufferAttribute(geometry.attributes.position, i),
index: i
};
});
const threshold = !options ? 1e-4 : options.mergeVerticesThreshold;
if (threshold) {
const hashToVertex = {}
this.vertices.forEach(v => {
v.origIndex = v.index;
const hash = `${~~(v.point.x / threshold)},${~~(v.point.y / threshold)},${~~(v.point.z / threshold)}`;
if (hash in hashToVertex) {
v.index = hashToVertex[hash];
} else {
hashToVertex[hash] = v.index;
}
});
}
const faceIndices = new THREE.Vector3();
this.faces = Array.from({ length: geometry.index.count / 3 }, (_, i) => {
faceIndices.fromArray(geometry.index.array, i * 3);
const face = Face.create(this.vertices[faceIndices.x], this.vertices[faceIndices.y], this.vertices[faceIndices.z]);
face.index = i;
return face;
});
const hashToEdge = new Map();
this.faces.forEach(face => {
this.forEdges(face, e => {
if (!e.twin) {
const hashInv = e.tail().index * num + e.head().index;
const other = hashToEdge.get(hashInv);
if (other) {
e.setTwin(other);
} else {
const hash = e.head().index * num + e.tail().index;
hashToEdge.set(hash, e);
}
}
});
});
}
forEdges(face, callback) {
const start = face.edge;
let e = start;
while (true) {
callback(e, face, this);
e = e.next;
if (e === start) {
break;
}
}
}
forAdjacentFaces(faceIndex, callback) {
this.forEdges(this.faces[faceIndex], e => {
callback(e.twin.face.index);
});
}
}