Adding unittests for Mesher class

This commit is contained in:
gumyr 2023-08-10 14:24:05 -04:00
parent 582a07c104
commit bc6189f448
2 changed files with 199 additions and 22 deletions

View file

@ -217,38 +217,42 @@ class Mesher:
must_preserve=False,
)
def get_meta_data(self) -> list[str]:
def get_meta_data(self) -> list[dict]:
"""Retrieve all of the metadata"""
meta_data_group = self.model.GetMetaDataGroup()
meta_data_contents = []
for i in range(meta_data_group.GetMetaDataCount()):
meta_data = meta_data_group.GetMetaData(i)
meta_data_contents.append(f"Name Space: {meta_data.GetNameSpace()}")
meta_data_contents.append(f"Name: {meta_data.GetName()}")
meta_data_contents.append(f"Type: {meta_data.GetType()}")
meta_data_contents.append(f"Value: {meta_data.GetValue()}")
meta_data_dict = {}
meta_data_dict["name_space"] = meta_data.GetNameSpace()
meta_data_dict["name"] = meta_data.GetName()
meta_data_dict["type"] = meta_data.GetType()
meta_data_dict["value"] = meta_data.GetValue()
meta_data_contents.append(meta_data_dict)
return meta_data_contents
def get_meta_data_by_key(self, name_space: str, name: str) -> list[str]:
def get_meta_data_by_key(self, name_space: str, name: str) -> dict:
"""Retrive the metadata value and type for the provided name space and name"""
meta_data_group = self.model.GetMetaDataGroup()
meta_data_contents = []
meta_data_contents = {}
meta_data = meta_data_group.GetMetaDataByKey(name_space, name)
meta_data_contents.append(f"Type: {meta_data.GetType()}")
meta_data_contents.append(f"Value: {meta_data.GetValue()}")
meta_data_contents["type"] = meta_data.GetType()
meta_data_contents["value"] = meta_data.GetValue()
return meta_data_contents
def get_mesh_properties(self) -> list[str]:
def get_mesh_properties(self) -> list[dict]:
"""Retrieve the properties from all the meshes"""
properties = []
for mesh in self.meshes:
properties += f"Name: {mesh.GetName()}"
properties += f"Part Number: {mesh.GetPartNumber()}"
property_dict = {}
property_dict["name"] = mesh.GetName()
property_dict["part_number"] = mesh.GetPartNumber()
type_3mf = Lib3MF.ObjectType(mesh.GetType())
properties += f"Type: {Mesher._map_3mf_to_b3d_mesh_type[type_3mf].name}"
uuid_valid, uuid_value = mesh.GetUUID()
if uuid_valid:
properties += f"UUID: {uuid_value}"
property_dict["type"] = Mesher._map_3mf_to_b3d_mesh_type[type_3mf].name
_uuid_valid, uuid_value = mesh.GetUUID()
property_dict["uuid"] = uuid_value # are bad values possible?
properties.append(property_dict)
return properties
@staticmethod
def _is_facet_forward(
@ -424,7 +428,10 @@ class Mesher:
ocp_mesh_vertices, triangles, b3d_shape.center()
)
# Add the meta data
# Build the mesh
mesh_3mf.SetGeometry(vertices_3mf, triangles_3mf)
# Add the mesh properties
mesh_3mf.SetType(Mesher._map_b3d_mesh_type_3mf[mesh_type])
if b3d_shape.label:
mesh_3mf.SetName(b3d_shape.label)
@ -435,9 +442,6 @@ class Mesher:
# mesh_3mf.SetAttachmentAsThumbnail
# mesh_3mf.SetPackagePart
# Create the mesh
mesh_3mf.SetGeometry(vertices_3mf, triangles_3mf)
# Add color
self._add_color(b3d_shape, mesh_3mf)
@ -514,6 +518,7 @@ class Mesher:
for mesh in self.meshes:
shape = self._get_shape(mesh)
shape.label = mesh.GetName()
# Extract color
color_indices = []
for triangle_property in mesh.GetAllTriangleProperties():
color_indices.extend(
@ -523,9 +528,13 @@ class Mesher:
]
)
unique_color_indices = list(set(color_indices))
try:
color_group = self.model.GetColorGroupByID(unique_color_indices[0][0])
except:
shapes.append(shape) # There are no colors
continue
if len(unique_color_indices) > 1:
warnings.warn("Warning multiple colors found on mesh - one used")
color_group = self.model.GetColorGroupByID(unique_color_indices[0][0])
warnings.warn("Warning multiple colors found on mesh - only one used")
color_3mf = color_group.GetColor(unique_color_indices[0][1])
color = (color_3mf.Red, color_3mf.Green, color_3mf.Blue, color_3mf.Alpha)
color = (c / 255.0 for c in color)

168
tests/test_mesher.py Normal file
View file

