@@ -152,10 +152,10 @@ private static bool TryCreateNoWallRoofSlab(
152152 return false ;
153153 }
154154
155- SurfaceProjectionInfo [ ] surfaceInfos = cityObject . Surfaces
156- . Select ( surface => CreateSurfaceProjectionInfo ( surface , cityObjectOrigin , cityObjectCartesian ) )
157- . Where ( static info => info . MinimumY . HasValue && info . MaximumY . HasValue )
158- . ToArray ( ) ;
155+ SurfaceProjectionInfo [ ] surfaceInfos = CreateSurfaceProjectionInfos (
156+ cityObject . Surfaces ,
157+ cityObjectOrigin ,
158+ cityObjectCartesian ) ;
159159 if ( surfaceInfos . Length == 0 )
160160 {
161161 return false ;
@@ -188,19 +188,19 @@ private static bool TryGetNoWallTopSurfaces(
188188 out ParsedSurface [ ] ? topSurfaces )
189189 {
190190 topSurfaces = null ;
191- SurfaceProjectionInfo [ ] surfaceInfos = cityObject . Surfaces
192- . Select ( surface => CreateSurfaceProjectionInfo ( surface , cityObjectOrigin , cityObjectCartesian ) )
193- . Where ( static info => info . MinimumY . HasValue && info . MaximumY . HasValue )
194- . ToArray ( ) ;
191+ SurfaceProjectionInfo [ ] surfaceInfos = CreateSurfaceProjectionInfos (
192+ cityObject . Surfaces ,
193+ cityObjectOrigin ,
194+ cityObjectCartesian ) ;
195195 if ( surfaceInfos . Length == 0 )
196196 {
197197 return false ;
198198 }
199199
200- double objectMaximumY = surfaceInfos . Max ( static info => info . MaximumY ! . Value ) ;
200+ double objectMaximumY = surfaceInfos . Max ( static info => info . MaximumY ) ;
201201 SurfaceProjectionInfo [ ] topSurfaceInfos = surfaceInfos
202202 . Where ( static info => info . IsNearHorizontal )
203- . Where ( info => info . MaximumY ! . Value >= objectMaximumY - 0.1 )
203+ . Where ( info => info . MaximumY >= objectMaximumY - 0.1 )
204204 . ToArray ( ) ;
205205 if ( topSurfaceInfos . Length == 0
206206 || topSurfaceInfos . Any ( static info => info . Surface . InteriorRings . Length != 0 ) )
@@ -217,10 +217,10 @@ private static bool TryGetNoWallTopSurfaces(
217217 . ToArray ( ) ;
218218 if ( lowerSurfaceInfos . Length != 0 )
219219 {
220- double objectMinimumY = lowerSurfaceInfos . Min ( static info => info . MinimumY ! . Value ) ;
220+ double objectMinimumY = lowerSurfaceInfos . Min ( static info => info . MinimumY ) ;
221221 topSurfaceInfos = topSurfaceInfos
222- . Where ( info => info . MinimumY ! . Value > objectMinimumY + BuildingBottomCullBandMeters )
223- . Where ( info => info . MinimumY ! . Value - NoWallRoofThicknessMeters > objectMinimumY + BuildingBottomCullBandMeters )
222+ . Where ( info => info . MinimumY > objectMinimumY + BuildingBottomCullBandMeters )
223+ . Where ( info => info . MinimumY - NoWallRoofThicknessMeters > objectMinimumY + BuildingBottomCullBandMeters )
224224 . ToArray ( ) ;
225225 if ( topSurfaceInfos . Length == 0 )
226226 {
@@ -442,22 +442,22 @@ private static bool TryCreateFootprint(
442442 out Lod1RoofFootprint ? footprint )
443443 {
444444 footprint = null ;
445- SurfaceProjectionInfo [ ] surfaceInfos = cityObject . Surfaces
446- . Select ( surface => CreateSurfaceProjectionInfo ( surface , cityObjectOrigin , cityObjectCartesian ) )
447- . Where ( static info => info . MinimumY . HasValue && info . MaximumY . HasValue )
448- . ToArray ( ) ;
445+ SurfaceProjectionInfo [ ] surfaceInfos = CreateSurfaceProjectionInfos (
446+ cityObject . Surfaces ,
447+ cityObjectOrigin ,
448+ cityObjectCartesian ) ;
449449 if ( surfaceInfos . Length == 0 )
450450 {
451451 return false ;
452452 }
453453
454- double objectMinimumY = surfaceInfos . Min ( static info => info . MinimumY ! . Value ) ;
455- double objectMaximumY = surfaceInfos . Max ( static info => info . MaximumY ! . Value ) ;
454+ double objectMinimumY = surfaceInfos . Min ( static info => info . MinimumY ) ;
455+ double objectMaximumY = surfaceInfos . Max ( static info => info . MaximumY ) ;
456456 double geometryHeight = objectMaximumY - objectMinimumY ;
457457 SurfaceProjectionInfo [ ] topCandidates = surfaceInfos
458458 . Where ( static info => info . IsNearHorizontal )
459- . Where ( info => info . MaximumY ! . Value >= objectMaximumY - 0.1 )
460- . Where ( info => info . MinimumY ! . Value > objectMinimumY + BuildingBottomCullBandMeters )
459+ . Where ( info => info . MaximumY >= objectMaximumY - 0.1 )
460+ . Where ( info => info . MinimumY > objectMinimumY + BuildingBottomCullBandMeters )
461461 . ToArray ( ) ;
462462 if ( topCandidates . Length != 1 )
463463 {
@@ -495,27 +495,47 @@ private static bool TryCreateFootprint(
495495 return true ;
496496 }
497497
498- private static SurfaceProjectionInfo CreateSurfaceProjectionInfo (
499- ParsedSurface surface ,
498+ private static SurfaceProjectionInfo [ ] CreateSurfaceProjectionInfos (
499+ IEnumerable < ParsedSurface > surfaces ,
500500 GeodeticPoint cityObjectOrigin ,
501501 LocalCartesian cityObjectCartesian )
502502 {
503+ List < SurfaceProjectionInfo > infos = [ ] ;
504+ foreach ( ParsedSurface surface in surfaces )
505+ {
506+ if ( TryCreateSurfaceProjectionInfo ( surface , cityObjectOrigin , cityObjectCartesian , out SurfaceProjectionInfo info ) )
507+ {
508+ infos . Add ( info ) ;
509+ }
510+ }
511+
512+ return [ .. infos ] ;
513+ }
514+
515+ private static bool TryCreateSurfaceProjectionInfo (
516+ ParsedSurface surface ,
517+ GeodeticPoint cityObjectOrigin ,
518+ LocalCartesian cityObjectCartesian ,
519+ out SurfaceProjectionInfo info )
520+ {
521+ info = default ;
503522 Float3 [ ] positions = surface . Vertices
504523 . Select ( point => CreateScenePosition ( point , cityObjectOrigin , cityObjectCartesian ) )
505524 . ToArray ( ) ;
506525 if ( positions . Length == 0 )
507526 {
508- return new SurfaceProjectionInfo ( surface , null , null , false ) ;
527+ return false ;
509528 }
510529
511530 Float3 ? normal = ComputePolygonNormal ( positions ) ;
512531 bool isNearHorizontal = normal is not null && Math . Abs ( normal . Y ) >= 0.98 ;
513532
514- return new SurfaceProjectionInfo (
533+ info = new SurfaceProjectionInfo (
515534 surface ,
516535 positions . Min ( static position => position . Y ) ,
517536 positions . Max ( static position => position . Y ) ,
518537 isNearHorizontal ) ;
538+ return true ;
519539 }
520540
521541 private static GeodeticPoint [ ] RemoveClosingPoint ( GeodeticPoint [ ] vertices )
@@ -682,8 +702,8 @@ private static double Dot(Float3 left, Float3 right)
682702
683703 private readonly record struct SurfaceProjectionInfo (
684704 ParsedSurface Surface ,
685- double ? MinimumY ,
686- double ? MaximumY ,
705+ double MinimumY ,
706+ double MaximumY ,
687707 bool IsNearHorizontal ) ;
688708
689709 private readonly record struct NoWallRoofRing (
0 commit comments