Skip to content

Commit

Permalink
Merge pull request #1021 from srudenkoamc/ifc-serialization-refactoring
Browse files Browse the repository at this point in the history
Ifc serialization improvements
  • Loading branch information
anthonie-kramer authored Nov 8, 2023
2 parents e49f5be + 20bcf69 commit 6d10065
Show file tree
Hide file tree
Showing 34 changed files with 125,200 additions and 914 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
- `Elements.MEP`
- `GeometricElement.RepresentationInstances`
- `ContentRepresentation`
- `Elements.Door`

### Fixed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Hypar.Elements.Serialization.IFC</AssemblyName>
<PackageTitle>Hypar Elements Serialization IFC</PackageTitle>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand All @@ -16,7 +16,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Hypar.IFC4" Version="0.1.4.1" />
<PackageReference Include="Hypar.IFC4" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Elements.Analysis;
using Elements.Geometry;
using Elements.Interfaces;
using Elements.Serialization.IFC.IFCToHypar;
using IFC;
using STEP;
using System;
Expand All @@ -25,141 +27,9 @@ public static class IFCModelExtensions
/// <returns>A model.</returns>
public static Model FromIFC(string path, out List<string> constructionErrors, IList<string> idsToConvert = null)
{
List<STEPError> errors;
var ifcModel = new Document(path, out errors);
foreach (var error in errors)
{
Console.WriteLine("***IFC ERROR***" + error.Message);
}

IEnumerable<IfcSlab> ifcSlabs = null;
IEnumerable<IfcSpace> ifcSpaces = null;
IEnumerable<IfcWallStandardCase> ifcWalls = null;
IEnumerable<IfcBeam> ifcBeams = null;
IEnumerable<IfcColumn> ifcColumns = null;
IEnumerable<IfcRelVoidsElement> ifcVoids = null;
IEnumerable<IfcRelAssociatesMaterial> ifcMaterials = null;
IEnumerable<IfcDoor> ifcDoors = null;

if (idsToConvert != null && idsToConvert.Count > 0)
{
ifcSlabs = ifcModel.AllInstancesOfType<IfcSlab>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcSpaces = ifcModel.AllInstancesOfType<IfcSpace>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcWalls = ifcModel.AllInstancesOfType<IfcWallStandardCase>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcBeams = ifcModel.AllInstancesOfType<IfcBeam>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcColumns = ifcModel.AllInstancesOfType<IfcColumn>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcVoids = ifcModel.AllInstancesOfType<IfcRelVoidsElement>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcMaterials = ifcModel.AllInstancesOfType<IfcRelAssociatesMaterial>().Where(i => idsToConvert.Contains(i.GlobalId));
ifcDoors = ifcModel.AllInstancesOfType<IfcDoor>().Where(i => idsToConvert.Contains(i.GlobalId));
}
else
{
ifcSlabs = ifcModel.AllInstancesOfType<IfcSlab>();
ifcSpaces = ifcModel.AllInstancesOfType<IfcSpace>();
ifcWalls = ifcModel.AllInstancesOfType<IfcWallStandardCase>();
ifcBeams = ifcModel.AllInstancesOfType<IfcBeam>();
ifcColumns = ifcModel.AllInstancesOfType<IfcColumn>();
ifcVoids = ifcModel.AllInstancesOfType<IfcRelVoidsElement>();
ifcMaterials = ifcModel.AllInstancesOfType<IfcRelAssociatesMaterial>();
ifcDoors = ifcModel.AllInstancesOfType<IfcDoor>();
}

constructionErrors = new List<string>();

var slabs = new List<Floor>();
foreach (var s in ifcSlabs)
{
try
{
slabs.Add(s.ToFloor(ifcVoids.Where(v => v.RelatingBuildingElement == s).Select(v => v.RelatedOpeningElement).Cast<IfcOpeningElement>()));
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}

}

var spaces = new List<Space>();
foreach (var sp in ifcSpaces)
{
try
{
spaces.Add(sp.ToSpace());
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}
}

var walls = new List<Wall>();
foreach (var w in ifcWalls)
{
try
{
walls.Add(w.ToWall(ifcVoids.Where(v => v.RelatingBuildingElement == w).Select(v => v.RelatedOpeningElement).Cast<IfcOpeningElement>()));
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}
}

var beams = new List<Beam>();
foreach (var b in ifcBeams)
{
try
{
beams.Add(b.ToBeam());
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}
}

var columns = new List<Column>();
foreach (var c in ifcColumns)
{
try
{
columns.Add(c.ToColumn());
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}
}

var doors = new List<Door>();
foreach (var d in ifcDoors)
{
try
{
doors.Add(d.ToDoor(walls));
}
catch (Exception ex)
{
constructionErrors.Add(ex.Message);
continue;
}
}

var model = new Model();
model.AddElements(slabs);
model.AddElements(spaces);
model.AddElements(walls);
model.AddElements(beams);
model.AddElements(columns);
model.AddElements(doors);

return model;
var modelProvider = new FromIfcModelProvider(path, idsToConvert: idsToConvert);
constructionErrors = modelProvider.GetConstructionErrors();
return modelProvider.Model;
}

