@@ -4199,29 +4199,140 @@ private void CreateGlobalCartesianOrigin(ExporterIFC exporterIFC)
4199
4199
ExporterIFCUtils . SetGlobal2DOriginHandle ( origin2d ) ;
4200
4200
}
4201
4201
4202
- private HashSet < IFCAnyHandle > RemoveContainedHandlesFromSet ( ICollection < IFCAnyHandle > initialSet )
4202
+ private static bool ValidateContainedHandle ( IFCAnyHandle initialHandle )
4203
+ {
4204
+ if ( ExporterCacheManager . ElementsInAssembliesCache . Contains ( initialHandle ) )
4205
+ return false ;
4206
+
4207
+ try
4208
+ {
4209
+ if ( ! IFCAnyHandleUtil . HasRelDecomposes ( initialHandle ) )
4210
+ return true ;
4211
+ }
4212
+ catch
4213
+ {
4214
+ }
4215
+
4216
+ return false ;
4217
+ }
4218
+
4219
+ /// <summary>
4220
+ /// Remove contained or invalid handles from this set.
4221
+ /// </summary>
4222
+ /// <param name="initialSet">The initial set that may have contained or invalid handles.</param>
4223
+ /// <returns>A cleaned set.</returns>
4224
+ public static HashSet < IFCAnyHandle > RemoveContainedHandlesFromSet ( ICollection < IFCAnyHandle > initialSet )
4203
4225
{
4204
4226
HashSet < IFCAnyHandle > filteredSet = new HashSet < IFCAnyHandle > ( ) ;
4205
4227
4206
4228
if ( initialSet != null )
4207
4229
{
4208
4230
foreach ( IFCAnyHandle initialHandle in initialSet )
4209
4231
{
4210
- if ( ExporterCacheManager . ElementsInAssembliesCache . Contains ( initialHandle ) )
4211
- continue ;
4232
+ if ( ValidateContainedHandle ( initialHandle ) )
4233
+ filteredSet . Add ( initialHandle ) ;
4234
+ }
4235
+ }
4212
4236
4213
- try
4237
+ return filteredSet ;
4238
+ }
4239
+
4240
+ private class IFCLevelExportInfo
4241
+ {
4242
+ public IFCLevelExportInfo ( ) { }
4243
+
4244
+ public IDictionary < ElementId , IList < IFCLevelInfo > > LevelMapping { get ; set ; } =
4245
+ new Dictionary < ElementId , IList < IFCLevelInfo > > ( ) ;
4246
+
4247
+ public IList < IFCLevelInfo > OrphanedLevelInfos { get ; set ; } = new List < IFCLevelInfo > ( ) ;
4248
+
4249
+ public void UnionLevelInfoRelated ( ElementId toLevelId , IFCLevelInfo fromLevel )
4250
+ {
4251
+ if ( fromLevel == null )
4252
+ return ;
4253
+
4254
+ if ( toLevelId == ElementId . InvalidElementId )
4255
+ {
4256
+ OrphanedLevelInfos . Add ( fromLevel ) ;
4257
+ return ;
4258
+ }
4259
+
4260
+ IList < IFCLevelInfo > levelMappingList ;
4261
+ if ( ! LevelMapping . TryGetValue ( toLevelId , out levelMappingList ) )
4262
+ {
4263
+ levelMappingList = new List < IFCLevelInfo > ( ) ;
4264
+ LevelMapping [ toLevelId ] = levelMappingList ;
4265
+ }
4266
+ levelMappingList . Add ( fromLevel ) ;
4267
+ }
4268
+
4269
+ public void TransferOrphanedLevelInfo ( ElementId toLevelId )
4270
+ {
4271
+ if ( toLevelId == ElementId . InvalidElementId )
4272
+ return ;
4273
+
4274
+ if ( OrphanedLevelInfos . Count == 0 )
4275
+ return ;
4276
+
4277
+ IList < IFCLevelInfo > toLevelMappingList ;
4278
+ if ( ! LevelMapping . TryGetValue ( toLevelId , out toLevelMappingList ) )
4279
+ {
4280
+ toLevelMappingList = new List < IFCLevelInfo > ( ) ;
4281
+ LevelMapping [ toLevelId ] = toLevelMappingList ;
4282
+ }
4283
+
4284
+ foreach ( IFCLevelInfo orphanedLevelInfo in OrphanedLevelInfos )
4285
+ {
4286
+ toLevelMappingList . Add ( orphanedLevelInfo ) ;
4287
+ }
4288
+ OrphanedLevelInfos . Clear ( ) ;
4289
+ }
4290
+
4291
+ public Tuple < HashSet < IFCAnyHandle > , HashSet < IFCAnyHandle > > CollectValidHandlesForLevel (
4292
+ ElementId levelId , IFCLevelInfo levelInfo )
4293
+ {
4294
+ if ( levelId == ElementId . InvalidElementId || levelInfo == null )
4295
+ return null ;
4296
+
4297
+ HashSet < IFCAnyHandle > levelRelatedProducts = new HashSet < IFCAnyHandle > ( ) ;
4298
+ levelRelatedProducts . UnionWith ( levelInfo . GetRelatedProducts ( ) ) ;
4299
+
4300
+ HashSet < IFCAnyHandle > levelRelatedElements = new HashSet < IFCAnyHandle > ( ) ;
4301
+ levelRelatedElements . UnionWith ( levelInfo . GetRelatedElements ( ) ) ;
4302
+
4303
+ IList < IFCLevelInfo > levelMappingList ;
4304
+ if ( LevelMapping . TryGetValue ( levelId , out levelMappingList ) )
4305
+ {
4306
+ foreach ( IFCLevelInfo containedLevelInfo in levelMappingList )
4214
4307
{
4215
- if ( ! IFCAnyHandleUtil . HasRelDecomposes ( initialHandle ) )
4216
- filteredSet . Add ( initialHandle ) ;
4308
+ if ( containedLevelInfo != null )
4309
+ {
4310
+ levelRelatedProducts . UnionWith ( containedLevelInfo . GetRelatedProducts ( ) ) ;
4311
+ levelRelatedElements . UnionWith ( containedLevelInfo . GetRelatedElements ( ) ) ;
4312
+ }
4217
4313
}
4218
- catch
4314
+ }
4315
+
4316
+ return Tuple . Create ( RemoveContainedHandlesFromSet ( levelRelatedProducts ) ,
4317
+ RemoveContainedHandlesFromSet ( levelRelatedElements ) ) ;
4318
+ }
4319
+
4320
+ public HashSet < IFCAnyHandle > CollectOrphanedHandles ( )
4321
+ {
4322
+ HashSet < IFCAnyHandle > orphanedHandles = new HashSet < IFCAnyHandle > ( ) ;
4323
+ foreach ( IFCLevelInfo containedLevelInfo in OrphanedLevelInfos )
4324
+ {
4325
+ if ( containedLevelInfo != null )
4219
4326
{
4327
+ orphanedHandles . UnionWith ( containedLevelInfo . GetRelatedProducts ( ) ) ;
4328
+ orphanedHandles . UnionWith ( containedLevelInfo . GetRelatedElements ( ) ) ;
4220
4329
}
4221
4330
}
4222
- }
4223
4331
4224
- return filteredSet ;
4332
+ // RemoveContainedHandlesFromSet will be called before these are used, so
4333
+ // don't bother doing it twice.
4334
+ return orphanedHandles ;
4335
+ }
4225
4336
}
4226
4337
4227
4338
/// <summary>
@@ -4235,66 +4346,33 @@ private void RelateLevels(ExporterIFC exporterIFC, Document document)
4235
4346
IList < ElementId > levelIds = ExporterCacheManager . LevelInfoCache . LevelsByElevation ;
4236
4347
IFCFile file = exporterIFC . GetFile ( ) ;
4237
4348
4349
+ ElementId lastValidLevelId = ElementId . InvalidElementId ;
4350
+ IFCLevelExportInfo levelInfoMapping = new IFCLevelExportInfo ( ) ;
4351
+
4238
4352
for ( int ii = 0 ; ii < levelIds . Count ; ii ++ )
4239
4353
{
4240
4354
ElementId levelId = levelIds [ ii ] ;
4241
4355
IFCLevelInfo levelInfo = ExporterCacheManager . LevelInfoCache . GetLevelInfo ( exporterIFC , levelId ) ;
4242
4356
if ( levelInfo == null )
4243
4357
continue ;
4244
4358
4245
- // remove products that are aggregated (e.g., railings in stairs).
4246
4359
Element level = document . GetElement ( levelId ) ;
4247
4360
4248
- ICollection < IFCAnyHandle > relatedProductsToCheck = levelInfo . GetRelatedProducts ( ) ;
4249
- ICollection < IFCAnyHandle > relatedElementsToCheck = levelInfo . GetRelatedElements ( ) ;
4250
-
4251
- // get coincident levels, if any.
4252
- double currentElevation = levelInfo . Elevation ;
4361
+ levelInfoMapping . TransferOrphanedLevelInfo ( levelId ) ;
4253
4362
int nextLevelIdx = ii + 1 ;
4254
- for ( int jj = ii + 1 ; jj < levelIds . Count ; jj ++ , nextLevelIdx ++ )
4255
- {
4256
- ElementId nextLevelId = levelIds [ jj ] ;
4257
- IFCLevelInfo levelInfo2 = ExporterCacheManager . LevelInfoCache . GetLevelInfo ( exporterIFC , nextLevelId ) ;
4258
- if ( levelInfo2 == null )
4259
- continue ;
4260
-
4261
- if ( MathUtil . IsAlmostEqual ( currentElevation , levelInfo2 . Elevation ) )
4262
- {
4263
- foreach ( IFCAnyHandle relatedProduct in levelInfo2 . GetRelatedProducts ( ) )
4264
- relatedProductsToCheck . Add ( relatedProduct ) ;
4265
-
4266
- foreach ( IFCAnyHandle relatedElement in levelInfo2 . GetRelatedElements ( ) )
4267
- relatedElementsToCheck . Add ( relatedElement ) ;
4268
- }
4269
- else
4270
- break ;
4271
- }
4272
4363
4273
4364
// We may get stale handles in here; protect against this.
4274
- HashSet < IFCAnyHandle > relatedProducts = RemoveContainedHandlesFromSet ( relatedProductsToCheck ) ;
4275
- HashSet < IFCAnyHandle > relatedElements = RemoveContainedHandlesFromSet ( relatedElementsToCheck ) ;
4276
-
4277
- // skip coincident levels, if any.
4278
- for ( int jj = ii + 1 ; jj < nextLevelIdx ; jj ++ )
4279
- {
4280
- ElementId nextLevelId = levelIds [ jj ] ;
4281
- IFCLevelInfo levelInfo2 = ExporterCacheManager . LevelInfoCache . GetLevelInfo ( exporterIFC , nextLevelId ) ;
4282
- if ( levelInfo2 == null )
4283
- continue ;
4365
+ Tuple < HashSet < IFCAnyHandle > , HashSet < IFCAnyHandle > > productsAndElements =
4366
+ levelInfoMapping . CollectValidHandlesForLevel ( levelId , levelInfo ) ;
4284
4367
4285
- if ( ! levelInfo . GetBuildingStorey ( ) . Equals ( levelInfo2 . GetBuildingStorey ( ) ) )
4286
- IFCAnyHandleUtil . Delete ( levelInfo2 . GetBuildingStorey ( ) ) ;
4287
- }
4288
- ii = nextLevelIdx - 1 ;
4368
+ HashSet < IFCAnyHandle > relatedProducts = productsAndElements . Item1 ;
4369
+ HashSet < IFCAnyHandle > relatedElements = productsAndElements . Item2 ;
4289
4370
4290
- if ( relatedProducts . Count == 0 && relatedElements . Count == 0 )
4291
- IFCAnyHandleUtil . Delete ( levelInfo . GetBuildingStorey ( ) ) ;
4292
- else
4371
+ using ( ProductWrapper productWrapper = ProductWrapper . Create ( exporterIFC , false ) )
4293
4372
{
4294
- // We have decided to keep the level - export properties, quantities and classifications.
4295
- using ( ProductWrapper productWrapper = ProductWrapper . Create ( exporterIFC , false ) )
4373
+ IFCAnyHandle buildingStoreyHandle = levelInfo . GetBuildingStorey ( ) ;
4374
+ if ( ! buildingStories . Contains ( buildingStoreyHandle ) )
4296
4375
{
4297
- IFCAnyHandle buildingStoreyHandle = levelInfo . GetBuildingStorey ( ) ;
4298
4376
buildingStories . Add ( buildingStoreyHandle ) ;
4299
4377
IFCExportInfoPair exportInfo = new IFCExportInfoPair ( IFCEntityType . IfcBuildingStorey ) ;
4300
4378
@@ -4307,24 +4385,18 @@ private void RelateLevels(ExporterIFC exporterIFC, Document document)
4307
4385
4308
4386
if ( relatedProducts . Count > 0 )
4309
4387
{
4310
- HashSet < IFCAnyHandle > buildingProducts = RemoveContainedHandlesFromSet ( relatedProducts ) ;
4311
- if ( buildingProducts . Count > 0 )
4312
- {
4313
- IFCAnyHandle buildingStorey = levelInfo . GetBuildingStorey ( ) ;
4314
- string guid = GUIDUtil . CreateSubElementGUID ( level , ( int ) IFCBuildingStoreySubElements . RelAggregates ) ;
4315
- ExporterCacheManager . ContainmentCache . AddRelations ( buildingStorey , guid , relatedProducts ) ;
4316
- }
4388
+ IFCAnyHandle buildingStorey = levelInfo . GetBuildingStorey ( ) ;
4389
+ string guid = GUIDUtil . CreateSubElementGUID ( level , ( int ) IFCBuildingStoreySubElements . RelAggregates ) ;
4390
+ ExporterCacheManager . ContainmentCache . AddRelations ( buildingStorey , guid , relatedProducts ) ;
4317
4391
}
4318
4392
4319
4393
if ( relatedElements . Count > 0 )
4320
4394
{
4321
- HashSet < IFCAnyHandle > buildingElements = RemoveContainedHandlesFromSet ( relatedElements ) ;
4322
- if ( buildingElements . Count > 0 )
4323
- {
4324
- string guid = GUIDUtil . CreateSubElementGUID ( level , ( int ) IFCBuildingStoreySubElements . RelContainedInSpatialStructure ) ;
4325
- IFCInstanceExporter . CreateRelContainedInSpatialStructure ( file , guid , ExporterCacheManager . OwnerHistoryHandle , null , null , buildingElements , levelInfo . GetBuildingStorey ( ) ) ;
4326
- }
4395
+ string guid = GUIDUtil . CreateSubElementGUID ( level , ( int ) IFCBuildingStoreySubElements . RelContainedInSpatialStructure ) ;
4396
+ IFCInstanceExporter . CreateRelContainedInSpatialStructure ( file , guid , ExporterCacheManager . OwnerHistoryHandle , null , null , relatedElements , levelInfo . GetBuildingStorey ( ) ) ;
4327
4397
}
4398
+
4399
+ ii = nextLevelIdx - 1 ;
4328
4400
}
4329
4401
4330
4402
if ( buildingStories . Count > 0 )
@@ -4334,6 +4406,11 @@ private void RelateLevels(ExporterIFC exporterIFC, Document document)
4334
4406
string guid = GUIDUtil . CreateSubElementGUID ( projectInfo , ( int ) IFCProjectSubElements . RelAggregatesBuildingStories ) ;
4335
4407
ExporterCacheManager . ContainmentCache . AddRelations ( buildingHnd , guid , buildingStories ) ;
4336
4408
}
4409
+
4410
+ // We didn't find a level for this. Put it in the IfcBuilding, IfcSite, or IfcProject later.
4411
+ HashSet < IFCAnyHandle > orphanedHandles = levelInfoMapping . CollectOrphanedHandles ( ) ;
4412
+
4413
+ ExporterCacheManager . LevelInfoCache . OrphanedElements . UnionWith ( orphanedHandles ) ;
4337
4414
}
4338
4415
4339
4416
/// <summary>
0 commit comments