97 lines
2.7 KiB
C++
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
|