mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 06:58:56 +00:00
Continue fixing failing tool tests. Fix regression where UV coordinates might have the wrong order.
This commit is contained in:
@@ -45,12 +45,12 @@ class BIMLibraryProperties(PropertyGroup):
|
|||||||
editing_mode: EnumProperty(
|
editing_mode: EnumProperty(
|
||||||
name="Editing Mode",
|
name="Editing Mode",
|
||||||
items=(
|
items=(
|
||||||
("-", "-", ""),
|
("NONE", "NONE", ""),
|
||||||
("LIBRARY", "LIBRARY", ""),
|
("LIBRARY", "LIBRARY", ""),
|
||||||
("REFERENCES", "REFERENCES", ""),
|
("REFERENCES", "REFERENCES", ""),
|
||||||
("REFERENCE", "REFERENCE", ""),
|
("REFERENCE", "REFERENCE", ""),
|
||||||
),
|
),
|
||||||
default="-",
|
default="NONE",
|
||||||
)
|
)
|
||||||
library_attributes: CollectionProperty(name="Library Attributes", type=Attribute)
|
library_attributes: CollectionProperty(name="Library Attributes", type=Attribute)
|
||||||
active_library_id: IntProperty(name="Active Library Id")
|
active_library_id: IntProperty(name="Active Library Id")
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from typing import Literal, Any, Union
|
|||||||
class Library(bonsai.core.tool.Library):
|
class Library(bonsai.core.tool.Library):
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_editing_mode(cls) -> None:
|
def clear_editing_mode(cls) -> None:
|
||||||
bpy.context.scene.BIMLibraryProperties.editing_mode = "-"
|
bpy.context.scene.BIMLibraryProperties.editing_mode = "NONE"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_library_attributes(cls) -> dict[str, Any]:
|
def export_library_attributes(cls) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -593,11 +593,11 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
|
|
||||||
faces_tex_coord_data = {}
|
faces_tex_coord_data = {}
|
||||||
for tex_coord_index, face_remap in zip(texture_map, faces_remap, strict=True):
|
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
|
# Apply attribute to each face
|
||||||
for bface in bm.faces:
|
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.
|
# Find the corresponding index in data list by matching ifc faceset with blender face.
|
||||||
data_index = None
|
data_index = None
|
||||||
if tex_coord_data := faces_tex_coord_data.get(face):
|
if tex_coord_data := faces_tex_coord_data.get(face):
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class TestIsMoved(test.bim.bootstrap.NewFile):
|
|||||||
tool.Geometry.record_object_position(obj)
|
tool.Geometry.record_object_position(obj)
|
||||||
assert subject.is_moved(obj) is False
|
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
|
assert subject.is_moved(obj) is True
|
||||||
|
|
||||||
def test_that_a_type_or_project_never_moves_but_a_grid_axis_does(self):
|
def test_that_a_type_or_project_never_moves_but_a_grid_axis_does(self):
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ class TestImplementsTool(NewFile):
|
|||||||
class TestClearEditingMode(NewFile):
|
class TestClearEditingMode(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
props = bpy.context.scene.BIMLibraryProperties
|
props = bpy.context.scene.BIMLibraryProperties
|
||||||
props.editing_mode = "foo"
|
props.editing_mode = "LIBRARY"
|
||||||
subject.clear_editing_mode()
|
subject.clear_editing_mode()
|
||||||
assert props.editing_mode == ""
|
assert props.editing_mode == "NONE"
|
||||||
|
|
||||||
|
|
||||||
class TestExportLibraryAttributes(NewFile):
|
class TestExportLibraryAttributes(NewFile):
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ class TestCreatingStyles(NewFile):
|
|||||||
def test_create_surface_style_with_textures_from_data(self):
|
def test_create_surface_style_with_textures_from_data(self):
|
||||||
# this case occurs when we edit shader properties without saving them to IFC
|
# this case occurs when we edit shader properties without saving them to IFC
|
||||||
bpy.ops.bim.create_project()
|
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))
|
bpy.ops.mesh.primitive_cube_add(size=10, location=(0, 0, 4))
|
||||||
obj = bpy.data.objects["Cube"]
|
obj = bpy.data.objects["Cube"]
|
||||||
@@ -59,7 +61,7 @@ class TestCreatingStyles(NewFile):
|
|||||||
texture_data = [
|
texture_data = [
|
||||||
{
|
{
|
||||||
"Mode": "DIFFUSE",
|
"Mode": "DIFFUSE",
|
||||||
"URLReference": "bonsai/test/files/image.jpg",
|
"URLReference": "../image.jpg",
|
||||||
"type": "IfcImageTexture",
|
"type": "IfcImageTexture",
|
||||||
"uv_mode": "Generated",
|
"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.outputs["Color"].links[0].to_socket.name == "Base Color"
|
||||||
assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated"
|
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)
|
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):
|
def test_create_surface_style_with_textures_from_ifc(self):
|
||||||
# this case occurs when we edit shader properties without saving them to IFC
|
# this case occurs when we edit shader properties without saving them to IFC
|
||||||
bpy.ops.bim.create_project()
|
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")
|
style = tool.Ifc.run("style.add_style", name="test")
|
||||||
material = bpy.data.materials.new(style.Name)
|
material = bpy.data.materials.new(style.Name)
|
||||||
@@ -114,7 +118,7 @@ class TestCreatingStyles(NewFile):
|
|||||||
|
|
||||||
textures = [
|
textures = [
|
||||||
{
|
{
|
||||||
"URLReference": "bonsai/test/files/image.jpg",
|
"URLReference": "../image.jpg",
|
||||||
"Mode": "DIFFUSE",
|
"Mode": "DIFFUSE",
|
||||||
"RepeatS": True,
|
"RepeatS": True,
|
||||||
"RepeatT": True,
|
"RepeatT": True,
|
||||||
@@ -149,7 +153,7 @@ class TestCreatingStyles(NewFile):
|
|||||||
image_node = tool.Blender.get_material_node(material, "TEX_IMAGE")
|
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.outputs["Color"].links[0].to_socket.name == "Base Color"
|
||||||
assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated"
|
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)
|
loaded_filepath = Path(image_node.image.filepath)
|
||||||
assert original_path == loaded_filepath
|
assert original_path == loaded_filepath
|
||||||
|
|
||||||
|
|||||||
@@ -68,14 +68,16 @@ class TestGetBooleans(NewFile):
|
|||||||
context = ifc.createIfcGeometricRepresentationContext()
|
context = ifc.createIfcGeometricRepresentationContext()
|
||||||
element = ifc.createIfcWall()
|
element = ifc.createIfcWall()
|
||||||
|
|
||||||
items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()]
|
items = [ifc.createIfcExtrudedAreaSolid()]
|
||||||
representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context)
|
representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context)
|
||||||
tool.Ifc.run("geometry.assign_representation", product=element, representation=representation)
|
tool.Ifc.run("geometry.assign_representation", product=element, representation=representation)
|
||||||
|
|
||||||
bool1 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4)))
|
builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc)
|
||||||
bool2 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4)))
|
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):
|
class TestGetManualBooleans(NewFile):
|
||||||
@@ -86,18 +88,23 @@ class TestGetManualBooleans(NewFile):
|
|||||||
context = ifc.createIfcGeometricRepresentationContext()
|
context = ifc.createIfcGeometricRepresentationContext()
|
||||||
element = ifc.createIfcWall()
|
element = ifc.createIfcWall()
|
||||||
|
|
||||||
items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()]
|
items = [ifc.createIfcExtrudedAreaSolid()]
|
||||||
representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context)
|
representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context)
|
||||||
tool.Ifc.run("geometry.assign_representation", product=element, representation=representation)
|
tool.Ifc.run("geometry.assign_representation", product=element, representation=representation)
|
||||||
|
|
||||||
bool1 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4)))
|
builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc)
|
||||||
bool2 = set(tool.Ifc.run("geometry.add_boolean", representation=representation, matrix=np.eye(4)))
|
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
|
assert len(subject.get_manual_booleans(element, representation)) == 0
|
||||||
|
|
||||||
subject.mark_manual_booleans(element, bool1)
|
bool1 = list(bools)[0]
|
||||||
assert set(subject.get_manual_booleans(element, representation)) == bool1
|
print(bools, bool1)
|
||||||
|
|
||||||
|
subject.mark_manual_booleans(element, [bool1])
|
||||||
|
assert set(subject.get_manual_booleans(element, representation)) == {bool1}
|
||||||
|
|
||||||
|
|
||||||
class TestMarkManualBooleans(NewFile):
|
class TestMarkManualBooleans(NewFile):
|
||||||
@@ -184,7 +191,7 @@ class TestGenerateStair2DProfile(NewFile):
|
|||||||
assert np.all(edges == np.array(edges_gen))
|
assert np.all(edges == np.array(edges_gen))
|
||||||
assert faces == tuple(tuple(face) for face in faces_gen)
|
assert faces == tuple(tuple(face) for face in faces_gen)
|
||||||
for vert, vert_gen in zip(verts, verts_gen, strict=True):
|
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):
|
def test_create_concrete_stair(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
@@ -510,11 +517,9 @@ class TestApplyIfcMaterialChanges(NewFile):
|
|||||||
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||||
with_opening = bpy.context.active_object
|
with_opening = bpy.context.active_object
|
||||||
with_opening.name = "With Opening"
|
with_opening.name = "With Opening"
|
||||||
bpy.ops.bim.add_potential_opening()
|
props = bpy.context.scene.BIMRootProperties
|
||||||
tool.Blender.set_objects_selection(
|
props.representation_obj = with_opening
|
||||||
bpy.context, active_object=with_opening, selected_objects=[with_opening, bpy.data.objects["Opening"]]
|
bpy.ops.bim.add_element(ifc_product="IfcFeatureElement", ifc_class="IfcOpeningElement")
|
||||||
)
|
|
||||||
bpy.ops.bim.add_opening()
|
|
||||||
|
|
||||||
# Occurrence with a material override.
|
# Occurrence with a material override.
|
||||||
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
bpy.ops.bim.add_constr_type_instance(relating_type_id=relating_type_id)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ else:
|
|||||||
SequenceOfVectors = Union[Sequence[VectorType], np.ndarray]
|
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.
|
"""Convert floats / vector / sequence of vectors to numpy array.
|
||||||
|
|
||||||
Note that `float` argument type also allows passing ints,
|
Note that `float` argument type also allows passing ints,
|
||||||
|
|||||||
Reference in New Issue
Block a user