Program Listing for File Geometry_impl.hpp
↰ Return to documentation for file (include/fields2cover/types/Geometry_impl.hpp
)
//=============================================================================
// Copyright (C) 2021-2024 Wageningen University - All Rights Reserved
// Author: Gonzalo Mier
// BSD-3 License
//=============================================================================
#pragma once
#ifndef FIELDS2COVER_TYPES_GEOMETRY_IMPL_HPP_
#define FIELDS2COVER_TYPES_GEOMETRY_IMPL_HPP_
#include <gdal/cpl_conv.h>
#include <geos_c.h>
#include <memory>
#include <vector>
#include <string>
namespace f2c::types {
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry() : data_(
downCast<T*>(OGRGeometryFactory::createGeometry(R)),
[](T* f) {OGRGeometryFactory::destroyGeometry(f);}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(const T& g) : data_(downCast<T*>(g.clone()),
[](T* f) {OGRGeometryFactory::destroyGeometry(f);}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(std::shared_ptr<T> g) : data_(g) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(T* g, EmptyDestructor) : data_(g, [](T* f) {}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(const T* g) : data_(downCast<T*>(g->clone()),
[](T* f) {OGRGeometryFactory::destroyGeometry(f);}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(OGRGeometry* g, EmptyDestructor) :
data_(downCast<T*>(g), [](T* f) {}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(const OGRGeometry* g) : data_(downCast<T*>(g->clone()),
[](T* f) {OGRGeometryFactory::destroyGeometry(f);}) {}
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::~Geometry() = default;
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(const Geometry& g) = default;
template <class T, OGRwkbGeometryType R>
Geometry<T, R>::Geometry(Geometry&& g) = default;
template <class T, OGRwkbGeometryType R>
typename Geometry<T, R>::Geometry& Geometry<T, R>::operator=(
Geometry&& g) = default;
template <class T, OGRwkbGeometryType R>
typename Geometry<T, R>::Geometry& Geometry<T, R>::operator=(
const Geometry& g) = default;
template <class T, OGRwkbGeometryType R>
std::shared_ptr<T> Geometry<T, R>::operator->() {return data_;}
template <class T, OGRwkbGeometryType R>
std::shared_ptr<const T> Geometry<T, R>::operator->() const {return data_;}
template <class T, OGRwkbGeometryType R>
T* Geometry<T, R>::get() {return data_.get();}
template <class T, OGRwkbGeometryType R>
const T* Geometry<T, R>::get() const {return data_.get();}
template <class T, OGRwkbGeometryType R>
bool Geometry<T, R>::operator!=(const Geometry<T, R>& geom2) const {
return !geom2->Equals(data_.get());
}
template <class T, OGRwkbGeometryType R>
bool Geometry<T, R>::operator==(const Geometry<T, R>& geom2) const {
return geom2->Equals(data_.get());
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getDimMinX() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MinX;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getDimMaxX() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MaxX;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getDimMinY() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MinY;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getDimMaxY() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MaxY;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getHeight() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MaxY - envelope.MinY;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getWidth() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return envelope.MaxX - envelope.MinX;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getMinSafeLength() const {
OGREnvelope envelope;
data_->getEnvelope(&envelope);
return (envelope.MaxX - envelope.MinX) +
(envelope.MaxY - envelope.MinY);
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
double Geometry<T, R>::distance(const Geometry<T2, R2>& p) const {
return data_->Distance(p.get());
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
bool Geometry<T, R>::disjoint(const Geometry<T2, R2>& geom) const {
return data_->Disjoint(geom.get());
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
bool Geometry<T, R>::crosses(const Geometry<T2, R2>& geom) const {
return data_->Crosses(geom.get());
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
bool Geometry<T, R>::touches(const Geometry<T2, R2>& geom) const {
return data_->Touches(geom.get());
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
bool Geometry<T, R>::within(const Geometry<T2, R2>& geom) const {
return data_->Within(geom.get());
}
template <class T, OGRwkbGeometryType R>
template <class T2, OGRwkbGeometryType R2>
bool Geometry<T, R>::intersects(const Geometry<T2, R2>& geom) const {
return data_->Intersects(geom.get());
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::mod_2pi(double val) {
return mod(val, boost::math::constants::two_pi<double>());
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getAngContinuity(double prev_val, double val) {
const auto two_pi = boost::math::constants::two_pi<double>();
auto val_id = round(prev_val / two_pi);
auto getNearVal =
[two_pi] (int i, double value) {return i * two_pi + mod_2pi(value);};
for (int i = -2; i <= 0; ++i) {
if (fabs(getNearVal(val_id + i + 1, val) - prev_val) >
fabs(getNearVal(val_id + i, val) - prev_val)) {
return getNearVal(val_id + i, val);
}
}
return getNearVal(val_id + 1, val);
}
template <class T, OGRwkbGeometryType R>
std::vector<double> Geometry<T, R>::getAngContinuity(
const std::vector<double>& val) {
std::vector<double> res {val[0]};
for (size_t i = 1; i < val.size(); ++i) {
res.emplace_back(getAngContinuity(res[i - 1], val[i]));
}
return res;
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getAngleDiffAbs(double a, double b) {
const auto pi = boost::math::constants::pi<double>();
return pi - fabs(mod_2pi(b - a) - pi);
}
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::getAngleAvg(double a, double b) {
const auto pi = boost::math::constants::pi<double>();
double ma = mod_2pi(a);
double mb = mod_2pi(b);
if (abs(mb - ma) < pi) {
return 0.5 * (ma + mb);
} else {
return 0.5 * (ma + mb) + pi;
}
}
template <class T, OGRwkbGeometryType R>
bool Geometry<T, R>::isEmpty() const {
return (!data_ || data_->IsEmpty());
}
template <class T, OGRwkbGeometryType R>
std::string Geometry<T, R>::exportToWkt() const {
char *pszWKT = nullptr;
data_->exportToWkt(&pszWKT);
std::string result{pszWKT};
CPLFree(pszWKT);
return result;
}
template <class T, OGRwkbGeometryType R>
std::string Geometry<T, R>::exportToGML() const {
char *s = data_->exportToGML();
std::string str(s);
CPLFree(s);
return str;
}
template <class T, OGRwkbGeometryType R>
std::string Geometry<T, R>::exportToKML() const {
char *s = data_->exportToKML();
std::string str(s);
CPLFree(s);
return str;
}
template <class T, OGRwkbGeometryType R>
std::string Geometry<T, R>::exportToJson() const {
char *s = data_->exportToJson();
std::string str(s);
CPLFree(s);
return str;
}
template <class T, OGRwkbGeometryType R>
void Geometry<T, R>::importFromWkt(const std::string& text) {
auto char_text = text.c_str();
data_->importFromWkt(&char_text);
}
// ###############################
// Code extracted from:
// https://github.com/OSGeo/gdal/blob/b0aa6065a39b252cb8306e9c2e2535d6dda0fb55/port/cpl_conv.h#L397
template <class T, OGRwkbGeometryType R>
template <typename To, typename From>
inline To Geometry<T, R>::downCast(From *f) const {
static_assert(
(std::is_base_of<From, typename std::remove_pointer<To>::type>::value),
"target type not derived from source type");
CPLAssert(f == nullptr || dynamic_cast<To>(f) != nullptr);
return static_cast<To>(f);
}
// ###############################
template <class T, OGRwkbGeometryType R>
template<typename RetType>
RetType Geometry<T, R>::destroyResGeom(OGRGeometry* g) {
RetType res(g);
OGRGeometryFactory::destroyGeometry(g);
return res;
}
// ###############################
// Code extracted from:
// https://github.com/OSGeo/gdal/blob/717dcc0eed252e2f78c142b1f7866e49c5511224/ogr/ogrgeometry.cpp#L4309
template <class T, OGRwkbGeometryType R>
OGRGeometry* Geometry<T, R>::OGRBuffer(double dfDist, int side) const {
OGRGeometry *poOGRProduct = nullptr;
GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext();
GEOSGeom hGeosGeom = this->data_->exportToGEOS(hGEOSCtxt);
if (hGeosGeom != nullptr) {
GEOSBufferParams* hBufParams = GEOSBufferParams_create_r(hGEOSCtxt);
GEOSBufferParams_setEndCapStyle_r(hGEOSCtxt, hBufParams,
GEOSBufCapStyles::GEOSBUF_CAP_FLAT);
GEOSBufferParams_setJoinStyle_r(hGEOSCtxt, hBufParams,
GEOSBufJoinStyles::GEOSBUF_JOIN_MITRE);
GEOSBufferParams_setSingleSided_r(hGEOSCtxt, hBufParams, side != 0);
GEOSGeom hGeosProduct = GEOSBufferWithParams_r(hGEOSCtxt, hGeosGeom,
hBufParams, side >= 0 ? dfDist : -dfDist);
GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
GEOSBufferParams_destroy_r(hGEOSCtxt, hBufParams);
poOGRProduct = buildGeometryFromGEOS(hGEOSCtxt, hGeosProduct,
this->data_.get(), nullptr);
}
OGRGeometry::freeGEOSContext(hGEOSCtxt);
return poOGRProduct;
}
// ###############################
// Code extracted from:
// https://github.com/OSGeo/gdal/blob/717dcc0eed252e2f78c142b1f7866e49c5511224/ogr/ogrgeometry.cpp#L4309
template <class T, OGRwkbGeometryType R>
OGRGeometry* Geometry<T, R>::OGRGeometryRebuildCurves(
const OGRGeometry *poGeom, const OGRGeometry *poOtherGeom,
OGRGeometry *poOGRProduct) const {
if (poOGRProduct != nullptr &&
wkbFlatten(poOGRProduct->getGeometryType()) != wkbPoint &&
(poGeom->hasCurveGeometry(true) ||
(poOtherGeom && poOtherGeom->hasCurveGeometry(true)))) {
OGRGeometry *poCurveGeom = poOGRProduct->getCurveGeometry();
delete poOGRProduct;
return poCurveGeom;
}
return poOGRProduct;
}
template <class T, OGRwkbGeometryType R>
OGRGeometry* Geometry<T, R>::buildGeometryFromGEOS(
GEOSContextHandle_t hGEOSCtxt, GEOSGeom hGeosProduct,
const OGRGeometry *poSelf, const OGRGeometry *poOtherGeom) const {
OGRGeometry *poOGRProduct = nullptr;
if (hGeosProduct != nullptr) {
poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosProduct);
if (poOGRProduct != nullptr &&
poSelf->getSpatialReference() != nullptr &&
(poOtherGeom == nullptr ||
(poOtherGeom->getSpatialReference() != nullptr &&
poOtherGeom->getSpatialReference()->IsSame(
poSelf->getSpatialReference())))) {
poOGRProduct->assignSpatialReference(poSelf->getSpatialReference());
}
poOGRProduct = OGRGeometryRebuildCurves(poSelf, poOtherGeom, poOGRProduct);
GEOSGeom_destroy_r(hGEOSCtxt, hGeosProduct);
}
return poOGRProduct;
}
// ###############################
template <class T, OGRwkbGeometryType R>
double Geometry<T, R>::mod(double a, double b) {
return fmod(fmod(a, b) + b, b);
}
} // namespace f2c::types
#endif // FIELDS2COVER_TYPES_GEOMETRY_IMPL_HPP_