@@ -10,20 +10,15 @@ internal static class BuildingAttributeParser
1010{
1111 internal static BuildingAttributeContext Parse ( XElement cityObjectElement )
1212 {
13+ BuildingMetricMeasurements metrics = ParseMetrics ( cityObjectElement ) ;
1314 return new BuildingAttributeContext (
1415 RoofShape : ParseOptionalRoofShape ( GetFirstDirectElementValue ( cityObjectElement , "roofType" ) ) ,
1516 Uses : ParseBuildingUses ( GetDirectElementValues ( cityObjectElement , "usage" ) ) ,
1617 DetailedUses : ParseBuildingUses ( GetDescendantElementValues ( cityObjectElement , "detailedUsage" ) ) ,
1718 Structures : ParseBuildingStructures ( GetDescendantElementValues ( cityObjectElement , "buildingStructureType" ) ) ,
1819 CityGmlClassCodes : GetDirectElementValues ( cityObjectElement , "class" ) ,
1920 CityGmlFunctionCodes : GetDirectElementValues ( cityObjectElement , "function" ) ,
20- MeasuredHeightMeters : ParseMetricValue ( GetFirstDirectElement ( cityObjectElement , "measuredHeight" ) , requireMeters : true ) ,
21- StoreysAboveGround : ParseIntegerMetricValue ( GetFirstDirectElement ( cityObjectElement , "storeysAboveGround" ) ) ,
22- StoreysBelowGround : ParseIntegerMetricValue ( GetFirstDirectElement ( cityObjectElement , "storeysBelowGround" ) ) ,
23- BuildingFootprintArea : ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingFootprintArea" ) , requireMeters : false ) ,
24- BuildingRoofEdgeArea : ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingRoofEdgeArea" ) , requireMeters : false ) ,
25- BuildingHeight : ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingHeight" ) , requireMeters : true ) ,
26- EaveHeight : ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "eaveHeight" ) , requireMeters : true ) ) ;
21+ Metrics : metrics ) ;
2722 }
2823
2924 private static XElement ? GetFirstDirectElement ( XElement element , string localName )
@@ -125,51 +120,96 @@ private static PlateauBuildingStructure MapBuildingStructure(string code)
125120 } ;
126121 }
127122
128- private static BuildingMetricValue ParseIntegerMetricValue ( XElement ? element )
123+ private static BuildingMetricMeasurements ParseMetrics ( XElement cityObjectElement )
124+ {
125+ Dictionary < BuildingMetricKind , BuildingMetricValue > values = [ ] ;
126+ AddMetric (
127+ values ,
128+ BuildingMetricKind . MeasuredHeightMeters ,
129+ ParseMetricValue ( GetFirstDirectElement ( cityObjectElement , "measuredHeight" ) , requireMeters : true ) ) ;
130+ AddMetric (
131+ values ,
132+ BuildingMetricKind . StoreysAboveGround ,
133+ ParseIntegerMetricValue ( GetFirstDirectElement ( cityObjectElement , "storeysAboveGround" ) ) ) ;
134+ AddMetric (
135+ values ,
136+ BuildingMetricKind . StoreysBelowGround ,
137+ ParseIntegerMetricValue ( GetFirstDirectElement ( cityObjectElement , "storeysBelowGround" ) ) ) ;
138+ AddMetric (
139+ values ,
140+ BuildingMetricKind . BuildingFootprintArea ,
141+ ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingFootprintArea" ) , requireMeters : false ) ) ;
142+ AddMetric (
143+ values ,
144+ BuildingMetricKind . BuildingRoofEdgeArea ,
145+ ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingRoofEdgeArea" ) , requireMeters : false ) ) ;
146+ AddMetric (
147+ values ,
148+ BuildingMetricKind . BuildingHeight ,
149+ ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "buildingHeight" ) , requireMeters : true ) ) ;
150+ AddMetric (
151+ values ,
152+ BuildingMetricKind . EaveHeight ,
153+ ParseMetricValue ( GetFirstDescendantElement ( cityObjectElement , "eaveHeight" ) , requireMeters : true ) ) ;
154+ return new BuildingMetricMeasurements ( values ) ;
155+ }
156+
157+ private static void AddMetric (
158+ Dictionary < BuildingMetricKind , BuildingMetricValue > values ,
159+ BuildingMetricKind kind ,
160+ BuildingMetricValue ? metric )
161+ {
162+ if ( metric . HasValue )
163+ {
164+ values . Add ( kind , metric . Value ) ;
165+ }
166+ }
167+
168+ private static BuildingMetricValue ? ParseIntegerMetricValue ( XElement ? element )
129169 {
130170 if ( element is null )
131171 {
132- return BuildingMetricValue . Missing ;
172+ return null ;
133173 }
134174
135175 string rawValue = element . Value . Trim ( ) ;
136176 if ( IsPlateauMissingMetricToken ( rawValue ) )
137177 {
138- return BuildingMetricValue . Missing ;
178+ return null ;
139179 }
140180
141181 return int . TryParse ( rawValue , NumberStyles . Integer , CultureInfo . InvariantCulture , out int value )
142182 && value >= 0
143- ? BuildingMetricValue . Known ( value )
144- : BuildingMetricValue . Invalid ( rawValue ) ;
183+ ? new BuildingMetricValue ( value )
184+ : null ;
145185 }
146186
147- private static BuildingMetricValue ParseMetricValue ( XElement ? element , bool requireMeters )
187+ private static BuildingMetricValue ? ParseMetricValue ( XElement ? element , bool requireMeters )
148188 {
149189 if ( element is null )
150190 {
151- return BuildingMetricValue . Missing ;
191+ return null ;
152192 }
153193
154194 string rawValue = element . Value . Trim ( ) ;
155195 if ( IsPlateauMissingMetricToken ( rawValue ) )
156196 {
157- return BuildingMetricValue . Missing ;
197+ return null ;
158198 }
159199
160200 string ? unitOfMeasure = element . Attribute ( "uom" ) ? . Value . Trim ( ) ;
161201 if ( requireMeters
162202 && ! string . IsNullOrWhiteSpace ( unitOfMeasure )
163203 && ! string . Equals ( unitOfMeasure , "m" , StringComparison . OrdinalIgnoreCase ) )
164204 {
165- return BuildingMetricValue . Invalid ( rawValue ) ;
205+ return null ;
166206 }
167207
168208 return double . TryParse ( rawValue , NumberStyles . Float , CultureInfo . InvariantCulture , out double value )
169209 && double . IsFinite ( value )
170210 && value > 0.0
171- ? BuildingMetricValue . Known ( value )
172- : BuildingMetricValue . Invalid ( rawValue ) ;
211+ ? new BuildingMetricValue ( value )
212+ : null ;
173213 }
174214
175215 private static bool IsPlateauMissingMetricToken ( string rawValue )
0 commit comments