gadm-ts/cpp/src/gpkg_reader.cpp
2026-03-23 15:47:35 +01:00

97 lines
2.7 KiB
C++

#include "gpkg_reader.h"
#include <stdexcept>
#include <map>
// GDAL/OGR C API
#include <gdal.h>
#include <ogr_api.h>
#include <cpl_conv.h>
namespace gpkg_reader {
std::vector<boundary::BoundaryFeature> 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<std::string, boundary::BoundaryFeature> 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<boundary::BoundaryFeature> result;
result.reserve(groups.size());
for (auto& [_, bf] : groups) {
result.push_back(std::move(bf));
}
return result;
}
} // namespace gpkg_reader