diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d85fc92..0ed520e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,5 +40,6 @@ jobs: - name: Install dependencies run: | python -m pip install .[dev] + python -m pip install --upgrade git+https://github.com/CadQuery/cadquery.git - name: Run tests run: python -m pytest -v diff --git a/assembly_mesh_plugin/plugin.py b/assembly_mesh_plugin/plugin.py index 3743372..5620938 100644 --- a/assembly_mesh_plugin/plugin.py +++ b/assembly_mesh_plugin/plugin.py @@ -161,6 +161,7 @@ def get_gmsh(self, imprint=True): tagged_faces = {} multi_material_groups = {} surface_groups = {} + solid_materials = [] gmsh.initialize() gmsh.option.setNumber( @@ -171,13 +172,23 @@ def get_gmsh(self, imprint=True): # Get all of the subshapes and their corresponding names/positions extract_subshape_names(self, self.name) - # Imprint the assembly - imprinted_assembly, imprinted_solids_with_orginal_ids = ( - cq.occ_impl.assembly.imprint(self) - ) - # Handle the imprinted assembly if imprint: + # Imprint the assembly + imprinted_assembly, imprinted_solids_with_orginal_ids = ( + cq.occ_impl.assembly.imprint(self) + ) + + # Collect the materials + for imp_solid, solid_id in imprinted_solids_with_orginal_ids.items(): + # Track down the original assembly object so that we can retrieve materials, if present + short_id = solid_id[0].split("/")[-1] if "/" in solid_id[0] else solid_id[0] + subassy = self.objects[short_id] + + # Save the assembly material associated with this solid + if subassy.material: + solid_materials.append(subassy.material.name) + for solid, name in imprinted_solids_with_orginal_ids.items(): # Get just the name of the current assembly short_name = name[0].split("/")[-1] @@ -202,12 +213,23 @@ def get_gmsh(self, imprint=True): # Add faces to the mesh and handle tagged faces add_faces_to_mesh(gmsh, solid, short_name, loc) + # Keep track of the materials + if self.objects[name.split("/")[-1]].material: + solid_materials.append(self.objects[name.split("/")[-1]].material.name) + # Step through each of the volumes and add physical groups for each for volume_id in volumes.keys(): gmsh.model.occ.synchronize() + + # Attach the name to the volume ps = gmsh.model.addPhysicalGroup(3, volumes[volume_id][0]) gmsh.model.setPhysicalName(3, ps, f"{volume_map[volume_id]}") + # Attach the material to the volume, if the material is present + if len(solid_materials) >= volume_id: + ps1 = gmsh.model.addPhysicalGroup(3, volumes[volume_id][0]) + gmsh.model.setPhysicalName(3, ps1, f"mat:{solid_materials[volume_id - 1]}") + # Handle tagged surface groups for t_name, surf_group in surface_groups.items(): gmsh.model.occ.synchronize() diff --git a/pyproject.toml b/pyproject.toml index ac64ade..233ad32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" name = "assembly_mesh_plugin" version = "0.1.4" dependencies = [ - "cadquery>=2.6.0", + "cadquery>=2.7.0", "gmsh", ] requires-python = ">=3.9" diff --git a/tests/sample_assemblies.py b/tests/sample_assemblies.py index 4e546c6..e99140f 100644 --- a/tests/sample_assemblies.py +++ b/tests/sample_assemblies.py @@ -315,3 +315,20 @@ def generate_subshape_assembly(): ) return assy + + +def generate_materials_assembly(): + """ + Generates a simple assembly with materials. + """ + + # Create the assembly children + cube_1 = cq.Workplane().box(10, 10, 10) + cube_2 = cq.Workplane().box(5, 5, 5) + + # Put the assembly together + assy = cq.Assembly(name="top-level") + assy.add(cube_1, name="cube_1", material="copper") + assy.add(cube_2, name="cube_2", loc=cq.Location(0, 0, 5), material="steel") + + return assy diff --git a/tests/test_meshes.py b/tests/test_meshes.py index 24485c9..7a9e226 100644 --- a/tests/test_meshes.py +++ b/tests/test_meshes.py @@ -8,6 +8,7 @@ generate_test_cross_section, generate_assembly, generate_subshape_assembly, + generate_materials_assembly, ) @@ -175,3 +176,48 @@ def _check_physical_groups(): # Ensure that there are physical groups _check_physical_groups() + + +def test_mesh_materials(): + """ + Tests to make sure that assembly materials are preserved in the mesh data. + """ + + # Create the basic assembly with materials + assy = generate_materials_assembly() + + # + # Imprinted assembly + # + gmsh = assy.getGmsh(imprint=True) + gmsh.model.mesh.generate(3) + + phys_groups = gmsh.model.getPhysicalGroups(3) + + # Make sure we got the correct names + name = gmsh.model.getPhysicalName(3, 1) + assert name == "cube_1" + name = gmsh.model.getPhysicalName(3, 2) + assert name == "mat:copper" + name = gmsh.model.getPhysicalName(3, 3) + assert name == "cube_2" + name = gmsh.model.getPhysicalName(3, 4) + assert name == "mat:steel" + + # + # Non-imprinted assembly + # + gmsh = assy.getGmsh(imprint=False) + gmsh.model.mesh.generate(3) + + phys_groups = gmsh.model.getPhysicalGroups(3) + + # Make sure we got the correct names + name = gmsh.model.getPhysicalName(3, 1) + assert name == "cube_1" + name = gmsh.model.getPhysicalName(3, 2) + assert name == "mat:copper" + name = gmsh.model.getPhysicalName(3, 3) + assert name == "cube_2" + name = gmsh.model.getPhysicalName(3, 4) + assert name == "mat:steel"