Skip to content

Commit 801b078

Browse files
committed
Merged PR 1623: Merged PR 1622: Added support for querying older schemas with newer types.
Merged PR 1622: Added support for querying older schemas with newer types. Added support for querying older schemas with newer types. Handles 'AirTerminal' scenario in IFC2x3. e.g. buildingSMART/IDS#116 Fixed up some of the PredefinedType searching gaps. Now queries ObjectType on the instance as well as PredefinedType. Inheritance from Type is TODO.
2 parents f19503c + 0dcf95c commit 801b078

19 files changed

+673
-113
lines changed

Xbim.IDS.Validator.Core.Tests/Binders/BaseModelTester.cs

+60-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.Logging;
1+
using FluentAssertions;
2+
using Microsoft.Extensions.Logging;
23
using Xbim.Common;
34
using Xbim.Common.Step21;
45
using Xbim.IDS.Validator.Core.Binders;
@@ -99,6 +100,63 @@ public enum ConstraintType
99100
Range,
100101
Structure
101102
}
102-
103+
104+
105+
protected void AssertIfcTypeFacetQuery(IfcTypeFacetBinder typeFacetBinder, string ifcType, int expectedCount, Type[] expectedTypes, string predefinedType = "",
106+
ConstraintType ifcTypeConstraint = ConstraintType.Exact, ConstraintType preConstraint = ConstraintType.Exact, bool includeSubTypes = true)
107+
{
108+
IfcTypeFacet facet = BuildIfcTypeFacetFromCsv(ifcType, predefinedType, includeSubTypes, ifcTypeConstraint, preDefConstraint: preConstraint);
109+
110+
// Act
111+
var expression = typeFacetBinder.BindSelectionExpression(query.InstancesExpression, facet);
112+
113+
// Assert
114+
115+
var result = query.Execute(expression, Model);
116+
117+
result.Should().HaveCount(expectedCount);
118+
119+
if (expectedCount > 0)
120+
{
121+
result.Should().AllSatisfy(t =>
122+
expectedTypes.Where(e => e.IsAssignableFrom(t.GetType()))
123+
.Should().ContainSingle($"Found {t.GetType().Name}, and expected one of {string.Join(',', expectedTypes.Select(t => t.Name))}"));
124+
125+
}
126+
}
127+
128+
129+
private static IfcTypeFacet BuildIfcTypeFacetFromCsv(string ifcTypeCsv, string predefinedTypeCsv = "", bool includeSubTypes = false,
130+
ConstraintType ifcConstraint = ConstraintType.Exact, ConstraintType preDefConstraint = ConstraintType.Exact)
131+
{
132+
IfcTypeFacet facet = new IfcTypeFacet
133+
{
134+
IfcType = new ValueConstraint(NetTypeName.String),
135+
PredefinedType = new ValueConstraint(NetTypeName.String),
136+
IncludeSubtypes = includeSubTypes,
137+
};
138+
139+
var ifcValues = ifcTypeCsv.Split(',');
140+
foreach (var ifcVal in ifcValues)
141+
{
142+
if (string.IsNullOrEmpty(ifcVal)) continue;
143+
if (ifcConstraint == ConstraintType.Pattern)
144+
facet.IfcType.AddAccepted(new PatternConstraint(ifcVal));
145+
else
146+
facet.IfcType.AddAccepted(new ExactConstraint(ifcVal));
147+
}
148+
149+
var pdTypes = predefinedTypeCsv.Split(',');
150+
foreach (var predef in pdTypes)
151+
{
152+
if (string.IsNullOrEmpty(predef)) continue;
153+
if (preDefConstraint == ConstraintType.Pattern)
154+
facet.PredefinedType.AddAccepted(new PatternConstraint(predef));
155+
else
156+
facet.PredefinedType.AddAccepted(new ExactConstraint(predef));
157+
}
158+
return facet;
159+
}
160+
103161
}
104162
}

