diff --git a/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ids b/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ids new file mode 100644 index 00000000..3b6e2425 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ids @@ -0,0 +1,43 @@ + + + + Bedrooms need a minimum floor area of 10m2 2/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCSPACE + + + + + Description + + + + + + + + + + + + Qto_SpaceBaseQuantities + + + NetFloorArea + + + + + + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ifc b/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ifc new file mode 100644 index 00000000..5eff0efd --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ifc @@ -0,0 +1,16 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROJECT('0nAJhbwG5A0uNieL5ozGvv',$,$,$,$,$,$,$,#2); +#2=IFCUNITASSIGNMENT((#3)); +#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#4=IFCSPACE('0eA6m4fELI9QBIhP3wiLAp',$,$,'BEDROOM 2',$,$,$,$,$,$,$); +#5=IFCELEMENTQUANTITY('16MocU_IDOF8_x3Iqllz0d',$,'Qto_SpaceBaseQuantities',$,$,(#6)); +#6=IFCQUANTITYAREA('NetFloorArea',$,$,8.,$); +#7=IFCRELDEFINESBYPROPERTIES('1xdwj8qGXK4hzoNbvMdXJW',$,$,$,(#4),#5); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ids b/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ids new file mode 100644 index 00000000..2298c291 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ids @@ -0,0 +1,43 @@ + + + + Bedrooms need a minimum floor area of 10m2 1/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCSPACE + + + + + Description + + + + + + + + + + + + Qto_SpaceBaseQuantities + + + NetFloorArea + + + + + + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ifc b/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ifc new file mode 100644 index 00000000..094fe0b5 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ifc @@ -0,0 +1,16 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROJECT('0nAJhbwG5A0uNieL5ozGvv',$,$,$,$,$,$,$,#2); +#2=IFCUNITASSIGNMENT((#3)); +#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#4=IFCSPACE('0eA6m4fELI9QBIhP3wiLAp',$,$,'BEDROOM 1',$,$,$,$,$,$,$); +#5=IFCELEMENTQUANTITY('16MocU_IDOF8_x3Iqllz0d',$,'Qto_SpaceBaseQuantities',$,$,(#6)); +#6=IFCQUANTITYAREA('NetFloorArea',$,$,12.,$); +#7=IFCRELDEFINESBYPROPERTIES('1xdwj8qGXK4hzoNbvMdXJW',$,$,$,(#4),#5); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ids b/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ids new file mode 100644 index 00000000..535a3a8a --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ids @@ -0,0 +1,35 @@ + + + + A classification facet can be used for applicability 2/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCWALL + + + + + + + + + + + + + + Name + + + Waldo + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ifc b/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ifc new file mode 100644 index 00000000..56d789cd --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ifc @@ -0,0 +1,13 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCWALL('1hqIFTRjfV6AWq_bMtnZwI',$,'Foobar',$,$,$,$,$,$); +#2=IFCCLASSIFICATION($,$,$,'Foobar',$,$,$); +#3=IFCCLASSIFICATIONREFERENCE($,'1',$,#2,$,$); +#4=IFCRELASSOCIATESCLASSIFICATION('05rScmOVzMoQXOfbYdtLYj',$,$,$,(#1),#3); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ids b/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ids new file mode 100644 index 00000000..dc42cb3d --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ids @@ -0,0 +1,35 @@ + + + + A classification facet can be used for applicability 1/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCWALL + + + + + + + + + + + + + + Name + + + Waldo + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ifc b/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ifc new file mode 100644 index 00000000..fe2c67f8 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ifc @@ -0,0 +1,13 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCWALL('1hqIFTRjfV6AWq_bMtnZwI',$,'Waldo',$,$,$,$,$,$); +#2=IFCCLASSIFICATION($,$,$,'Foobar',$,$,$); +#3=IFCCLASSIFICATIONREFERENCE($,'1',$,#2,$,$); +#4=IFCRELASSOCIATESCLASSIFICATION('05rScmOVzMoQXOfbYdtLYj',$,$,$,(#1),#3); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ids b/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ids new file mode 100644 index 00000000..c644e4f6 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ids @@ -0,0 +1,39 @@ + + + + External load bearing walls need a fire rating property 2/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCWALL + + + + + Pset_WallCommon + + + LoadBearing + + + true + + + + + + + Pset_WallCommon + + + FireRating + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ifc b/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ifc new file mode 100644 index 00000000..890fbae6 --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ifc @@ -0,0 +1,16 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROJECT('0nAJhbwG5A0uNieL5ozGvv',$,$,$,$,$,$,$,#2); +#2=IFCUNITASSIGNMENT((#3)); +#3=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#4=IFCWALL('1hqIFTRjfV6AWq_bMtnZwI',$,$,$,$,$,$,$,$); +#5=IFCPROPERTYSET('16MocU_IDOF8_x3Iqllz0d',$,'Pset_WallCommon',$,(#7)); +#6=IFCRELDEFINESBYPROPERTIES('1xdwj8qGXK4hzoNbvMdXJW',$,$,$,(#4),#5); +#7=IFCPROPERTYSINGLEVALUE('LoadBearing',$,IFCBOOLEAN(.T.),$); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ids b/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ids new file mode 100644 index 00000000..7395a09c --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ids @@ -0,0 +1,39 @@ + + + + External load bearing walls need a fire rating property 1/2 + Generated via code automation in the Ids Repository on github. + + + + + + + IFCWALL + + + + + Pset_WallCommon + + + LoadBearing + + + true + + + + + + + Pset_WallCommon + + + FireRating + + + + + + \ No newline at end of file diff --git a/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ifc b/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ifc new file mode 100644 index 00000000..81ab773e --- /dev/null +++ b/Documentation/ImplementersDocumentation/TestCases/property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ifc @@ -0,0 +1,17 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2024-01-01T00:00:00',(),(),'','',''); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROJECT('0nAJhbwG5A0uNieL5ozGvv',$,$,$,$,$,$,$,#2); +#2=IFCUNITASSIGNMENT((#3)); +#3=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#4=IFCWALL('1hqIFTRjfV6AWq_bMtnZwI',$,$,$,$,$,$,$,$); +#5=IFCPROPERTYSET('16MocU_IDOF8_x3Iqllz0d',$,'Pset_WallCommon',$,(#7,#8)); +#6=IFCRELDEFINESBYPROPERTIES('1xdwj8qGXK4hzoNbvMdXJW',$,$,$,(#4),#5); +#7=IFCPROPERTYSINGLEVALUE('LoadBearing',$,IFCBOOLEAN(.T.),$); +#8=IFCPROPERTYSINGLEVALUE('FireRating',$,IFCLABEL('1HR'),$); +ENDSEC; +END-ISO-10303-21; diff --git a/Documentation/ImplementersDocumentation/TestCases/scripts.md b/Documentation/ImplementersDocumentation/TestCases/scripts.md index 0a0dd2e8..0c024028 100644 --- a/Documentation/ImplementersDocumentation/TestCases/scripts.md +++ b/Documentation/ImplementersDocumentation/TestCases/scripts.md @@ -214,6 +214,28 @@ Requirements: Attribute: ''Name'' ``` +### Bedrooms need a minimum floor area of 10m2 1/2 + +Hand authored to close the applicability coverage gap identified in buildingSMART/IDS#181. Mirrors the "Bedrooms should have a minimum area of 10m2" worked example in specifications.md, which uses an Attribute facet in the applicability to select bedrooms by their Description. + +``` ids attribute/pass-bedrooms_need_a_minimum_floor_area_of_10m2_1_2.ids +Bedrooms need a minimum floor area of 10m2 1/2 +Entity: ''IFCSPACE'' +Attribute: ''Description'',Pattern(''.*BEDROOM.*'') +Requirements: +Property: ''Qto_SpaceBaseQuantities'',''NetFloorArea'',IFCAREAMEASURE,xs:double MinInclusive(''10'') +``` + +### Bedrooms need a minimum floor area of 10m2 2/2 + +``` ids attribute/fail-bedrooms_need_a_minimum_floor_area_of_10m2_2_2.ids +Bedrooms need a minimum floor area of 10m2 2/2 +Entity: ''IFCSPACE'' +Attribute: ''Description'',Pattern(''.*BEDROOM.*'') +Requirements: +Property: ''Qto_SpaceBaseQuantities'',''NetFloorArea'',IFCAREAMEASURE,xs:double MinInclusive(''10'') +``` + ### Booleans must be specified as lowercase strings 1/3 ``` ids attribute/fail-booleans_must_be_specified_as_lowercase_strings_1_3.ids @@ -549,6 +571,28 @@ Attribute: ''Name'',Enumeration(''Foo'',''Bar'') ## classification +### A classification facet can be used for applicability 1/2 + +Hand authored to close the applicability coverage gap identified in buildingSMART/IDS#181. Every applicability block in the shipped test suite uses only the Entity facet; berlotti confirmed on #181 that "as you see in the XSD there is symmetry in applicability and requirements", so a classification facet should also be usable there. Only classified walls become applicable, so an unclassified wall with the wrong name is never checked, while a classified wall with the wrong name fails. + +``` ids classification/pass-a_classification_facet_can_be_used_for_applicability_1_2.ids +A classification facet can be used for applicability 1/2 +Entity: ''IFCWALL'' +Classification: Pattern(''\w+'') +Requirements: +Attribute: ''Name'',''Waldo'' +``` + +### A classification facet can be used for applicability 2/2 + +``` ids classification/fail-a_classification_facet_can_be_used_for_applicability_2_2.ids +A classification facet can be used for applicability 2/2 +Entity: ''IFCWALL'' +Classification: Pattern(''\w+'') +Requirements: +Attribute: ''Name'',''Waldo'' +``` + ### A classification facet with no data matches any classification 1/2 ``` ids classification/fail-a_classification_facet_with_no_data_matches_any_classification_1_2.ids @@ -2144,6 +2188,28 @@ Requirements: Property: ''Foo_Bar'',''Foo'',IFCLABEL ``` +### External load bearing walls need a fire rating property 1/2 + +Hand authored to close the applicability coverage gap identified in buildingSMART/IDS#181, and to add conformance coverage for the "External load bearing walls need to have a fire rating property for code compliance" worked example in specifications.md, which combines an Entity facet and a Property facet in the applicability with AND (intersection) semantics. + +``` ids property/pass-external_load_bearing_walls_need_a_fire_rating_property_1_2.ids +External load bearing walls need a fire rating property 1/2 +Entity: ''IFCWALL'' +Property: ''Pset_WallCommon'',''LoadBearing'',IFCBOOLEAN,''true'' +Requirements: +Property: ''Pset_WallCommon'',''FireRating'',IFCLABEL +``` + +### External load bearing walls need a fire rating property 2/2 + +``` ids property/fail-external_load_bearing_walls_need_a_fire_rating_property_2_2.ids +External load bearing walls need a fire rating property 2/2 +Entity: ''IFCWALL'' +Property: ''Pset_WallCommon'',''LoadBearing'',IFCBOOLEAN,''true'' +Requirements: +Property: ''Pset_WallCommon'',''FireRating'',IFCLABEL +``` + ### IDS does not handle string truncation such as for identifiers ``` ids property/fail-ids_does_not_handle_string_truncation_such_as_for_identifiers.ids diff --git a/RepositoryAutomation/SchemaProject/DocAutomation/IdsScript.cs b/RepositoryAutomation/SchemaProject/DocAutomation/IdsScript.cs index 0cde24ee..a514e0f8 100644 --- a/RepositoryAutomation/SchemaProject/DocAutomation/IdsScript.cs +++ b/RepositoryAutomation/SchemaProject/DocAutomation/IdsScript.cs @@ -183,6 +183,21 @@ private void PopulateApplicability(string app, SpecificationType spec) case EntityPrefix: spec.Applicability.Entity = MakeEntity(parts); break; + case AttributePrefix: + spec.Applicability.Attribute.Add(MakeAttribute(parts)); + break; + case ClassificationPrefix: + spec.Applicability.Classification.Add(MakeClassification(parts)); + break; + case MaterialPrefix: + spec.Applicability.Material.Add(MakeMaterial(parts)); + break; + case PartOfPrefix: + spec.Applicability.PartOf.Add(MakePartOf(parts)); + break; + case PropertyPrefix: + spec.Applicability.Property.Add(MakeProperty(parts)); + break; default: break; } @@ -359,6 +374,112 @@ private RequirementsTypeAttribute MakeReqAttribute(IList parts) return ret; } + private PropertyType MakeProperty(IList parts) + { + var ret = new PropertyType(); + if (parts.Count > 0 && parts[0] is ConditionalCardinality) + { + // cardinality is a requirements-only concept, not available on applicability facets + parts.RemoveAt(0); + } + + // try get datatype + for (int i = 0; i < parts.Count;) + { + if (parts[i] is IfcClassName st) + { + ret.DataType = st.Value; + parts.RemoveAt(i); + continue; + } + i++; + } + + if (parts.Count > 0) + ret.PropertySet = MakeIdsValue(parts[0]); + if (parts.Count > 1) + ret.BaseName = MakeIdsValue(parts[1]); + if (parts.Count > 2) + ret.Value = MakeIdsValue(parts[2]); + return ret; + } + + private PartOfType MakePartOf(IList parts) + { + var ret = new PartOfType(); + if (parts.Count > 0 && parts[0] is ConditionalCardinality) + { + // cardinality is a requirements-only concept, not available on applicability facets + parts.RemoveAt(0); + } + for (int i = 0; i < parts.Count; ) + { + if (parts[i] is IfcClassName st) + { + if (TryGetRelation(st.Value, out var rel)) + { + ret.Relation = rel; + parts.RemoveAt(i); + continue; + } + } + i++; + } + ret.Entity = new EntityType(); + if (parts.Count > 0) + ret.Entity.Name = MakeIdsValue(parts[0]); + if (parts.Count > 1) + { + ret.Entity.PredefinedType = MakeIdsValue(parts[1]); + } + return ret; + } + + private MaterialType MakeMaterial(IList parts) + { + var ret = new MaterialType(); + if (parts.Count > 0 && parts[0] is ConditionalCardinality) + { + // cardinality is a requirements-only concept, not available on applicability facets + parts.RemoveAt(0); + } + if (parts.Count > 0) + ret.Value = MakeIdsValue(parts[0]); + return ret; + } + + private ClassificationType MakeClassification(IList parts) + { + var ret = new ClassificationType(); + if (parts.Count > 0 && parts[0] is ConditionalCardinality) + { + // cardinality is a requirements-only concept, not available on applicability facets + parts.RemoveAt(0); + } + if (parts.Count > 0) + ret.System = MakeIdsValue(parts[0]); + if (parts.Count > 1) + ret.Value = MakeIdsValue(parts[1]); + + return ret; + } + + private AttributeType MakeAttribute(IList parts) + { + var ret = new AttributeType(); + if (parts.Count > 0 && parts[0] is ConditionalCardinality) + { + // cardinality is a requirements-only concept, not available on applicability facets + parts.RemoveAt(0); + } + if (parts.Count > 0) + ret.Name = MakeIdsValue(parts[0]); + if (parts.Count > 1) + ret.Value = MakeIdsValue(parts[1]); + + return ret; + } + private EntityType? MakeEntity(IList parts) { var ret = new EntityType();