Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
OGRLayerAdapter.hpp
Go to the documentation of this file.
1#pragma once
4#include <gdal/gdal.h>
5#include "ogrsf_frmts.h"
6#include <gdal/ogr_core.h>
7#include <gdal/gdal_priv.h>
8#include "OGRFieldAdapter.hpp"
9
10namespace fishnet {
11
19template<geometry::OGRWritableGeometry G>
21private:
28 static void addOGRField(VectorLayer<G> & layer,OGRFieldDefn * fieldDef,int id){
29 std::string fieldName = fieldDef->GetNameRef();
30 switch (fieldDef->GetType()){
31 case OFTReal:
32 layer.addDoubleField(fieldName,id);
33 break;
34 case OFTInteger:
35 layer.addIntegerField(fieldName,id);
36 break;
37 case OFTInteger64:
38 layer.addSizeField(fieldName,id);
39 break;
40 case OFTString:
41 layer.addTextField(fieldName,id);
42 break;
43 default:
44 break;
45 }
46 }
47
48
53 struct AddAttributeVisitor{
54 Feature<G> * feature;
55 OGRFeature * ogrFeature;
56
57 template<typename T>
58 bool operator()(FieldDefinition<T> const & fieldDef) {
59 if constexpr(std::same_as<T,int>)
60 return feature->addAttribute(fieldDef,ogrFeature->GetFieldAsInteger(fieldDef.getFieldID()));
61
62 else if constexpr(std::integral<T>)
63 return feature->addAttribute(fieldDef,T(ogrFeature->GetFieldAsInteger64(fieldDef.getFieldID())));
64
65 else if constexpr(std::floating_point<T>)
66 return feature->addAttribute(fieldDef,T(ogrFeature->GetFieldAsDouble(fieldDef.getFieldID())));
67
68 else if constexpr(std::convertible_to<T,std::string>)
69 return feature->addAttribute(fieldDef,ogrFeature->GetFieldAsString(fieldDef.getFieldID()));
70 }
71 };
72public:
76 static OGRwkbGeometryType layerGeometryType() {
78 return wkbUnknown; // takes whatever its features happen to hold
79 else
81 }
82
90 static Either<VectorLayer<G>, std::string> fromOGR(OGRLayer * ogrLayer)
92 if(ogrLayer == nullptr)
93 return std::unexpected("Could not read from OGRLayer, pointer is null");
94 VectorLayer<G> layer {};
95 OGRFeatureDefn * layerDef = ogrLayer->GetLayerDefn();
96 for(int i = 0; i < layerDef->GetFieldCount();i++) {
97 addOGRField(layer, layerDef->GetFieldDefn(i),i);
98 }
99 auto addFeatureIfPresent = [&layer](std::optional<G> && geometry, OGRFeature * ogrFeaturePtr) -> void{
100 if (not geometry)
101 return;
102 Feature<G> f {std::move(geometry.value())};
103 for(const auto & [_,fieldDefinition]: layer.getFieldsMap()){
104 std::visit(AddAttributeVisitor(&f,ogrFeaturePtr),fieldDefinition);
105 }
106 layer.addFeature(std::move(f));
107 };
108 for(const auto & ogrFeature: ogrLayer){
109 if (ogrFeature->GetGeometryRef() == nullptr)
110 continue;
111 // The geometry is taken off the feature rather than copied out of it: the feature is
112 // destroyed at the end of this iteration, so borrowing it would leave the layer holding
113 // dangling pointers. Which geometries a layer of G accepts is narrowTo's business.
115 fishnet::geometry::OGRUniquePtr<OGRGeometry>(ogrFeature->StealGeometry())};
116 addFeatureIfPresent(std::move(geometry).template narrowTo<G>(), ogrFeature.get());
117 }
118 if (auto * spatialRef = ogrLayer->GetSpatialRef(); spatialRef != nullptr)
119 layer.setSpatialReference(*spatialRef);
120 return layer;
121 }
129 static Either<OGRLayer *, std::string> toOGR(const VectorLayer<G> & layer, OGRLayer * outputLayer){
130 for(const auto & [fieldName,fieldDefinition] : layer.getFieldsMap()) {
131 OGRFieldType fieldType;
132 // get OGRFieldType from FieldDefinition<T> type -> T
133 std::visit([&fieldType](auto && fieldVariant){
134 using T = typename std::decay_t<decltype(fieldVariant)>::value_type;
135 fieldType = OGRFieldAdapter::fromTypeIndex(typeid(T));
136 },fieldDefinition);
137 auto fieldDefn = OGRFieldDefn(fieldName.c_str(),fieldType);
138 fieldDefn.SetPrecision(20);
139 std::ignore = outputLayer->CreateField(&fieldDefn); // add OGRFieldDefinition to output layer, ignore return value since it is not needed
140 }
141 for(const auto & f : layer.getFeatures()){
142 auto * feature = new OGRFeature(outputLayer->GetLayerDefn());
143 // the geometry is backed by an OGR geometry already, so it is handed over as it is
144 // instead of being rebuilt point by point
146 // a type erased geometry needs no inspection at all, whatever it holds is written
147 feature->SetGeometry(f.getGeometry().raw());
148 } else if constexpr (G::type == fishnet::geometry::GeometryType::POINT) {
149 OGRPoint point {f.getGeometry().getX(), f.getGeometry().getY()};
150 feature->SetGeometry(&point);
151 } else if constexpr (std::same_as<G, fishnet::geometry::OGRRingAdapter>) {
152 // a ring adapter wraps its ring in a shell polygon, the ring is its boundary
153 feature->SetGeometry(f.getGeometry().raw()->getExteriorRing());
154 } else if constexpr (fishnet::geometry::OGRLayerGeometry<G>) {
155 feature->SetGeometry(f.getGeometry().raw()); // already backed by an OGR geometry
156 } else if constexpr (fishnet::geometry::IRing<G>) {
157 // a fishnet geometry is converted through the adapter of its own kind, which is
158 // the same conversion the adapters offer everywhere else
159 fishnet::geometry::OGRRingAdapter adapted {f.getGeometry()};
160 feature->SetGeometry(adapted.raw()->getExteriorRing());
161 } else if constexpr (fishnet::geometry::IPolygon<G>) {
162 fishnet::geometry::OGRPolygonAdapter adapted {f.getGeometry()};
163 feature->SetGeometry(adapted.raw());
164 } else if constexpr (fishnet::geometry::IMultiPolygon<G>) {
165 fishnet::geometry::OGRMultiPolygonAdapter adapted {f.getGeometry()};
166 feature->SetGeometry(adapted.raw());
167 } else {
168 static_assert(false, "toOGR has no case for this geometry: a type was added to "
169 "OGRWritableGeometry without saying how it is turned into an OGR geometry");
170 }
171
172 for(const auto & [fieldName,fieldDefinition]: layer.getFieldsMap()){
173 // visitor to set attributes for OGRFeature
174 std::visit([&fieldName,&f,feature]( auto && var){
175 auto optionalAttribute = f.getAttribute(var);
176 if(optionalAttribute)
177 OGRFieldAdapter::setFieldValue(feature, fieldName, optionalAttribute.value());
178 },fieldDefinition);
179
180 }
181 OGRErr success = outputLayer->CreateFeature(feature);
182 if(success != 0){
183 return std::unexpected("Could not write Geometry: "+f.getGeometry().toString());
184 }
185 }
186 return outputLayer;
187
188 }
189};
190}
Definition Either.hpp:11
Feature implementation storing a geometry and associated attributes.
Definition Feature.hpp:51
constexpr bool addAttribute(const FieldDef &fieldDefinition, math::convertible_without_loss< typename FieldDef::value_type > auto value) noexcept
Definition Feature.hpp:78
Field definition implementation. Defines name, id and data type of a field.
Definition FieldDefinition.hpp:43
constexpr int getFieldID() const noexcept
Definition FieldDefinition.hpp:63
static void setFieldValue(OGRFeature *feature, const std::string &fieldName, const T &value) noexcept
Definition OGRFieldAdapter.hpp:25
static OGRFieldType fromTypeIndex(const std::type_index &type) noexcept
Definition OGRFieldAdapter.hpp:14
Reads and writes a VectorLayer whose geometries are backed by the OGR data source.
Definition OGRLayerAdapter.hpp:20
static OGRwkbGeometryType layerGeometryType()
WKB type an output layer holding G has to be created with.
Definition OGRLayerAdapter.hpp:76
static Either< VectorLayer< G >, std::string > fromOGR(OGRLayer *ogrLayer)
Converts an OGRLayer to a fishnet::VectorLayer.
Definition OGRLayerAdapter.hpp:90
static Either< OGRLayer *, std::string > toOGR(const VectorLayer< G > &layer, OGRLayer *outputLayer)
Converts a fishnet::VectorLayer to an OGRLayer.
Definition OGRLayerAdapter.hpp:129
Stores the geometries, wrapped in features (which hold the field values / attributes) Keeps track of ...
Definition VectorLayer.hpp:28
constexpr void setSpatialReference(const OGRSpatialReference &spatialReference) noexcept
Definition VectorLayer.hpp:95
constexpr fishnet::Either< FieldDefinition< std::string >, error_type > addTextField(const std::string &fieldName, const std::optional< int > &fieldID=std::nullopt) noexcept
Definition VectorLayer.hpp:180
constexpr fishnet::Either< FieldDefinition< size_t >, error_type > addSizeField(const std::string &fieldName, const std::optional< int > &fieldID=std::nullopt) noexcept
Definition VectorLayer.hpp:184
constexpr fishnet::Either< FieldDefinition< double >, error_type > addDoubleField(const std::string &fieldName, const std::optional< int > &fieldID=std::nullopt) noexcept
Definition VectorLayer.hpp:176
constexpr void addFeature(Feature< G > &&feature) noexcept
Definition VectorLayer.hpp:129
constexpr const std::unordered_map< std::string, FieldDefinitionVariant > & getFieldsMap() const noexcept
Definition VectorLayer.hpp:239
constexpr fishnet::Either< FieldDefinition< int >, error_type > addIntegerField(const std::string &fieldName, const std::optional< int > &fieldID=std::nullopt) noexcept
Definition VectorLayer.hpp:172
constexpr util::view_of< Feature< G > > auto getFeatures() const noexcept
Definition VectorLayer.hpp:83
static OGRwkbGeometryType toWKB(GeometryType type)
Definition OGRAdapterBase.hpp:137
Adapter for an OGRGeometry of statically unknown type, as handed out by a data source.
Definition OGRGeometryAdapter.hpp:83
IMultiPolygon implementation backed by an OGRMultiPolygon.
Definition OGRMultiPolygonAdapter.hpp:19
IPolygon implementation backed by an OGRPolygon.
Definition OGRPolygonAdapter.hpp:22
IRing implementation backed by an OGRPolygon holding nothing but an exterior ring.
Definition OGRRingAdapter.hpp:30
A geometry which carries its type at runtime instead of statically.
Definition IGeometry.hpp:41
Interface for a multi-polygon A multi-polygon is a collection of polygons.
Definition IMultiPolygon.hpp:93
Interface for a polygon A polygon is a two-dimensional shape defined by a boundary and zero or more h...
Definition IPolygon.hpp:98
Interface for a ring A ring is a closed loop of segments, forming a boundary of a shape.
Definition IRing.hpp:143
A geometry an OGR layer can be read into and written from.
Definition OGRGeometryAdapter.hpp:26
std::unique_ptr< T, __impl::OGRGeometryDeleter > OGRUniquePtr
Definition OGRAdapterBase.hpp:48
Definition BFSClustering.hpp:5