#include "gpkg_reader.h" #include #include // GDAL/OGR C API #include #include #include namespace gpkg_reader { std::vector read_features( const std::string& gpkg_path, const std::string& country_code, int level ) { GDALAllRegister(); GDALDatasetH ds = GDALOpenEx( gpkg_path.c_str(), GDAL_OF_VECTOR | GDAL_OF_READONLY, nullptr, nullptr, nullptr ); if (!ds) { throw std::runtime_error("Cannot open GeoPackage: " + gpkg_path); } // GADM uses layer name pattern "ADM_ADM_{level}" std::string layer_name = "ADM_ADM_" + std::to_string(level); OGRLayerH layer = GDALDatasetGetLayerByName(ds, layer_name.c_str()); if (!layer) { // Fallback: try first layer layer = GDALDatasetGetLayer(ds, 0); } if (!layer) { GDALClose(ds); return {}; } // Filter by country std::string filter = "GID_0 = '" + country_code + "'"; OGR_L_SetAttributeFilter(layer, filter.c_str()); // Column names for this level std::string gid_col = "GID_" + std::to_string(level); std::string name_col = (level == 0) ? "COUNTRY" : ("NAME_" + std::to_string(level)); // Group features by GID code, collecting geometries std::map groups; OGRFeatureH feat; OGR_L_ResetReading(layer); while ((feat = OGR_L_GetNextFeature(layer)) != nullptr) { const char* gid_val = OGR_F_GetFieldAsString(feat, OGR_F_GetFieldIndex(feat, gid_col.c_str())); const char* name_val = OGR_F_GetFieldAsString(feat, OGR_F_GetFieldIndex(feat, name_col.c_str())); if (!gid_val || !name_val) { OGR_F_Destroy(feat); continue; } std::string code(gid_val); OGRGeometryH geom = OGR_F_GetGeometryRef(feat); if (groups.find(code) == groups.end()) { boundary::BoundaryFeature bf; bf.code = code; bf.name = std::string(name_val); groups[code] = bf; } // TODO: Clone geometry into GEOS handle for merging phase // For now, export to GeoJSON directly if (geom) { char* geojson_str = OGR_G_ExportToJson(geom); if (geojson_str) { groups[code].geojson = nlohmann::json::parse(geojson_str); CPLFree(geojson_str); } } OGR_F_Destroy(feat); } GDALClose(ds); // Flatten map to vector std::vector result; result.reserve(groups.size()); for (auto& [_, bf] : groups) { result.push_back(std::move(bf)); } return result; } } // namespace gpkg_reader