GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
gsds.c
Go to the documentation of this file.
1/*!
2 \file lib/ogsf/gsds.c
3
4 \brief OGSF library - dataset loading and management (lower level functions)
5
6 GRASS OpenGL gsurf OGSF Library
7
8 The idea here is to treat datasets as separate objects, which SHOULD:
9 - allow easier reuse of data for different attributes.
10 - allow a mechanism for changing data and have changes reflected
11 in each attribute using that data.
12 - allow a mechanism to automatically update data when the data source
13 is changed.
14 - allow easier weaning from GRASS.
15 - allow easier use of shared memory between processes.
16
17 These structures are defined in gstypes.h:
18
19 <code>
20 typedef struct{
21 float *fb;
22 int *ib;
23 short *sb;
24 char *cb;
25 struct BM *bm;
26 } typbuff;
27 </code>
28
29 How about adding a transform func here, so GET_MAPATT would do an
30 on-the-fly transformation? Or even a transform func LIST!
31
32 <code>
33 typedef struct{
34 int data_id;
35 int dims[MAXDIMS];
36 int ndims;
37 int numbytes;
38 char unique_name[80];
39 typbuff databuff;
40 int changed;
41 int need_reload;
42 } dataset;
43 </code>
44
45 (C) 1999-2008 by the GRASS Development Team
46
47 This program is free software under the
48 GNU General Public License (>=v2).
49 Read the file COPYING that comes with GRASS
50 for details.
51
52 \author Bill Brown UI GMS Lab
53 \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
54 */
55
56#include <stdlib.h>
57#include <string.h>
58
59#include <grass/gis.h>
60#include <grass/glocale.h>
61#include <grass/ogsf.h>
62
63#define LUCKY 33
64#define BLOC 20
65#define MAX_DS 100
66
67static int init_gsds(void);
68static int check_numsets(void);
69static dataset *get_dataset(int);
70static int get_type(dataset *);
71
72static dataset *Data[MAX_DS];
73static dataset Ds[MAX_DS]; /* trying to avoid allocation */
74
75static int Numsets = 0;
76
77static int Cur_id = LUCKY;
78static int Cur_max;
79static size_t Tot_mem = 0;
80
81/*!
82 \brief Initialize gsds
83 */
84static int init_gsds(void)
85{
86 int i;
87
88 for (i = 0; i < MAX_DS; i++) {
89 /* avoiding dynamic allocation */
90 Data[i] = &(Ds[i]);
91 }
92
93 Cur_max = MAX_DS;
94
95 return (1);
96}
97
98/*!
99 \brief Check numsets
100
101 \return 0 numset < cur_max
102 */
103static int check_numsets(void)
104{
105 if (Numsets < Cur_max) {
106 return (0);
107 }
108
109 G_fatal_error(_("Maximum number of datasets exceeded"));
110
111 /* This return statement keeps compilers happy, it is never executed */
112 return (0);
113}
114
115/*!
116 \brief Get dataset
117
118 \param id data id
119
120 \return pointer to dataset struct
121 \return NULL dataset not found
122 */
123static dataset *get_dataset(int id)
124{
125 int i;
126
127 for (i = 0; i < Numsets; i++) {
128 if (Data[i]->data_id == id) {
129 return (Data[i]);
130 }
131 }
132
133 return (NULL);
134}
135
136/*!
137 \brief Get type
138
139 \param ds pointer to dataset struct
140
141 \return type code
142 \return -1 unsupported type
143 */
144static int get_type(dataset *ds)
145{
146 if (ds) {
147 if (ds->databuff.bm) {
148 return (ATTY_MASK);
149 }
150
151 if (ds->databuff.cb) {
152 return (ATTY_CHAR);
153 }
154
155 if (ds->databuff.sb) {
156 return (ATTY_SHORT);
157 }
158
159 if (ds->databuff.ib) {
160 return (ATTY_INT);
161 }
162
163 if (ds->databuff.fb) {
164 return (ATTY_FLOAT);
165 }
166 }
167
168 return (-1);
169}
170
171/*!
172 \brief Get handle to gsds.
173
174 Successive calls will continue search until "begin" is set
175 (problem here is, unique_name no longer uniquely identifies
176 dataset, since changes may be made; but unique_name should still
177 be useful for reloading dataset)
178 changes & types are set to actual for dataset if found.
179
180 \param name
181 \param changes,types acceptable changes & types, flags may be or'd
182 not changed is assumed to always be acceptable
183 \param begin flag to indicate search from beginning
184
185 \return data id
186 \return -1 not found
187 */
188int gsds_findh(const char *name, IFLAG *changes, IFLAG *types, int begin)
189{
190 static int i;
191 int start;
192
193 start = begin ? 0 : i + 1;
194
195 for (i = start; i < Numsets; i++) {
196 if (!strcmp(Data[i]->unique_name, name)) {
197 if ((Data[i]->changed & *changes) || !(Data[i]->changed)) {
198 if (get_type(Data[i]) & *types) {
199 *changes = Data[i]->changed;
200 *types = get_type(Data[i]);
201
202 return (Data[i]->data_id);
203 }
204 }
205 }
206 }
207
208 return (-1);
209}
210
211/*!
212 \brief Get handle to gsds
213
214 \param name raster map name
215
216 \return -1 on failure
217 \return data id
218 */
219int gsds_newh(const char *name)
220{
221 dataset *new;
222 static int first = 1;
223 int i;
224
225 if (first) {
226 if (0 > init_gsds()) {
227 return (-1);
228 }
229
230 first = 0;
231 }
232 else if (0 > check_numsets()) {
233 return (-1);
234 }
235
236 if (!name) {
237 return (-1);
238 }
239
240 new = Data[Numsets];
241
242 if (new) {
243 Numsets++;
244 new->data_id = Cur_id++;
245
246 for (i = 0; i < MAXDIMS; i++) {
247 new->dims[i] = 0;
248 }
249
250 new->unique_name = G_store(name);
251 new->databuff.fb = NULL;
252 new->databuff.ib = NULL;
253 new->databuff.sb = NULL;
254 new->databuff.cb = NULL;
255 new->databuff.bm = NULL;
256 new->databuff.nm = NULL;
257 new->databuff.k = 0.0;
258 new->changed = 0;
259 new->ndims = 0;
260 new->need_reload = 1;
261
262 return (new->data_id);
263 }
264
265 return (-1);
266}
267
268/*!
269 \brief Get data buffer
270
271 Doesn't prevent writing a buff thats's been gotten with change_flag
272 == 0 (could return a copy, but willing to trust calling func for
273 now)
274
275 \param id dataset id
276 \param change_flag set changed flag
277
278 \return pointer to typbuff struct
279 \return NULL on failure
280 */
281typbuff *gsds_get_typbuff(int id, IFLAG change_flag)
282{
283 dataset *ds;
284
285 if ((ds = get_dataset(id))) {
286 ds->changed = ds->changed | change_flag;
287 ds->need_reload = 0;
288
289 return (&(ds->databuff));
290 }
291
292 return (NULL);
293}
294
295/*!
296 \brief Get name
297
298 \param id
299
300 \return name
301 \return NULL on failure
302 */
303char *gsds_get_name(int id)
304{
305 int i;
306 dataset *fds;
307 static char retstr[GPATH_MAX];
308
309 for (i = 0; i < Numsets; i++) {
310 if (Data[i]->data_id == id) {
311 fds = Data[i];
312 strcpy(retstr, fds->unique_name);
313
314 return (retstr);
315 }
316 }
317
318 return (NULL);
319}
320
321/*!
322 \brief Free allocated dataset
323
324 \param id
325
326 \return 0 not found
327 \return 1 found
328 */
330{
331 int i, j, found = 0;
332 dataset *fds;
333
334 G_debug(3, "gsds_free_datah");
335
336 for (i = 0; i < Numsets; i++) {
337 if (Data[i]->data_id == id) {
338 found = 1;
339 fds = Data[i];
340 free_data_buffs(fds, ATTY_ANY);
341 G_free((void *)fds->unique_name);
342 fds->unique_name = NULL;
343 fds->data_id = 0;
344
345 for (j = i; j < (Numsets - 1); j++) {
346 Data[j] = Data[j + 1];
347 }
348
349 Data[j] = fds;
350 }
351 }
352
353 if (found) {
354 --Numsets;
355 }
356
357 return (found);
358}
359
360/*!
361 \brief Free allocated buffer
362
363 \param id dataset id
364 \param typ data type
365
366 \return 0 not found
367 \return 1 found
368 */
369int gsds_free_data_buff(int id, int typ)
370{
371 int i, found = 0;
372 dataset *fds;
373
374 for (i = 0; i < Numsets; i++) {
375 if (Data[i]->data_id == id) {
376 found = 1;
377 fds = Data[i];
378 free_data_buffs(fds, typ);
379 }
380 }
381
382 return (found);
383}
384
385/*!
386 \brief Free data buffer
387
388 \param ds pointer to dataset struct
389 \param typ data type
390
391 \return freed size
392 */
393size_t free_data_buffs(dataset *ds, int typ)
394{
395 int i;
396 size_t siz, nsiz = 1, freed = 0;
397
398 for (i = 0; i < ds->ndims; i++) {
399 nsiz *= ds->dims[i];
400 }
401
402 if (typ & ATTY_NULL) {
403 if (ds->databuff.nm) {
404 siz = BM_get_map_size(ds->databuff.nm);
405 BM_destroy(ds->databuff.nm);
406 ds->databuff.nm = NULL;
407 freed += siz;
408 }
409 }
410
411 if (typ & ATTY_MASK) {
412 if (ds->databuff.bm) {
413 siz = BM_get_map_size(ds->databuff.bm);
414 BM_destroy(ds->databuff.bm);
415 ds->databuff.bm = NULL;
416 freed += siz;
417 }
418 }
419
420 if (typ & ATTY_CHAR) {
421 if (ds->databuff.cb) {
422 siz = nsiz * sizeof(char);
423 free(ds->databuff.cb);
424 ds->databuff.cb = NULL;
425 freed += siz;
426 }
427 }
428
429 if (typ & ATTY_SHORT) {
430 if (ds->databuff.sb) {
431 siz = nsiz * sizeof(short);
432 free(ds->databuff.sb);
433 ds->databuff.sb = NULL;
434 freed += siz;
435 }
436 }
437
438 if (typ & ATTY_INT) {
439 if (ds->databuff.ib) {
440 siz = nsiz * sizeof(int);
441 free(ds->databuff.ib);
442 ds->databuff.ib = NULL;
443 freed += siz;
444 }
445 }
446
447 if (typ & ATTY_FLOAT) {
448 if (ds->databuff.fb) {
449 siz = nsiz * sizeof(float);
450 free(ds->databuff.fb);
451 ds->databuff.fb = NULL;
452 freed += siz;
453 }
454 }
455
456 Tot_mem -= freed;
457 ds->numbytes -= freed;
458
459 if (freed) {
460 G_debug(5, "free_data_buffs(): freed data from id no. %d", ds->data_id);
461 G_debug(5, "free_data_buffs(): %.3f Kbytes freed, current total = %.3f",
462 freed / 1000., Tot_mem / 1000.);
463 }
464
465 return (freed);
466}
467
468/*!
469 \brief Allocates correct buffer according to type, keeps track of total mem
470
471 \todo add ATTY_CONST
472
473 \param id dataset id
474 \param dims array of dimensions
475 \param ndims number of dimensions
476 \param type data type
477
478 \return amount of allocated memory
479 */
480size_t gsds_alloc_typbuff(int id, int *dims, int ndims, int type)
481{
482 dataset *ds;
483 int i;
484 size_t siz = 1;
485
486 if ((ds = get_dataset(id))) {
487 /*
488 free_data_buffs(ds);
489 careful here - allowing > 1 type to coexist (for float -> color
490 conv.) now also use this to allocate a null mask (then if not used,
491 use gsds_free_data_buff(id, ATTY_NULL))
492 */
493
494 for (i = 0; i < ndims; i++) {
495 ds->dims[i] = dims[i];
496 siz *= dims[i];
497 }
498
499 switch (type) {
500 case ATTY_NULL:
501 if (ndims != 2) {
502 /* higher dimension bitmaps not supported */
503 return 0;
504 }
505
506 if (NULL == (ds->databuff.nm = BM_create(dims[1], dims[0]))) {
507 return 0;
508 }
509
510 siz = BM_get_map_size(ds->databuff.nm);
511
512 break;
513
514 case ATTY_MASK:
515 if (ndims != 2) {
516 /* higher dimension bitmaps not supported */
517 return (-1);
518 }
519
520 if (NULL == (ds->databuff.bm = BM_create(dims[1], dims[0]))) {
521 return 0;
522 }
523
524 siz = BM_get_map_size(ds->databuff.bm);
525
526 break;
527
528 case ATTY_CHAR:
529 siz *= sizeof(char);
530
531 if (siz) {
532 if (NULL ==
533 (ds->databuff.cb = (unsigned char *)G_malloc(siz))) {
534 return 0;
535 }
536 }
537 else {
538 return 0;
539 }
540
541 break;
542
543 case ATTY_SHORT:
544 siz *= sizeof(short);
545
546 if (siz) {
547 if (NULL == (ds->databuff.sb = (short *)G_malloc(siz))) {
548 return 0;
549 }
550 }
551 else {
552 return 0;
553 }
554
555 break;
556
557 case ATTY_INT:
558 siz *= sizeof(int);
559
560 if (siz) {
561 if (NULL == (ds->databuff.ib = (int *)G_malloc(siz))) {
562 return 0;
563 }
564 }
565 else {
566 return 0;
567 }
568
569 break;
570
571 case ATTY_FLOAT:
572 siz *= sizeof(float);
573
574 if (siz) {
575 if (NULL == (ds->databuff.fb = (float *)G_malloc(siz))) {
576 return 0;
577 }
578 }
579 else {
580 return 0;
581 }
582
583 break;
584
585 default:
586 return 0;
587 }
588
589 ds->changed = 0; /* starting with clean slate */
590 ds->need_reload = 1;
591 ds->numbytes += siz;
592 ds->ndims = ndims;
593 Tot_mem += siz;
594
595 G_debug(5,
596 "gsds_alloc_typbuff(): %f Kbytes allocated, current total = %f",
597 siz / 1000., Tot_mem / 1000.);
598
599 return (siz);
600 }
601
602 return 0;
603}
604
605/*!
606 \brief ADD
607
608 \param id
609
610 \return -1 on error
611 \return
612 */
614{
615 dataset *ds;
616
617 if ((ds = get_dataset(id))) {
618 return ((int)ds->changed);
619 }
620
621 return (-1);
622}
623
624/*!
625 \brief ADD
626
627 \param id
628 \param reason
629
630 \return -1 on error
631 \return
632 */
633int gsds_set_changed(int id, IFLAG reason)
634{
635 dataset *ds;
636
637 if ((ds = get_dataset(id))) {
638 ds->changed = reason;
639 }
640
641 return (-1);
642}
643
644/*!
645 \brief ADD
646
647 \param id
648
649 \return
650 */
651int gsds_get_type(int id)
652{
653 dataset *ds;
654
655 ds = get_dataset(id);
656
657 return (get_type(ds));
658}
void G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
struct BM * BM_create(int x, int y)
Create bitmap of dimension x/y and return structure token.
Definition bitmap.c:58
size_t BM_get_map_size(struct BM *map)
Returns size in bytes that bitmap is taking up.
Definition bitmap.c:241
int BM_destroy(struct BM *map)
Destroy bitmap and free all associated memory.
Definition bitmap.c:89
#define NULL
Definition ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition gis/error.c:159
#define MAX_DS
Definition gsds.c:65
char * gsds_get_name(int id)
Get name.
Definition gsds.c:303
int gsds_get_type(int id)
ADD.
Definition gsds.c:651
int gsds_newh(const char *name)
Get handle to gsds.
Definition gsds.c:219
int gsds_findh(const char *name, IFLAG *changes, IFLAG *types, int begin)
Get handle to gsds.
Definition gsds.c:188
#define LUCKY
Definition gsds.c:63
typbuff * gsds_get_typbuff(int id, IFLAG change_flag)
Get data buffer.
Definition gsds.c:281
size_t free_data_buffs(dataset *ds, int typ)
Free data buffer.
Definition gsds.c:393
int gsds_set_changed(int id, IFLAG reason)
ADD.
Definition gsds.c:633
int gsds_free_datah(int id)
Free allocated dataset.
Definition gsds.c:329
size_t gsds_alloc_typbuff(int id, int *dims, int ndims, int type)
Allocates correct buffer according to type, keeps track of total mem.
Definition gsds.c:480
int gsds_free_data_buff(int id, int typ)
Free allocated buffer.
Definition gsds.c:369
int gsds_get_changed(int id)
ADD.
Definition gsds.c:613
const char * name
Definition named_colr.c:6
char * G_store(const char *s)
Copy string to allocated memory.
Definition strings.c:87