mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 22:31:55 +00:00
WIP refactor of geometry for stabilisation and optimisation. Switch representation now done.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user