From b7fb5c90bca22fde6aea1a69deccda4b00473a1b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 6 Feb 2025 17:22:54 +1100 Subject: [PATCH] Continue fixing failing tool tests. Fix regression where UV coordinates might have the wrong order. --- src/bonsai/bonsai/bim/module/library/prop.py | 4 +- src/bonsai/bonsai/tool/library.py | 2 +- src/bonsai/bonsai/tool/loader.py | 4 +- src/bonsai/test/tool/test_ifc.py | 2 +- src/bonsai/test/tool/test_library.py | 4 +- src/bonsai/test/tool/test_loader.py | 14 ++++--- src/bonsai/test/tool/test_model.py | 37 +++++++++++-------- .../ifcopenshell/util/shape_builder.py | 2 +- 8 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/library/prop.py b/src/bonsai/bonsai/bim/module/library/prop.py index d3e00c710c..b7ddb74ed6 100644 --- a/src/bonsai/bonsai/bim/module/library/prop.py +++ b/src/bonsai/bonsai/bim/module/library/prop.py @@ -45,12 +45,12 @@ class BIMLibraryProperties(PropertyGroup): editing_mode: EnumProperty( name="Editing Mode", items=( - ("-", "-", ""), + ("NONE", "NONE", ""), ("LIBRARY", "LIBRARY", ""), ("REFERENCES", "REFERENCES", ""), ("REFERENCE", "REFERENCE", ""), ), - default="-", + default="NONE", ) library_attributes: CollectionProperty(name="Library Attributes", type=Attribute) active_library_id: IntProperty(name="Active Library Id") diff --git a/src/bonsai/bonsai/tool/library.py b/src/bonsai/bonsai/tool/library.py index 0bf8c3ec9c..c28173482b 100644 --- a/src/bonsai/bonsai/tool/library.py +++ b/src/bonsai/bonsai/tool/library.py @@ -27,7 +27,7 @@ from typing import Literal, Any, Union class Library(bonsai.core.tool.Library): @classmethod def clear_editing_mode(cls) -> None: - bpy.context.scene.BIMLibraryProperties.editing_mode = "-" + bpy.context.scene.BIMLibraryProperties.editing_mode = "NONE" @classmethod def export_library_attributes(cls) -> dict[str, Any]: diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 930fa90c72..79c2e785a1 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -593,11 +593,11 @@ class Loader(bonsai.core.tool.Loader): faces_tex_coord_data = {} for tex_coord_index, face_remap in zip(texture_map, faces_remap, strict=True): - faces_tex_coord_data[frozenset(face_remap)] = (tex_coord_index, face_remap) + faces_tex_coord_data[tuple(face_remap)] = (tex_coord_index, face_remap) # Apply attribute to each face for bface in bm.faces: - face = frozenset(loop.vert.index for loop in bface.loops) + face = tuple(loop.vert.index for loop in bface.loops) # Find the corresponding index in data list by matching ifc faceset with blender face. data_index = None if tex_coord_data := faces_tex_coord_data.get(face): diff --git a/src/bonsai/test/tool/test_ifc.py b/src/bonsai/test/tool/test_ifc.py index e291e2fa28..429dd76212 100644 --- a/src/bonsai/test/tool/test_ifc.py +++ b/src/bonsai/test/tool/test_ifc.py @@ -91,7 +91,7 @@ class TestIsMoved(test.bim.bootstrap.NewFile): tool.Geometry.record_object_position(obj) assert subject.is_moved(obj) is False - obj.matrix_world[0][2] += 1 + obj.matrix_world[0][3] += 1 assert subject.is_moved(obj) is True def test_that_a_type_or_project_never_moves_but_a_grid_axis_does(self): diff --git a/src/bonsai/test/tool/test_library.py b/src/bonsai/test/tool/test_library.py index 5bc941da43..7ce2308d69 100644 --- a/src/bonsai/test/tool/test_library.py +++ b/src/bonsai/test/tool/test_library.py @@ -32,9 +32,9 @@ class TestImplementsTool(NewFile): class TestClearEditingMode(NewFile): def test_run(self): props = bpy.context.scene.BIMLibraryProperties - props.editing_mode = "foo" + props.editing_mode = "LIBRARY" subject.clear_editing_mode() - assert props.editing_mode == "" + assert props.editing_mode == "NONE" class TestExportLibraryAttributes(NewFile): diff --git a/src/bonsai/test/tool/test_loader.py b/src/bonsai/test/tool/test_loader.py index 3780c6b28e..c8235ed52b 100644 --- a/src/bonsai/test/tool/test_loader.py +++ b/src/bonsai/test/tool/test_loader.py @@ -39,6 +39,8 @@ class TestCreatingStyles(NewFile): def test_create_surface_style_with_textures_from_data(self): # this case occurs when we edit shader properties without saving them to IFC bpy.ops.bim.create_project() + ifc_path = Path("test/files/temp/test.ifc").absolute() + bpy.ops.bim.save_project(filepath=str(ifc_path), should_save_as=True) bpy.ops.mesh.primitive_cube_add(size=10, location=(0, 0, 4)) obj = bpy.data.objects["Cube"] @@ -59,7 +61,7 @@ class TestCreatingStyles(NewFile): texture_data = [ { "Mode": "DIFFUSE", - "URLReference": "bonsai/test/files/image.jpg", + "URLReference": "../image.jpg", "type": "IfcImageTexture", "uv_mode": "Generated", }, @@ -85,13 +87,15 @@ class TestCreatingStyles(NewFile): assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color" assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated" - original_path = Path(tool.Ifc.get_path()).parent / Path(texture_data[0]["URLReference"]) + original_path = (Path(tool.Ifc.get_path()).parent / Path(texture_data[0]["URLReference"])).absolute().resolve() loaded_filepath = Path(image_node.image.filepath) - assert original_path == loaded_filepath + assert original_path.absolute() == loaded_filepath def test_create_surface_style_with_textures_from_ifc(self): # this case occurs when we edit shader properties without saving them to IFC bpy.ops.bim.create_project() + ifc_path = Path("test/files/temp/test.ifc").absolute() + bpy.ops.bim.save_project(filepath=str(ifc_path), should_save_as=True) style = tool.Ifc.run("style.add_style", name="test") material = bpy.data.materials.new(style.Name) @@ -114,7 +118,7 @@ class TestCreatingStyles(NewFile): textures = [ { - "URLReference": "bonsai/test/files/image.jpg", + "URLReference": "../image.jpg", "Mode": "DIFFUSE", "RepeatS": True, "RepeatT": True, @@ -149,7 +153,7 @@ class TestCreatingStyles(NewFile): image_node = tool.Blender.get_material_node(material, "TEX_IMAGE") assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color" assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated" - original_path = Path(tool.Ifc.get_path()).parent / Path(textures[0].URLReference) + original_path = (Path(tool.Ifc.get_path()).parent / Path(textures[0].URLReference)).absolute().resolve() loaded_filepath = Path(image_node.image.filepath) assert original_path == loaded_filepath diff --git a/src/bonsai/test/tool/test_model.py b/src/bonsai/test/tool/test_model.py index 92f4b42e64..9475aaac7b 100644 --- a/src/bonsai/test/tool/test_model.py +++ b/src/bonsai/test/tool/test_model.py @@ -68,14 +68,16 @@ class TestGetBooleans(NewFile): context = ifc.createIfcGeometricRepresentationContext() element = ifc.createIfcWall() - items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()] + items = [ifc.createIfcExtrudedAreaSolid()] representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context) tool.Ifc.run("geometry.assign_representation", product=element, representation=representation) - bool1 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4))) - bool2 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4))) + builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc) + cut1 = builder.half_space_solid(builder.plane()) + cut2 = builder.half_space_solid(builder.plane()) + bools = ifcopenshell.api.geometry.add_boolean(ifc, first_item=items[0], second_items=[cut1, cut2]) - assert set(subject.get_booleans(element, representation)) == bool1 | bool2 + assert set(subject.get_booleans(element, representation)) == set(bools) class TestGetManualBooleans(NewFile): @@ -86,18 +88,23 @@ class TestGetManualBooleans(NewFile): context = ifc.createIfcGeometricRepresentationContext() element = ifc.createIfcWall() - items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()] + items = [ifc.createIfcExtrudedAreaSolid()] representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context) tool.Ifc.run("geometry.assign_representation", product=element, representation=representation) - bool1 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4))) - bool2 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4))) + builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc) + cut1 = builder.half_space_solid(builder.plane()) + cut2 = builder.half_space_solid(builder.plane()) + bools = ifcopenshell.api.geometry.add_boolean(ifc, first_item=items[0], second_items=[cut1, cut2]) - assert set(subject.get_booleans(element, representation)) == bool1 | bool2 + assert set(subject.get_booleans(element, representation)) == set(bools) assert len(subject.get_manual_booleans(element, representation)) == 0 - subject.mark_manual_booleans(element, bool1) - assert set(subject.get_manual_booleans(element, representation)) == bool1 + bool1 = list(bools)[0] + print(bools, bool1) + + subject.mark_manual_booleans(element, [bool1]) + assert set(subject.get_manual_booleans(element, representation)) == {bool1} class TestMarkManualBooleans(NewFile): @@ -184,7 +191,7 @@ class TestGenerateStair2DProfile(NewFile): assert np.all(edges == np.array(edges_gen)) assert faces == tuple(tuple(face) for face in faces_gen) for vert, vert_gen in zip(verts, verts_gen, strict=True): - assert tool.Cad.are_vectors_equal(vert, vert_gen, 0.01) + assert np.allclose(vert, V(vert_gen), atol=0.01) def test_create_concrete_stair(self): kwargs = { @@ -510,11 +517,9 @@ class TestApplyIfcMaterialChanges(NewFile): bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id) with_opening = bpy.context.active_object with_opening.name = "With Opening" - bpy.ops.bim.add_potential_opening() - tool.Blender.set_objects_selection( - bpy.context, active_object=with_opening, selected_objects=[with_opening, bpy.data.objects["Opening"]] - ) - bpy.ops.bim.add_opening() + props = bpy.context.scene.BIMRootProperties + props.representation_obj = with_opening + bpy.ops.bim.add_element(ifc_product="IfcFeatureElement", ifc_class="IfcOpeningElement") # Occurrence with a material override. bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 5b336d8e1e..4f33b243fd 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -49,7 +49,7 @@ else: SequenceOfVectors = Union[Sequence[VectorType], np.ndarray] -def V(*args: Union[float, VectorType, SequenceOfVectors]) -> npt.NDArray[np.float64]: +def V(*args: Union[float, int, VectorType, SequenceOfVectors]) -> npt.NDArray[np.float64]: """Convert floats / vector / sequence of vectors to numpy array. Note that `float` argument type also allows passing ints,