Skip to content

Commit 4e1884b

Browse files
authored
IVS-369 SPS002 behaviour update (#344)
1 parent f3163d7 commit 4e1884b

File tree

4 files changed

+74
-15
lines changed

4 files changed

+74
-15
lines changed

features/SPS002_Correct-spatial-breakdown.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@implementer-agreement
22
@SPS
3-
@version2
3+
@version3
44
@E00100
55
Feature: SPS002 - Correct spatial breakdown
66
The rule verifies that spatial elements are aggregated as per the Spatial Composition Table.

features/steps/thens/relations.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,23 @@ def step_impl(context, inst, relationship, table):
4242
# raise Exception(f'Entity {entity} was not found in the {table}')
4343
continue
4444

45-
applicable_entity = ifc.order_by_ifc_inheritance(applicable_entities, base_class_last = True)[0]
46-
expected_relationship_objects = aggregated_table[applicable_entity]
45+
# For all applicable entities (could be multiple e.g IfcRoad, IfcFacility) we union the allowed types
46+
expected_relationship_objects = sorted(set(functools.reduce(operator.or_, map(set, [aggregated_table[e] for e in applicable_entities]))))
4747
try:
4848
relation = getattr(inst, stmt_to_op[relationship], True)[0]
4949
except IndexError: # no relationship found for the entity
5050
if is_required:
5151
yield ValidationOutcome(inst=inst, expected={"oneOf": expected_relationship_objects, "context": context}, severity=OutcomeSeverity.ERROR)
5252
continue
53+
5354
relationship_objects = getattr(relation, relationship_tbl_header, True)
5455
if not isinstance(relationship_objects, tuple):
5556
relationship_objects = (relationship_objects,)
5657

57-
5858
for relationship_object in relationship_objects:
5959
is_correct = any(relationship_object.is_a(expected_relationship_object) for expected_relationship_object in expected_relationship_objects)
6060
if not is_correct:
61+
# related object not of the correct type
6162
yield ValidationOutcome(inst=inst, expected={"oneOf": expected_relationship_objects, "context": context}, observed=relationship_object, severity=OutcomeSeverity.ERROR)
6263

6364

features/steps/utils/ifc.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ def instance_getter(i, representation_id, representation_type, negative=False):
5050
if condition(i, representation_id, representation_type):
5151
return i
5252

53-
def order_by_ifc_inheritance(instances, base_class_last):
54-
import ifcopenshell
55-
ifc = ifcopenshell.file(schema='IFC4X3')
56-
inheritance_nr = {}
57-
for instance in instances:
58-
ifc_instance = ifc.create_entity(instance)
59-
result = sum(1 for str_instance in instances if ifc_instance.is_a(str_instance))
60-
inheritance_nr[instance] = result
61-
inheritance_nr = dict(sorted(inheritance_nr.items(), key=lambda item: item[1], reverse=base_class_last))
62-
return list(inheritance_nr.keys())
63-
6453

6554
def recurrently_get_entity_attr(ifc_context, inst, entity_to_look_for, attr_to_get, attr_found=None):
6655
if attr_found is None:
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
ISO-10303-21;
2+
/* Testfile: pass-sps002-road_facilitypart.ifc */
3+
/* IFC-Requirement: sps002; Correct spatial breakdown */
4+
HEADER;
5+
FILE_DESCRIPTION(('ViewDefinition [Ifc4X3NotAssigned]'),'2;1');
6+
FILE_NAME ('pass-sps002-road_facilitypart.ifc', '2023-03-14T15:36:48', ('redacted'), ('redacted'), 'Python+IfcOpenShell', '','');
7+
FILE_SCHEMA(('IFC4X3_ADD2'));
8+
ENDSEC;
9+
DATA;
10+
#1= IFCAPPLICATION(#2,'1.0.0.0','redacted','redacted');
11+
#2= IFCORGANIZATION($,'Geometry Gym Pty Ltd',$,$,$);
12+
#3= IFCPERSONANDORGANIZATION(#4,#5,$);
13+
#4= IFCPERSON('redacted','redacted',$,$,$,$,$,$);
14+
#5= IFCORGANIZATION($,'redacted',$,$,$);
15+
#6= IFCOWNERHISTORY(#3,#1,$,.ADDED.,1418084874,$,$,1418084874);
16+
#7= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.0001,#8,#10);
17+
#8= IFCAXIS2PLACEMENT3D(#9,$,$);
18+
#9= IFCCARTESIANPOINT((0.0,0.0,0.0));
19+
#10= IFCDIRECTION((0.0,1.0));
20+
#11= IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#7,$,.MODEL_VIEW.,$);
21+
#12= IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#7,$,.MODEL_VIEW.,$);
22+
#13= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.0001,#8,#14);
23+
#14= IFCDIRECTION((0.0,1.0));
24+
#50= IFCBUILDING('0Cd2Mw3cP09wW6qWHK8v2f',$,'IfcBuilding',$,$,#51,$,$,.ELEMENT.,$,$,#57);
25+
#51= IFCLOCALPLACEMENT($,#52);
26+
#52= IFCAXIS2PLACEMENT3D(#53,$,$);
27+
#53= IFCCARTESIANPOINT((0.0,0.0,0.0));
28+
#54= IFCRELCONTAINEDINSPATIALSTRUCTURE('3ffS1zvV94ExNgP6hOHMLr',$,'Building','Building Container for Elements',(#302),#50);
29+
#57= IFCPOSTALADDRESS($,$,$,$,$,$,$,'Unknown',$,$);
30+
#100= IFCPROJECT('3KEb34nozBu9ezspX8gM9d',#6,'IfcProject',$,$,'IfcProject','',(#13),#101);
31+
#101= IFCUNITASSIGNMENT((#102,#103,#104));
32+
#102= IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
33+
#103= IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
34+
#104= IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.);
35+
#200= IFCMATERIAL('Masonry - Brick - Brown',$,$);
36+
#203= IFCMATERIAL('Masonry',$,$);
37+
#206= IFCMATERIALLAYER(#200,110.0,.F.,'Finish',$,$,$);
38+
#208= IFCMATERIALLAYER($,50.0,.T.,'Air Infiltration Barrier',$,$,$);
39+
#210= IFCMATERIALLAYER(#203,110.0,.F.,'Core',$,$,$);
40+
#212= IFCMATERIALLAYERSET((#206,#208,#210),'Double Brick - 270',$);
41+
#213= IFCRELASSOCIATESMATERIAL('2D3xie$bD8YgahfQF1htfq',$,'MatAssoc','Material Associates',(#300),#212);
42+
#300= IFCWALLTYPE('2GdZ7nhi52Geyiua9QcAH9',$,'Double Brick - 270',$,$,$,$,$,$,.NOTDEFINED.);
43+
#301= IFCRELDEFINESBYTYPE('3Gcd0t0WTDWe18S5rhROgf',$,'Double Brick - 270',$,(#302),#300);
44+
#302= IFCWALLSTANDARDCASE('0czCsOQ5z4dg8QGBRFInu2',$,$,$,$,#305,#320,$,$);
45+
#303= IFCMATERIALLAYERSETUSAGE(#212,.AXIS2.,.POSITIVE.,0.0,$);
46+
#304= IFCRELASSOCIATESMATERIAL('0PFtmoJBHDOvVAl6M9w55u',$,'MatAssoc','Material Associates',(#302),#303);
47+
#305= IFCLOCALPLACEMENT($,#306);
48+
#306= IFCAXIS2PLACEMENT3D(#307,#308,#309);
49+
#307= IFCCARTESIANPOINT((0.0,0.0,0.0));
50+
#308= IFCDIRECTION((0.0,0.0,1.0));
51+
#309= IFCDIRECTION((1.0,0.0,0.0));
52+
#310= IFCCARTESIANPOINT((5000.0,0.0));
53+
#311= IFCCARTESIANPOINT((0.0,0.0));
54+
#312= IFCPOLYLINE((#311,#310));
55+
#313= IFCSHAPEREPRESENTATION(#11,'Axis','Curve2D',(#312));
56+
#314= IFCAXIS2PLACEMENT2D(#315,$);
57+
#315= IFCCARTESIANPOINT((2500.0,135.0));
58+
#316= IFCRECTANGLEPROFILEDEF(.AREA.,'Wall Perim',#314,5000.0,270.0);
59+
#317= IFCDIRECTION((0.0,0.0,1.0));
60+
#318= IFCEXTRUDEDAREASOLID(#316,$,#317,2000.0);
61+
#319= IFCSHAPEREPRESENTATION(#12,'Body','SweptSolid',(#318));
62+
#320= IFCPRODUCTDEFINITIONSHAPE($,$,(#313,#319));
63+
#321=IFCROAD('0hb5vCxjv2ZetiycRLI_Fx',#6,'','',$,$,$,$,$,$);
64+
#322=IFCFACILITYPARTCOMMON('0hb5vCxjv2ZetiycRLI_Fy',#6,'','',$,$,$,$,$,.NOTDEFINED.,$);
65+
#323= IFCRELAGGREGATES('2G17HB5orFmhdpTVYmbgKX',$,'RailwayContainer','Container for Railway Parts',#321,(#322));
66+
#324= IFCRELAGGREGATES('2G17HB5orFmhdpTVYmbgCX',$,'RailwayContainer','Container for Railway Parts',#100,(#321,#50));
67+
ENDSEC;
68+
69+
END-ISO-10303-21;

0 commit comments

Comments
 (0)