Xbim.IDS.Validator.Core.Tests/Binders/IfcTypeFacetBinder2x3Tests.cs

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using FluentAssertions;
22
using Xbim.IDS.Validator.Core.Binders;
3+
using Xbim.Ifc4.Interfaces;
34
using Xbim.InformationSpecifications;
45
using Xunit.Abstractions;
56

@@ -54,5 +55,22 @@ public void Can_Validate_Types(int entityLabel, string expectedType, string expe
5455
}
5556

5657
}
58+
59+
[InlineData("IFCELECTRICAPPLIANCETYPE", "", 1, typeof(IIfcElectricApplianceType))] // In 2x3
60+
[InlineData("IFCELECTRICAPPLIANCE", "", 3, typeof(IIfcFlowTerminal))] // Implicit via Type
61+
[InlineData("IFCLIGHTFIXTURE", "", 24, typeof(IIfcFlowTerminal))] // Implicit via Type
62+
[InlineData("IFCLAMP", "", 0, typeof(IIfcFlowTerminal))] // Implicit via Type
63+
[InlineData("IFCOUTLET", "", 0, typeof(IIfcFlowTerminal))] // Implicit via Type
64+
[InlineData("IfcSanitaryTerminal", "", 0, typeof(IIfcFlowTerminal))] // Implicit via Type
65+
[InlineData("IFCDOORTYPE", "", 19, typeof(IIfcDoorStyle))] // Using 4x equivalent in 2x3
66+
[InlineData("IFCWINDOWTYPE", "", 9, typeof(IIfcWindowStyle))] // Using 4x equivalent in 2x3
67+
[InlineData("IFCWINDOWTYPE", "Unknown", 0, typeof(IIfcWindowStyle))] // Using 4x equivalent in 2x3
68+
// [InlineData("IFCLIGHTFIXTURE", "NOTDEFINED", 24, typeof(IIfcFlowTerminal))] // Implicit via Type with Predefined TODO: Needs implementation
69+
[Theory]
70+
public void Ifc2x3_Can_Use_Types_From_Newer_Schemas(string ifcType, string predefinedType, int expectedCount, params Type[] expectedTypes)
71+
{
72+
73+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, predefinedType, ifcTypeConstraint: ConstraintType.Exact, includeSubTypes: false);
74+
}
5775
}
5876
}

Xbim.IDS.Validator.Core.Tests/Binders/IfcTypeFacetBinderTests.cs

+7-60
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public IfcTypeFacetBinderTests(ITestOutputHelper output) : base(output)
3434
[Theory]
3535
public void Can_Query_Exact_IfcType(string ifcType, int expectedCount, params Type[] expectedTypes)
3636
{
37-
AssertIfcTypeFacetQuery(ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Exact);
37+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Exact);
3838
}
3939

4040

@@ -45,7 +45,7 @@ public void Can_Query_Exact_IfcType(string ifcType, int expectedCount, params Ty
4545
[Theory]
4646
public void Can_Query_Exact_IfcType_WithoutSubtypes(string ifcType, int expectedCount, params Type[] expectedTypes)
4747
{
48-
AssertIfcTypeFacetQuery(ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Exact, includeSubTypes: false);
48+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Exact, includeSubTypes: false);
4949
}
5050

5151
[InlineData("IfcWall.*", 9, typeof(IIfcWall), typeof(IIfcWallType))]
@@ -59,7 +59,7 @@ public void Can_Query_Exact_IfcType_WithoutSubtypes(string ifcType, int expected
5959
[Theory]
6060
public void Can_Query_IfcType_Patterns(string ifcType, int expectedCount, params Type[] expectedTypes)
6161
{
62-
AssertIfcTypeFacetQuery(ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Pattern);
62+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, ifcTypeConstraint: ConstraintType.Pattern);
6363
}
6464

6565

