File size: 3,727 Bytes
2b7aae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import * as MathUtils from '../math/MathUtils.js';
import { Triangle } from '../math/Triangle.js';
import { Vector3 } from '../math/Vector3.js';

const _v0 = new Vector3();
const _v1 = new Vector3();
const _normal = new Vector3();
const _triangle = new Triangle();

class EdgesGeometry extends BufferGeometry {
	constructor(geometry = null, thresholdAngle = 1) {
		super();
		this.type = 'EdgesGeometry';

		this.parameters = {
			geometry: geometry,
			thresholdAngle: thresholdAngle,
		};

		if (geometry !== null) {
			const precisionPoints = 4;
			const precision = Math.pow(10, precisionPoints);
			const thresholdDot = Math.cos(MathUtils.DEG2RAD * thresholdAngle);

			const indexAttr = geometry.getIndex();
			const positionAttr = geometry.getAttribute('position');
			const indexCount = indexAttr ? indexAttr.count : positionAttr.count;

			const indexArr = [0, 0, 0];
			const vertKeys = ['a', 'b', 'c'];
			const hashes = new Array(3);

			const edgeData = {};
			const vertices = [];
			for (let i = 0; i < indexCount; i += 3) {
				if (indexAttr) {
					indexArr[0] = indexAttr.getX(i);
					indexArr[1] = indexAttr.getX(i + 1);
					indexArr[2] = indexAttr.getX(i + 2);
				} else {
					indexArr[0] = i;
					indexArr[1] = i + 1;
					indexArr[2] = i + 2;
				}

				const { a, b, c } = _triangle;
				a.fromBufferAttribute(positionAttr, indexArr[0]);
				b.fromBufferAttribute(positionAttr, indexArr[1]);
				c.fromBufferAttribute(positionAttr, indexArr[2]);
				_triangle.getNormal(_normal);

				// create hashes for the edge from the vertices
				hashes[0] = `${Math.round(a.x * precision)},${Math.round(a.y * precision)},${Math.round(a.z * precision)}`;
				hashes[1] = `${Math.round(b.x * precision)},${Math.round(b.y * precision)},${Math.round(b.z * precision)}`;
				hashes[2] = `${Math.round(c.x * precision)},${Math.round(c.y * precision)},${Math.round(c.z * precision)}`;

				// skip degenerate triangles
				if (hashes[0] === hashes[1] || hashes[1] === hashes[2] || hashes[2] === hashes[0]) {
					continue;
				}

				// iterate over every edge
				for (let j = 0; j < 3; j++) {
					// get the first and next vertex making up the edge
					const jNext = (j + 1) % 3;
					const vecHash0 = hashes[j];
					const vecHash1 = hashes[jNext];
					const v0 = _triangle[vertKeys[j]];
					const v1 = _triangle[vertKeys[jNext]];

					const hash = `${vecHash0}_${vecHash1}`;
					const reverseHash = `${vecHash1}_${vecHash0}`;

					if (reverseHash in edgeData && edgeData[reverseHash]) {
						// if we found a sibling edge add it into the vertex array if
						// it meets the angle threshold and delete the edge from the map.
						if (_normal.dot(edgeData[reverseHash].normal) <= thresholdDot) {
							vertices.push(v0.x, v0.y, v0.z);
							vertices.push(v1.x, v1.y, v1.z);
						}

						edgeData[reverseHash] = null;
					} else if (!(hash in edgeData)) {
						// if we've already got an edge here then skip adding a new one
						edgeData[hash] = {
							index0: indexArr[j],
							index1: indexArr[jNext],
							normal: _normal.clone(),
						};
					}
				}
			}

			// iterate over all remaining, unmatched edges and add them to the vertex array
			for (const key in edgeData) {
				if (edgeData[key]) {
					const { index0, index1 } = edgeData[key];
					_v0.fromBufferAttribute(positionAttr, index0);
					_v1.fromBufferAttribute(positionAttr, index1);

					vertices.push(_v0.x, _v0.y, _v0.z);
					vertices.push(_v1.x, _v1.y, _v1.z);
				}
			}

			this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
		}
	}
}

export { EdgesGeometry };