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 __NETCDFSGWRITERUTIL_H__
29 : #define __NETCDFSGWRITERUTIL_H__
30 : #include <cstdio>
31 : #include <queue>
32 : #include <typeinfo>
33 : #include <vector>
34 : #include "cpl_vsi.h"
35 : #include "ogr_core.h"
36 : #include "ogrsf_frmts.h"
37 : #include "netcdflayersg.h"
38 : #include "netcdfsg.h"
39 : #include "netcdfvirtual.h"
40 :
41 : namespace nccfdriver
42 : {
43 :
44 : /* OGR_SGeometry_Feature
45 : * Constructs over a OGRFeature
46 : * gives some basic information about that SGeometry Feature such as
47 : * Hold references... limited to scope of its references
48 : * - what's its geometry type
49 : * - how much total points it has
50 : * - how many parts it has
51 : * - a vector of counts of points for each part
52 : */
53 : class SGeometry_Feature
54 : {
55 : bool hasInteriorRing;
56 : const OGRGeometry *geometry_ref;
57 : geom_t type;
58 : size_t total_point_count;
59 : size_t total_part_count;
60 : std::vector<size_t> ppart_node_count;
61 : std::vector<bool> part_at_ind_interior; // for use with Multipolygons ONLY
62 : mutable OGRPoint pt_buffer;
63 :
64 : public:
65 446 : geom_t getType()
66 : {
67 446 : return this->type;
68 : }
69 :
70 409 : size_t getTotalNodeCount()
71 : {
72 409 : return this->total_point_count;
73 : }
74 :
75 1558 : size_t getTotalPartCount()
76 : {
77 1558 : return this->total_part_count;
78 : }
79 :
80 68422 : std::vector<size_t> &getPerPartNodeCount()
81 : {
82 68422 : return this->ppart_node_count;
83 : }
84 :
85 : const OGRPoint &getPoint(size_t part_no, int point_index) const;
86 : explicit SGeometry_Feature(OGRFeature &);
87 :
88 : bool getHasInteriorRing()
89 : {
90 : return this->hasInteriorRing;
91 : }
92 :
93 591 : bool IsPartAtIndInteriorRing(size_t ind)
94 : {
95 591 : return this->part_at_ind_interior[ind];
96 : } // ONLY used for Multipolygon
97 : };
98 :
99 : /* A memory buffer with a soft limit
100 : * Has basic capability of over quota checking, and memory counting
101 : */
102 : class WBuffer
103 : {
104 : unsigned long long used_mem = 0;
105 :
106 : public:
107 : /* addCount(...)
108 : * Takes in a size, and directly adds that size to memory count
109 : */
110 : void addCount(unsigned long long memuse);
111 :
112 : /* subCount(...)
113 : * Directly subtracts the specified size from used_mem
114 : */
115 : void subCount(unsigned long long memfree);
116 :
117 892 : unsigned long long &getUsage()
118 : {
119 892 : return used_mem;
120 : }
121 :
122 360 : void reset()
123 : {
124 360 : this->used_mem = 0;
125 360 : }
126 :
127 1922 : WBuffer()
128 1922 : {
129 1922 : }
130 : };
131 :
132 : /* OGR_SGFS_Transaction
133 : * Abstract class for a committable transaction
134 : *
135 : */
136 : class OGR_SGFS_Transaction
137 : {
138 : int varId = INVALID_VAR_ID;
139 :
140 : public:
141 : /* int commit(...);
142 : * Arguments: int ncid, the dataset to write to
143 : * int write_loc, the index in which to write to
144 : * Implementation: should write the transaction to netCDF file
145 : *
146 : */
147 : virtual void commit(netCDFVID &n, size_t write_loc) = 0;
148 :
149 : /* unsigned long long count(...)
150 : * Implementation: supposed to return an approximate count of memory usage
151 : * Most classes will implement with sizeof(*this), except if otherwise
152 : * uncounted for dynamic allocation is involved.
153 : */
154 : virtual unsigned long long count() = 0;
155 :
156 : /* appendToLog
157 : * Implementation - given a file pointer, a transaction will be written to
158 : * that log file in the format:
159 : * -
160 : * transactionVarId - sizeof(int) bytes
161 : * NC_TYPE - sizeof(int) bytes
162 : * (nc_char only) OP - 1 byte (0 if does not require COUNT or non-zero i.e.
163 : * 1 if does) (nc_char only): SIZE of data - sizeof(size_t) bytes DATA -
164 : * size depends on NC_TYPE
165 : */
166 : virtual void appendToLog(VSILFILE *) = 0;
167 :
168 : /* ~OGR_SGFS_Transaction()
169 : * Empty. Simply here to stop the compiler from complaining...
170 : */
171 224718 : virtual ~OGR_SGFS_Transaction()
172 224718 : {
173 224718 : }
174 :
175 : /* OGR_SGFS_Transaction()
176 : * Empty. Simply here to stop one of the CI machines from complaining...
177 : */
178 224718 : OGR_SGFS_Transaction()
179 224718 : {
180 224718 : }
181 :
182 : /* void getVarId(...);
183 : * Gets the var in which to commit the transaction to.
184 : */
185 769574 : int getVarId()
186 : {
187 769574 : return this->varId;
188 : }
189 :
190 : /* nc_type getType
191 : * Returns the type of transaction being saved
192 : */
193 : virtual nc_type getType() = 0;
194 :
195 : /* void setVarId(...);
196 : * Sets the var in which to commit the transaction to.
197 : */
198 224718 : void setVarId(int vId)
199 : {
200 224718 : this->varId = vId;
201 224718 : }
202 : };
203 :
204 : typedef std::map<int, void *> NCWMap;
205 : typedef std::pair<int, void *> NCWEntry; // NC Writer Entry
206 : typedef std::unique_ptr<OGR_SGFS_Transaction>
207 : MTPtr; // a.k.a Managed Transaction Ptr
208 :
209 : template <class T_c_type, nc_type T_nc_type>
210 87851 : void genericLogAppend(T_c_type r, int vId, VSILFILE *f)
211 : {
212 87851 : T_c_type rep = r;
213 87851 : int varId = vId;
214 87851 : int type = T_nc_type;
215 87851 : VSIFWriteL(&varId, sizeof(int), 1, f); // write varID data
216 87851 : VSIFWriteL(&type, sizeof(int), 1, f); // write NC type
217 87851 : VSIFWriteL(&rep, sizeof(T_c_type), 1, f); // write data
218 87851 : }
219 :
220 : template <class T_c_type, class T_r_type>
221 87851 : MTPtr genericLogDataRead(int varId, VSILFILE *f)
222 : {
223 : T_r_type data;
224 87851 : if (!VSIFReadL(&data, sizeof(T_r_type), 1, f))
225 : {
226 0 : return MTPtr(nullptr); // invalid read case
227 : }
228 87851 : return MTPtr(new T_c_type(varId, data));
229 : }
230 :
231 : /* OGR_SGFS_NC_Char_Transaction
232 : * Writes to an NC_CHAR variable
233 : */
234 : class OGR_SGFS_NC_Char_Transaction : public OGR_SGFS_Transaction
235 : {
236 : std::string char_rep;
237 :
238 : public:
239 0 : void commit(netCDFVID &n, size_t write_loc) override
240 : {
241 0 : n.nc_put_vvar1_text(OGR_SGFS_Transaction::getVarId(), &write_loc,
242 : char_rep.c_str());
243 0 : }
244 :
245 0 : unsigned long long count() override
246 : {
247 0 : return char_rep.size() + sizeof(*this);
248 : } // account for actual character representation, this class
249 :
250 : void appendToLog(VSILFILE *f) override;
251 :
252 0 : nc_type getType() override
253 : {
254 0 : return NC_CHAR;
255 : }
256 :
257 0 : OGR_SGFS_NC_Char_Transaction(int i_varId, const char *pszVal)
258 0 : : char_rep(pszVal)
259 : {
260 0 : OGR_SGFS_Transaction::setVarId(i_varId);
261 0 : }
262 : };
263 :
264 : /* OGR_SGFS_NC_CharA_Transaction
265 : * Writes to an NC_CHAR variable, using vara instead of var1
266 : * Used to store 2D character array values, specifically
267 : */
268 : class OGR_SGFS_NC_CharA_Transaction : public OGR_SGFS_Transaction
269 : {
270 : std::string char_rep;
271 : size_t counts[2];
272 :
273 : public:
274 884 : void commit(netCDFVID &n, size_t write_loc) override
275 : {
276 884 : size_t ind[2] = {write_loc, 0};
277 884 : n.nc_put_vvara_text(OGR_SGFS_Transaction::getVarId(), ind, counts,
278 : char_rep.c_str());
279 884 : }
280 :
281 2356 : unsigned long long count() override
282 : {
283 2356 : return char_rep.size() + sizeof(*this);
284 : } // account for actual character representation, this class
285 :
286 : void appendToLog(VSILFILE *f) override;
287 :
288 884 : nc_type getType() override
289 : {
290 884 : return NC_CHAR;
291 : }
292 :
293 1472 : OGR_SGFS_NC_CharA_Transaction(int i_varId, const char *pszVal)
294 1472 : : char_rep(pszVal), counts{1, char_rep.length()}
295 : {
296 1472 : OGR_SGFS_Transaction::setVarId(i_varId);
297 1472 : }
298 : };
299 :
300 : template <class VClass, nc_type ntype>
301 : class OGR_SGFS_NC_Transaction_Generic : public OGR_SGFS_Transaction
302 : {
303 : VClass rep;
304 :
305 : public:
306 23250 : void commit(netCDFVID &n, size_t write_loc) override
307 : {
308 23250 : n.nc_put_vvar_generic<VClass>(OGR_SGFS_Transaction::getVarId(),
309 23250 : &write_loc, &rep);
310 23250 : }
311 :
312 358613 : unsigned long long count() override
313 : {
314 358613 : return sizeof(*this);
315 : }
316 :
317 87851 : void appendToLog(VSILFILE *f) override
318 : {
319 87851 : genericLogAppend<VClass, ntype>(rep, OGR_SGFS_Transaction::getVarId(),
320 : f);
321 87851 : }
322 :
323 223232 : OGR_SGFS_NC_Transaction_Generic(int i_varId, VClass in) : rep(in)
324 : {
325 223232 : OGR_SGFS_Transaction::setVarId(i_varId);
326 223232 : }
327 :
328 112131 : VClass getData()
329 : {
330 112131 : return rep;
331 : }
332 :
333 382893 : nc_type getType() override
334 : {
335 382893 : return ntype;
336 : }
337 : };
338 :
339 : typedef OGR_SGFS_NC_Transaction_Generic<signed char, NC_BYTE>
340 : OGR_SGFS_NC_Byte_Transaction;
341 : typedef OGR_SGFS_NC_Transaction_Generic<short, NC_SHORT>
342 : OGR_SGFS_NC_Short_Transaction;
343 : typedef OGR_SGFS_NC_Transaction_Generic<int, NC_INT>
344 : OGR_SGFS_NC_Int_Transaction;
345 : typedef OGR_SGFS_NC_Transaction_Generic<float, NC_FLOAT>
346 : OGR_SGFS_NC_Float_Transaction;
347 : typedef OGR_SGFS_NC_Transaction_Generic<double, NC_DOUBLE>
348 : OGR_SGFS_NC_Double_Transaction;
349 : typedef OGR_SGFS_NC_Transaction_Generic<unsigned, NC_UINT>
350 : OGR_SGFS_NC_UInt_Transaction;
351 : typedef OGR_SGFS_NC_Transaction_Generic<unsigned long long, NC_UINT64>
352 : OGR_SGFS_NC_UInt64_Transaction;
353 : typedef OGR_SGFS_NC_Transaction_Generic<long long, NC_INT64>
354 : OGR_SGFS_NC_Int64_Transaction;
355 : typedef OGR_SGFS_NC_Transaction_Generic<unsigned char, NC_UBYTE>
356 : OGR_SGFS_NC_UByte_Transaction;
357 : typedef OGR_SGFS_NC_Transaction_Generic<unsigned short, NC_USHORT>
358 : OGR_SGFS_NC_UShort_Transaction;
359 :
360 : /* OGR_SGFS_NC_String_Transaction
361 : * Writes to an NC_STRING variable, in a similar manner as NC_Char
362 : */
363 : class OGR_SGFS_NC_String_Transaction : public OGR_SGFS_Transaction
364 : {
365 : std::string char_rep;
366 :
367 : public:
368 14 : void commit(netCDFVID &n, size_t write_loc) override
369 : {
370 14 : const char *writable = char_rep.c_str();
371 14 : n.nc_put_vvar1_string(OGR_SGFS_Transaction::getVarId(), &write_loc,
372 : &(writable));
373 14 : }
374 :
375 28 : unsigned long long count() override
376 : {
377 28 : return char_rep.size() + sizeof(*this);
378 : } // account for actual character representation, this class
379 :
380 28 : nc_type getType() override
381 : {
382 28 : return NC_STRING;
383 : }
384 :
385 : void appendToLog(VSILFILE *f) override;
386 :
387 14 : OGR_SGFS_NC_String_Transaction(int i_varId, const char *pszVal)
388 14 : : char_rep(pszVal)
389 : {
390 14 : OGR_SGFS_Transaction::setVarId(i_varId);
391 14 : }
392 : };
393 :
394 : /* WTransactionLog
395 : * -
396 : * A temporary file which contains transactions to be written to a netCDF file.
397 : * Once the transaction log is created it is set on write mode, it can only be
398 : * read to after startRead() is called
399 : */
400 : class WTransactionLog
401 : {
402 : bool readMode = false;
403 : std::string wlogName; // name of the temporary file, should be unique
404 : VSILFILE *log = nullptr;
405 :
406 : WTransactionLog(WTransactionLog &); // avoid possible undefined behavior
407 : WTransactionLog operator=(const WTransactionLog &);
408 :
409 : public:
410 360 : bool logIsNull()
411 : {
412 360 : return log == nullptr;
413 : }
414 :
415 : void startLog(); // always call this first to open the file
416 : void startRead(); // then call this before reading it
417 : void push(MTPtr);
418 :
419 : // read mode
420 : MTPtr
421 : pop(); // to test for EOF, test to see if pointer returned is null ptr
422 :
423 : // construction, destruction
424 : explicit WTransactionLog(const std::string &logName);
425 : ~WTransactionLog();
426 : };
427 :
428 : /* OGR_NCScribe
429 : * Buffers several netCDF transactions in memory or in a log.
430 : * General scribe class
431 : */
432 : class OGR_NCScribe
433 : {
434 : netCDFVID &ncvd;
435 : WBuffer buf;
436 : WTransactionLog wl;
437 : bool singleDatumMode = false;
438 :
439 : std::queue<MTPtr> transactionQueue;
440 : std::map<int, size_t> varWriteInds;
441 : std::map<int, size_t> varMaxInds;
442 :
443 : public:
444 : /* size_t getWriteCount()
445 : * Return the total write count (happened + pending) of certain variable
446 : */
447 : size_t getWriteCount(int varId)
448 : {
449 : return this->varMaxInds.at(varId);
450 : }
451 :
452 : /* void commit_transaction()
453 : * Replays all transactions to disk (according to fs stipulations)
454 : */
455 : void commit_transaction();
456 :
457 : /* MTPtr pop()
458 : * Get the next transaction, if it exists.
459 : * If not, it will just return a shared_ptr with nullptr inside
460 : */
461 : MTPtr pop();
462 :
463 : /* void log_transacion()
464 : * Saves the current queued transactions to a log.
465 : */
466 : void log_transaction();
467 :
468 : /* void enqueue_transaction()
469 : * Add a transaction to perform
470 : * Once a transaction is enqueued, it will only be dequeued on commit
471 : */
472 : void enqueue_transaction(MTPtr transactionAdd);
473 :
474 1922 : WBuffer &getMemBuffer()
475 : {
476 1922 : return buf;
477 : }
478 :
479 : /* OGR_SGeometry_Field_Scribe()
480 : * Constructs a Field Scribe over a dataset
481 : */
482 1922 : OGR_NCScribe(netCDFVID &ncd, const std::string &name) : ncvd(ncd), wl(name)
483 : {
484 1922 : }
485 :
486 : /* setSingleDatumMode(...)
487 : * Enables or disables single datum mode
488 : * DO NOT use this when a commit is taking place, otherwise
489 : * corruption may occur...
490 : */
491 2 : void setSingleDatumMode(bool sdm)
492 : {
493 2 : this->singleDatumMode = sdm;
494 2 : }
495 : };
496 :
497 : class ncLayer_SG_Metadata
498 : {
499 : int &ncID; // ncid REF. which tracks ncID changes that may be made upstream
500 :
501 : netCDFVID &vDataset;
502 : OGR_NCScribe &ncb;
503 : geom_t writableType = NONE;
504 : std::string containerVarName;
505 : int containerVar_realID = INVALID_VAR_ID;
506 : bool interiorRingDetected =
507 : false; // flips on when an interior ring polygon has been detected
508 : std::vector<int>
509 : node_coordinates_varIDs; // ids in X, Y (and then possibly Z) order
510 : int node_coordinates_dimID = INVALID_DIM_ID; // dim of all node_coordinates
511 : int node_count_dimID = INVALID_DIM_ID; // node count dim
512 : int node_count_varID = INVALID_DIM_ID;
513 : int pnc_dimID =
514 : INVALID_DIM_ID; // part node count dim AND interior ring dim
515 : int pnc_varID = INVALID_VAR_ID;
516 : int intring_varID = INVALID_VAR_ID;
517 : size_t next_write_pos_node_coord = 0;
518 : size_t next_write_pos_node_count = 0;
519 : size_t next_write_pos_pnc = 0;
520 :
521 : public:
522 354 : geom_t getWritableType()
523 : {
524 354 : return this->writableType;
525 : }
526 :
527 : void writeSGeometryFeature(SGeometry_Feature &ft);
528 :
529 563 : int get_containerRealID()
530 : {
531 563 : return this->containerVar_realID;
532 : }
533 :
534 77 : std::string get_containerName()
535 : {
536 77 : return this->containerVarName;
537 : }
538 :
539 121 : int get_node_count_dimID()
540 : {
541 121 : return this->node_count_dimID;
542 : }
543 :
544 124 : int get_node_coord_dimID()
545 : {
546 124 : return this->node_coordinates_dimID;
547 : }
548 :
549 78 : int get_pnc_dimID()
550 : {
551 78 : return this->pnc_dimID;
552 : }
553 :
554 4 : int get_pnc_varID()
555 : {
556 4 : return this->pnc_varID;
557 : }
558 :
559 17 : int get_intring_varID()
560 : {
561 17 : return this->intring_varID;
562 : }
563 :
564 38 : std::vector<int> &get_nodeCoordVarIDs()
565 : {
566 38 : return this->node_coordinates_varIDs;
567 : }
568 :
569 42 : size_t get_next_write_pos_node_coord()
570 : {
571 42 : return this->next_write_pos_node_coord;
572 : }
573 :
574 32 : size_t get_next_write_pos_node_count()
575 : {
576 32 : return this->next_write_pos_node_count;
577 : }
578 :
579 27 : size_t get_next_write_pos_pnc()
580 : {
581 27 : return this->next_write_pos_pnc;
582 : }
583 :
584 114 : bool getInteriorRingDetected()
585 : {
586 114 : return this->interiorRingDetected;
587 : }
588 :
589 : void initializeNewContainer(int containerVID);
590 : ncLayer_SG_Metadata(int &i_ncID, geom_t geo, netCDFVID &ncdf,
591 : OGR_NCScribe &scribe);
592 : };
593 :
594 : /* WBufferManager
595 : * -
596 : * Simply takes a collection of buffers in and a quota limit and sums all the
597 : * usages up to establish if buffers are over the soft limit (collectively)
598 : *
599 : * The buffers added, however, are not memory managed by WBufferManager
600 : */
601 : class WBufferManager
602 : {
603 : unsigned long long buffer_soft_limit = 0;
604 : std::vector<WBuffer *> bufs;
605 :
606 : public:
607 : bool isOverQuota();
608 :
609 4 : void adjustLimit(unsigned long long lim)
610 : {
611 4 : this->buffer_soft_limit = lim;
612 4 : }
613 :
614 1922 : void addBuffer(WBuffer *b)
615 : {
616 1922 : this->bufs.push_back(b);
617 1922 : }
618 :
619 961 : explicit WBufferManager(unsigned long long lim) : buffer_soft_limit(lim)
620 : {
621 961 : }
622 : };
623 :
624 : // Exception Classes
625 : class SGWriter_Exception : public SG_Exception
626 : {
627 : public:
628 0 : const char *get_err_msg() override
629 : {
630 0 : return "A general error occurred when writing a netCDF dataset";
631 : }
632 : };
633 :
634 : class SGWriter_Exception_NCWriteFailure : public SGWriter_Exception
635 : {
636 : std::string msg;
637 :
638 : public:
639 0 : const char *get_err_msg() override
640 : {
641 0 : return this->msg.c_str();
642 : }
643 :
644 : SGWriter_Exception_NCWriteFailure(const char *layer_name,
645 : const char *failure_name,
646 : const char *failure_type);
647 : };
648 :
649 : class SGWriter_Exception_NCInqFailure : public SGWriter_Exception
650 : {
651 : std::string msg;
652 :
653 : public:
654 0 : const char *get_err_msg() override
655 : {
656 0 : return this->msg.c_str();
657 : }
658 :
659 : SGWriter_Exception_NCInqFailure(const char *layer_name,
660 : const char *failure_name,
661 : const char *failure_type);
662 : };
663 :
664 : class SGWriter_Exception_NCDefFailure : public SGWriter_Exception
665 : {
666 : std::string msg;
667 :
668 : public:
669 0 : const char *get_err_msg() override
670 : {
671 0 : return this->msg.c_str();
672 : }
673 :
674 : SGWriter_Exception_NCDefFailure(const char *layer_name,
675 : const char *failure_name,
676 : const char *failure_type);
677 : };
678 :
679 : class SGWriter_Exception_NullGeometry : public SGWriter_Exception
680 : {
681 : std::string msg;
682 :
683 : public:
684 0 : const char *get_err_msg() override
685 : {
686 0 : return this->msg.c_str();
687 : }
688 :
689 0 : SGWriter_Exception_NullGeometry()
690 0 : : msg("A null geometry was detected when writing a netCDF file. "
691 0 : "Empty geometries are not allowed.")
692 : {
693 0 : }
694 : };
695 :
696 : class SGWriter_Exception_NCDelFailure : public SGWriter_Exception
697 : {
698 : std::string msg;
699 :
700 : public:
701 0 : const char *get_err_msg() override
702 : {
703 0 : return this->msg.c_str();
704 : }
705 :
706 0 : SGWriter_Exception_NCDelFailure(const char *layer, const char *what)
707 0 : : msg("[" + std::string(layer) +
708 0 : "] Failed to delete: " + std::string(what))
709 : {
710 0 : }
711 : };
712 :
713 : // Helper Functions that for writing
714 :
715 : /* std::vector<..> writeGeometryContainer(...)
716 : * Writes a geometry container of a given geometry type given the following
717 : * arguments: int ncID - ncid as used in netcdf.h, group or file id std::string
718 : * name - what to name this container geom_t geometry_type - the geometry type
719 : * of the container std::vector<..> node_coordinate_names - variable names
720 : * corresponding to each axis Only writes attributes that are for sure required.
721 : * i.e. does NOT required interior ring for anything or part node count for
722 : * Polygons
723 : *
724 : * Returns: geometry container variable ID
725 : */
726 : int write_Geometry_Container(
727 : int ncID, const std::string &name, geom_t geometry_type,
728 : const std::vector<std::string> &node_coordinate_names);
729 :
730 : template <class W_type>
731 112131 : inline void NCWMapAllocIfNeeded(int varid, NCWMap &mapAdd, size_t numEntries,
732 : std::vector<int> &v)
733 : {
734 112131 : if (mapAdd.count(varid) < 1)
735 : {
736 201 : mapAdd.insert(NCWEntry(varid, CPLMalloc(sizeof(W_type) * numEntries)));
737 201 : v.push_back(varid);
738 : }
739 112131 : }
740 :
741 : template <class W_type>
742 112131 : inline void NCWMapWriteAndCommit(int varid, NCWMap &mapAdd, size_t currentEntry,
743 : size_t numEntries, W_type data,
744 : netCDFVID &vcdf)
745 : {
746 112131 : W_type *ptr = static_cast<W_type *>(mapAdd.at(varid));
747 112131 : ptr[currentEntry] = data;
748 : static const size_t BEGIN = 0;
749 :
750 : // If all items are ready, write the array, and free it, delete the pointer
751 112131 : if (currentEntry == (numEntries - 1))
752 : {
753 : try
754 : {
755 : // Write the whole array at once
756 201 : vcdf.nc_put_vvara_generic<W_type>(varid, &BEGIN, &numEntries, ptr);
757 : }
758 0 : catch (SG_Exception_VWrite_Failure &e)
759 : {
760 0 : CPLError(CE_Warning, CPLE_FileIO, "%s", e.get_err_msg());
761 : }
762 :
763 201 : CPLFree(mapAdd.at(varid));
764 201 : mapAdd.erase(varid);
765 : }
766 112131 : }
767 : } // namespace nccfdriver
768 :
769 : #endif
|