Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: netCDF read/write Driver
4 : * Purpose: GDAL bindings over netCDF library.
5 : * Author: Winor Chen <wchen329 at wisc.edu>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2019, Winor Chen <wchen329 at wisc.edu>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 : #ifndef __NETCDFSG_H__
13 : #define __NETCDFSG_H__
14 : #include <cstring>
15 : #include <memory>
16 : #include <set>
17 : #include <string>
18 : #include <vector>
19 : #include "netcdf.h"
20 :
21 : // Interface used for netCDF functions
22 : // implementing awareness for the CF-1.8 convention
23 : //
24 : // Author: wchen329
25 : namespace nccfdriver
26 : {
27 : // Constants
28 : const int INVALID_VAR_ID = -2;
29 : const int INVALID_DIM_ID = INVALID_VAR_ID;
30 :
31 : // Enum used for easily identifying Geometry types
32 : enum geom_t
33 : {
34 : NONE, // no geometry found
35 : POLYGON, // OGRPolygon
36 : MULTIPOLYGON, // OGRMultipolygon
37 : LINE, // OGRLineString
38 : MULTILINE, // OGRMultiLineString
39 : POINT, // OGRPoint
40 : MULTIPOINT, // OGRMultiPoint
41 : UNSUPPORTED // Unsupported feature type
42 : };
43 :
44 : // Concrete "Point" class, holds n dimensional double precision floating point
45 : // value, defaults to all zero values
46 : class Point
47 : {
48 : int size;
49 : std::unique_ptr<double, std::default_delete<double[]>> values;
50 : Point(Point &);
51 : Point operator=(const Point &);
52 :
53 : public:
54 67 : explicit Point(int dim)
55 67 : : size(dim),
56 : values(std::unique_ptr<double, std::default_delete<double[]>>(
57 67 : new double[dim]))
58 : {
59 67 : }
60 :
61 269842 : double &operator[](size_t i)
62 : {
63 269842 : return this->values.get()[i];
64 : }
65 :
66 : int getOrder()
67 : {
68 : return this->size;
69 : }
70 : };
71 :
72 : // Simple geometry - doesn't actually hold the points, rather serves
73 : // as a pseudo reference to a NC variable
74 : class SGeometry_Reader
75 : {
76 : std::string container_name_s; // name of the underlying geometry container
77 : geom_t type; // internal geometry type structure
78 : int ncid; // ncid - as used in netcdf.h
79 : int gc_varId; // the id of the underlying geometry_container variable
80 : std::string gm_name_s; // grid mapping variable name
81 : int gm_varId; // id used for grid mapping
82 : int inst_dimId; // dimension id for geometry instance dimension
83 : size_t inst_dimLen; // value of instance dimension
84 : int touple_order; // amount of "coordinates" in a point
85 : std::vector<int> nodec_varIds; // varIds for each node_coordinate entry
86 : std::vector<int>
87 : node_counts; // node counts of each geometry in a container
88 : std::vector<int>
89 : pnode_counts; // part node counts of each geometry in a container
90 : std::vector<bool> int_rings; // list of parts that are interior rings
91 : std::vector<size_t> bound_list; // a quick list used to store the real
92 : // beginning indices of shapes
93 : std::vector<size_t> pnc_bl; // a quick list of indices for part counts
94 : // corresponding to a geometry
95 : std::vector<int>
96 : parts_count; // a count of total parts in a single geometry instance
97 : std::vector<int> poly_count; // count of polygons, for use only when
98 : // interior rings are present
99 : std::unique_ptr<Point> pt_buffer; // holds the current point
100 : SGeometry_Reader(SGeometry_Reader &);
101 : SGeometry_Reader operator=(const SGeometry_Reader &);
102 :
103 : public:
104 : /* int SGeometry_Reader::get_ncID()
105 : * return the group/file ID that the SGeometry object is operating over
106 : */
107 86 : int get_ncID()
108 : {
109 86 : return ncid;
110 : }
111 :
112 : /* int SGeometry_Reader::get_axisCount()
113 : * Returns the count of axis (i.e. X, Y, Z)
114 : */
115 68284 : int get_axisCount()
116 : {
117 68284 : return this->touple_order;
118 : }
119 :
120 : /* int SGeometry_Reader::getInstDim()
121 : * Returns the geometry instance dimension ID of this geometry
122 : */
123 492 : int getInstDim()
124 : {
125 492 : return this->inst_dimId;
126 : }
127 :
128 : /* size_t SGeometry_Reader::getInstDimLen()
129 : * Returns the length of the instance dimension
130 : */
131 : size_t getInstDimLen()
132 : {
133 : return this->inst_dimLen;
134 : }
135 :
136 : /* std::string& getGridMappingName()
137 : * returns the variable name which holds grid mapping data
138 : */
139 43 : std::string &getGridMappingName()
140 : {
141 43 : return this->gm_name_s;
142 : }
143 :
144 : /* int SGeometry_Reader::getGridMappingVarID();
145 : * returns the varID of the associated grid mapping variable ID
146 : */
147 67 : int getGridMappingVarID()
148 : {
149 67 : return this->gm_varId;
150 : }
151 :
152 : /* geom_t getGeometryType()
153 : * Retrieves the associated geometry type with this geometry
154 : */
155 1543 : geom_t getGeometryType()
156 : {
157 1543 : return this->type;
158 : }
159 :
160 : /* void SGeometry_Reader::get_geometry_count()
161 : * returns a size, indicating the amount of geometries
162 : * contained in the variable
163 : */
164 : size_t get_geometry_count();
165 :
166 : /* const char* SGeometry_Reader::getContainerName()
167 : * Returns the container name as a string
168 : */
169 : std::string &getContainerName()
170 : {
171 : return container_name_s;
172 : }
173 :
174 : /* int SGeometry_Reader::getContainerId()
175 : * Get the ncID of the geometry_container variable
176 : */
177 67 : int getContainerId()
178 : {
179 67 : return gc_varId;
180 : }
181 :
182 : /* std::vector<unsigned char> serializeToWKB
183 : * Returns a pre-allocated array which serves as the WKB reference to this
184 : * geometry
185 : */
186 : std::vector<unsigned char> serializeToWKB(size_t featureInd);
187 :
188 : /* Return a point at a specific index specifically
189 : * this point should NOT be explicitly freed.
190 : *
191 : */
192 : Point &operator[](size_t ind);
193 :
194 : /* std::vector<int>& getNodeCoordVars
195 : * Returns a vector with the node coord vars in X, Y, Z (if present) order
196 : */
197 86 : std::vector<int> &getNodeCoordVars()
198 : {
199 86 : return this->nodec_varIds;
200 : }
201 :
202 : /* ncID - as used in netcdf.h
203 : * baseVarId - the id of a variable with a geometry container attribute
204 : */
205 : SGeometry_Reader(int ncId, int baseVarId);
206 : };
207 :
208 : /* SGeometry_PropertyScanner
209 : * Holds names of properties for geometry containers
210 : * Pass in the geometry_container ID, automatically scans the netcdf Dataset for
211 : * properties associated
212 : *
213 : * to construct: pass in the ncid which the reader should work over
214 : */
215 : class SGeometry_PropertyScanner
216 : {
217 : std::vector<int> v_ids;
218 : std::vector<std::string> v_headers;
219 : int nc;
220 :
221 : void open(int container_id); // opens and initializes a geometry_container
222 : // into the scanner
223 :
224 : public:
225 : std::vector<std::string> &headers()
226 : {
227 : return this->v_headers;
228 : }
229 :
230 66 : std::vector<int> &ids()
231 : {
232 66 : return this->v_ids;
233 : }
234 :
235 67 : SGeometry_PropertyScanner(int ncid, int cid) : nc(ncid)
236 : {
237 67 : this->open(cid);
238 67 : }
239 : };
240 :
241 : // General exception interface for Simple Geometries
242 : // Whatever pointer returned should NOT be freed- it will be deconstructed
243 : // automatically, if needed
244 : class SG_Exception
245 : {
246 : public:
247 : ~SG_Exception();
248 :
249 7 : const char *get_err_msg() const
250 : {
251 7 : return err_msg.c_str();
252 : }
253 :
254 : protected:
255 3 : SG_Exception() = default;
256 :
257 4 : explicit SG_Exception(const std::string &s) : err_msg(s)
258 : {
259 4 : }
260 :
261 : std::string err_msg;
262 : };
263 :
264 : // Mismatched dimension exception
265 : class SG_Exception_Dim_MM : public SG_Exception
266 : {
267 : public:
268 : SG_Exception_Dim_MM(const char *geometry_container, const char *field_1,
269 : const char *field_2);
270 : };
271 :
272 : // Missing (existential) property error
273 : class SG_Exception_Existential : public SG_Exception
274 : {
275 : public:
276 : SG_Exception_Existential(const char *geometry_container,
277 : const char *missing_name);
278 : };
279 :
280 : // Missing dependent property (arg_1 is dependent on arg_2)
281 : class SG_Exception_Dep : public SG_Exception
282 : {
283 : public:
284 : SG_Exception_Dep(const char *geometry_container, const char *arg_1,
285 : const char *arg_2);
286 : };
287 :
288 : // The sum of all values in a variable does not match the sum of another
289 : // variable
290 : class SG_Exception_BadSum : public SG_Exception
291 : {
292 : public:
293 : SG_Exception_BadSum(const char *geometry_container, const char *arg_1,
294 : const char *arg_2);
295 : };
296 :
297 : // Unsupported Feature Type
298 : class SG_Exception_BadFeature : public SG_Exception
299 : {
300 : public:
301 1 : SG_Exception_BadFeature()
302 1 : : SG_Exception("Unsupported or unrecognized feature type.")
303 : {
304 1 : }
305 : };
306 :
307 : // Failed Read
308 : class SG_Exception_BadPoint : public SG_Exception
309 : {
310 : public:
311 0 : SG_Exception_BadPoint()
312 0 : : SG_Exception(
313 : "An attempt was made to read an invalid point (likely index "
314 0 : "out of bounds).")
315 : {
316 0 : }
317 : };
318 :
319 : // Too many dimensions on node coordinates variable
320 : class SG_Exception_Not1D : public SG_Exception
321 : {
322 : public:
323 0 : SG_Exception_Not1D()
324 0 : : SG_Exception(
325 : "A node coordinates axis variable or node_counts is not one "
326 0 : "dimensional.")
327 : {
328 0 : }
329 : };
330 :
331 : // Too many empty dimension
332 : class SG_Exception_EmptyDim : public SG_Exception
333 : {
334 : public:
335 0 : SG_Exception_EmptyDim()
336 0 : : SG_Exception(
337 0 : "A dimension has length <= 0, but it must have length > 0")
338 : {
339 0 : }
340 : };
341 :
342 : // general corruption or malformed error
343 : class SG_Exception_General_Malformed : public SG_Exception
344 : {
345 : public:
346 : explicit SG_Exception_General_Malformed(const char *);
347 : };
348 :
349 : // Invalid value detected
350 : class SG_Exception_Value_Violation : public SG_Exception
351 : {
352 : public:
353 2 : SG_Exception_Value_Violation(const char *containername, const char *type,
354 : const char *badvalue)
355 4 : : SG_Exception(std::string("[") + std::string(containername) +
356 8 : std::string("] ") + std::string(type) +
357 8 : std::string(" values may not be ") +
358 6 : std::string(badvalue))
359 : {
360 2 : }
361 : };
362 :
363 : // Required value(s)
364 : class SG_Exception_Value_Required : public SG_Exception
365 : {
366 : public:
367 1 : SG_Exception_Value_Required(const char *containername, const char *type,
368 : const char *expvalue)
369 2 : : SG_Exception(std::string("[") + std::string(containername) +
370 4 : std::string("] ") + std::string(type) +
371 3 : std::string(" values must be ") + std::string(expvalue))
372 : {
373 1 : }
374 : };
375 :
376 : // Some helpers which simply call some netcdf library functions, unless
377 : // otherwise mentioned, ncid, refers to its use in netcdf.h
378 :
379 : /* Retrieves the version from the value Conventions global attr
380 : * Returns: a double precision decimal corresponding to the conventions value
381 : * if not CF-x.y then return negative value, -1
382 : */
383 : double getCFVersion(int ncid);
384 :
385 : /* Given a geometry_container varID, searches that variable for a geometry_type
386 : * attribute Returns: the equivalent geometry type
387 : */
388 : geom_t getGeometryType(int ncid, int varid);
389 :
390 : void inPlaceSerialize_Point(SGeometry_Reader *ge, size_t seek_pos,
391 : std::vector<unsigned char> &buffer);
392 : void inPlaceSerialize_LineString(SGeometry_Reader *ge, int node_count,
393 : size_t seek_begin,
394 : std::vector<unsigned char> &buffer);
395 : void inPlaceSerialize_PolygonExtOnly(SGeometry_Reader *ge, int node_count,
396 : size_t seek_begin,
397 : std::vector<unsigned char> &buffer);
398 : void inPlaceSerialize_Polygon(SGeometry_Reader *ge, std::vector<int> &pnc,
399 : int ring_count, size_t seek_begin,
400 : std::vector<unsigned char> &buffer);
401 :
402 : /* scanForGeometryContainers
403 : * A simple function that scans a netCDF File for Geometry Containers
404 : * -
405 : * Scans the given ncid for geometry containers
406 : * The vector passed in will be overwritten with a vector of scan results
407 : */
408 : int scanForGeometryContainers(int ncid, std::set<int> &r_ids);
409 :
410 : /* Attribute Fetch
411 : * -
412 : * A function which makes it a bit easier to fetch single text attribute values
413 : * ncid: as used in netcdf.h
414 : * varID: variable id in which to look for the attribute
415 : * attrName: name of attribute to fine
416 : * alloc: a reference to a string that will be filled with the attribute (i.e.
417 : * truncated and filled with the return value) Returns: a reference to the
418 : * string to fill (a.k.a. string pointed to by alloc reference)
419 : */
420 : std::string &attrf(int ncid, int varId, const char *attrName,
421 : std::string &alloc);
422 : } // namespace nccfdriver
423 :
424 : #endif
|