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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 : #ifndef __NETCDFSG_H__
29 : #define __NETCDFSG_H__
30 : #include <cstring>
31 : #include <memory>
32 : #include <set>
33 : #include <string>
34 : #include <vector>
35 : #include "netcdf.h"
36 :
37 : // Interface used for netCDF functions
38 : // implementing awareness for the CF-1.8 convention
39 : //
40 : // Author: wchen329
41 : namespace nccfdriver
42 : {
43 : // Constants
44 : const int INVALID_VAR_ID = -2;
45 : const int INVALID_DIM_ID = INVALID_VAR_ID;
46 :
47 : // Enum used for easily identifying Geometry types
48 : enum geom_t
49 : {
50 : NONE, // no geometry found
51 : POLYGON, // OGRPolygon
52 : MULTIPOLYGON, // OGRMultipolygon
53 : LINE, // OGRLineString
54 : MULTILINE, // OGRMultiLineString
55 : POINT, // OGRPoint
56 : MULTIPOINT, // OGRMultiPoint
57 : UNSUPPORTED // Unsupported feature type
58 : };
59 :
60 : // Concrete "Point" class, holds n dimensional double precision floating point
61 : // value, defaults to all zero values
62 : class Point
63 : {
64 : int size;
65 : std::unique_ptr<double, std::default_delete<double[]>> values;
66 : Point(Point &);
67 : Point operator=(const Point &);
68 :
69 : public:
70 72 : explicit Point(int dim)
71 72 : : size(dim),
72 : values(std::unique_ptr<double, std::default_delete<double[]>>(
73 72 : new double[dim]))
74 : {
75 72 : }
76 :
77 269842 : double &operator[](size_t i)
78 : {
79 269842 : return this->values.get()[i];
80 : }
81 :
82 : int getOrder()
83 : {
84 : return this->size;
85 : }
86 : };
87 :
88 : // Simple geometry - doesn't actually hold the points, rather serves
89 : // as a pseudo reference to a NC variable
90 : class SGeometry_Reader
91 : {
92 : std::string container_name_s; // name of the underlying geometry container
93 : geom_t type; // internal geometry type structure
94 : int ncid; // ncid - as used in netcdf.h
95 : int gc_varId; // the id of the underlying geometry_container variable
96 : std::string gm_name_s; // grid mapping variable name
97 : int gm_varId; // id used for grid mapping
98 : int inst_dimId; // dimension id for geometry instance dimension
99 : size_t inst_dimLen; // value of instance dimension
100 : int touple_order; // amount of "coordinates" in a point
101 : std::vector<int> nodec_varIds; // varIds for each node_coordinate entry
102 : std::vector<int>
103 : node_counts; // node counts of each geometry in a container
104 : std::vector<int>
105 : pnode_counts; // part node counts of each geometry in a container
106 : std::vector<bool> int_rings; // list of parts that are interior rings
107 : std::vector<size_t> bound_list; // a quick list used to store the real
108 : // beginning indices of shapes
109 : std::vector<size_t> pnc_bl; // a quick list of indices for part counts
110 : // corresponding to a geometry
111 : std::vector<int>
112 : parts_count; // a count of total parts in a single geometry instance
113 : std::vector<int> poly_count; // count of polygons, for use only when
114 : // interior rings are present
115 : std::unique_ptr<Point> pt_buffer; // holds the current point
116 : SGeometry_Reader(SGeometry_Reader &);
117 : SGeometry_Reader operator=(const SGeometry_Reader &);
118 :
119 : public:
120 : /* int SGeometry_Reader::get_ncID()
121 : * return the group/file ID that the SGeometry object is operating over
122 : */
123 96 : int get_ncID()
124 : {
125 96 : return ncid;
126 : }
127 :
128 : /* int SGeometry_Reader::get_axisCount()
129 : * Returns the count of axis (i.e. X, Y, Z)
130 : */
131 68289 : int get_axisCount()
132 : {
133 68289 : return this->touple_order;
134 : }
135 :
136 : /* int SGeometry_Reader::getInstDim()
137 : * Returns the geometry instance dimension ID of this geometry
138 : */
139 492 : int getInstDim()
140 : {
141 492 : return this->inst_dimId;
142 : }
143 :
144 : /* size_t SGeometry_Reader::getInstDimLen()
145 : * Returns the length of the instance dimension
146 : */
147 : size_t getInstDimLen()
148 : {
149 : return this->inst_dimLen;
150 : }
151 :
152 : /* std::string& getGridMappingName()
153 : * returns the variable name which holds grid mapping data
154 : */
155 48 : std::string &getGridMappingName()
156 : {
157 48 : return this->gm_name_s;
158 : }
159 :
160 : /* int SGeometry_Reader::getGridMappingVarID();
161 : * returns the varID of the associated grid mapping variable ID
162 : */
163 72 : int getGridMappingVarID()
164 : {
165 72 : return this->gm_varId;
166 : }
167 :
168 : /* geom_t getGeometryType()
169 : * Retrieves the associated geometry type with this geometry
170 : */
171 1548 : geom_t getGeometryType()
172 : {
173 1548 : return this->type;
174 : }
175 :
176 : /* void SGeometry_Reader::get_geometry_count()
177 : * returns a size, indicating the amount of geometries
178 : * contained in the variable
179 : */
180 : size_t get_geometry_count();
181 :
182 : /* const char* SGeometry_Reader::getContainerName()
183 : * Returns the container name as a string
184 : */
185 : std::string &getContainerName()
186 : {
187 : return container_name_s;
188 : }
189 :
190 : /* int SGeometry_Reader::getContainerId()
191 : * Get the ncID of the geometry_container variable
192 : */
193 72 : int getContainerId()
194 : {
195 72 : return gc_varId;
196 : }
197 :
198 : /* std::vector<unsigned char> serializeToWKB
199 : * Returns a pre-allocated array which serves as the WKB reference to this
200 : * geometry
201 : */
202 : std::vector<unsigned char> serializeToWKB(size_t featureInd);
203 :
204 : /* Return a point at a specific index specifically
205 : * this point should NOT be explicitly freed.
206 : *
207 : */
208 : Point &operator[](size_t ind);
209 :
210 : /* std::vector<int>& getNodeCoordVars
211 : * Returns a vector with the node coord vars in X, Y, Z (if present) order
212 : */
213 96 : std::vector<int> &getNodeCoordVars()
214 : {
215 96 : return this->nodec_varIds;
216 : }
217 :
218 : /* ncID - as used in netcdf.h
219 : * baseVarId - the id of a variable with a geometry container attribute
220 : */
221 : SGeometry_Reader(int ncId, int baseVarId);
222 : };
223 :
224 : /* SGeometry_PropertyScanner
225 : * Holds names of properties for geometry containers
226 : * Pass in the geometry_container ID, automatically scans the netcdf Dataset for
227 : * properties associated
228 : *
229 : * to construct: pass in the ncid which the reader should work over
230 : */
231 : class SGeometry_PropertyScanner
232 : {
233 : std::vector<int> v_ids;
234 : std::vector<std::string> v_headers;
235 : int nc;
236 :
237 : void open(int container_id); // opens and initializes a geometry_container
238 : // into the scanner
239 :
240 : public:
241 : std::vector<std::string> &headers()
242 : {
243 : return this->v_headers;
244 : }
245 :
246 71 : std::vector<int> &ids()
247 : {
248 71 : return this->v_ids;
249 : }
250 :
251 72 : SGeometry_PropertyScanner(int ncid, int cid) : nc(ncid)
252 : {
253 72 : this->open(cid);
254 72 : }
255 : };
256 :
257 : // General exception interface for Simple Geometries
258 : // Whatever pointer returned should NOT be freed- it will be deconstructed
259 : // automatically, if needed
260 : class SG_Exception
261 : {
262 : public:
263 : virtual const char *get_err_msg() = 0;
264 : virtual ~SG_Exception();
265 : };
266 :
267 : // Mismatched dimension exception
268 : class SG_Exception_Dim_MM : public SG_Exception
269 : {
270 : std::string err_msg;
271 :
272 : public:
273 1 : const char *get_err_msg() override
274 : {
275 1 : return err_msg.c_str();
276 : }
277 :
278 : SG_Exception_Dim_MM(const char *geometry_container, const char *field_1,
279 : const char *field_2);
280 : };
281 :
282 : // Missing (existential) property error
283 : class SG_Exception_Existential : public SG_Exception
284 : {
285 : std::string err_msg;
286 :
287 : public:
288 2 : const char *get_err_msg() override
289 : {
290 2 : return err_msg.c_str();
291 : }
292 :
293 : SG_Exception_Existential(const char *geometry_container,
294 : const char *missing_name);
295 : };
296 :
297 : // Missing dependent property (arg_1 is dependent on arg_2)
298 : class SG_Exception_Dep : 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_Dep(const char *geometry_container, const char *arg_1,
309 : const char *arg_2);
310 : };
311 :
312 : // The sum of all values in a variable does not match the sum of another
313 : // variable
314 : class SG_Exception_BadSum : public SG_Exception
315 : {
316 : std::string err_msg;
317 :
318 : public:
319 0 : const char *get_err_msg() override
320 : {
321 0 : return err_msg.c_str();
322 : }
323 :
324 : SG_Exception_BadSum(const char *geometry_container, const char *arg_1,
325 : const char *arg_2);
326 : };
327 :
328 : // Unsupported Feature Type
329 : class SG_Exception_BadFeature : public SG_Exception
330 : {
331 : std::string err_msg;
332 :
333 : public:
334 1 : const char *get_err_msg() override
335 : {
336 1 : return err_msg.c_str();
337 : }
338 :
339 1 : SG_Exception_BadFeature()
340 1 : : err_msg("Unsupported or unrecognized feature type.")
341 : {
342 1 : }
343 : };
344 :
345 : // Failed Read
346 : class SG_Exception_BadPoint : public SG_Exception
347 : {
348 : std::string err_msg;
349 :
350 : public:
351 0 : const char *get_err_msg() override
352 : {
353 0 : return err_msg.c_str();
354 : }
355 :
356 0 : SG_Exception_BadPoint()
357 0 : : err_msg("An attempt was made to read an invalid point (likely index "
358 0 : "out of bounds).")
359 : {
360 0 : }
361 : };
362 :
363 : // Too many dimensions on node coordinates variable
364 : class SG_Exception_Not1D : public SG_Exception
365 : {
366 : std::string err_msg;
367 :
368 : public:
369 0 : const char *get_err_msg() override
370 : {
371 0 : return err_msg.c_str();
372 : }
373 :
374 0 : SG_Exception_Not1D()
375 0 : : err_msg("A node coordinates axis variable or node_counts is not one "
376 0 : "dimensional.")
377 : {
378 0 : }
379 : };
380 :
381 : // Too many empty dimension
382 : class SG_Exception_EmptyDim : public SG_Exception
383 : {
384 : std::string err_msg;
385 :
386 : public:
387 0 : const char *get_err_msg() override
388 : {
389 0 : return err_msg.c_str();
390 : }
391 :
392 0 : SG_Exception_EmptyDim()
393 0 : : err_msg("A dimension has length <= 0, but it must have length > 0")
394 : {
395 0 : }
396 : };
397 :
398 : // general corruption or malformed error
399 : class SG_Exception_General_Malformed : public SG_Exception
400 : {
401 : std::string err_msg;
402 :
403 : public:
404 0 : const char *get_err_msg() override
405 : {
406 0 : return err_msg.c_str();
407 : }
408 :
409 : explicit SG_Exception_General_Malformed(const char *);
410 : };
411 :
412 : // Invalid value detected
413 : class SG_Exception_Value_Violation : public SG_Exception
414 : {
415 : std::string err_msg;
416 :
417 : public:
418 2 : const char *get_err_msg() override
419 : {
420 2 : return err_msg.c_str();
421 : }
422 :
423 2 : SG_Exception_Value_Violation(const char *containername, const char *type,
424 : const char *badvalue)
425 4 : : err_msg(std::string("[") + std::string(containername) +
426 8 : std::string("] ") + std::string(type) +
427 6 : std::string(" values may not be ") + std::string(badvalue))
428 : {
429 2 : }
430 : };
431 :
432 : // Required value(s)
433 : class SG_Exception_Value_Required : public SG_Exception
434 : {
435 : std::string err_msg;
436 :
437 : public:
438 1 : const char *get_err_msg() override
439 : {
440 1 : return err_msg.c_str();
441 : }
442 :
443 1 : SG_Exception_Value_Required(const char *containername, const char *type,
444 : const char *expvalue)
445 2 : : err_msg(std::string("[") + std::string(containername) +
446 4 : std::string("] ") + std::string(type) +
447 3 : std::string(" values must be ") + std::string(expvalue))
448 : {
449 1 : }
450 : };
451 :
452 : // Some helpers which simply call some netcdf library functions, unless
453 : // otherwise mentioned, ncid, refers to its use in netcdf.h
454 :
455 : /* Retrieves the version from the value Conventions global attr
456 : * Returns: a double precision decimal corresponding to the conventions value
457 : * if not CF-x.y then return negative value, -1
458 : */
459 : double getCFVersion(int ncid);
460 :
461 : /* Given a geometry_container varID, searches that variable for a geometry_type
462 : * attribute Returns: the equivalent geometry type
463 : */
464 : geom_t getGeometryType(int ncid, int varid);
465 :
466 : void inPlaceSerialize_Point(SGeometry_Reader *ge, size_t seek_pos,
467 : std::vector<unsigned char> &buffer);
468 : void inPlaceSerialize_LineString(SGeometry_Reader *ge, int node_count,
469 : size_t seek_begin,
470 : std::vector<unsigned char> &buffer);
471 : void inPlaceSerialize_PolygonExtOnly(SGeometry_Reader *ge, int node_count,
472 : size_t seek_begin,
473 : std::vector<unsigned char> &buffer);
474 : void inPlaceSerialize_Polygon(SGeometry_Reader *ge, std::vector<int> &pnc,
475 : int ring_count, size_t seek_begin,
476 : std::vector<unsigned char> &buffer);
477 :
478 : /* scanForGeometryContainers
479 : * A simple function that scans a netCDF File for Geometry Containers
480 : * -
481 : * Scans the given ncid for geometry containers
482 : * The vector passed in will be overwritten with a vector of scan results
483 : */
484 : int scanForGeometryContainers(int ncid, std::set<int> &r_ids);
485 :
486 : /* Attribute Fetch
487 : * -
488 : * A function which makes it a bit easier to fetch single text attribute values
489 : * ncid: as used in netcdf.h
490 : * varID: variable id in which to look for the attribute
491 : * attrName: name of attribute to fine
492 : * alloc: a reference to a string that will be filled with the attribute (i.e.
493 : * truncated and filled with the return value) Returns: a reference to the
494 : * string to fill (a.k.a. string pointed to by alloc reference)
495 : */
496 : std::string &attrf(int ncid, int varId, const char *attrName,
497 : std::string &alloc);
498 : } // namespace nccfdriver
499 :
500 : #endif
|