47#include <gdal_version.h>
49#include <ogrsf_frmts.h>
53namespace quetzal::geography::gdalcpp
56using gdal_driver_type = GDALDriver;
57using gdal_dataset_type = GDALDataset;
66 std::string m_dataset;
72 gdal_error(
const std::string &message, OGRErr error,
const std::string &driver =
"",
73 const std::string &dataset =
"",
const std::string &layer =
"",
const std::string &field =
"")
74 : std::runtime_error(message), m_driver(driver), m_dataset(dataset), m_layer(layer), m_field(field),
79 const std::string &driver()
const
84 const std::string &dataset()
const
89 const std::string &layer()
const
94 const std::string &field()
const
128 gdal_driver_type *m_driver;
131 Driver(
const std::string &driver_name)
132 :
init_library(), m_driver(GetGDALDriverManager()->GetDriverByName(driver_name.c_str()))
136 throw gdal_error(std::string(
"unknown driver: '") + driver_name +
"'", OGRERR_NONE, driver_name);
140 gdal_driver_type &get()
const
150 std::vector<std::string> m_options;
151 std::unique_ptr<const char *[]> m_ptrs;
153 Options(
const std::vector<std::string> &options) : m_options(options), m_ptrs(
new const char *[options.size() + 1])
155 std::transform(m_options.begin(), m_options.end(), m_ptrs.get(),
156 [&](
const std::string &s) { return s.data(); });
157 m_ptrs[options.size()] =
nullptr;
162 return const_cast<char **
>(m_ptrs.get());
172 OGRSpatialReference m_spatial_reference;
175 SRS() : m_spatial_reference()
177 auto result = m_spatial_reference.SetWellKnownGeogCS(
"WGS84");
178 if (result != OGRERR_NONE)
180 throw gdal_error(std::string(
"can not initialize spatial reference system WGS84"), result);
184 explicit SRS(
int epsg) : m_spatial_reference()
186 auto result = m_spatial_reference.importFromEPSG(epsg);
187 if (result != OGRERR_NONE)
190 std::string(
"can not initialize spatial reference system for EPSG:") + std::to_string(epsg), result);
194 explicit SRS(
const char *name) : m_spatial_reference()
196 auto result = m_spatial_reference.importFromProj4(name);
197 if (result != OGRERR_NONE)
199 throw gdal_error(std::string(
"can not initialize spatial reference system '") + name +
"'", result);
203 explicit SRS(
const std::string &name) : m_spatial_reference()
205 auto result = m_spatial_reference.importFromProj4(name.c_str());
206 if (result != OGRERR_NONE)
208 throw gdal_error(std::string(
"can not initialize spatial reference system '") + name +
"'", result);
212 explicit SRS(
const OGRSpatialReference &spatial_reference) : m_spatial_reference(spatial_reference)
216 OGRSpatialReference &get()
218 return m_spatial_reference;
221 const OGRSpatialReference &get()
const
223 return m_spatial_reference;
231 struct gdal_dataset_deleter
234 void operator()(gdal_dataset_type *ds)
241 GDALDataset *raster_read_only(
const std::string &dataset_name)
244 return static_cast<GDALDataset *
>(GDALOpen(dataset_name.c_str(), GA_ReadOnly));
247 std::string m_driver_name;
248 std::string m_dataset_name;
251 mutable std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
252 uint64_t m_edit_count = 0;
253 uint64_t m_max_edit_count = 0;
257 Dataset(
const std::string &driver_name,
const std::string &dataset_name,
const SRS &srs =
SRS{},
258 const std::vector<std::string> &options = {})
259 : m_driver_name(driver_name), m_dataset_name(dataset_name), m_options(options), m_srs(srs),
261 detail::Driver(driver_name).get().Create(dataset_name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get()))
266 throw gdal_error(std::string(
"failed to create dataset '") + dataset_name +
"'", OGRERR_NONE, driver_name,
272 Dataset(
const std::string &dataset_name,
const SRS &srs =
SRS{},
const std::vector<std::string> &options = {})
273 : m_driver_name(), m_dataset_name(dataset_name), m_options(options), m_srs(srs),
274 m_dataset(raster_read_only(dataset_name))
278 throw gdal_error(std::string(
"failed to create dataset '") + dataset_name +
"'", OGRERR_NONE, m_driver_name,
281 m_driver_name = std::string(m_dataset->GetDriverName());
288 if (m_edit_count > 0)
290 commit_transaction();
301 return m_dataset->GetRasterXSize();
307 return m_dataset->GetRasterYSize();
313 return m_dataset->GetRasterCount();
317 auto &
band(
unsigned int i)
const
319 assert(i >= 1 and i <=
depth());
320 return *(m_dataset->GetRasterBand(i));
326 std::vector<double> v;
328 if (m_dataset->GetGeoTransform(g) == CE_None)
330 v.assign(std::begin(g), std::end(g));
334 throw gdal_error(std::string(
"failed to get affine transformation coefficients in dataset '") +
335 m_dataset_name +
"'",
336 OGRERR_NONE, m_driver_name, m_dataset_name);
341 const std::string &driver_name()
const
343 return m_driver_name;
346 const std::string &dataset_name()
const
348 return m_dataset_name;
351 gdal_dataset_type &get()
const
361 void exec(
const char *sql)
363 auto result = m_dataset->ExecuteSQL(sql,
nullptr,
nullptr);
366 m_dataset->ReleaseResultSet(result);
370 void exec(
const std::string &sql)
377 m_dataset->StartTransaction();
383 m_dataset->CommitTransaction();
391 if (m_max_edit_count != 0 && m_edit_count == 0)
399 if (m_max_edit_count != 0 && ++m_edit_count > m_max_edit_count)
401 commit_transaction();
405 Dataset &enable_auto_transactions(uint64_t edits = 100000)
407 m_max_edit_count = edits;
411 Dataset &disable_auto_transactions()
413 if (m_max_edit_count != 0 && m_edit_count > 0)
415 commit_transaction();
417 m_max_edit_count = 0;
430 Layer(
Dataset &dataset,
const std::string &layer_name, OGRwkbGeometryType type,
431 const std::vector<std::string> &options = {})
432 : m_options(options), m_dataset(dataset),
433 m_layer(dataset.get().CreateLayer(layer_name.c_str(), &dataset.srs().get(), type, m_options.get()))
437 throw gdal_error(std::string(
"failed to create layer '") + layer_name +
"'", OGRERR_NONE,
438 dataset.driver_name(), dataset.dataset_name(), layer_name);
447 const OGRLayer &get()
const
457 const char *name()
const
459 return m_layer->GetName();
462 Layer &add_field(
const std::string &field_name, OGRFieldType type,
int width,
int precision = 0)
464 OGRFieldDefn field(field_name.c_str(), type);
465 field.SetWidth(width);
466 field.SetPrecision(precision);
468 if (m_layer->CreateField(&field) != OGRERR_NONE)
470 throw gdal_error(std::string(
"failed to create field '") + field_name +
"' in layer '" + name() +
"'",
471 OGRERR_NONE, m_dataset.driver_name(), m_dataset.dataset_name(), name(), field_name);
477 void create_feature(OGRFeature *feature)
479 dataset().prepare_edit();
480 OGRErr result = m_layer->CreateFeature(feature);
481 if (result != OGRERR_NONE)
483 throw gdal_error(std::string(
"creating feature in layer '") + name() +
"' failed", result,
484 dataset().driver_name(), dataset().dataset_name());
486 dataset().finalize_edit();
489 Layer &start_transaction()
494 Layer &commit_transaction()
504 struct ogr_feature_deleter
507 void operator()(OGRFeature *feature)
509 OGRFeature::DestroyFeature(feature);
515 std::unique_ptr<OGRFeature, ogr_feature_deleter> m_feature;
518 Feature(
Layer &layer, std::unique_ptr<OGRGeometry> &&geometry)
519 : m_layer(layer), m_feature(OGRFeature::CreateFeature(m_layer.get().GetLayerDefn()))
523 throw std::bad_alloc();
525 OGRErr result = m_feature->SetGeometryDirectly(geometry.release());
526 if (result != OGRERR_NONE)
528 throw gdal_error(std::string(
"setting feature geometry in layer '") + m_layer.name() +
"' failed", result,
529 m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
535 m_layer.create_feature(m_feature.get());
538 template <
class T>
Feature &set_field(
int n, T &&arg)
540 m_feature->SetField(n, std::forward<T>(arg));
544 template <
class T>
Feature &set_field(
const char *name, T &&arg)
546 m_feature->SetField(name, std::forward<T>(arg));
Definition gdalcpp.hpp:229
auto & band(unsigned int i) const
Fetch a band object for a dataset, zeroth-based numbering.
Definition gdalcpp.hpp:317
unsigned int depth() const
Fetch the number of raster bands on this dataset.
Definition gdalcpp.hpp:311
auto affine_transformation_coefficients()
Fetch the affine transformation coefficients.
Definition gdalcpp.hpp:324
Dataset(const std::string &driver_name, const std::string &dataset_name, const SRS &srs=SRS{}, const std::vector< std::string > &options={})
Vector constructor.
Definition gdalcpp.hpp:257
unsigned int height() const
Fetch raster height in pixels.
Definition gdalcpp.hpp:305
unsigned int width() const
Fetch raster width in pixels.
Definition gdalcpp.hpp:299
Dataset(const std::string &dataset_name, const SRS &srs=SRS{}, const std::vector< std::string > &options={})
Raster constructor.
Definition gdalcpp.hpp:272
Definition gdalcpp.hpp:502
Definition gdalcpp.hpp:423
Definition gdalcpp.hpp:170
Definition gdalcpp.hpp:126
Definition gdalcpp.hpp:63
Definition gdalcpp.hpp:148
Definition gdalcpp.hpp:118
Definition gdalcpp.hpp:110