@@ -96,17 +96,19 @@ public void Invalid_IfcTypes_Handled(string ifcType)
9696
[InlineData("IfcWall", "SOLIDWALL,PARTITIONING", 2, typeof(IIfcWall))]
9797
[InlineData("IfcWall,IfcWallType", "SOLIDWALL,PARTITIONING", 3, typeof(IIfcWall), typeof(IIfcWallType))]
9898
[InlineData("IfcWallStandardCase,IfcWallType", "NOTDEFINED", 2, typeof(IIfcWallStandardCase), typeof(IIfcWallType))]
99+
[InlineData("IfcDoor", "1810x2110mm", 1, typeof(IIfcDoor))]
100+
[InlineData("IfcDoor", "DOOR", 3, typeof(IIfcDoor))]
99101
[Theory]
100102
public void Can_Query_Exact_IfcTypeWith_PredefinedType(string ifcType, string predefinedType, int expectedCount, params Type[] expectedTypes)
101103
{
102-
AssertIfcTypeFacetQuery(ifcType, expectedCount, expectedTypes, predefinedType, preConstraint: ConstraintType.Exact);
104+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, predefinedType, preConstraint: ConstraintType.Exact);
103105
}
104106

105107
[InlineData("IfcWall", "SOLID.*", 1, typeof(IIfcWall))]
106108
[Theory]
107109
public void Can_Query_IfcTypeWith_PredefinedType_ByPattern(string ifcType, string predefinedType, int expectedCount, params Type[] expectedTypes)
108110
{
109-
AssertIfcTypeFacetQuery(ifcType, expectedCount, expectedTypes, predefinedType, preConstraint: ConstraintType.Pattern);
111+
AssertIfcTypeFacetQuery(Binder, ifcType, expectedCount, expectedTypes, predefinedType, preConstraint: ConstraintType.Pattern);
110112
}
111113

112114

@@ -152,61 +154,6 @@ public void Can_Validate_Types(int entityLabel, string expectedType, string expe
152154

153155

154156

155-
private void AssertIfcTypeFacetQuery(string ifcType, int expectedCount, Type[] expectedTypes, string predefinedType = "",
156-
ConstraintType ifcTypeConstraint = ConstraintType.Exact, ConstraintType preConstraint = ConstraintType.Exact, bool includeSubTypes = true)
157-
{
158-
IfcTypeFacet facet = BuildIfcTypeFacetFromCsv(ifcType, predefinedType, includeSubTypes, ifcTypeConstraint, preDefConstraint: preConstraint);
159-
160-
// Act
161-
var expression = Binder.BindSelectionExpression(query.InstancesExpression, facet);
162-
163-
// Assert
164-
165-
var result = query.Execute(expression, Model);
166-
167-
result.Should().HaveCount(expectedCount);
168-
169-
if (expectedCount > 0)
170-
{
171-
result.Should().AllSatisfy(t =>
172-
expectedTypes.Where(e => e.IsAssignableFrom(t.GetType()))
173-
.Should().ContainSingle($"Found {t.GetType().Name}, and expected one of {string.Join(',', expectedTypes.Select(t => t.Name))}"));
174-
175-
}
176-
}
177-
178-
179-
private static IfcTypeFacet BuildIfcTypeFacetFromCsv(string ifcTypeCsv, string predefinedTypeCsv = "", bool includeSubTypes = false,
180-
ConstraintType ifcConstraint = ConstraintType.Exact, ConstraintType preDefConstraint = ConstraintType.Exact)
181-
{
182-
IfcTypeFacet facet = new IfcTypeFacet
183-
{
184-
IfcType = new ValueConstraint(NetTypeName.String),
185-
PredefinedType = new ValueConstraint(NetTypeName.String),
186-
IncludeSubtypes = includeSubTypes,
187-
};
188-
189-
var ifcValues = ifcTypeCsv.Split(',');
190-
foreach (var ifcVal in ifcValues)
191-
{
192-
if (string.IsNullOrEmpty(ifcVal)) continue;
193-
if (ifcConstraint == ConstraintType.Pattern)
194-
facet.IfcType.AddAccepted(new PatternConstraint(ifcVal));
195-
else
196-
facet.IfcType.AddAccepted(new ExactConstraint(ifcVal));
197-
}
198-
199-
var pdTypes = predefinedTypeCsv.Split(',');
200-
foreach (var predef in pdTypes)
201-
{
202-
if (string.IsNullOrEmpty(predef)) continue;
203-
if (preDefConstraint == ConstraintType.Pattern)
204-
facet.PredefinedType.AddAccepted(new PatternConstraint(predef));
205-
else
206-
facet.PredefinedType.AddAccepted(new ExactConstraint(predef));
207-
}
208-
return facet;
209-
}
210157

211158

212159
}

