# GeoIntel Kempen — Analysis Specifications v1.0 This file defines exact inputs, outputs and formulas for the first implementation of the analysis engine. ## Global rules - All area-based metrics must be calculated in a projected CRS suitable for Belgium/Flanders, preferably EPSG:31370 internally for metric calculations. - Store geometries consistently and transform only at API/render boundaries when needed. - All metrics must include unit, input dataset ids, analysis run id and calculation parameters. - Never let the AI copilot invent metrics. Metrics must come from the analysis engine. ## AreaAnalyzer ### Input - Area polygon. ### Output metrics | Key | Unit | Formula | |---|---|---| | `area_m2` | m² | `ST_Area(area.geometry)` | | `area_km2` | km² | `area_m2 / 1_000_000` | | `perimeter_m` | m | `ST_Perimeter(area.geometry)` | | `bbox` | geometry/json | calculated bounds | ## BuildingAnalyzer ### Input - Area polygon. - Building polygons from GRB, OSM, user vector layer, or AI segmentation/detection polygons. ### Processing 1. Clip building geometries to area. 2. Remove invalid geometries or repair with `make_valid`. 3. Calculate per-building clipped area. 4. Aggregate. ### Output metrics | Key | Unit | Formula | |---|---|---| | `building_count` | count | number of building features intersecting area | | `building_area_total_m2` | m² | sum clipped building area | | `building_area_total_ha` | ha | `building_area_total_m2 / 10000` | | `building_coverage_ratio` | ratio | `building_area_total_m2 / area_m2` | | `building_density_per_km2` | count/km² | `building_count / area_km2` | | `mean_building_area_m2` | m² | `building_area_total_m2 / building_count` | | `largest_building_area_m2` | m² | max building area | ### Output layers - `buildings_clipped` - `building_centroids` - `large_buildings_top_20` ## RoadAnalyzer ### Input - Area polygon. - Road line or polygon features. ### Output metrics | Key | Unit | Formula | |---|---|---| | `road_length_total_m` | m | sum clipped road lengths | | `road_length_total_km` | km | `/1000` | | `road_density_km_per_km2` | km/km² | `road_length_total_km / area_km2` | | `major_road_length_km` | km | filtered by road class if available | ### Output layers - `roads_clipped` - `major_roads_clipped` ## GreenAnalyzer ### Input options - Green polygons from OSM/GRB/landuse. - NDVI raster threshold result. - Segmentation polygons classified as vegetation. ### Output metrics | Key | Unit | Formula | |---|---|---| | `green_area_total_m2` | m² | sum green polygons clipped to area | | `green_ratio` | ratio | `green_area_total_m2 / area_m2` | | `green_patch_count` | count | number of disjoint green patches | | `largest_green_patch_m2` | m² | max patch area | | `green_fragmentation_index` | index | `green_patch_count / max(green_area_total_ha, 0.01)` | ### Interpretation High fragmentation means green is split into many smaller patches. ## WaterAnalyzer ### Input - Water polygons/lines from GRB/OSM. - NDWI threshold polygons later. ### Output metrics | Key | Unit | Formula | |---|---|---| | `water_area_total_m2` | m² | sum clipped water polygon area | | `water_ratio` | ratio | `water_area_total_m2 / area_m2` | | `watercourse_length_m` | m | sum water line length | | `distance_to_nearest_water_m` | m | minimum distance from area centroid to water geometry | ## RasterAnalyzer ### Input - Raster dataset. - Optional area polygon. ### Output metrics Per band: | Key | Unit | |---|---| | `band_min` | band unit | | `band_max` | band unit | | `band_mean` | band unit | | `band_std` | band unit | | `nodata_ratio` | ratio | ### Required operations - Read metadata. - Clip by area. - Compute statistics. - Generate preview tile or PNG. ## RemoteSensingIndexAnalyzer ### NDVI Formula: ```text NDVI = (NIR - Red) / (NIR + Red) ``` Output: - `ndvi_mean` - `ndvi_median` - `ndvi_low_ratio` using threshold configurable, default `< 0.2` - `ndvi_high_ratio` using threshold configurable, default `> 0.5` - vectorized high/low vegetation zones later ### NDWI ```text NDWI = (Green - NIR) / (Green + NIR) ``` ### NDBI ```text NDBI = (SWIR - NIR) / (SWIR + NIR) ``` ## DetectionAnalyzer ### Input - Detection records with class, confidence and geometry. - Area polygon. ### Output metrics | Key | Unit | Formula | |---|---|---| | `detection_count` | count | detections within area | | `detection_count_by_class` | json | group by class | | `mean_confidence` | ratio | average confidence | | `low_confidence_count` | count | confidence below threshold | | `detected_area_m2_by_class` | json | sum polygon area where available | ## ScoreEngine v1 The score engine must be transparent. Every score returns value, inputs, weights and explanation. ### Open Space Pressure Score Default weights: ```yaml building_coverage_ratio: 0.35 road_density_normalized: 0.25 green_ratio_inverse: 0.25 urban_growth_normalized: 0.15 ``` Score: ```text 100 * weighted_sum(normalized_factors) ``` ### Nature Connectivity Score Default weights: ```yaml green_ratio: 0.35 largest_green_patch_ratio: 0.25 fragmentation_inverse: 0.25 major_road_barrier_inverse: 0.15 ``` ### Water Resilience Score Default weights: ```yaml green_ratio: 0.30 water_buffer_presence: 0.20 impervious_inverse: 0.30 low_point_risk_inverse: 0.20 ``` V1 may calculate a simplified score without height data by marking height-dependent factors as unavailable. ## Metric storage contract Each metric row must include: ```json { "analysis_run_id": "uuid", "key": "building_density_per_km2", "value": 123.4, "unit": "count/km2", "method": "BuildingAnalyzer.v1", "inputs": ["dataset_uuid"], "parameters": {}, "quality_flags": [] } ```