Skip to content

Commit d5df2b3

Browse files
fix: restore STLExporter (#321)
1 parent 4f06413 commit d5df2b3

File tree

3 files changed

+187
-195
lines changed

3 files changed

+187
-195
lines changed

src/exporters/STLExporter.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Object3D } from 'three'
2+
3+
export interface STLExporterOptionsBinary {
4+
binary: true
5+
}
6+
7+
export interface STLExporterOptionsString {
8+
binary?: false
9+
}
10+
11+
export interface STLExporterOptions {
12+
binary?: boolean
13+
}
14+
15+
export class STLExporter {
16+
constructor()
17+
18+
parse(scene: Object3D, options: STLExporterOptionsBinary): DataView
19+
parse(scene: Object3D, options?: STLExporterOptionsString): string
20+
parse(scene: Object3D, options?: STLExporterOptions): string | DataView
21+
}

src/exporters/STLExporter.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import { Vector3 } from 'three'
2+
3+
/**
4+
* Usage:
5+
* const exporter = new STLExporter();
6+
*
7+
* // second argument is a list of options
8+
* const data = exporter.parse( mesh, { binary: true } );
9+
*
10+
*/
11+
12+
class STLExporter {
13+
parse(scene, options = {}) {
14+
options = Object.assign(
15+
{
16+
binary: false,
17+
},
18+
options,
19+
)
20+
21+
const binary = options.binary
22+
23+
//
24+
25+
const objects = []
26+
let triangles = 0
27+
28+
scene.traverse(function (object) {
29+
if (object.isMesh) {
30+
const geometry = object.geometry
31+
32+
const index = geometry.index
33+
const positionAttribute = geometry.getAttribute('position')
34+
35+
triangles += index !== null ? index.count / 3 : positionAttribute.count / 3
36+
37+
objects.push({
38+
object3d: object,
39+
geometry: geometry,
40+
})
41+
}
42+
})
43+
44+
let output
45+
let offset = 80 // skip header
46+
47+
if (binary === true) {
48+
const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4
49+
const arrayBuffer = new ArrayBuffer(bufferLength)
50+
output = new DataView(arrayBuffer)
51+
output.setUint32(offset, triangles, true)
52+
offset += 4
53+
} else {
54+
output = ''
55+
output += 'solid exported\n'
56+
}
57+
58+
const vA = new Vector3()
59+
const vB = new Vector3()
60+
const vC = new Vector3()
61+
const cb = new Vector3()
62+
const ab = new Vector3()
63+
const normal = new Vector3()
64+
65+
for (let i = 0, il = objects.length; i < il; i++) {
66+
const object = objects[i].object3d
67+
const geometry = objects[i].geometry
68+
69+
const index = geometry.index
70+
const positionAttribute = geometry.getAttribute('position')
71+
72+
if (index !== null) {
73+
// indexed geometry
74+
75+
for (let j = 0; j < index.count; j += 3) {
76+
const a = index.getX(j + 0)
77+
const b = index.getX(j + 1)
78+
const c = index.getX(j + 2)
79+
80+
writeFace(a, b, c, positionAttribute, object)
81+
}
82+
} else {
83+
// non-indexed geometry
84+
85+
for (let j = 0; j < positionAttribute.count; j += 3) {
86+
const a = j + 0
87+
const b = j + 1
88+
const c = j + 2
89+
90+
writeFace(a, b, c, positionAttribute, object)
91+
}
92+
}
93+
}
94+
95+
if (binary === false) {
96+
output += 'endsolid exported\n'
97+
}
98+
99+
return output
100+
101+
function writeFace(a, b, c, positionAttribute, object) {
102+
vA.fromBufferAttribute(positionAttribute, a)
103+
vB.fromBufferAttribute(positionAttribute, b)
104+
vC.fromBufferAttribute(positionAttribute, c)
105+
106+
if (object.isSkinnedMesh === true) {
107+
object.applyBoneTransform(a, vA)
108+
object.applyBoneTransform(b, vB)
109+
object.applyBoneTransform(c, vC)
110+
}
111+
112+
vA.applyMatrix4(object.matrixWorld)
113+
vB.applyMatrix4(object.matrixWorld)
114+
vC.applyMatrix4(object.matrixWorld)
115+
116+
writeNormal(vA, vB, vC)
117+
118+
writeVertex(vA)
119+
writeVertex(vB)
120+
writeVertex(vC)
121+
122+
if (binary === true) {
123+
output.setUint16(offset, 0, true)
124+
offset += 2
125+
} else {
126+
output += '\t\tendloop\n'
127+
output += '\tendfacet\n'
128+
}
129+
}
130+
131+
function writeNormal(vA, vB, vC) {
132+
cb.subVectors(vC, vB)
133+
ab.subVectors(vA, vB)
134+
cb.cross(ab).normalize()
135+
136+
normal.copy(cb).normalize()
137+
138+
if (binary === true) {
139+
output.setFloat32(offset, normal.x, true)
140+
offset += 4
141+
output.setFloat32(offset, normal.y, true)
142+
offset += 4
143+
output.setFloat32(offset, normal.z, true)
144+
offset += 4
145+
} else {
146+
output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'
147+
output += '\t\touter loop\n'
148+
}
149+
}
150+
151+
function writeVertex(vertex) {
152+
if (binary === true) {
153+
output.setFloat32(offset, vertex.x, true)
154+
offset += 4
155+
output.setFloat32(offset, vertex.y, true)
156+
offset += 4
157+
output.setFloat32(offset, vertex.z, true)
158+
offset += 4
159+
} else {
160+
output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'
161+
}
162+
}
163+
}
164+
}
165+
166+
export { STLExporter }

src/exporters/STLExporter.ts

Lines changed: 0 additions & 195 deletions
This file was deleted.

0 commit comments

Comments
 (0)