@ -0,0 +1,168 @@
import os, unittest, uuid
from build123d.build_enums import MeshType, Unit
from build123d.topology import Compound, Solid
from build123d.geometry import Color, Vector, VectorLike, Location
from build123d.mesher import Mesher
class DirectApiTestCase(unittest.TestCase):
def assertTupleAlmostEquals(
self,
first: tuple[float, ...],
second: tuple[float, ...],
places: int,
msg: str = None,
):
"""Check Tuples"""
self.assertEqual(len(second), len(first))
for i, j in zip(second, first):
self.assertAlmostEqual(i, j, places, msg=msg)
def assertVectorAlmostEquals(
self, first: Vector, second: VectorLike, places: int, msg: str = None
):
second_vector = Vector(second)
self.assertAlmostEqual(first.X, second_vector.X, places, msg=msg)
self.assertAlmostEqual(first.Y, second_vector.Y, places, msg=msg)
self.assertAlmostEqual(first.Z, second_vector.Z, places, msg=msg)
class TestProperties(unittest.TestCase):
def test_version(self):
exporter = Mesher()
self.assertEqual(exporter.library_version, "2.2.0")
def test_units(self):
for unit in Unit:
exporter = Mesher(unit=unit)
exporter.add_shape(Solid.make_box(1, 1, 1))
exporter.write("test.3mf")
importer = Mesher()
_shape = importer.read("test.3mf")
self.assertEqual(unit, importer.model_unit)
def test_vertex_and_triangle_counts(self):
exporter = Mesher()
exporter.add_shape(Solid.make_box(1, 1, 1))
self.assertEqual(exporter.vertex_counts[0], 8)
self.assertEqual(exporter.triangle_counts[0], 12)
def test_mesh_counts(self):
exporter = Mesher()
exporter.add_shape(Solid.make_box(1, 1, 1))
exporter.add_shape(Solid.make_cone(1, 0, 2))
self.assertEqual(exporter.mesh_count, 2)
class TestMetaData(unittest.TestCase):
def test_add_meta_data(self):
exporter = Mesher()
exporter.add_shape(Solid.make_box(1, 1, 1))
exporter.add_meta_data("test_space", "test0", "some data", "str", True)
exporter.add_meta_data("test_space", "test1", "more data", "str", True)
exporter.write("test.3mf")
importer = Mesher()
_shape = importer.read("test.3mf")
imported_meta_data: list[dict] = importer.get_meta_data()
self.assertEqual(imported_meta_data[0]["name_space"], "test_space")
self.assertEqual(imported_meta_data[0]["name"], "test0")
self.assertEqual(imported_meta_data[0]["value"], "some data")
self.assertEqual(imported_meta_data[0]["type"], "str")
self.assertEqual(imported_meta_data[1]["name_space"], "test_space")
self.assertEqual(imported_meta_data[1]["name"], "test1")
self.assertEqual(imported_meta_data[1]["value"], "more data")
self.assertEqual(imported_meta_data[1]["type"], "str")
def test_add_code(self):
exporter = Mesher()
exporter.add_shape(Solid.make_box(1, 1, 1))
exporter.add_code_to_metadata()
exporter.write("test.3mf")
importer = Mesher()
_shape = importer.read("test.3mf")
source_code = importer.get_meta_data_by_key("build123d", "test_mesher.py")
self.assertEqual(len(source_code), 2)
self.assertEqual(source_code["type"], "python")
self.assertGreater(len(source_code["value"]), 10)
class TestMeshProperties(unittest.TestCase):
def test_properties(self):
# Note: MeshType.OTHER can't be used with a Solid shape
for mesh_type in [MeshType.MODEL, MeshType.SUPPORT, MeshType.SOLIDSUPPORT]:
with self.subTest("MeshTYpe", mesh_type=mesh_type):
exporter = Mesher()
if mesh_type != MeshType.SUPPORT:
test_uuid = uuid.uuid1()
else:
test_uuid = None
name = "test" + mesh_type.name
shape = Solid.make_box(1, 1, 1)
shape.label = name
exporter.add_shape(
shape,
mesh_type=mesh_type,
part_number=str(mesh_type.value),
uuid_value=test_uuid,
)
exporter.write("test.3mf")
importer = Mesher()
shape = importer.read("test.3mf")
self.assertEqual(shape[0].label, name)
self.assertEqual(importer.mesh_count, 1)
properties = importer.get_mesh_properties()
self.assertEqual(properties[0]["name"], name)
self.assertEqual(properties[0]["part_number"], str(mesh_type.value))
self.assertEqual(properties[0]["type"], mesh_type.name)
if mesh_type != MeshType.SUPPORT:
self.assertEqual(properties[0]["uuid"], str(test_uuid))
class TestAddShape(DirectApiTestCase):
def test_add_shape(self):
exporter = Mesher()
blue_shape = Solid.make_box(1, 1, 1)
blue_shape.color = Color("blue")
blue_shape.label = "blue"
red_shape = Solid.make_cone(1, 0, 2).locate(Location((0, -1, 0)))
red_shape.color = Color("red")
red_shape.label = "red"
exporter.add_shape([blue_shape, red_shape])
exporter.write("test.3mf")
importer = Mesher()
box, cone = importer.read("test.3mf")
self.assertVectorAlmostEquals(box.bounding_box().size, (1, 1, 1), 2)
self.assertVectorAlmostEquals(box.bounding_box().size, (1, 1, 1), 2)
self.assertEqual(len(box.clean().faces()), 6)
self.assertEqual(box.label, "blue")
self.assertEqual(cone.label, "red")
self.assertTupleAlmostEquals(box.color.to_tuple(), (0, 0, 1, 1), 5)
self.assertTupleAlmostEquals(cone.color.to_tuple(), (1, 0, 0, 1), 5)
def test_add_compound(self):
exporter = Mesher()
box = Solid.make_box(1, 1, 1)
cone = Solid.make_cone(1, 0, 2).locate(Location((0, -1, 0)))
shape_assembly = Compound.make_compound([box, cone])
exporter.add_shape(shape_assembly)
exporter.write("test.3mf")
importer = Mesher()
shapes = importer.read("test.3mf")
self.assertEqual(importer.mesh_count, 2)
class TestErrorChecking(unittest.TestCase):
def test_read_invalid_file(self):
with self.assertRaises(ValueError):
importer = Mesher()
importer.read("unknown_file.type")
def test_write_invalid_file(self):
exporter = Mesher()
exporter.add_shape(Solid.make_box(1, 1, 1))
with self.assertRaises(ValueError):
exporter.write("unknown_file.type")
if __name__ == "__main__":
unittest.main()