private static Document CreateIfcDocument(this Model model, bool updateElementsRepresentation = true)
Expand Down Expand Up @@ -304,7 +174,7 @@ public static void ToIFC(this Model model,
{
File.Delete(path);
}
File.WriteAllText(path, ifc.ToSTEP(path));
File.WriteAllText(path, ifc.ToSTEP());
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Elements.Serialization.IFC.IFCToHypar.RepresentationsExtraction;
using IFC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Elements.Serialization.IFC.IFCToHypar.Converters
{
/// <summary>Uses a list of IFromIfcProductConverter to convert an IfcProduct to a GeometricElement.</summary>
internal class CompositeFromIfcProductConverter : IFromIfcProductConverter
{
private readonly List<IFromIfcProductConverter> _converters;
private readonly IFromIfcProductConverter _defaultConverter;

/// <summary>
/// Create a CompositeFromIfcProductConverter that uses <paramref name="converters"/> and <paramref name="defaultConverter"/>
/// to convert an IfcProduct to a GeometricElement.
/// </summary>
/// <param name="converters">A list, where CompositeFromIfcProductConverter looks for a converter that can convert an IfcProduct
/// to a GeometricElement.</param>
/// <param name="defaultConverter">A fallback converter, which will be used if none of <paramref name="converters"/> can convert
/// an IfcProduct to a GeometricElement.</param>
public CompositeFromIfcProductConverter(List<IFromIfcProductConverter> converters, IFromIfcProductConverter defaultConverter)
{
_converters = converters;
_defaultConverter = defaultConverter;
}

/// <summary>
/// Looks for a converter that can convert <paramref name="ifcProduct"/> to a GeometricElement within _converters.
/// If none of _converters can do the conversion, _defaultConverter is used instead.
/// Returns null if the conversion was unsuccessful.
/// </summary>
/// <param name="ifcProduct">IfcProduct to convert to a GeometricElement.</param>
/// <param name="representationData">Parsed Representation of <paramref name="ifcProduct"/>.</param>
/// <param name="constructionErrors">The list of construction errors that appeared during conversion.</param>
public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationData representationData, List<string> constructionErrors)
{
GeometricElement result;

foreach (var converter in _converters)
{
if (!converter.CanConvert(ifcProduct))
{
continue;
}

result = converter.ConvertToElement(ifcProduct, representationData, constructionErrors);

if (result != null)
{
return result;
}
}

return _defaultConverter.ConvertToElement(ifcProduct, representationData, constructionErrors);
}

/// <summary>
/// Returns true, if any of _converters or _defaultConverter can convert <paramref name="ifcProduct"/> to a GeometricElement.
/// </summary>
/// <param name="ifcProduct">IfcProduct that will be checked if it can be converted with this converter.</param>
public bool CanConvert(IfcProduct ifcProduct)
{
return _converters.Any(converter => converter.CanConvert(ifcProduct)) || _defaultConverter.CanConvert(ifcProduct);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Elements.Geometry;
using Elements.Geometry.Solids;
using Elements.Serialization.IFC.IFCToHypar.RepresentationsExtraction;
using IFC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Elements.Serialization.IFC.IFCToHypar.Converters
{
internal class FromIfcBeamConverter : IFromIfcProductConverter
{
public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationData repData, List<string> constructionErrors)
{
if (!(ifcProduct is IfcBeam ifcBeam))
{
return null;
}

var elementTransform = repData.Transform;

if (repData.Extrude == null)
{
constructionErrors.Add($"#{ifcProduct.StepId}: Conversion of IfcBeam without extrude or mapped item representation to Beam is not supported.");
return null;
}

var representation = new Representation(repData.SolidOperations);

var centerLine = new Line(Vector3.Origin, repData.Extrude.Direction, repData.Extrude.Height);
var transformedLine = centerLine.TransformedLine(repData.ExtrudeTransform);
var result = new Beam(transformedLine,
repData.Extrude.Profile,
0,
0,
0,
elementTransform,
repData.Material,
representation,
false,
IfcGuid.FromIfcGUID(ifcBeam.GlobalId),
ifcBeam.Name);

return result;
}

public bool CanConvert(IfcProduct ifcProduct)
{
return ifcProduct is IfcBeam;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Elements.Geometry;
using Elements.Geometry.Solids;
using Elements.Serialization.IFC.IFCToHypar.RepresentationsExtraction;
using IFC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Elements.Serialization.IFC.IFCToHypar.Converters
{
internal class FromIfcColumnConverter : IFromIfcProductConverter
{
public GeometricElement ConvertToElement(IfcProduct ifcProduct, RepresentationData repData, List<string> constructionErrors)
{
if (!(ifcProduct is IfcColumn ifcColumn))
{
return null;
}

var elementTransform = repData.Transform;

if (repData.Extrude == null)
{
constructionErrors.Add($"#{ifcProduct.StepId}: Conversion of IfcColumn without extrude or mapped item representation to Column is not supported.");
return null;
}

var result = new Column(repData.ExtrudeTransform.Origin,
repData.Extrude.Height,
null,
repData.Extrude.Profile,
0,
0,
0,
elementTransform,
repData.Material,
new Representation(repData.SolidOperations),
false,
IfcGuid.FromIfcGUID(ifcColumn.GlobalId),
ifcColumn.Name);
return result;
}

public bool CanConvert(IfcProduct ifcProduct)
{
return ifcProduct is IfcColumn;
}
}
}
Loading

0 comments on commit 6d10065

Please sign in to comment.