diff --git a/backend/metadata-database/init-db.js b/backend/metadata-database/init-db.js index 212c2ae0..983351d2 100644 --- a/backend/metadata-database/init-db.js +++ b/backend/metadata-database/init-db.js @@ -146,6 +146,7 @@ const datasets = [ additionalData: { Icon: '', Type: "areas", + DataType: "CITYGML", LongDescription: `The building models have a 3D object of each building plus additional information on its dimentions.`, MinZoomLevel: 11, MarkersThreshold: 17, diff --git a/backend/src/BIE.Core/BIE.Core.API/Controllers/DatasetController.cs b/backend/src/BIE.Core/BIE.Core.API/Controllers/DatasetController.cs index 24ad21c8..6819ee12 100644 --- a/backend/src/BIE.Core/BIE.Core.API/Controllers/DatasetController.cs +++ b/backend/src/BIE.Core/BIE.Core.API/Controllers/DatasetController.cs @@ -106,11 +106,12 @@ public ActionResult GetDatasetViewportData([FromQuery] QueryParameters parameter switch (metadata.additionalData.DataType) { case "CITYGML": + handler = new ShapeDatasetHandler(metadata); + break; case "SHAPE": handler = new ShapeDatasetHandler(metadata); break; case "CSV": - // TODO handler = new CsvDatasetHandler(metadata); break; default: @@ -151,7 +152,7 @@ public IActionResult LoadLocationData([FromBody, Required] LocationDataRequest r return Ok(data); } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.ToString()); } } diff --git a/backend/src/BIE.Core/BIE.Core.API/LoadLocationHelper.cs b/backend/src/BIE.Core/BIE.Core.API/LoadLocationHelper.cs index eedc0724..e1162e3b 100644 --- a/backend/src/BIE.Core/BIE.Core.API/LoadLocationHelper.cs +++ b/backend/src/BIE.Core/BIE.Core.API/LoadLocationHelper.cs @@ -63,23 +63,34 @@ public static LocationDataResponse loadLocationDataforPolygons(LocationDataReque }); var housefootprints = new List>(); + var columns = new HashSet { "Id" }; + var datasetId = "house_footprints"; foreach (var polygonWkt in polygons) + getDataInPolygon(housefootprints, columns, datasetId, polygonWkt); + + AggregateDataForHousefootprints(generalData, individualData, totalAreaSearchPolygon, housefootprints); + + var lod2buildings = new List>(); + foreach (var polygonWkt in polygons) + getDataInPolygon(lod2buildings, new() { "Id", "GroundArea", "BuildingWallHeight", "LivingArea", "RoofArea" }, "building_models", polygonWkt); + + AggregateDataForLod2Citygml(generalData, individualData, totalAreaSearchPolygon, lod2buildings); + + LocationDataResponse locationDataResponse = new() { - // then go through house footprints - var metadata = MetadataDbHelper.GetMetadata("house_footprints"); - if (metadata != null) - { - foreach (var table in metadata.additionalData.Tables) - { - var sqlQuery = $"SELECT Id, Location.STAsText() AS Location" + - ApiHelper.FromTableWhereIntersectsPolygon(table.Name, polygonWkt); - housefootprints.AddRange(DbHelper.GetData(sqlQuery)); - } - } + SelectionData = generalData, + IndividualData = individualData.Take(500).ToList() - } + }; + + return locationDataResponse; + } + private static void AggregateDataForHousefootprints(List generalData, List individualData, double totalAreaSearchPolygon, List> housefootprints) + { long totalCountHouseFootprints = housefootprints.Count(); + if (totalCountHouseFootprints == 0) + return; double totalBuildingArea = 0.0; List totalBuildingAreas = new List(); foreach (var h in housefootprints) @@ -108,29 +119,103 @@ public static LocationDataResponse loadLocationDataforPolygons(LocationDataReque }); generalData.Add(new DatasetItem { - DisplayName = "Total number of buildings in area", + DisplayName = "Total number of buildings", Value = totalCountHouseFootprints.ToString() }); - generalData.Add(new DatasetItem + if(totalBuildingAreas.Count > 0) + generalData.Add(GenerateDatalistStatisticsEntry(totalBuildingAreas, "Total building area")); + + } + + private static void AggregateDataForLod2Citygml(List generalData, List individualData, double totalAreaSearchPolygon, List> citygmldata) + { + long totalCountLod2Buildings = citygmldata.Count(); + if (totalCountLod2Buildings == 0) + return; + + // GroundHeight, DistrictKey, CheckDate, GroundArea, BuildingWallHeight, LivingArea, RoofArea + List totalBuildingAreas = new(); + List totalBuildingLivingAreas = new(); + List totalBuildingRoofAreas = new(); + foreach (var h in citygmldata) { - DisplayName = "Total building area", - Value = totalBuildingArea.ToString("0.##") + "m²", - Subdata = new List + double area = double.Parse(h["GroundArea"]); + totalBuildingAreas.Add(area); + + double livingArea = double.Parse(h["LivingArea"]); + totalBuildingLivingAreas.Add(livingArea); + + double roofArea = double.Parse(h["RoofArea"]); + totalBuildingRoofAreas.Add(roofArea); + + double wallHeight = double.Parse(h["BuildingWallHeight"]); + totalBuildingRoofAreas.Add(roofArea); + + Point p = (GeoReader.Read(h["Location"]) as Polygon).Centroid; + var item = new DatasetItem { - new() { Key = "Average", Value = totalBuildingAreas.Average().ToString() }, - new() { Key = "Median", Value = totalBuildingAreas.Median().ToString() }, - new() { Key = "Variance", Value = totalBuildingAreas.Variance().ToString() } - } - }); + DisplayName = "Building model: " + (h.ContainsKey("Id") ? h["Id"] : ""), + DatasetId = "building_models", + Value = area.ToString("0.##") + "m²", + Coordinate = new double[] { p.X, p.Y }, + Subdata = new List + { + new() { Key = "Ground area", Value = area.ToString("0.##") + "m²" }, + new() { Key = "Living area", Value = livingArea.ToString("0.##") + "m²" }, + new() { Key = "Roof surface", Value = roofArea.ToString("0.##") + "m²" }, + new() { Key = "Building wall height", Value = wallHeight.ToString("0.##") + "m" } + } + }; + individualData.Add(item); + } - LocationDataResponse locationDataResponse = new() + double totalBuildingArea = totalBuildingAreas.Sum(); + generalData.Add(new DatasetItem { - SelectionData = generalData, - IndividualData = individualData.Take(500).ToList() + DisplayName = "Potential Area for geothermal use", + Value = Math.Max(totalAreaSearchPolygon - totalBuildingArea, 0).ToString("0.##") + "m²", + }); + generalData.Add(new DatasetItem + { + DisplayName = "Total number of LOD2 buildings", + Value = totalCountLod2Buildings.ToString() + }); + if (totalBuildingAreas.Count > 0) + generalData.Add(GenerateDatalistStatisticsEntry(totalBuildingAreas, "Total ground area")); + if (totalBuildingLivingAreas.Count > 0) + generalData.Add(GenerateDatalistStatisticsEntry(totalBuildingLivingAreas, "Total living area")); + if (totalBuildingRoofAreas.Count > 0) + generalData.Add(GenerateDatalistStatisticsEntry(totalBuildingRoofAreas, "Total roof surface")); + } + private static DatasetItem GenerateDatalistStatisticsEntry(List listOfDataValues, string displayText) + { + return new DatasetItem + { + DisplayName = displayText, + Value = listOfDataValues.Sum().ToString("0.##") + "m²", + Subdata = new List + { + new() { Key = "Average", Value = listOfDataValues.Average().ToString() + "m²" }, + new() { Key = "Median", Value = listOfDataValues.Median().ToString() + "m²"}, + new() { Key = "Variance", Value = listOfDataValues.Variance().ToString()} + } }; + } - return locationDataResponse; + private static void getDataInPolygon(List> housefootprints, HashSet columns, string datasetId, string polygonWkt) + { + var metadata = MetadataDbHelper.GetMetadata(datasetId); + if (metadata != null) + { + foreach (var table in metadata.additionalData.Tables) + { + var sqlQuery = $"SELECT {string.Join(", ", columns)}, Location.STAsText() AS Location" + + ApiHelper.FromTableWhereIntersectsPolygon(table.Name, polygonWkt); + Console.WriteLine(sqlQuery); + housefootprints.AddRange(DbHelper.GetData(sqlQuery)); + } + } } public static LocationDataResponse loadLocationDataForSinglePoint(LocationDataRequest request) @@ -193,10 +278,10 @@ public static LocationDataResponse loadLocationDataForSinglePoint(LocationDataRe } private static IEnumerable> getMatchingObjects( - string datasetId, - double longitude, - double latitude, - IEnumerable columns) + string datasetId, + double longitude, + double latitude, + IEnumerable columns) { // Convert the columns set to a comma-separated string string columnsString = string.Join(", ", columns); diff --git a/backend/src/BIE.DataPipeline/Program.cs b/backend/src/BIE.DataPipeline/Program.cs index 1a781ab7..a2f916d1 100644 --- a/backend/src/BIE.DataPipeline/Program.cs +++ b/backend/src/BIE.DataPipeline/Program.cs @@ -77,7 +77,9 @@ case "SHAPE": importer = new ShapeImporter(description); + dbHelper.SetInfo(description.table_name, importer.GetInsertHeader() + ",Area"); + break; case "CITYGML": diff --git a/frontend/src/components/DataView/DataRow.tsx b/frontend/src/components/DataView/DataRow.tsx index 9732e8d8..c0cd9df6 100644 --- a/frontend/src/components/DataView/DataRow.tsx +++ b/frontend/src/components/DataView/DataRow.tsx @@ -99,7 +99,7 @@ const DataRow: React.FC = ({ row, currentDatasets }) => { return ( - {row.subdata.length > 0 ? ( + {row.subdata && row.subdata.length > 0 ? ( = ({ row, currentDatasets }) => { - {row.subdata.map((subItem) => ( - - - {subItem.key} - - {subItem.value} - - ))} + {row.subdata ? ( + + {row.subdata.map((subItem) => ( + + + {subItem.key} + + {subItem.value} + + ))} + + ) : ( + + )} diff --git a/frontend/src/components/DataView/DataView.tsx b/frontend/src/components/DataView/DataView.tsx index 4cbe3896..ac4aa091 100644 --- a/frontend/src/components/DataView/DataView.tsx +++ b/frontend/src/components/DataView/DataView.tsx @@ -219,7 +219,7 @@ const DataView = () => { {filterData(data?.selectionData ?? []).map((row) => ( @@ -241,7 +241,7 @@ const DataView = () => { {filterData(data?.individualData ?? []).map((row) => ( diff --git a/frontend/src/types/LocationDataTypes.tsx b/frontend/src/types/LocationDataTypes.tsx index 4a55fd48..f6b2b066 100644 --- a/frontend/src/types/LocationDataTypes.tsx +++ b/frontend/src/types/LocationDataTypes.tsx @@ -14,7 +14,7 @@ export interface DatasetItem { value: string | null; datasetID: string | null; coordinate: number[] | null; - subdata: SubdataItem[]; + subdata: SubdataItem[] | null; } /**