WIP refactor of geometry for stabilisation and optimisation. Switch representation now done.

This commit is contained in:
Dion Moult
2021-10-19 12:57:21 +11:00
parent 63f85beb7e
commit c1b53859ee
13 changed files with 415 additions and 112 deletions
@@ -23,6 +23,16 @@ Scenario: Add representation
And I press "bim.add_representation"
Then nothing happens
Scenario: Switch representation
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
When the variable "representation" is "{ifc}.by_type('IfcShapeRepresentation')[0].id()"
And I press "bim.switch_representation(obj='IfcWall/Cube', ifc_definition_id={representation})"
Then nothing happens
Scenario: Copy representation
Given an empty IFC project
And I add a cube
+27 -4
View File
@@ -76,8 +76,8 @@ class TestAddRepresentation:
# Update mesh
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
geometry.get_representation_name("context", "representation").should_be_called().will_return("name")
geometry.rename_object_data("data", "name").should_be_called()
geometry.get_representation_name("representation").should_be_called().will_return("name")
geometry.rename_object("data", "name").should_be_called()
geometry.link("representation", "data").should_be_called()
assert (
@@ -124,8 +124,8 @@ class TestAddRepresentation:
# Update mesh
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
geometry.get_representation_name("context", "representation").should_be_called().will_return("name")
geometry.rename_object_data("data", "name").should_be_called()
geometry.get_representation_name("representation").should_be_called().will_return("name")
geometry.rename_object("data", "name").should_be_called()
geometry.link("representation", "data").should_be_called()
assert (
@@ -176,3 +176,26 @@ class TestAddRepresentation:
)
is None
)
class TestSwitchRepresentation:
def test_run(self, ifc, geometry, style, surveyor):
geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
geometry.get_representation_data("representation").should_be_called().will_return("data")
geometry.import_representation(
"obj", "representation", enable_dynamic_voids=True
).should_be_called().will_return("new_data")
geometry.get_representation_name("representation").should_be_called().will_return("name")
geometry.rename_object("new_data", "name").should_be_called()
geometry.link("representation", "new_data").should_be_called()
geometry.change_object_data("obj", "new_data", is_global=True).should_be_called()
geometry.is_body_representation("representation").should_be_called().will_return(True)
geometry.create_dynamic_voids("obj").should_be_called()
subject.switch_representation(
geometry,
obj="obj",
representation="mapped_rep",
should_reload=True,
enable_dynamic_voids=True,
is_global=True,
)
+77
View File
@@ -0,0 +1,77 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
FILE_NAME('annotation.ifc','2021-10-19T11:50:01+11:00',(),(),'IfcOpenShell v0.7.0-6cc7d796','BlenderBIM 0.0.999999','Nobody');
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
#1=IFCPERSON('HSeldon','Seldon','Hari',$,$,$,$,$);
#2=IFCORGANIZATION('APTR','Aperture Science',$,$,$);
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
#4=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$);
#5=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$);
#6=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#4),(#5));
#7=IFCAPPLICATION(#6,'0.0.999999','BlenderBIM Add-on','BlenderBIM');
#8=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
#9=IFCPROJECT('0NqkoFmWPBxvsDLeGa5rDc',#8,'My Project',$,$,$,$,(#18,#24),#13);
#10=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#11=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#12=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#13=IFCUNITASSIGNMENT((#11,#12,#10));
#14=IFCCARTESIANPOINT((0.,0.,0.));
#15=IFCDIRECTION((0.,0.,1.));
#16=IFCDIRECTION((1.,0.,0.));
#17=IFCAXIS2PLACEMENT3D(#14,#15,#16);
#18=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#17,$);
#19=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#18,$,.MODEL_VIEW.,$);
#20=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#18,$,.MODEL_VIEW.,$);
#21=IFCCARTESIANPOINT((0.,0.,0.));
#22=IFCDIRECTION((1.,0.,0.));
#23=IFCAXIS2PLACEMENT2D(#21,#22);
#24=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#23,$);
#25=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#24,$,.PLAN_VIEW.,$);
#26=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
#27=IFCSITE('3kJImD6Rr4NfpxM218DNpq',#26,'My Site',$,$,#53,$,$,$,$,$,$,$,$);
#33=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
#34=IFCBUILDING('3afq36fJb80A_bTAB9RB0f',#33,'My Building',$,$,#60,$,$,$,$,$,$);
#40=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
#41=IFCBUILDINGSTOREY('2vQTqYOy13G8THztmBknz3',#40,'My Storey',$,$,#67,$,$,$,$);
#47=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
#48=IFCRELAGGREGATES('22R8p4a0z4jAFLUof7ha5H',#47,$,$,#9,(#27));
#49=IFCCARTESIANPOINT((0.,0.,0.));
#50=IFCDIRECTION((0.,0.,1.));
#51=IFCDIRECTION((1.,0.,0.));
#52=IFCAXIS2PLACEMENT3D(#49,#50,#51);
#53=IFCLOCALPLACEMENT($,#52);
#54=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
#55=IFCRELAGGREGATES('1ty5GrCRX0vPrGpg4F_2JL',#54,$,$,#27,(#34));
#56=IFCCARTESIANPOINT((0.,0.,0.));
#57=IFCDIRECTION((0.,0.,1.));
#58=IFCDIRECTION((1.,0.,0.));
#59=IFCAXIS2PLACEMENT3D(#56,#57,#58);
#60=IFCLOCALPLACEMENT(#53,#59);
#61=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
#62=IFCRELAGGREGATES('1Lbqbq3O56pg1ouvCD5WR9',#61,$,$,#34,(#41));
#63=IFCCARTESIANPOINT((0.,0.,0.));
#64=IFCDIRECTION((0.,0.,1.));
#65=IFCDIRECTION((1.,0.,0.));
#66=IFCAXIS2PLACEMENT3D(#63,#64,#65);
#67=IFCLOCALPLACEMENT(#60,#66);
#68=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604586,#3,#7,1634604586);
#69=IFCWALL('2iJrnC5QfEH8KDFgXqLR5J',#68,'Square',$,$,#88,#81,$,.ELEMENTEDWALL.);
#75=IFCCARTESIANPOINTLIST2D(((1.,1.),(1.,-1.),(-1.,1.),(-1.,-1.)));
#76=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((3,4))),$);
#77=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((1,3))),$);
#78=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((4,2)),IFCLINEINDEX((2,1))),$);
#79=IFCGEOMETRICCURVESET((#76,#77,#78));
#80=IFCSHAPEREPRESENTATION(#25,'Annotation','Annotation2D',(#79));
#81=IFCPRODUCTDEFINITIONSHAPE($,$,(#80));
#82=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604586,#3,#7,1634604586);
#83=IFCRELCONTAINEDINSPATIALSTRUCTURE('1AG29wImP3hgw6L3xSIacB',#82,$,$,(#69),#41);
#84=IFCCARTESIANPOINT((0.,0.,0.));
#85=IFCDIRECTION((0.,0.,1.));
#86=IFCDIRECTION((1.,0.,0.));
#87=IFCAXIS2PLACEMENT3D(#84,#85,#86);
#88=IFCLOCALPLACEMENT(#67,#87);
ENDSEC;
END-ISO-10303-21;
+117 -2
View File
@@ -33,6 +33,55 @@ class TestImplementsTool(test.bim.bootstrap.NewFile):
assert isinstance(subject(), blenderbim.core.tool.Geometry)
class TestChangeObjectData(test.bim.bootstrap.NewFile):
def test_change_single_object_data(self):
data1 = bpy.data.meshes.new("Mesh")
data2 = bpy.data.meshes.new("Mesh")
obj1 = bpy.data.objects.new("Object", data1)
obj2 = bpy.data.objects.new("Object", data1)
subject.change_object_data(obj1, data2, is_global=False)
assert obj1.data == data2
assert obj2.data == data1
def test_change_object_data_globally(self):
data1 = bpy.data.meshes.new("Mesh")
data2 = bpy.data.meshes.new("Mesh")
obj1 = bpy.data.objects.new("Object", data1)
obj2 = bpy.data.objects.new("Object", data1)
subject.change_object_data(obj1, data2, is_global=True)
assert obj1.data == data2
assert obj2.data == data2
class TestClearDynamicVoids(test.bim.bootstrap.NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
subject.clear_dynamic_voids(obj)
assert len(obj.modifiers) == 0
class TestCreateDynamicVoids(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
wall = ifc.createIfcWall()
opening = ifc.createIfcOpeningElement()
ifcopenshell.api.run("void.add_opening", ifc, opening=opening, element=wall)
wall_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
opening_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
tool.Ifc.link(wall, wall_obj)
tool.Ifc.link(opening, opening_obj)
subject.create_dynamic_voids(wall_obj)
modifier = wall_obj.modifiers[0]
assert modifier.type == "BOOLEAN"
assert modifier.name == "IfcOpeningElement"
assert modifier.operation == "DIFFERENCE"
assert modifier.object == opening_obj
assert modifier.solver == "EXACT"
assert modifier.use_self is True
class TestDoesObjectHaveMeshWithFaces(test.bim.bootstrap.NewFile):
def test_empties_return_false(self):
obj = bpy.data.objects.new("Object", None)
@@ -81,12 +130,23 @@ class TestGetObjectMaterialsWithoutStyles(test.bim.bootstrap.NewFile):
assert subject.get_object_materials_without_styles(obj) == [material1, material2]
class TestGetRepresentationData(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
representation = ifc.createIfcShapeRepresentation()
representation.ContextOfItems = context
data = bpy.data.meshes.new("1/2")
assert subject.get_representation_data(representation) == data
class TestGetRepresentationName(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
representation = ifc.createIfcShapeRepresentation()
assert subject.get_representation_name(context, representation) == f"{context.id()}/{representation.id()}"
representation.ContextOfItems = context
assert subject.get_representation_name(representation) == f"{context.id()}/{representation.id()}"
class TestGetCartesianPointCoordinateOffset(test.bim.bootstrap.NewFile):
@@ -127,6 +187,44 @@ class TestGetTotalRepresentationItems(test.bim.bootstrap.NewFile):
assert subject.get_total_representation_items(obj) == 2
class TestImportRepresentation(test.bim.bootstrap.NewFile):
def test_importing_a_normal_shape(self):
ifc = ifcopenshell.open("test/files/basic.ifc")
tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
material = bpy.data.materials.new("Material")
material.BIMMaterialProperties.ifc_style_id = 101
element = ifc.by_type("IfcWall")[0]
tool.Ifc.link(element, obj)
representation = element.Representation.Representations[0]
mesh = subject.import_representation(obj, representation, enable_dynamic_voids=False)
assert len(mesh.polygons) == 12
assert mesh.materials[0] == material
def test_importing_non_body_curves(self):
ifc = ifcopenshell.open("test/files/annotation.ifc")
tool.Ifc.set(ifc)
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
element = ifc.by_type("IfcWall")[0]
tool.Ifc.link(element, obj)
representation = element.Representation.Representations[0]
mesh = subject.import_representation(obj, representation, enable_dynamic_voids=False)
assert len(mesh.polygons) == 0
assert len(mesh.edges) == 4
class TestIsBodyRepresentation(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
representation = ifc.createIfcShapeRepresentation()
representation.ContextOfItems = context
context.ContextIdentifier = "Body"
assert subject.is_body_representation(representation) is True
context.ContextIdentifier = "Clearance"
assert subject.is_body_representation(representation) is False
class TestLink(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
@@ -139,10 +237,27 @@ class TestLink(test.bim.bootstrap.NewFile):
class TestRenameObjectData(test.bim.bootstrap.NewFile):
def test_run(self):
obj = bpy.data.meshes.new("Mesh")
subject.rename_object_data(obj, "name")
subject.rename_object(obj, "name")
assert obj.name == "name"
class TestResolveMappedRepresentation(test.bim.bootstrap.NewFile):
def test_run(self):
ifc = ifcopenshell.file()
mapped_representation = ifc.createIfcShapeRepresentation()
representation = ifc.createIfcShapeRepresentation()
mapped_representation.RepresentationType = "MappedRepresentation"
mapped_representation.Items = [
ifc.createIfcMappedItem(MappingSource=ifc.createIfcRepresentationMap(MappedRepresentation=representation))
]
assert subject.resolve_mapped_representation(mapped_representation) == representation
def test_return_a_representation_if_not_mapped(self):
ifc = ifcopenshell.file()
representation = ifc.createIfcShapeRepresentation()
assert subject.resolve_mapped_representation(representation) == representation
class TestShouldForceFacetedBrep(test.bim.bootstrap.NewFile):
def test_run(self):
result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep