@@ -182,7 +182,131 @@ def assembly_to_gmsh(self, mesh_path="tagged_mesh.msh"):
182182 gmsh .finalize ()
183183
184184
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+
185308# Patch the new assembly functions into CadQuery's importers package
186309cq .Assembly .assemblyToGmsh = assembly_to_gmsh
187310cq .Assembly .saveToGmsh = assembly_to_gmsh # Alias name that works better on cq.Assembly
188311cq .Assembly .getTaggedGmsh = get_tagged_gmsh
312+ cq .Assembly .assemblyToImprintedGmsh = assembly_to_imprinted_gmsh
0 commit comments