Xbim.IDS.Validator.Core.Tests/ModelGenerator.cs

+64-12
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,29 @@
33
using Xbim.Common.Enumerations;
44
using Xbim.Common.Step21;
55
using Xbim.Ifc;
6+
using Xbim.IO.Memory;
67

78
namespace Xbim.IDS.Validator.Core.Tests
89
{
910
[Collection(nameof(TestEnvironment))]
1011
public class ModelGenerator
1112
{
13+
XbimEditorCredentials editor = new XbimEditorCredentials
14+
{
15+
ApplicationFullName = "xbim IDS",
16+
ApplicationIdentifier = "xbim IDS Tests",
17+
EditorsOrganisationName = "xbim Ltd",
18+
EditorsGivenName = "Andy",
19+
EditorsFamilyName = "Ward",
20+
ApplicationVersion = "1.0",
21+
ApplicationDevelopersName = "xbim"
22+
};
23+
1224
[Fact]
1325
public void CanCreateMinimalModel()
1426
{
1527
string filename = "file.ifc";
16-
var editor = new XbimEditorCredentials
17-
{
18-
ApplicationFullName = "xbim IDS",
19-
ApplicationIdentifier = "xbim IDS Tests",
20-
EditorsOrganisationName = "xbim Ltd",
21-
EditorsGivenName = "Andy",
22-
EditorsFamilyName="Ward",
23-
ApplicationVersion= "1.0",
24-
ApplicationDevelopersName="xbim"
25-
};
28+
2629
//new MemoryModel(new Ifc2x3.EntityFactoryIfc2x3());
2730
var model = IfcStore.Create(editor, XbimSchemaVersion.Ifc4x3, IO.XbimStoreType.InMemoryModel);
2831
AddHeaders(model, filename);
@@ -45,15 +48,64 @@ public void CanCreateMinimalModel()
4548
trans.Commit();
4649
}
4750

48-
49-
5051
using (var sw = new FileStream(filename, FileMode.Create))
5152
{
5253
model.SaveAsIfc(sw);
5354
}
5455
model.Dispose();
5556
}
5657

58+
[Fact]
59+
public void CanCreateIfc2x3Model()
60+
{
61+
string filename = "ifc2x3.ifc";
62+
63+
using var model = new MemoryModel(new Ifc2x3.EntityFactoryIfc2x3());
64+
using var trans = model.BeginTransaction("Create");
65+
using var sw = new FileStream(filename, FileMode.Create);
66+
67+
AddHeaders(model, filename);
68+
model.Instances.New<Ifc2x3.SharedBldgElements.IfcDoorStyle>(w =>
69+
{
70+
w.Name = "Test";
71+
w.ConstructionType = Ifc2x3.SharedBldgElements.IfcDoorStyleConstructionEnum.NOTDEFINED;
72+
});
73+
74+
trans.Commit();
75+
model.SaveAsIfc(sw);
76+
}
77+
78+
[Fact]
79+
public void CanCreateIfc2x3AirTerminalModel()
80+
{
81+
string filename = "ifc2x3-air-terminal.ifc";
82+
83+
using var model = new MemoryModel(new Ifc2x3.EntityFactoryIfc2x3());
84+
using var trans = model.BeginTransaction("Create");
85+
using var sw = new FileStream(filename, FileMode.Create);
86+
87+
AddHeaders(model, filename);
88+
var type = model.Instances.New<Ifc2x3.HVACDomain.IfcAirTerminalType>(w =>
89+
{
90+
w.Name = "AirTerminalType";
91+
w.PredefinedType = Ifc2x3.HVACDomain.IfcAirTerminalTypeEnum.GRILLE;
92+
});
93+
var instance = model.Instances.New<Ifc2x3.SharedBldgServiceElements.IfcFlowTerminal>(w =>
94+
{
95+
w.Name = "AirTerminal";
96+
});
97+
98+
//var instance4 = model.Instances.New<Ifc4.HvacDomain.IfcAirTerminal>(w =>
99+
//{
100+
// w.Name = "AirTerminal";
101+
// w.PredefinedType = Ifc4.Interfaces.IfcAirTerminalTypeEnum.GRILLE;
102+
//});
103+
instance.AddDefiningType(type);
104+
105+
trans.Commit();
106+
model.SaveAsIfc(sw);
107+
}
108+
57109
private static void AddHeaders(IModel model, string filename)
58110
{
59111
model.Header.FileDescription.Description.Add("ViewDefinition [CoordinationView]");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<ids xmlns="http://standards.buildingsmart.org/IDS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://standards.buildingsmart.org/IDS/ids_05.xsd">
2+
<info>
3+
<title>IFC2x3 doesn't have AirTerminal instance, but does have AirTerminalType which can be used to infer instance</title>
4+
</info>
5+
<specifications>
6+
<specification name="IFC2x3 doesn't have AirTerminal instance, but does have AirTerminalType which can be used to infer instance" ifcVersion="IFC2X3" minOccurs="1" maxOccurs="unbounded">
7+
<applicability>
8+
<entity>
9+
<name>
10+
<simpleValue>IFCAIRTERMINAL</simpleValue>
11+
</name>
12+
<predefinedType>
13+
<simpleValue>NOTVALID</simpleValue>
14+
</predefinedType>
15+
</entity>
16+
</applicability>
17+
<requirements>
18+
<entity>
19+
<name>
20+
<simpleValue>IFCFLOWTERMINAL</simpleValue>
21+
</name>
22+
</entity>
23+
</requirements>
24+
</specification>
25+
</specifications>
26+
</ids>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
ISO-10303-21;
2+
HEADER;
3+
FILE_DESCRIPTION (('ViewDefinition [CoordinationView]'), '2;1');
4+
FILE_NAME ('pass-ifc2x3-air_terminal_edge_case.ifc', '2023-05-03T18:17:26', ('Andy Ward'), ('xbim Ltd'), 'xbim Toolkit', 'xbim IDS Unit tests', 'n/a');
5+
FILE_SCHEMA (('IFC2X3'));
6+
ENDSEC;
7+
DATA;
8+
#1=IFCAIRTERMINALTYPE($,$,'AirTerminalType',$,$,$,$,$,$,.GRILLE.);
9+
#2=IFCFLOWTERMINAL($,$,'AirTerminal',$,$,$,$,$);
10+
#3=IFCRELDEFINESBYTYPE($,$,$,$,(#2),#1);
11+
ENDSEC;
12+
END-ISO-10303-21;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<ids xmlns="http://standards.buildingsmart.org/IDS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://standards.buildingsmart.org/IDS/ids_05.xsd">
2+
<info>
3+
<title>IFC2x3 doesn't have AirTerminal instance, but does have AirTerminalType which can be used to infer instance</title>
4+
</info>
5+
<specifications>
6+
<specification name="IFC2x3 doesn't have AirTerminal instance, but does have AirTerminalType which can be used to infer instance" ifcVersion="IFC2X3" minOccurs="1" maxOccurs="unbounded">
7+
<applicability>
8+
<entity>
9+
<name>
10+
<simpleValue>IFCAIRTERMINAL</simpleValue>
11+
</name>
12+
</entity>
13+
</applicability>
14+
<requirements>
15+
<entity>
16+
<name>
17+
<simpleValue>IFCFLOWTERMINAL</simpleValue>
18+
</name>
19+
<predefinedType>
20+
<simpleValue>GRILLE</simpleValue>
21+
</predefinedType>
22+
</entity>
23+
</requirements>
24+
</specification>
25+
</specifications>
26+
</ids>

0 commit comments

Comments
 (0)