@@ -182,7 +182,131 @@ def assembly_to_gmsh(self, mesh_path="tagged_mesh.msh"):
182
182
gmsh .finalize ()
183
183
184
184
185
+ def assembly_to_imprinted_gmsh (self , mesh_path = "tagged_mesh.msh" ):
186
+ """
187
+ Exports an imprinted assembly to capture conformal meshes.
188
+ """
189
+
190
+ gmsh .initialize ()
191
+ gmsh .option .setNumber ("General.Terminal" , 0 )
192
+ gmsh .model .add ("assembly" )
193
+
194
+ # The mesh volume and surface ids should line up with the order of solids and faces in the assembly
195
+ vol_id = 1
196
+ surface_id = 1
197
+
198
+ # Tracks multi-surface physical groups
199
+ multi_material_groups = {}
200
+ surface_groups = {}
201
+
202
+ # Tracks the solids with tagged faces
203
+ tagged_faces = {}
204
+ solids_with_tagged_faces = {}
205
+
206
+ # Imprint the assembly
207
+ imprinted_assembly , imprinted_solids_with_orginal_ids = (
208
+ cq .occ_impl .assembly .imprint (self )
209
+ )
210
+
211
+ print (imprinted_solids_with_orginal_ids )
212
+ for solid , id in imprinted_solids_with_orginal_ids .items ():
213
+ # Add the current solid to the mesh
214
+ # Work-around for a segfault with in-memory passing of OCCT objects
215
+ with tempfile .NamedTemporaryFile (suffix = ".brep" ) as temp_file :
216
+ solid .exportBrep (temp_file .name )
217
+ ps = gmsh .model .occ .importShapes (temp_file .name )
218
+ gmsh .model .occ .synchronize ()
219
+
220
+ # Technically, importShapes could import multiple entities/dimensions, so filter those
221
+ vol_ents = []
222
+ for p in ps :
223
+ if p [0 ] == 3 :
224
+ vol_ents .append (p [1 ])
225
+
226
+ # Set the physical name to be the part name in the assembly for all the solids
227
+ ps2 = gmsh .model .addPhysicalGroup (3 , vol_ents )
228
+ gmsh .model .setPhysicalName (3 , ps2 , f"{ id [0 ].split ('/' )[- 1 ]} " )
229
+
230
+ # Get the original assembly part
231
+ object_name = id [0 ].split ("/" )[- 1 ]
232
+ assembly_part = self .objects [object_name ]
233
+
234
+ # Collect any tags from the part
235
+ for tag , wp in assembly_part .obj .ctx .tags .items ():
236
+ tagged_face = wp .faces ().all ()[0 ].val ()
237
+ for face in wp .faces ().all ():
238
+ tagged_faces [face .val ()] = tag
239
+
240
+ # Iterate over the faces of the assembly part
241
+ for face in assembly_part .obj .faces ():
242
+ for tagged_face , tag in tagged_faces .items ():
243
+ if TopoDS_Shape .IsEqual (face .wrapped , tagged_face .wrapped ):
244
+ print (f"{ vol_id } _{ surface_id } " , tag )
245
+ solids_with_tagged_faces [f"{ vol_id } _{ surface_id } " ] = (
246
+ object_name ,
247
+ tag ,
248
+ )
249
+
250
+ surface_id += 1
251
+ vol_id += 1
252
+
253
+ # Reset the volume and surface IDs
254
+ vol_id = 1
255
+ surface_id = 1
256
+
257
+ # Step through the imprinted assembly/shape and check for tagged faces
258
+ for solid in imprinted_assembly .solids ():
259
+ for face in solid .faces ().Faces ():
260
+ # Check to see if this face has been tagged
261
+ if f"{ vol_id } _{ surface_id } " in solids_with_tagged_faces .keys ():
262
+ short_name = solids_with_tagged_faces [f"{ vol_id } _{ surface_id } " ][0 ]
263
+ tag = solids_with_tagged_faces [f"{ vol_id } _{ surface_id } " ][1 ]
264
+
265
+ # Find out if this is a multi-material tag
266
+ if tag .startswith ("~" ):
267
+ # Set the surface name to be the name of the tag without the ~
268
+ group_name = tag .replace ("~" , "" ).split ("-" )[0 ]
269
+
270
+ # Add this face to the multi-material group
271
+ if group_name in multi_material_groups :
272
+ multi_material_groups [group_name ].append (surface_id )
273
+ else :
274
+ multi_material_groups [group_name ] = [surface_id ]
275
+ else :
276
+ # We want to track all surfaces that might be in a tag group
277
+ cur_tag_name = f"{ short_name } _{ tag } "
278
+ if cur_tag_name in surface_groups :
279
+ print ("Append: " , cur_tag_name , short_name , surface_id )
280
+ surface_groups [cur_tag_name ].append (surface_id )
281
+ else :
282
+ print ("New: " , cur_tag_name , short_name , surface_id )
283
+ surface_groups [cur_tag_name ] = [surface_id ]
284
+
285
+ surface_id += 1
286
+ vol_id += 1
287
+
288
+ # Handle tagged surface groups
289
+ for t_name , surf_group in surface_groups .items ():
290
+ ps = gmsh .model .addPhysicalGroup (2 , surf_group )
291
+ gmsh .model .setPhysicalName (2 , ps , t_name )
292
+
293
+ # Handle multi-material tags
294
+ for group_name , mm_group in multi_material_groups .items ():
295
+ ps = gmsh .model .addPhysicalGroup (2 , mm_group )
296
+ gmsh .model .setPhysicalName (2 , ps , f"{ group_name } " )
297
+
298
+ gmsh .model .occ .synchronize ()
299
+
300
+ gmsh .model .mesh .field .setAsBackgroundMesh (2 )
301
+
302
+ gmsh .model .mesh .generate (3 )
303
+ gmsh .write (mesh_path )
304
+
305
+ gmsh .finalize ()
306
+
307
+
185
308
# Patch the new assembly functions into CadQuery's importers package
186
309
cq .Assembly .assemblyToGmsh = assembly_to_gmsh
187
310
cq .Assembly .saveToGmsh = assembly_to_gmsh # Alias name that works better on cq.Assembly
188
311
cq .Assembly .getTaggedGmsh = get_tagged_gmsh
312
+ cq .Assembly .assemblyToImprintedGmsh = assembly_to_imprinted_gmsh
0 commit comments