From d3d12f001711bbcee4d97e4e3a5629e85f108424 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 19 Dec 2024 14:25:02 +0100 Subject: [PATCH 01/11] IFC105 --- features/steps/givens/attributes.py | 29 ++++++++++++++++++ features/steps/givens/entities.py | 42 ++++++++++++++++++--------- features/steps/thens/relations.py | 11 ++++++- features/steps/utils/misc.py | 8 +++++ features/steps/validation_handling.py | 5 ++-- 5 files changed, 78 insertions(+), 17 deletions(-) diff --git a/features/steps/givens/attributes.py b/features/steps/givens/attributes.py index 41ad8a35..0384f258 100644 --- a/features/steps/givens/attributes.py +++ b/features/steps/givens/attributes.py @@ -1,4 +1,5 @@ import ast +import functools import operator import ifcopenshell @@ -147,6 +148,34 @@ def step_impl(context, file_or_model, field, values): context.applicable = getattr(context, 'applicable', True) and applicable +@gherkin_ifc.step('a traversal over the full model originating from subtypes of {entity}') +def step_impl(context, entity): + WHITELISTED_INVERSES = {'StyledByItem'} + schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(context.model.schema_identifier) + @functools.cache + def names(entity_type): + decl = schema.declaration_by_name(entity_type) + if isinstance(decl, ifcopenshell.ifcopenshell_wrapper.entity): + non_derived_forward_attributes = map(operator.itemgetter(1), filter(lambda t: not t[0], zip(decl.derived(), decl.all_attributes()))) + whitelisted_inverse_attributes = filter(lambda attr: attr.name() in WHITELISTED_INVERSES, decl.all_inverse_attributes()) + return {a.name() for a in [*non_derived_forward_attributes, *whitelisted_inverse_attributes]} + else: + return set() + + visited = set() + def visit(inst, path=None): + if inst in visited: + return + visited.add(inst) + for attr in names(inst.is_a()): + for ref in filter(lambda inst: isinstance(inst, ifcopenshell.entity_instance), misc.iflatten(getattr(inst, attr))): + visit(ref, (path or ()) + (inst, attr,)) + + for inst in context.model.by_type(entity): + visit(inst) + + context.visited_instances = visited + @gherkin_ifc.step('Its attribute {attribute}') def step_impl(context, inst, attribute, tail="single"): yield ValidationOutcome(instance_id=getattr(inst, attribute, None), severity=OutcomeSeverity.PASSED) diff --git a/features/steps/givens/entities.py b/features/steps/givens/entities.py index ea313666..2198fe14 100644 --- a/features/steps/givens/entities.py +++ b/features/steps/givens/entities.py @@ -20,18 +20,21 @@ def step_impl(context, entity_opt_stmt, insts=False): within_model = (insts == 'instances') # True for given statement containing {insts} - entity2 = pyparsing.Word(pyparsing.alphas)('entity') - sub_stmts = ['with subtypes', 'without subtypes', pyparsing.LineEnd()] - incl_sub_stmt = functools.reduce(operator.or_, [misc.rtrn_pyparse_obj(i) for i in sub_stmts])('include_subtypes') - grammar = entity2 + incl_sub_stmt - parse = grammar.parseString(entity_opt_stmt) - entity = parse['entity'] - include_subtypes = misc.do_try(lambda: not 'without' in parse['include_subtypes'], True) - - try: - instances = context.model.by_type(entity, include_subtypes) - except: - instances = [] + if entity_opt_stmt == "entity instance": + instances = list(context.model) + else: + entity2 = pyparsing.Word(pyparsing.alphas)('entity') + sub_stmts = ['with subtypes', 'without subtypes', pyparsing.LineEnd()] + incl_sub_stmt = functools.reduce(operator.or_, [misc.rtrn_pyparse_obj(i) for i in sub_stmts])('include_subtypes') + grammar = entity2 + incl_sub_stmt + parse = grammar.parseString(entity_opt_stmt) + entity = parse['entity'] + include_subtypes = misc.do_try(lambda: not 'without' in parse['include_subtypes'], True) + + try: + instances = context.model.by_type(entity, include_subtypes) + except: + instances = [] context.within_model = getattr(context, 'within_model', True) and within_model if instances: @@ -73,4 +76,17 @@ def step_impl(context, inst, relationship_direction): def step_impl(context, inst): # Note that this includes `inst` as the first element in this list instances = context.model.traverse(inst) - yield ValidationOutcome(instance_id=instances, severity=OutcomeSeverity.PASSED) \ No newline at end of file + yield ValidationOutcome(instance_id=instances, severity=OutcomeSeverity.PASSED) + +""" +@gherkin_ifc.step("its entity type is {entity}") +def step_impl(context, inst, entity): + negate = False + entity = entity.split(' ') + if entity[0] == 'not': + negate = not negate + entity = entity[1:] + entity = entity[0] + if inst.is_a(entity): + yield ValidationOutcome(instance_id=inst, severity=OutcomeSeverity.PASSED) +""" \ No newline at end of file diff --git a/features/steps/thens/relations.py b/features/steps/thens/relations.py index 15db983d..b944e459 100644 --- a/features/steps/thens/relations.py +++ b/features/steps/thens/relations.py @@ -388,4 +388,13 @@ def schema_has_declaration_name(s): # @tfk not sure about this one, but for now empty values on a property are probably # not a universal error. This is more IDS territory. # if not values: - # yield ValidationOutcome(inst=inst, expected= {"oneOf": accepted_data_type['instance']}, observed = {'value':None}, severity=OutcomeSeverity.ERROR) \ No newline at end of file + # yield ValidationOutcome(inst=inst, expected= {"oneOf": accepted_data_type['instance']}, observed = {'value':None}, severity=OutcomeSeverity.ERROR) + +@gherkin_ifc.step('it must be referenced by an entity instance inheriting from IfcRoot directly or indirectly') +def step_impl(context, inst): + # context.visited_instances is set in the gherkin statement: + # 'Given a traversal over the full model originating from subtypes of IfcRoot' + assert hasattr(context, 'visited_instances') + + if inst not in context.visited_instances: + yield ValidationOutcome(inst=inst, severity=OutcomeSeverity.ERROR) diff --git a/features/steps/utils/misc.py b/features/steps/utils/misc.py index 4003833b..e6d3ef3e 100644 --- a/features/steps/utils/misc.py +++ b/features/steps/utils/misc.py @@ -31,6 +31,14 @@ def recursive_flatten(lst): return flattened_list +def iflatten(any): + if isinstance(any, (tuple, list)): + for v in any: + yield from iflatten(v) + else: + yield any + + def do_try(fn, default=None): try: return fn() diff --git a/features/steps/validation_handling.py b/features/steps/validation_handling.py index eb4a9f6c..8f0aed8b 100644 --- a/features/steps/validation_handling.py +++ b/features/steps/validation_handling.py @@ -65,10 +65,9 @@ class SubtypeHandling(Enum): def generate_error_message(context, errors): """ - Function to trigger the behave error mechanism so that the JSON output is generated correctly. - Miscellaneous errors also are also printed to the console this way. + Function to trigger the behave error mechanism by raising an exception so that errors are printed to the console. """ - assert not errors, "Behave errors occured:\n{}".format([str(error) for error in errors]) + assert not errors, "Errors occured:" + ''.join(f'\n - {error}' for error in errors) """ From 9adacfc4a06d6ead0074cd79f6d4da884cd6df29 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 19 Dec 2024 14:25:56 +0100 Subject: [PATCH 02/11] test files --- .../fail-gem105-product-representation.ifc | 73 +++++++++++++++++++ .../pass-gem105-product-representation.ifc | 71 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 test/files/ifc105/fail-gem105-product-representation.ifc create mode 100644 test/files/ifc105/pass-gem105-product-representation.ifc diff --git a/test/files/ifc105/fail-gem105-product-representation.ifc b/test/files/ifc105/fail-gem105-product-representation.ifc new file mode 100644 index 00000000..da3789df --- /dev/null +++ b/test/files/ifc105/fail-gem105-product-representation.ifc @@ -0,0 +1,73 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2022-11-08T16:54:40',(''),(''),'IfcOpenShell-v0.7.0-fa6bbf2d','IfcOpenShell-v0.7.0-fa6bbf2d',''); +FILE_SCHEMA(('IFC2X3')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION($,'',$,$,$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'v0.7.0-fa6bbf2d','IfcOpenShell-v0.7.0-fa6bbf2d',''); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,$,#3,#4,1667926480); +#6=IFCDIRECTION((1.,0.,0.)); +#7=IFCDIRECTION((0.,0.,1.)); +#8=IFCCARTESIANPOINT((0.,0.,0.)); +#9=IFCAXIS2PLACEMENT3D(#8,#7,#6); +#10=IFCDIRECTION((0.,1.,0.)); +#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,#10); +#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#15=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#16=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16); +#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17); +#19=IFCUNITASSIGNMENT((#13,#14,#15,#18)); +#20=IFCPROJECT('3KwPrT3OP4Gg7qpalgQO1_',#5,'',$,$,$,$,(#11),#19); +#21=IFCCARTESIANPOINT((0.,0.,0.)); +#22=IFCDIRECTION((0.,0.,1.)); +#23=IFCDIRECTION((1.,0.,0.)); +#24=IFCAXIS2PLACEMENT3D(#21,#22,#23); +#25=IFCLOCALPLACEMENT($,#24); +#26=IFCSITE('098$knNuOHxPTbB6t11Jwi',#5,'Site',$,$,#25,$,$,.ELEMENT.,$,$,$,$,$); +#27=IFCCARTESIANPOINT((0.,0.,0.)); +#28=IFCDIRECTION((0.,0.,1.)); +#29=IFCDIRECTION((1.,0.,0.)); +#30=IFCAXIS2PLACEMENT3D(#27,#28,#29); +#31=IFCLOCALPLACEMENT(#25,#30); +#32=IFCBUILDING('098$koNuOHxPGoB6t11Jwi',#5,'Building',$,$,#31,$,$,.ELEMENT.,$,$,$); +#33=IFCCARTESIANPOINT((0.,0.,0.)); +#34=IFCDIRECTION((0.,0.,1.)); +#35=IFCDIRECTION((1.,0.,0.)); +#36=IFCAXIS2PLACEMENT3D(#33,#34,#35); +#37=IFCLOCALPLACEMENT(#31,#36); +#38=IFCBUILDINGSTOREY('098$kpNuOHxQvuB6t11Jwi',#5,'Storey',$,$,#37,$,$,.ELEMENT.,0.); +#39=IFCRELAGGREGATES('098$kqNuOHxRbKB6t11Jwi',#5,'Building Container',$,#32,(#38)); +#40=IFCRELAGGREGATES('098$krNuOHxQdqB6t11Jwi',#5,'Site Container',$,#26,(#32)); +#41=IFCRELAGGREGATES('098$ksNuOHxO9OB6t11Jwi',#5,'Project Container',$,#20,(#26)); +#42=IFCCARTESIANPOINT((0.,0.,0.)); +#43=IFCDIRECTION((0.,0.,1.)); +#44=IFCDIRECTION((1.,0.,0.)); +#45=IFCAXIS2PLACEMENT3D(#42,#43,#44); +#46=IFCLOCALPLACEMENT(#37,#45); +#47=IFCCARTESIANPOINT((0.,0.,0.)); +#48=IFCCARTESIANPOINT((5.,0.,0.)); +#49=IFCPOLYLINE((#47,#48)); +#50=IFCCARTESIANPOINT((0.,0.,0.)); +#51=IFCDIRECTION((0.,0.,1.)); +#52=IFCDIRECTION((1.,0.,0.)); +#53=IFCAXIS2PLACEMENT3D(#50,#51,#52); +#54=IFCCARTESIANPOINT((0.,-0.1,0.)); +#55=IFCCARTESIANPOINT((5.,-0.1,0.)); +#56=IFCCARTESIANPOINT((10.,0.1,0.)); +#57=IFCCARTESIANPOINT((0.,0.1,0.)); +#58=IFCCARTESIANPOINT((0.,-0.1,0.)); +#59=IFCPOLYLINE((#54,#55,#56,#57,#58)); +#60=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#59); +#61=IFCDIRECTION((0.,0.,1.)); +#62=IFCEXTRUDEDAREASOLID(#60,#53,#61,3.); +#63=IFCSHAPEREPRESENTATION(#11,'Body','CSG',(#62)); +#64=IFCPRODUCTDEFINITIONSHAPE($,$,(#63)); +ENDSEC; +END-ISO-10303-21; diff --git a/test/files/ifc105/pass-gem105-product-representation.ifc b/test/files/ifc105/pass-gem105-product-representation.ifc new file mode 100644 index 00000000..d8394d8e --- /dev/null +++ b/test/files/ifc105/pass-gem105-product-representation.ifc @@ -0,0 +1,71 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2022-11-08T16:54:40',(''),(''),'IfcOpenShell-v0.7.0-fa6bbf2d','IfcOpenShell-v0.7.0-fa6bbf2d',''); +FILE_SCHEMA(('IFC2X3')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION($,'',$,$,$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'v0.7.0-fa6bbf2d','IfcOpenShell-v0.7.0-fa6bbf2d',''); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,$,#3,#4,1667926480); +#6=IFCDIRECTION((1.,0.,0.)); +#7=IFCDIRECTION((0.,0.,1.)); +#8=IFCCARTESIANPOINT((0.,0.,0.)); +#9=IFCAXIS2PLACEMENT3D(#8,#7,#6); +#10=IFCDIRECTION((0.,1.,0.)); +#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,#10); +#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#15=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#16=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16); +#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17); +#19=IFCUNITASSIGNMENT((#13,#14,#15,#18)); +#20=IFCPROJECT('3KwPrT3OP4Gg7qpalgQO1_',#5,'',$,$,$,$,(#11),#19); +#21=IFCCARTESIANPOINT((0.,0.,0.)); +#22=IFCDIRECTION((0.,0.,1.)); +#23=IFCDIRECTION((1.,0.,0.)); +#24=IFCAXIS2PLACEMENT3D(#21,#22,#23); +#25=IFCLOCALPLACEMENT($,#24); +#26=IFCSITE('098$knNuOHxPTbB6t11Jwi',#5,'Site',$,$,#25,$,$,.ELEMENT.,$,$,$,$,$); +#27=IFCCARTESIANPOINT((0.,0.,0.)); +#28=IFCDIRECTION((0.,0.,1.)); +#29=IFCDIRECTION((1.,0.,0.)); +#30=IFCAXIS2PLACEMENT3D(#27,#28,#29); +#31=IFCLOCALPLACEMENT(#25,#30); +#32=IFCBUILDING('098$koNuOHxPGoB6t11Jwi',#5,'Building',$,$,#31,$,$,.ELEMENT.,$,$,$); +#33=IFCCARTESIANPOINT((0.,0.,0.)); +#34=IFCDIRECTION((0.,0.,1.)); +#35=IFCDIRECTION((1.,0.,0.)); +#36=IFCAXIS2PLACEMENT3D(#33,#34,#35); +#37=IFCLOCALPLACEMENT(#31,#36); +#38=IFCBUILDINGSTOREY('098$kpNuOHxQvuB6t11Jwi',#5,'Storey',$,$,#37,$,$,.ELEMENT.,0.); +#39=IFCRELAGGREGATES('098$kqNuOHxRbKB6t11Jwi',#5,'Building Container',$,#32,(#38)); +#40=IFCRELAGGREGATES('098$krNuOHxQdqB6t11Jwi',#5,'Site Container',$,#26,(#32)); +#41=IFCRELAGGREGATES('098$ksNuOHxO9OB6t11Jwi',#5,'Project Container',$,#20,(#26)); +#42=IFCCARTESIANPOINT((0.,0.,0.)); +#43=IFCDIRECTION((0.,0.,1.)); +#44=IFCDIRECTION((1.,0.,0.)); +#45=IFCAXIS2PLACEMENT3D(#42,#43,#44); +#46=IFCLOCALPLACEMENT(#37,#45); +#50=IFCCARTESIANPOINT((0.,0.,0.)); +#51=IFCDIRECTION((0.,0.,1.)); +#52=IFCDIRECTION((1.,0.,0.)); +#53=IFCAXIS2PLACEMENT3D(#50,#51,#52); +#54=IFCCARTESIANPOINT((0.,-0.1,0.)); +#55=IFCCARTESIANPOINT((5.,-0.1,0.)); +#56=IFCCARTESIANPOINT((10.,0.1,0.)); +#57=IFCCARTESIANPOINT((0.,0.1,0.)); +#58=IFCCARTESIANPOINT((0.,-0.1,0.)); +#59=IFCPOLYLINE((#54,#55,#56,#57,#58)); +#60=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#59); +#61=IFCDIRECTION((0.,0.,1.)); +#62=IFCEXTRUDEDAREASOLID(#60,#53,#61,3.); +#63=IFCSHAPEREPRESENTATION(#11,'Body','CSG',(#62)); +#64=IFCPRODUCTDEFINITIONSHAPE($,$,(#63)); +#65=IFCSPACE('098$ktNuOHxOUOB6t11Jwi',#5,'space','An awesome space',$,#46,#64,$,$,$,$); +ENDSEC; +END-ISO-10303-21; From 826aca4996d08b0e6e2985a95f5dd375745db0ed Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 19 Dec 2024 14:27:20 +0100 Subject: [PATCH 03/11] reverse --- features/steps/givens/entities.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/features/steps/givens/entities.py b/features/steps/givens/entities.py index 2198fe14..cd59ff86 100644 --- a/features/steps/givens/entities.py +++ b/features/steps/givens/entities.py @@ -76,17 +76,4 @@ def step_impl(context, inst, relationship_direction): def step_impl(context, inst): # Note that this includes `inst` as the first element in this list instances = context.model.traverse(inst) - yield ValidationOutcome(instance_id=instances, severity=OutcomeSeverity.PASSED) - -""" -@gherkin_ifc.step("its entity type is {entity}") -def step_impl(context, inst, entity): - negate = False - entity = entity.split(' ') - if entity[0] == 'not': - negate = not negate - entity = entity[1:] - entity = entity[0] - if inst.is_a(entity): - yield ValidationOutcome(instance_id=inst, severity=OutcomeSeverity.PASSED) -""" \ No newline at end of file + yield ValidationOutcome(instance_id=instances, severity=OutcomeSeverity.PASSED) \ No newline at end of file From 71690ecbc07c204f3c30ca31acf1358d52bfe57a Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 19 Dec 2024 14:28:23 +0100 Subject: [PATCH 04/11] Feature --- ...need-to-be-referenced-by-rooted-entity.feature | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature diff --git a/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature new file mode 100644 index 00000000..e67a9f43 --- /dev/null +++ b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature @@ -0,0 +1,15 @@ +@IFC +@version5 +@E00030 +@implementer-agreement +Feature: IFC105 - Resource entities need to be referenced by rooted entity + +The rule verifies that resource entities are directly or indirectly related to at least on rooted entity instance by means of forward or inverse attributes. +Resource entities are the schema classes that do not inherit from IfcRoot, typically defined in the resource layer of the schema (e.g Geometry Resource). + + Scenario: Resource entities need to be referenced by rooted entity + + Given a traversal over the full model originating from subtypes of IfcRoot + Given an entity instance + Given its entity type is not 'IfcRoot' + Then it must be referenced by an entity instance inheriting from IfcRoot directly or indirectly \ No newline at end of file From 5ffd37129e5ef09261b12e10c3fe8ea956a5eaf6 Mon Sep 17 00:00:00 2001 From: Geert Hesselink Date: Fri, 20 Dec 2024 00:17:29 +0100 Subject: [PATCH 05/11] ifcopenshell version update --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2e1ee16..473de25d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: - name: Install dependencies run: | pip install behave pytest tabulate pyparsing sqlalchemy numpy pydantic pydot sqlalchemy_utils django python-dotenv deprecated pandas pyspellchecker rtree - wget -O /tmp/ifcopenshell_python.zip https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-`python3 -c 'import sys;print("".join(map(str, sys.version_info[0:2])))'`-v0.8.1-0267e2b-linux64.zip + wget -O /tmp/ifcopenshell_python.zip https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-`python3 -c 'import sys;print("".join(map(str, sys.version_info[0:2])))'`-v0.8.1-1d27161-linux64.zip mkdir -p `python3 -c 'import site; print(site.getusersitepackages())'` unzip -d `python3 -c 'import site; print(site.getusersitepackages())'` /tmp/ifcopenshell_python.zip - name: Lint with flake8 From 179c49c6d542b631d6853e7eaab1d57ec9d20ec5 Mon Sep 17 00:00:00 2001 From: Geert Hesselink Date: Fri, 20 Dec 2024 00:18:01 +0100 Subject: [PATCH 06/11] testfile name gem0105-> ifc105 --- ...-representation.ifc => fail-ifc105-product-representation.ifc} | 0 ...-representation.ifc => pass-ifc105-product-representation.ifc} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test/files/ifc105/{fail-gem105-product-representation.ifc => fail-ifc105-product-representation.ifc} (100%) rename test/files/ifc105/{pass-gem105-product-representation.ifc => pass-ifc105-product-representation.ifc} (100%) diff --git a/test/files/ifc105/fail-gem105-product-representation.ifc b/test/files/ifc105/fail-ifc105-product-representation.ifc similarity index 100% rename from test/files/ifc105/fail-gem105-product-representation.ifc rename to test/files/ifc105/fail-ifc105-product-representation.ifc diff --git a/test/files/ifc105/pass-gem105-product-representation.ifc b/test/files/ifc105/pass-ifc105-product-representation.ifc similarity index 100% rename from test/files/ifc105/pass-gem105-product-representation.ifc rename to test/files/ifc105/pass-ifc105-product-representation.ifc From e9205d7e7b245959287989827ae5691199073c5a Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 20 Dec 2024 09:22:39 +0100 Subject: [PATCH 07/11] Update features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature Co-authored-by: Geert Hesselink <54070862+Ghesselink@users.noreply.github.com> --- ...urce-entities-need-to-be-referenced-by-rooted-entity.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature index e67a9f43..b1d1c120 100644 --- a/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature +++ b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature @@ -1,5 +1,5 @@ @IFC -@version5 +@version1 @E00030 @implementer-agreement Feature: IFC105 - Resource entities need to be referenced by rooted entity From 972d942269ff11823697e53acfca19567fecf658 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 14 Jan 2025 11:10:40 +0100 Subject: [PATCH 08/11] Update features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature Co-authored-by: Scott Lecher --- ...urce-entities-need-to-be-referenced-by-rooted-entity.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature index b1d1c120..b1ce1bfd 100644 --- a/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature +++ b/features/IFC105_Resource-entities-need-to-be-referenced-by-rooted-entity.feature @@ -4,7 +4,7 @@ @implementer-agreement Feature: IFC105 - Resource entities need to be referenced by rooted entity -The rule verifies that resource entities are directly or indirectly related to at least on rooted entity instance by means of forward or inverse attributes. +The rule verifies that resource entities are directly or indirectly related to at least one rooted entity instance by means of forward or inverse attributes. Resource entities are the schema classes that do not inherit from IfcRoot, typically defined in the resource layer of the schema (e.g Geometry Resource). Scenario: Resource entities need to be referenced by rooted entity From 17ae9a6b70b56e395fab7b8afd0b0aec5fbe5c16 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 23 Jan 2025 21:00:59 +0100 Subject: [PATCH 09/11] Whitelist HasCoordinateOperation in IFC105 --- features/steps/givens/attributes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/givens/attributes.py b/features/steps/givens/attributes.py index 18d42687..1898dc72 100644 --- a/features/steps/givens/attributes.py +++ b/features/steps/givens/attributes.py @@ -150,7 +150,7 @@ def step_impl(context, file_or_model, field, values): @gherkin_ifc.step('a traversal over the full model originating from subtypes of {entity}') def step_impl(context, entity): - WHITELISTED_INVERSES = {'StyledByItem'} + WHITELISTED_INVERSES = {'StyledByItem', 'HasCoordinateOperation'} schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(context.model.schema_identifier) @functools.cache def names(entity_type): From c46f559817c35554ac52f639a6be634e3e7c4689 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 23 Jan 2025 21:12:06 +0100 Subject: [PATCH 10/11] Address schema errors in ifc105 test files --- .../ifc105/fail-ifc105-product-representation.ifc | 15 +++++++-------- .../ifc105/pass-ifc105-product-representation.ifc | 15 ++++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/files/ifc105/fail-ifc105-product-representation.ifc b/test/files/ifc105/fail-ifc105-product-representation.ifc index da3789df..40daceac 100644 --- a/test/files/ifc105/fail-ifc105-product-representation.ifc +++ b/test/files/ifc105/fail-ifc105-product-representation.ifc @@ -50,7 +50,6 @@ DATA; #43=IFCDIRECTION((0.,0.,1.)); #44=IFCDIRECTION((1.,0.,0.)); #45=IFCAXIS2PLACEMENT3D(#42,#43,#44); -#46=IFCLOCALPLACEMENT(#37,#45); #47=IFCCARTESIANPOINT((0.,0.,0.)); #48=IFCCARTESIANPOINT((5.,0.,0.)); #49=IFCPOLYLINE((#47,#48)); @@ -58,16 +57,16 @@ DATA; #51=IFCDIRECTION((0.,0.,1.)); #52=IFCDIRECTION((1.,0.,0.)); #53=IFCAXIS2PLACEMENT3D(#50,#51,#52); -#54=IFCCARTESIANPOINT((0.,-0.1,0.)); -#55=IFCCARTESIANPOINT((5.,-0.1,0.)); -#56=IFCCARTESIANPOINT((10.,0.1,0.)); -#57=IFCCARTESIANPOINT((0.,0.1,0.)); -#58=IFCCARTESIANPOINT((0.,-0.1,0.)); +#54=IFCCARTESIANPOINT((0.,-0.1)); +#55=IFCCARTESIANPOINT((5.,-0.1)); +#56=IFCCARTESIANPOINT((10.,0.1)); +#57=IFCCARTESIANPOINT((0.,0.1)); +#58=IFCCARTESIANPOINT((0.,-0.1)); #59=IFCPOLYLINE((#54,#55,#56,#57,#58)); #60=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#59); #61=IFCDIRECTION((0.,0.,1.)); #62=IFCEXTRUDEDAREASOLID(#60,#53,#61,3.); -#63=IFCSHAPEREPRESENTATION(#11,'Body','CSG',(#62)); -#64=IFCPRODUCTDEFINITIONSHAPE($,$,(#63)); +#63=IFCSHAPEREPRESENTATION(#11,'Body','SweptSolid',(#62)); +#64=IFCREPRESENTATIONMAP(#53,#63); ENDSEC; END-ISO-10303-21; diff --git a/test/files/ifc105/pass-ifc105-product-representation.ifc b/test/files/ifc105/pass-ifc105-product-representation.ifc index d8394d8e..4d789580 100644 --- a/test/files/ifc105/pass-ifc105-product-representation.ifc +++ b/test/files/ifc105/pass-ifc105-product-representation.ifc @@ -46,6 +46,7 @@ DATA; #39=IFCRELAGGREGATES('098$kqNuOHxRbKB6t11Jwi',#5,'Building Container',$,#32,(#38)); #40=IFCRELAGGREGATES('098$krNuOHxQdqB6t11Jwi',#5,'Site Container',$,#26,(#32)); #41=IFCRELAGGREGATES('098$ksNuOHxO9OB6t11Jwi',#5,'Project Container',$,#20,(#26)); +#4100=IFCRELAGGREGATES('098$ksNuOHxO9OB6t11Jwj',#5,'Storey Container',$,#38,(#65)); #42=IFCCARTESIANPOINT((0.,0.,0.)); #43=IFCDIRECTION((0.,0.,1.)); #44=IFCDIRECTION((1.,0.,0.)); @@ -55,17 +56,17 @@ DATA; #51=IFCDIRECTION((0.,0.,1.)); #52=IFCDIRECTION((1.,0.,0.)); #53=IFCAXIS2PLACEMENT3D(#50,#51,#52); -#54=IFCCARTESIANPOINT((0.,-0.1,0.)); -#55=IFCCARTESIANPOINT((5.,-0.1,0.)); -#56=IFCCARTESIANPOINT((10.,0.1,0.)); -#57=IFCCARTESIANPOINT((0.,0.1,0.)); -#58=IFCCARTESIANPOINT((0.,-0.1,0.)); +#54=IFCCARTESIANPOINT((0.,-0.1)); +#55=IFCCARTESIANPOINT((5.,-0.1)); +#56=IFCCARTESIANPOINT((10.,0.1)); +#57=IFCCARTESIANPOINT((0.,0.1)); +#58=IFCCARTESIANPOINT((0.,-0.1)); #59=IFCPOLYLINE((#54,#55,#56,#57,#58)); #60=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#59); #61=IFCDIRECTION((0.,0.,1.)); #62=IFCEXTRUDEDAREASOLID(#60,#53,#61,3.); -#63=IFCSHAPEREPRESENTATION(#11,'Body','CSG',(#62)); +#63=IFCSHAPEREPRESENTATION(#11,'Body','SweptSolid',(#62)); #64=IFCPRODUCTDEFINITIONSHAPE($,$,(#63)); -#65=IFCSPACE('098$ktNuOHxOUOB6t11Jwi',#5,'space','An awesome space',$,#46,#64,$,$,$,$); +#65=IFCSPACE('098$ktNuOHxOUOB6t11Jwi',#5,'space','An awesome space',$,#46,#64,$,.ELEMENT.,.INTERNAL.,$); ENDSEC; END-ISO-10303-21; From 9b17b806af5f9f01c5a950a3cafb572581d8baf1 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Sat, 25 Jan 2025 09:59:50 -0500 Subject: [PATCH 11/11] add georeference file to unit tests; cleanup unit test file names (IVS-99) --- ...=> fail-ifc105-product_representation.ifc} | 0 ...=> pass-ifc105-product_representation.ifc} | 0 .../pass-ifc105-with_georeferencing.ifc | 71 +++++++++++++++++++ 3 files changed, 71 insertions(+) rename test/files/ifc105/{fail-ifc105-product-representation.ifc => fail-ifc105-product_representation.ifc} (100%) rename test/files/ifc105/{pass-ifc105-product-representation.ifc => pass-ifc105-product_representation.ifc} (100%) create mode 100644 test/files/ifc105/pass-ifc105-with_georeferencing.ifc diff --git a/test/files/ifc105/fail-ifc105-product-representation.ifc b/test/files/ifc105/fail-ifc105-product_representation.ifc similarity index 100% rename from test/files/ifc105/fail-ifc105-product-representation.ifc rename to test/files/ifc105/fail-ifc105-product_representation.ifc diff --git a/test/files/ifc105/pass-ifc105-product-representation.ifc b/test/files/ifc105/pass-ifc105-product_representation.ifc similarity index 100% rename from test/files/ifc105/pass-ifc105-product-representation.ifc rename to test/files/ifc105/pass-ifc105-product_representation.ifc diff --git a/test/files/ifc105/pass-ifc105-with_georeferencing.ifc b/test/files/ifc105/pass-ifc105-with_georeferencing.ifc new file mode 100644 index 00000000..a51526c7 --- /dev/null +++ b/test/files/ifc105/pass-ifc105-with_georeferencing.ifc @@ -0,0 +1,71 @@ +ISO-10303-21; +HEADER; + +FILE_DESCRIPTION( +/* description */ ('GeoReference'), +/* implementation level */ '2;1'); +FILE_NAME( +/* name */ 'pass-ifc105-with_referencing.ifc', +/* time_stamp */ '2017-07-10T15:03:00', +/* author */ ('redacted'), +/* organization */ ('redacted'), +/* preprocessor_version */ 'redacted', +/* originating_system */ '', +/* authorisation */ 'none'); + +FILE_SCHEMA (('IFC4X3_ADD2')); +ENDSEC; +DATA; +/* Geographic reference*/ +#1= IFCPROJECTEDCRS('EPSG:31467','DHDN / 3-Degree Gauss-Krueger Zone 3','ETRS89',$,'Gaus-Krueger','3',#3); +#2= IFCMAPCONVERSION(#100011,#1,3458715.92,5439966.65,113.7,0.270600445976,0.962691746426,$); +#3= IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); + + +/* BuildingElementProxy */ +#149= IFCBUILDINGELEMENTPROXY('0rBru4syGxGOZb$M8kVJuS',#100005,'Geographic Position',$,$,#121,#5037,$,$); +#121= IFCLOCALPLACEMENT(#5044,#243); +#243= IFCAXIS2PLACEMENT3D(#173,#217,#218); +#173= IFCCARTESIANPOINT((0.,0.,0.)); +#217= IFCDIRECTION((0.,0.,1.)); +#218= IFCDIRECTION((1.,0.,0.)); +#5037= IFCPRODUCTDEFINITIONSHAPE('',$,(#5038)); +#5038= IFCSHAPEREPRESENTATION(#100011,'Body','Tessellation',(#5000)); +/* Tesselated geometry */ +#5000= IFCTRIANGULATEDFACESET(#5001,$,.T.,((1,3,2),(1,4,3),(1,5,4),(1,2,5),/*(2,3,4),(4,5,2),*/(2,3,6),(3,7,6),(3,4,7),(4,8,7),(4,5,8),(5,9,8),(5,2,9),(2,6,9),(6,7,8),(6,8,9)),$); +#5001= IFCCARTESIANPOINTLIST3D(((0.0,0.0,0.0),(-500.0,-500.0,2000.0),(500.0,-500.0,2000.0),(500.0,500.0,2000.0),(-500.0,500.0,2000.0),(-500.0,-500.0,4000.0),(500.0,-500.0,4000.0),(500.0,500.0,4000.0),(-500.0,500.0,4000.0)),$); +/* BuildingStorey */ +#5043= IFCBUILDINGSTOREY('3_fv_WeK63IPclwapZa9MD',#100005,'Storey 1',$,$,#5044,$,$,.ELEMENT.,0.); +#5044= IFCLOCALPLACEMENT(#100025,#100040); +#5045= IFCRELCONTAINEDINSPATIALSTRUCTURE('2lLFgu3KhSGw4jMC3$Ak50',#100005,'Storey 1',$,(#149),#5043); +#5046= IFCRELAGGREGATES('3INy2PAPGPJ8Dpwhrq610o',#100005,'All stories',$,#100023,(#5043)); +/* Person, Org, App, Project */ + +#100001= IFCPERSON($,'redacted',$,$,$,$,$,$); +#100002= IFCORGANIZATION($,'redacted',$,$,$); +#100003= IFCPERSONANDORGANIZATION(#100001,#100002,$); +#100004= IFCAPPLICATION(#100002,'redacted','redacted','redacted'); +#100005= IFCOWNERHISTORY(#100003,#100004,$,.NOTDEFINED.,$,$,$,1122650864); +#100010= IFCPROJECT('01JwSt5ycUHvKFlMZUleKS',#100005,'Notch',$,$,$,$,(#100011),#100060); +#100011= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.0E-5,#100040,$); +/* Site */ +#100020= IFCSITE('1BPCQAtTW7GhKrUF$Sytrr',#100005,'Site',$,$,#100022,$,$,.ELEMENT.,(49,5,43,983700),(8,26,1,247300),113.7,$,$); +#100021= IFCRELAGGREGATES('2vOmTZNmbvJAJRbSGMMNrC',#100005,$,$,#100010,(#100020)); +#100022= IFCLOCALPLACEMENT($,#100040); +/* Building */ +#100023= IFCBUILDING('0cVTYHAI3nGeTXA2X4Gxyo',#100005,'Building',$,$,#100025,$,$,.ELEMENT.,$,$,$); +#100024= IFCRELAGGREGATES('1F_GRhxz1GJgGgcJgzjvKX',#100005,$,$,#100020,(#100023)); +#100025= IFCLOCALPLACEMENT(#100022,#100040); +/* Placement */ +#100040= IFCAXIS2PLACEMENT3D(#100041,#100044,#100042); +#100041= IFCCARTESIANPOINT((0.,0.,0.)); +#100042= IFCDIRECTION((1.,0.,0.)); +#100044= IFCDIRECTION((0.,0.,1.)); +/* Units */ +#100060= IFCUNITASSIGNMENT((#100061,#100062,#100063,#100064)); +#100061= IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.); +#100062= IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#100063= IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#100064= IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +ENDSEC; +END-ISO-10303-21; \ No newline at end of file