Skip to content

Commit bce861e

Browse files
Merge pull request #1010 from hypar-io/ifc-openings-for-instances
instance openings for ifc (#1010)
2 parents 657afd7 + 07b7071 commit bce861e

File tree

4 files changed

+1030
-12
lines changed

4 files changed

+1030
-12
lines changed

Elements.Serialization.IFC/src/Serialization/IFC/IFCElementExtensions.cs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,27 @@ internal static List<IfcProduct> ToIfcProducts(this Element e,
3030
if (e is ElementInstance)
3131
{
3232
// If we're using an element instance, get the transform
33-
// and the id and use those to uniquely position and
33+
// and the id and use those to uniquely position and
3434
// identify the element.
3535
var instance = (ElementInstance)e;
3636
geoElement = instance.BaseDefinition;
3737
id = instance.Id;
3838
trans = instance.Transform;
39+
40+
if (geoElement is IHasOpenings geoElementWithOpenings)
41+
{
42+
for (int i = 0; i < geoElementWithOpenings.Openings.Count; i++)
43+
{
44+
Opening opening = geoElementWithOpenings.Openings[i];
45+
var transform = opening.Transform.Concatenated(trans);
46+
var newOpening = new Opening(opening.Perimeter, opening.DepthFront, opening.DepthBack, transform,
47+
opening.Representation, opening.IsElementDefinition, default, opening.Name);
48+
49+
ToIfcProducts(newOpening, context, doc, styleAssignments, updateElementRepresentation);
50+
51+
geoElementWithOpenings.Openings[i] = newOpening;
52+
}
53+
}
3954
}
4055
else if (e is GeometricElement)
4156
{
@@ -75,17 +90,17 @@ internal static List<IfcProduct> ToIfcProducts(this Element e,
7590
if (op is Sweep sweep)
7691
{
7792

78-
// Neither of these entities, which are part of the
79-
// IFC4 specification, and which would allow a sweep
80-
// along a curve, are supported by many applications
93+
// Neither of these entities, which are part of the
94+
// IFC4 specification, and which would allow a sweep
95+
// along a curve, are supported by many applications
8196
// which are supposedly IFC4 compliant (Revit). For
8297
// Those applications where these entities appear,
83-
// the rotation of the profile is often wrong or
98+
// the rotation of the profile is often wrong or
8499
// inconsistent.
85100
// geom = sweep.ToIfcSurfaceCurveSweptAreaSolid(doc);
86101
// geom = sweep.ToIfcFixedReferenceSweptAreaSolid(geoElement.Transform, doc);
87102

88-
// Instead, we'll divide the curve and create a set of
103+
// Instead, we'll divide the curve and create a set of
89104
// linear extrusions instead.
90105
Polyline pline;
91106
if (sweep.Curve is Line)
@@ -169,7 +184,7 @@ internal static List<IfcProduct> ToIfcProducts(this Element e,
169184

170185
// If the element has openings, make opening relationships in
171186
// the IfcElement.
172-
if (e is IHasOpenings openings)
187+
if (geoElement is IHasOpenings openings)
173188
{
174189
if (openings.Openings.Count > 0)
175190
{
@@ -232,7 +247,7 @@ private static IfcDoorTypeOperationEnum GetIfcDoorTypeOperation(this Door door)
232247
{
233248
if (door.OpeningType == DoorOpeningType.SingleSwing)
234249
{
235-
switch(door.OpeningSide)
250+
switch (door.OpeningSide)
236251
{
237252
case DoorOpeningSide.LeftHand:
238253
return IfcDoorTypeOperationEnum.SINGLE_SWING_LEFT;
@@ -241,7 +256,7 @@ private static IfcDoorTypeOperationEnum GetIfcDoorTypeOperation(this Door door)
241256
case DoorOpeningSide.DoubleDoor:
242257
return IfcDoorTypeOperationEnum.DOUBLE_DOOR_SINGLE_SWING;
243258
}
244-
}
259+
}
245260
else if (door.OpeningType == DoorOpeningType.DoubleSwing)
246261
{
247262
switch (door.OpeningSide)
@@ -274,7 +289,9 @@ internal static IfcLocalPlacement ToIfcLocalPlacement(this Transform transform,
274289

275290
internal static IfcExtrudedAreaSolid ToIfcExtrudedAreaSolid(this Extrude extrude, Document doc)
276291
{
277-
var position = new Transform().ToIfcAxis2Placement3D(doc);
292+
// Add local transform to the IFC placement
293+
var transform = extrude.LocalTransform ?? new Transform();
294+
var position = transform.ToIfcAxis2Placement3D(doc);
278295

279296
var extrudeDepth = extrude.Height;
280297
var extrudeProfile = extrude.Profile.Perimeter.ToIfcArbitraryClosedProfileDef(doc);
@@ -301,7 +318,7 @@ private static IfcBoundedCurve ToIfcCurve(this ICurve curve, Document doc)
301318
{
302319
return arc.ToIfcTrimmedCurve(doc);
303320
}
304-
// Test Polygon before Polyline to avoid
321+
// Test Polygon before Polyline to avoid
305322
// Polygons being treated as Polylines.
306323
else if (curve is Polygon polygon)
307324
{
@@ -527,7 +544,7 @@ private static IfcSlab ToIfc(this Floor floor, Guid id,
527544
}
528545

529546
// TODO: There is a lot of duplicate code used to create products.
530-
// Can we make a generic method like ToIfc<TProduct>()? There are
547+
// Can we make a generic method like ToIfc<TProduct>()? There are
531548
// exceptions for which this won't work like IfcSpace.
532549

533550
private static IfcSpace ToIfc(this Space space, Guid id,

Elements.Serialization.IFC/test/Elements.Serialization.IFC.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@
1818
<ProjectReference Include="..\src\Elements.Serialization.IFC.csproj" />
1919
</ItemGroup>
2020

21+
<ItemGroup>
22+
<Folder Include="models\Hypar\" />
23+
</ItemGroup>
24+
2125
</Project>

Elements.Serialization.IFC/test/IFCTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Xunit.Abstractions;
88
using System.Collections.Generic;
99
using Elements.Geometry.Profiles;
10+
using System.Linq;
1011

1112
namespace Elements.IFC.Tests
1213
{
@@ -56,6 +57,26 @@ public void IFC2X3(string name, string ifcPath, string[] idsToConvert = null)
5657
model.ToGlTF(ConstructGlbPath(name));
5758
}
5859

60+
[Fact]
61+
public void InstanceOpenings()
62+
{
63+
var model = System.IO.File.ReadAllText("../../../models/Hypar/instance-openings-test-model.json");
64+
var hyparModel = Model.FromJson(model);
65+
var walls = hyparModel.AllElementsOfType<StandardWall>();
66+
var path = ConstructIfcPath("instance-openings-test");
67+
hyparModel.ToIFC(path);
68+
69+
var file = System.IO.File.ReadAllLines(path);
70+
71+
var wallCount = file.Count(x => x.Contains("IFCWALLSTANDARDCASE"));
72+
var openingCount = file.Count(x => x.Contains("IFCRELVOIDSELEMENT"));
73+
var floorCount = file.Count(x => x.Contains("IFCSLAB"));
74+
75+
Assert.Equal(wallCount, 4);
76+
Assert.Equal(openingCount, 5);
77+
Assert.Equal(floorCount, 1);
78+
}
79+
5980
[Fact]
6081
public void Doors()
6182
{

0 commit comments

Comments
 (0)