Skip to content

Commit 854a7b9

Browse files
committed
speed up brep meshing with lower quality
1 parent e44670b commit 854a7b9

File tree

2 files changed

+50
-45
lines changed

2 files changed

+50
-45
lines changed

packages/freecad/src/main.ts

+45-40
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ export class FreeCADObject {
2828
public label: string
2929
public visibility: boolean
3030

31-
public shape_file: string
31+
public brep: string
3232

3333
constructor(public name: string, public type: string) {}
3434

35-
hasShapeBRep() {
36-
if (this.shape_file) {
35+
isVisible() {
36+
if (this.brep) {
3737
return this.visibility === undefined || this.visibility
3838
} else {
3939
for (const child of this.group || []) {
40-
if (child.hasShapeBRep()) {
40+
if (child.isVisible()) {
4141
return true
4242
}
4343
}
@@ -56,36 +56,39 @@ function traverse(object: Object3D, material: MeshStandardMaterial) {
5656
}
5757

5858
export async function parseFCStdModel(data: ReadableStream | BlobReader, brep2Glb: (content: string) => Promise<Uint8Array>) {
59-
const diffuse: {[name: string]: MeshStandardMaterial[]} = {}
59+
// Data stuctures
60+
const colors: {[name: string]: MeshStandardMaterial[]} = {}
6061
const breps: {[name: string]: Entry} = {}
62+
const gltfs: {[name: string]: GLTF} = {}
63+
// Main document
6164
let doc: FreeCADDocument
65+
// Read ZIP file
6266
const reader = new ZipReader(data)
63-
const parser = new DOMParser()
64-
// Read files in ZIP archive
6567
const entries = await reader.getEntries()
6668
for (const entry of entries) {
67-
//console.log(entry.filename)
68-
// Check file type
6969
if (entry.filename == 'Document.xml') {
70-
// Parse XML file
70+
// Read main document
7171
const writer = new TextWriter()
7272
const content = await entry.getData(writer)
73+
const parser = new DOMParser()
7374
const document = parser.parseFromString(content, 'application/xml')
7475
doc = parseFCStdDocument(document)
7576
} else if (entry.filename.startsWith('DiffuseColor')) {
77+
// Read color specification
7678
const writer = new Uint8ArrayWriter()
7779
const content = await entry.getData(writer)
78-
diffuse[entry.filename] = []
80+
colors[entry.filename] = []
7981
for (let i = 1; i < content.length / 4; i++) {
8082
const a = 1 - content[i * 4 + 0] / 255
8183
const b = 1 - content[i * 4 + 1] / 255
8284
const g = 1 - content[i * 4 + 2] / 255
8385
const r = 1 - content[i * 4 + 3] / 255
8486
const color = new Color(r, g, b)
8587
const material = new MeshStandardMaterial({ color, opacity: a })
86-
diffuse[entry.filename].push(material)
88+
colors[entry.filename].push(material)
8789
}
8890
} else if (entry.filename.endsWith('.brp')) {
91+
// Remember brep entry
8992
breps[entry.filename] = entry
9093
}
9194
}
@@ -96,57 +99,59 @@ export async function parseFCStdModel(data: ReadableStream | BlobReader, brep2Gl
9699
delete doc.objects[object.name]
97100
}
98101
}
99-
// Log result
100-
console.log(doc)
101102
// Convert to THREEJS
102103
const model = new Group()
103104
model.name = doc.label
104105
model.rotateX(-Math.PI / 2)
105106
for (const obj of Object.values(doc.objects)) {
106-
if (obj.hasShapeBRep()) {
107-
model.add(await convertFCObject(obj, diffuse, breps, brep2Glb))
107+
if (obj.isVisible()) {
108+
model.add(await convertFCObject(obj, colors, breps, gltfs, brep2Glb))
108109
}
109110
}
110111
return model
111112
}
112113

113-
async function convertFCObject(obj: FreeCADObject, diffuse: {[name: string]: MeshStandardMaterial[]}, breps: {[name: string]: Entry}, brep2Glb: (content: string) => Promise<Uint8Array>) {
114+
async function convertFCObject(obj: FreeCADObject, colors: {[name: string]: MeshStandardMaterial[]}, breps: {[name: string]: Entry}, gltfs: {[name: string]: GLTF}, brep2Glb: (content: string) => Promise<Uint8Array>) {
114115
const container = new Group()
115116
container.name = obj.label
116-
117-
if (obj.shape_file) {
117+
if (obj.brep) {
118118
try {
119-
// Parse BRep file
120-
const entry = breps[obj.shape_file]
121-
const writer = new TextWriter()
122-
const content = await entry.getData(writer)
123-
console.log('Parsing', entry.filename)
124-
const glbFileData = await brep2Glb(content)
125-
const gltf = await new Promise<GLTF>((resolve, reject) => {
126-
GLTF.parse(glbFileData.buffer, undefined, resolve, reject)
127-
})
128-
const clone = gltf.scene.clone(true)
119+
const file = obj.brep
120+
// Parse brep
121+
if (!(file in gltfs)) {
122+
const entry = breps[obj.brep]
123+
const writer = new TextWriter()
124+
const content = await entry.getData(writer)
125+
console.log('Converting', file)
126+
const data = await brep2Glb(content)
127+
console.log('Parsing', file)
128+
gltfs[file] = await new Promise<GLTF>((resolve, reject) => {
129+
GLTF.parse(data.buffer, undefined, resolve, reject)
130+
})
131+
}
132+
// Clone scene
133+
const face = gltfs[file].scene.clone(true)
134+
const wire = gltfs[file].scene.clone(true)
129135
// Update mesh materials
130-
const other = entry.filename.replace('PartShape', 'DiffuseColor').replace('.brp', '')
131-
if (other in diffuse) {
132-
const material = diffuse[other][0]
133-
traverse(gltf.scene, material)
136+
const other = file.replace('PartShape', 'DiffuseColor').replace('.brp', '')
137+
if (other in colors) {
138+
const material = colors[other][0]
139+
traverse(face, material)
134140
}
135-
traverse(clone, new MeshStandardMaterial({ color: 'black', wireframe: true }))
141+
traverse(wire, new MeshStandardMaterial({ color: 'black', wireframe: true }))
136142
// Add scene objects
137-
container.add(clone)
138-
container.add(gltf.scene)
143+
container.add(face)
144+
container.add(wire)
139145
} catch (e) {
140146
console.log(e)
141147
}
142148
} else if (obj.group) {
143149
for (const child of obj.group) {
144-
if (child.hasShapeBRep()) {
145-
container.add(await convertFCObject(child, diffuse, breps, brep2Glb))
150+
if (child.isVisible()) {
151+
container.add(await convertFCObject(child, colors, breps, gltfs, brep2Glb))
146152
}
147153
}
148154
}
149-
150155
return container
151156
}
152157

@@ -226,7 +231,7 @@ function parseFCStdDocumentObjectProperty(data: Element, obj: FreeCADObject, doc
226231
} else if (name == 'Shape') {
227232
if (type == 'Part::PropertyPartShape') {
228233
const child = data.getElementsByTagName('Part')[0]
229-
obj.shape_file = child.getAttribute('file')
234+
obj.brep = child.getAttribute('file')
230235
} else if (type == 'App::PropertyLink') {
231236
const child = data.getElementsByTagName('LinkSub')[0]
232237
const other = doc.objects[child.getAttribute('value')]

packages/worker/src/main.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ addEventListener('message', async message => {
1616
const occt = await OCCT
1717

1818
// Parse shape
19-
//console.log('Reading BRep')
19+
console.log('Reading BRep')
2020
const shape = new occt.TopoDS_Shape()
2121
occt.FS.createDataFile('.', 'part.brp', content, true, true, true)
2222
const builder = new occt.BRep_Builder()
@@ -25,15 +25,15 @@ addEventListener('message', async message => {
2525
occt.FS.unlink('./part.brp')
2626

2727
// Visualize shape
28-
//console.log('Meshing BRep')
28+
console.log('Meshing BRep')
2929
const storageformat = new occt.TCollection_ExtendedString_1()
3030
const doc = new occt.TDocStd_Document(storageformat)
3131
const shapeTool = occt.XCAFDoc_DocumentTool.ShapeTool(doc.Main()).get()
3232
shapeTool.SetShape(shapeTool.NewShape(), shape)
33-
new occt.BRepMesh_IncrementalMesh_2(shape, 0.1, false, 0.1, false)
33+
new occt.BRepMesh_IncrementalMesh_2(shape, 1, false, 1, false)
3434

3535
// Export a GLB file (this will also perform the meshing)
36-
//console.log('Writing GLB')
36+
console.log('Writing GLB')
3737
const glbFileName = new occt.TCollection_AsciiString_2('./part.glb')
3838
const cafWriter = new occt.RWGltf_CafWriter(glbFileName, true)
3939
const docHandle = new occt.Handle_TDocStd_Document_2(doc)
@@ -42,7 +42,7 @@ addEventListener('message', async message => {
4242
cafWriter.Perform_2(docHandle, fileInfo, writeProgress)
4343

4444
// Read the GLB file from the virtual file system
45-
//console.log('Readling GLB')
45+
console.log('Readling GLB')
4646
const glbFileData = occt.FS.readFile('./part.glb', { encoding: "binary" })
4747
occt.FS.unlink('./part.glb')
4848

0 commit comments

Comments
 (0)