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 : virtual const char *get_err_msg() = 0;
248 : virtual ~SG_Exception();
249 : };
250 :
251 : // Mismatched dimension exception
252 : class SG_Exception_Dim_MM : public SG_Exception
253 : {
254 : std::string err_msg;
255 :
256 : public:
257 1 : const char *get_err_msg() override
258 : {
259 1 : return err_msg.c_str();
260 : }
261 :
262 : SG_Exception_Dim_MM(const char *geometry_container, const char *field_1,
263 : const char *field_2);
264 : };
265 :
266 : // Missing (existential) property error
267 : class SG_Exception_Existential : public SG_Exception
268 : {
269 : std::string err_msg;
270 :
271 : public:
272 2 : const char *get_err_msg() override
273 : {
274 2 : return err_msg.c_str();
275 : }
276 :
277 : SG_Exception_Existential(const char *geometry_container,
278 : const char *missing_name);
279 : };
280 :
281 : // Missing dependent property (arg_1 is dependent on arg_2)
282 : class SG_Exception_Dep : public SG_Exception
283 : {
284 : std::string err_msg;
285 :
286 : public:
287 0 : const char *get_err_msg() override
288 : {
289 0 : return err_msg.c_str();
290 : }
291 :
292 : SG_Exception_Dep(const char *geometry_container, const char *arg_1,
293 : const char *arg_2);
294 : };
295 :
296 : // The sum of all values in a variable does not match the sum of another
297 : // variable
298 : class SG_Exception_BadSum : public SG_Exception
299 : {
300 : std::string err_msg;
301 :
302 : public:
303 0 : const char *get_err_msg() override
304 : {
305 0 : return err_msg.c_str();
306 : }
307 :
308 : SG_Exception_BadSum(const char *geometry_container, const char *arg_1,
309 : const char *arg_2);
310 : };
311 :
312 : // Unsupported Feature Type
313 : class SG_Exception_BadFeature : public SG_Exception
314 : {
315 : std::string err_msg;
316 :
317 : public:
318 1 : const char *get_err_msg() override
319 : {
320 1 : return err_msg.c_str();
321 : }
322 :
323 1 : SG_Exception_BadFeature()
324 1 : : err_msg("Unsupported or unrecognized feature type.")
325 : {
326 1 : }
327 : };
328 :
329 : // Failed Read
330 : class SG_Exception_BadPoint : public SG_Exception
331 : {
332 : std::string err_msg;
333 :
334 : public:
335 0 : const char *get_err_msg() override
336 : {
337 0 : return err_msg.c_str();
338 : }
339 :
340 0 : SG_Exception_BadPoint()
341 0 : : err_msg("An attempt was made to read an invalid point (likely index "
342 0 : "out of bounds).")
343 : {
344 0 : }
345 : };
346 :
347 : // Too many dimensions on node coordinates variable
348 : class SG_Exception_Not1D : public SG_Exception
349 : {
350 : std::string err_msg;
351 :
352 : public:
353 0 : const char *get_err_msg() override
354 : {
355 0 : return err_msg.c_str();
356 : }
357 :
358 0 : SG_Exception_Not1D()
359 0 : : err_msg("A node coordinates axis variable or node_counts is not one "
360 0 : "dimensional.")
361 : {
362 0 : }
363 : };
364 :
365 : // Too many empty dimension
366 : class SG_Exception_EmptyDim : public SG_Exception
367 : {
368 : std::string err_msg;
369 :
370 : public:
371 0 : const char *get_err_msg() override
372 : {
373 0 : return err_msg.c_str();
374 : }
375 :
376 0 : SG_Exception_EmptyDim()
377 0 : : err_msg("A dimension has length <= 0, but it must have length > 0")
378 : {
379 0 : }
380 : };
381 :
382 : // general corruption or malformed error
383 : class SG_Exception_General_Malformed : public SG_Exception
384 : {
385 : std::string err_msg;
386 :
387 : public:
388 0 : const char *get_err_msg() override
389 : {
390 0 : return err_msg.c_str();
391 : }
392 :
393 : explicit SG_Exception_General_Malformed(const char *);
394 : };
395 :
396 : // Invalid value detected
397 : class SG_Exception_Value_Violation : public SG_Exception
398 : {
399 : std::string err_msg;
400 :
401 : public:
402 2 : const char *get_err_msg() override
403 : {
404 2 : return err_msg.c_str();
405 : }
406 :
407 2 : SG_Exception_Value_Violation(const char *containername, const char *type,
408 : const char *badvalue)
409 4 : : err_msg(std::string("[") + std::string(containername) +
410 8 : std::string("] ") + std::string(type) +
411 6 : std::string(" values may not be ") + std::string(badvalue))
412 : {
413 2 : }
414 : };
415 :
416 : // Required value(s)
417 : class SG_Exception_Value_Required : public SG_Exception
418 : {
419 : std::string err_msg;
420 :
421 : public:
422 1 : const char *get_err_msg() override
423 : {
424 1 : return err_msg.c_str();
425 : }
426 :
427 1 : SG_Exception_Value_Required(const char *containername, const char *type,
428 : const char *expvalue)
429 2 : : err_msg(std::string("[") + std::string(containername) +
430 4 : std::string("] ") + std::string(type) +
431 3 : std::string(" values must be ") + std::string(expvalue))
432 : {
433 1 : }
434 : };
435 :
436 : // Some helpers which simply call some netcdf library functions, unless
437 : // otherwise mentioned, ncid, refers to its use in netcdf.h
438 :
439 : /* Retrieves the version from the value Conventions global attr
440 : * Returns: a double precision decimal corresponding to the conventions value
441 : * if not CF-x.y then return negative value, -1
442 : */
443 : double getCFVersion(int ncid);
444 :
445 : /* Given a geometry_container varID, searches that variable for a geometry_type
446 : * attribute Returns: the equivalent geometry type
447 : */
448 : geom_t getGeometryType(int ncid, int varid);
449 :
450 : void inPlaceSerialize_Point(SGeometry_Reader *ge, size_t seek_pos,
451 : std::vector<unsigned char> &buffer);
452 : void inPlaceSerialize_LineString(SGeometry_Reader *ge, int node_count,
453 : size_t seek_begin,
454 : std::vector<unsigned char> &buffer);
455 : void inPlaceSerialize_PolygonExtOnly(SGeometry_Reader *ge, int node_count,
456 : size_t seek_begin,
457 : std::vector<unsigned char> &buffer);
458 : void inPlaceSerialize_Polygon(SGeometry_Reader *ge, std::vector<int> &pnc,
459 : int ring_count, size_t seek_begin,
460 : std::vector<unsigned char> &buffer);
461 :
462 : /* scanForGeometryContainers
463 : * A simple function that scans a netCDF File for Geometry Containers
464 : * -
465 : * Scans the given ncid for geometry containers
466 : * The vector passed in will be overwritten with a vector of scan results
467 : */
468 : int scanForGeometryContainers(int ncid, std::set<int> &r_ids);
469 :
470 : /* Attribute Fetch
471 : * -
472 : * A function which makes it a bit easier to fetch single text attribute values
473 : * ncid: as used in netcdf.h
474 : * varID: variable id in which to look for the attribute
475 : * attrName: name of attribute to fine
476 : * alloc: a reference to a string that will be filled with the attribute (i.e.
477 : * truncated and filled with the return value) Returns: a reference to the
478 : * string to fill (a.k.a. string pointed to by alloc reference)
479 : */
480 : std::string &attrf(int ncid, int varId, const char *attrName,
481 : std::string &alloc);
482 : } // namespace nccfdriver
483 :
484 : #endif
|