File size: 2,750 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
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';

class WireframeGeometry extends BufferGeometry {
	constructor(geometry = null) {
		super();
		this.type = 'WireframeGeometry';

		this.parameters = {
			geometry: geometry,
		};

		if (geometry !== null) {
			// buffer

			const vertices = [];
			const edges = new Set();

			// helper variables

			const start = new Vector3();
			const end = new Vector3();

			if (geometry.index !== null) {
				// indexed BufferGeometry

				const position = geometry.attributes.position;
				const indices = geometry.index;
				let groups = geometry.groups;

				if (groups.length === 0) {
					groups = [{ start: 0, count: indices.count, materialIndex: 0 }];
				}

				// create a data structure that contains all eges without duplicates

				for (let o = 0, ol = groups.length; o < ol; ++o) {
					const group = groups[o];

					const groupStart = group.start;
					const groupCount = group.count;

					for (let i = groupStart, l = groupStart + groupCount; i < l; i += 3) {
						for (let j = 0; j < 3; j++) {
							const index1 = indices.getX(i + j);
							const index2 = indices.getX(i + ((j + 1) % 3));

							start.fromBufferAttribute(position, index1);
							end.fromBufferAttribute(position, index2);

							if (isUniqueEdge(start, end, edges) === true) {
								vertices.push(start.x, start.y, start.z);
								vertices.push(end.x, end.y, end.z);
							}
						}
					}
				}
			} else {
				// non-indexed BufferGeometry

				const position = geometry.attributes.position;

				for (let i = 0, l = position.count / 3; i < l; i++) {
					for (let j = 0; j < 3; j++) {
						// three edges per triangle, an edge is represented as (index1, index2)
						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)

						const index1 = 3 * i + j;
						const index2 = 3 * i + ((j + 1) % 3);

						start.fromBufferAttribute(position, index1);
						end.fromBufferAttribute(position, index2);

						if (isUniqueEdge(start, end, edges) === true) {
							vertices.push(start.x, start.y, start.z);
							vertices.push(end.x, end.y, end.z);
						}
					}
				}
			}

			// build geometry

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

function isUniqueEdge(start, end, edges) {
	const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;
	const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge

	if (edges.has(hash1) === true || edges.has(hash2) === true) {
		return false;
	} else {
		edges.add(hash1, hash2);
		return true;
	}
}

export { WireframeGeometry };