Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ea3983e
WIP: Implemented partial featuires for IfcObjects as cross schema ext…
andyward Feb 1, 2025
8820d6d
Added ActorResource and DateTimeResource partials for 4x3
andyward Feb 2, 2025
9a1bfe2
Further Extensions added
andyward Feb 3, 2025
54bfeb0
AddedMonetary and related Unit handling logic to IFC4x3. Reintroduced…
andyward Feb 4, 2025
120d8ca
WIP Unit assignment refactoring
andyward Feb 27, 2025
d86676a
Added IFC4 mapping support for IfcCoordinateReferenceSystem.VerticalD…
andyward Mar 5, 2025
4aa855a
Implement missing PredefinedType maps for IFC4x3
andyward Mar 6, 2025
a14aa29
Further IFc4x3 fixups and IFC4 mappings
andyward Mar 6, 2025
849ce6a
Merge pull request #604 from xBimTeam/feature/4x3-helpers
andyward Mar 6, 2025
ba17da4
Update to ExpressMetaData so we can host multiple schemas in a single…
andyward Mar 11, 2025
65aceb5
Added support for handling IfcStyledByItem creation with cross-schema…
andyward Mar 13, 2025
e85ef59
Added Test case for #605
andyward Mar 20, 2025
711e139
Fix parsing of invalid escape sequences in string literals (#606)
andyward Mar 25, 2025
2ec7561
Fixed up test issues after late change to how StepHeader FileName is …
andyward Mar 25, 2025
6dd8405
Merge pull request #607 from xBimTeam/fix/uptests
andyward Mar 25, 2025
bb3c80e
Re-use IfcApplications, IfcOrganisations/Persons when adding /editing…
andyward Mar 26, 2025
46fd49b
OptionalIfcLogicalTest for issue #502
highan911 Apr 17, 2023
81450e3
Updated to latest develop and expanded the tests to show the issue
andyward Mar 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,4 @@ FakesAssemblies/
SharedFileVersionInfo.cs
*.jfm
*.idea
/Xbim.Common/Step21/Parser/*.lst
4 changes: 2 additions & 2 deletions Tests/CommonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public void Can_skip_entities_while_parsing()
using (var strm = File.OpenRead(@"TestFiles\4walls1floorSite.ifc"))
{

var ifc2x3MetaData = ExpressMetaData.GetMetadata((new Xbim.Ifc2x3.EntityFactoryIfc2x3()).GetType().GetTypeInfo().Module);
var ifc4MetaData = ExpressMetaData.GetMetadata((new Xbim.Ifc4.EntityFactoryIfc4()).GetType().GetTypeInfo().Module);
var ifc2x3MetaData = ExpressMetaData.GetMetadata(new Xbim.Ifc2x3.EntityFactoryIfc2x3());
var ifc4MetaData = ExpressMetaData.GetMetadata(new Xbim.Ifc4.EntityFactoryIfc4());
var allTypes = new HashSet<string>(
ifc2x3MetaData.Types().Where(et => typeof(IPersistEntity).IsAssignableFrom(et.Type) && !et.Type.IsAbstract ).Select(et => et.ExpressNameUpper)
.Concat(ifc2x3MetaData.Types().Where(et => typeof(IPersistEntity).IsAssignableFrom(et.Type) && !et.Type.IsAbstract).Select(et => et.ExpressNameUpper)));
Expand Down
54 changes: 54 additions & 0 deletions Tests/ExpressMetadataTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using FluentAssertions;
using System;
using System.Reflection;
using Xbim.Common;
using Xbim.Common.Metadata;
using Xunit;

namespace Xbim.Essentials.Tests
{
public class ExpressMetadataTests
{
[InlineData(typeof(Xbim.Common.PersistEntity), 0)] // Nothing defined in this schema
[InlineData(typeof(Xbim.Ifc2x3.EntityFactoryIfc2x3), 771)]
[InlineData(typeof(Xbim.Ifc4.EntityFactoryIfc4), 933)]
[InlineData(typeof(Xbim.Ifc4.EntityFactoryIfc4x1), 933)]
[InlineData(typeof(Xbim.Ifc4x3.EntityFactoryIfc4x3Add2), 1008)]
[Theory]
[Obsolete]
public void HasExpectedSchemaTypesByModule(Type moduleType, int expectedTypes)
{

var m = moduleType.GetTypeInfo().Module;
var metaData = ExpressMetaData.GetMetadata(moduleType.Module);
metaData.Types().Should().HaveCount(expectedTypes);
}

[InlineData(typeof(Xbim.Ifc2x3.EntityFactoryIfc2x3), 771)]
[InlineData(typeof(Xbim.Ifc4.EntityFactoryIfc4), 933)]
[InlineData(typeof(Xbim.Ifc4.EntityFactoryIfc4x1), 933)]
[InlineData(typeof(Xbim.Ifc4x3.EntityFactoryIfc4x3Add2), 1008)]
[Theory]
public void HasExpectedSchemaTypesByFactory(Type moduleType, int expectedTypes)
{

var factory = Activator.CreateInstance(moduleType) as IEntityFactory;
factory.Should().NotBeNull();
var metaData = ExpressMetaData.GetMetadata(factory);
metaData.Types().Should().HaveCount(expectedTypes);
}

[Fact]
public void InvalidExpressTypeHandled()
{
var expressType = new ExpressType(typeof(Ifc2x3.ActorResource.IfcActorRole));
expressType.Should().NotBeNull();


Action act = () => new ExpressType(typeof(IPersistEntity));

act.Should().Throw<Exception>().WithMessage("Express Type is not defined for IPersistEntity");

}
}
}
318 changes: 318 additions & 0 deletions Tests/Ifc4ExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
using FluentAssertions;
using System;
using System.Linq;
using Xbim.Common;
using Xbim.Ifc;
using Xbim.IO.Memory;
using Xunit;
using XbimCommonSchema = Xbim.Ifc4;


namespace Xbim.Essentials.Tests
{
public class Ifc4ExtensionsTests : IDisposable
{
protected IModel Model { get; set; }
protected ITransaction Txn { get; set; }

public Ifc4ExtensionsTests()
{
Model = new MemoryModel(new Ifc4.EntityFactoryIfc4());
Txn = Model.BeginTransaction("Test");
}

[Fact]
public void CanAddDefiningType()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var type = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPileType>();
pile.AddDefiningType(type);

var relatingType = pile.IsTypedBy.First().RelatingType;
relatingType.Should().NotBeNull();
relatingType.Should().Be(type);
}

[Fact]
public void CanAddPropertySet()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p=>
{
p.Name = "Pset_Test";
});
pile.AddPropertySet(pset);

var pset2 = pile.PropertySets.First();
pset2.Should().NotBeNull();
pset2.Should().Be(pset);
}

[Fact]
public void CanGetPropertySet()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p => p.Name = "Pset_Test");
pile.AddPropertySet(pset);

var pset2 = pile.GetPropertySet("Pset_Test");
pset2.Should().NotBeNull();
pset2.Should().Be(pset);
}

[Fact]
public void GetPropertySetIsCaseSensitive()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p => p.Name = "Pset_Test");
pile.AddPropertySet(pset);

var pset2 = pile.GetPropertySet("pset_test");
pset2.Should().BeNull();
}

[Fact]
public void GetPropertySetCanBeCaseInsensitive()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p => p.Name = "Pset_Test");
pile.AddPropertySet(pset);

var pset2 = pile.GetPropertySet("pset_test", false);

pset2.Should().NotBeNull();
pset2.Should().Be(pset);
}

[Fact]
public void CanGetPropertySingle()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var prop = Model.Instances.New<Ifc4.PropertyResource.IfcPropertySingleValue>(p=>
{
p.Name = "SomeValue";
p.NominalValue = new Ifc4.MeasureResource.IfcLabel("Abc");
});
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p =>
{
p.Name = "Pset_Test";
p.HasProperties.Add(prop);
});
pile.AddPropertySet(pset);

var value = pile.GetPropertySingleValue("Pset_Test", "SomeValue");
value.Should().NotBeNull();
value.NominalValue.Value.Should().Be("Abc");
}

[Fact]
public void CanGetPropertySingleValue()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var prop = Model.Instances.New<Ifc4.PropertyResource.IfcPropertySingleValue>(p =>
{
p.Name = "SomeNumber";
p.NominalValue = new Ifc4.MeasureResource.IfcReal(100.5d);
});
var pset = Model.Instances.New<Ifc4.Kernel.IfcPropertySet>(p =>
{
p.Name = "Pset_Test";
p.HasProperties.Add(prop);
});
pile.AddPropertySet(pset);
var x= pile.GetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcReal >("", "");
var value = pile.GetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcReal>("Pset_Test", "SomeNumber");
value.Should().NotBeNull();
value.Value.Should().Be(100.5);
}

[Fact]
public void CanSetPropertySingleValue()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();

pile.SetPropertySingleValue("Pset_Test", "SomeProp", typeof(XbimCommonSchema.MeasureResource.IfcReal));

var value = pile.GetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcReal>("Pset_Test", "SomeProp");
value.Should().NotBeNull();
value.Value.Should().Be(0);
}


[Fact]
public void CanSetPropertySingleValueGeneric()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();

pile.SetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcReal>("Pset_Test", "SomeProp");

var value = pile.GetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcReal>("Pset_Test", "SomeProp");
value.Should().NotBeNull();
value.Value.Should().Be(0);
}

[Fact]
public void CanSetPropertySingleValueGenericEdgeCase()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();

pile.SetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcPositiveLengthMeasure>("Pset_Test", "SomeProp");

var value = pile.GetPropertySingleValue<XbimCommonSchema.MeasureResource.IfcPositiveLengthMeasure>("Pset_Test", "SomeProp");
value.Should().NotBeNull();
value.Value.Should().Be(1.0);
}

[Fact]
public void CanAddElementAndReadQuantity()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var quant = Model.Instances.New<Ifc4.QuantityResource.IfcQuantityArea>(qa =>
{
qa.Name = "GrossArea";
qa.AreaValue = 123.4d;
});
pile.AddQuantity("BaseQuants", quant, "Some measure");

var quantities = pile.GetElementQuantity("BaseQuants");
quantities.Should().NotBeNull();
var val = quantities.Quantities.First(q => q.Name == "GrossArea");

val.Should().BeOfType<Ifc4.QuantityResource.IfcQuantityArea>();
(val as Ifc4.QuantityResource.IfcQuantityArea).AreaValue.Value.Should().Be(123.4d);

}

[Fact]
public void CanAddElementAndReadPhysicalQuantity()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var quant = Model.Instances.New<Ifc4.QuantityResource.IfcQuantityArea>(qa =>
{
qa.Name = "GrossArea";
qa.AreaValue = 123.4d;
});
pile.AddQuantity("BaseQuants", quant, "Some measure");

var val = pile.GetQuantity<Ifc4.QuantityResource.IfcQuantityArea>("GrossArea");
val.Should().NotBeNull();
val.AreaValue.Value.Should().Be(123.4d);
}

[Fact]
public void CanAddElementAndReadPhysicalQuantityWithPset()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var quant = Model.Instances.New<Ifc4.QuantityResource.IfcQuantityArea>(qa =>
{
qa.Name = "GrossArea";
qa.AreaValue = 123.4d;
});
pile.AddQuantity("BaseQuants", quant, "Some measure");

var val = pile.GetQuantity<Ifc4.QuantityResource.IfcQuantityArea>("BaseQuants", "GrossArea");
val.Should().NotBeNull();
val.AreaValue.Value.Should().Be(123.4d);
}

[Fact]
public void CanAddElementAndReadPhysicalSimpleQuantityWithPset()
{
var pile = Model.Instances.New<Ifc4.StructuralElementsDomain.IfcPile>();
var quant = Model.Instances.New<Ifc4.QuantityResource.IfcQuantityArea>(qa =>
{
qa.Name = "GrossArea";
qa.AreaValue = 123.4d;
});
pile.AddQuantity("BaseQuants", quant, "Some measure");

var val = pile.GetElementPhysicalSimpleQuantity("BaseQuants", "GrossArea");
val.Should().NotBeNull();
val.Should().BeOfType<Ifc4.QuantityResource.IfcQuantityArea>();
}

[InlineData("GFA", XbimQuantityTypeEnum.Area, 15.5d, Ifc4.Interfaces.IfcSIUnitName.SQUARE_METRE)]
[InlineData("Width", XbimQuantityTypeEnum.Length, 1200.4d, Ifc4.Interfaces.IfcSIUnitName.METRE)]
[InlineData("Volume", XbimQuantityTypeEnum.Volume, 12234d, Ifc4.Interfaces.IfcSIUnitName.CUBIC_METRE)]
[InlineData("Count", XbimQuantityTypeEnum.Count, 14d, null)]
[InlineData("Weight", XbimQuantityTypeEnum.Weight, 999, Ifc4.Interfaces.IfcSIUnitName.GRAM, Ifc4.Interfaces.IfcSIPrefix.KILO)]
[InlineData("Duration", XbimQuantityTypeEnum.Time, 10d, Ifc4.Interfaces.IfcSIUnitName.SECOND)]
[Theory]
public void CanSetElementPhysicalSimpleQuantity(string quantName, XbimQuantityTypeEnum measure, double value,
Ifc4.Interfaces.IfcSIUnitName? unitType, Ifc4.Interfaces.IfcSIPrefix? unitPrefix = null)
{
var space = Model.Instances.New<Ifc4.ProductExtension.IfcSpace>();
Ifc4.MeasureResource.IfcNamedUnit unit = null;
if(unitType != null)
{
unit = Model.Instances.New<Ifc4.MeasureResource.IfcSIUnit>(u =>
{
u.Name = unitType.Value;
u.Prefix = unitPrefix;
});
}

space.SetElementPhysicalSimpleQuantity("BaseQuants", quantName, value, measure, unit);

Ifc4.MeasureResource.IfcMeasureValue val = measure switch
{
XbimQuantityTypeEnum.Area => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityArea>("BaseQuants", quantName).AreaValue,
XbimQuantityTypeEnum.Length => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityLength>("BaseQuants", quantName).LengthValue,
XbimQuantityTypeEnum.Volume => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityVolume>("BaseQuants", quantName).VolumeValue,
XbimQuantityTypeEnum.Count => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityCount>("BaseQuants", quantName).CountValue,
XbimQuantityTypeEnum.Weight => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityWeight>("BaseQuants", quantName).WeightValue,
XbimQuantityTypeEnum.Time => space.GetQuantity<Ifc4.QuantityResource.IfcQuantityTime>("BaseQuants", quantName).TimeValue,
_ => throw new NotImplementedException(),
};

val.Value.Should().Be(value);
//area.Unit.FullName.Should().Be("SQUAREMETRE");

}

[InlineData("USD", "$", "US Dollar")]
[InlineData("GBP", "£", "British Pound", "Pound Sterling")]
[InlineData("EUR", "€", "Euro", "euro")] // 'euro' since French culture picked up by default
[InlineData("CAD", "$", "Canadian Dollar")]
[InlineData("AUD", "$", "Australian Dollar")]
[InlineData("PLN", "zł", "Polish Zloty", "złoty polski")]
[Theory]
public void CanReadMonetaryUnit(string tla, string expectedSymbol, string expectedName, string nativeName = null)
{
nativeName = nativeName ?? expectedName;
var currency = Model.Instances.New<Ifc4.MeasureResource.IfcMonetaryUnit>(u =>
{
u.Currency = tla;
});

currency.Symbol().Should().Be(expectedSymbol);
currency.FullEnglishName().Should().Be(expectedName);
currency.FullNativeName().Should().Be(nativeName);
}

#region Dispose
private bool disposedValue;

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
Txn.Dispose();
Model?.Dispose();
}

disposedValue = true;
}
}

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
#endregion
}
}
Loading
Loading