1 /******************************************************************************
2 *  LibGHT, software to manage point clouds.
3 *  LibGHT is free and open source software provided by the Government of Canada
4 *  Copyright (c) 2012 Natural Resources Canada
5 *
6 *  Nouri Sabo <nsabo@NRCan.gc.ca>, Natural Resources Canada
7 *  Paul Ramsey <pramsey@opengeo.org>, OpenGeo
8 *
9 ******************************************************************************/
10 
11 #include "ght_internal.h"
12 #include <strings.h>
13 
ght_type_from_str(const char * str,GhtType * type)14 GhtErr ght_type_from_str(const char *str, GhtType *type)
15 {
16     int i;
17     for ( i = 0; i < GHT_NUM_TYPES; i++ )
18     {
19         if ( strcasecmp(str, GhtTypeStrings[i]) == 0 )
20         {
21             *type = i;
22             return GHT_OK;
23         }
24     }
25     return GHT_ERROR;
26 }
27 
28 
29 /******************************************************************************/
30 /* GhtAttribute */
31 
ght_attribute_new_from_double(const GhtDimension * dim,double val,GhtAttribute ** attr)32 GhtErr ght_attribute_new_from_double(const GhtDimension *dim, double val, GhtAttribute **attr)
33 {
34     GhtAttribute *a;
35     a = ght_malloc(sizeof(GhtAttribute));
36     if ( ! a ) return GHT_ERROR;
37     memset(a, 0, sizeof(GhtAttribute));
38     a->dim = dim;
39     a->next = NULL;
40     GHT_TRY(ght_attribute_set_value(a, val));
41     *attr = a;
42     return GHT_OK;
43 }
44 
ght_attribute_new_from_bytes(const GhtDimension * dim,uint8_t * bytes,GhtAttribute ** attr)45 GhtErr ght_attribute_new_from_bytes(const GhtDimension *dim, uint8_t *bytes, GhtAttribute **attr)
46 {
47     GhtAttribute *a;
48     a = ght_malloc(sizeof(GhtAttribute));
49     if ( ! a ) return GHT_ERROR;
50     memset(a, 0, sizeof(GhtAttribute));
51     a->dim = dim;
52     a->next = NULL;
53     memcpy(a->val, bytes, GhtTypeSizes[dim->type]);
54     *attr = a;
55     return GHT_OK;
56 }
57 
58 GhtErr
ght_attribute_free(GhtAttribute * attr)59 ght_attribute_free(GhtAttribute *attr)
60 {
61     /* No-op on null */
62     if ( ! attr ) return GHT_OK;
63 
64     if ( attr->next )
65     {
66         ght_attribute_free(attr->next);
67     }
68     ght_free(attr);
69     return GHT_OK;
70 }
71 
72 GhtErr
ght_attribute_get_next(const GhtAttribute * attr,GhtAttribute ** nextattr)73 ght_attribute_get_next(const GhtAttribute *attr, GhtAttribute **nextattr)
74 {
75     if ( attr->next )
76     {
77         *nextattr = attr->next;
78         return GHT_OK;
79     }
80     *nextattr = NULL;
81     return GHT_ERROR;
82 }
83 
84 GhtErr
ght_attribute_get_dimension(const GhtAttribute * attr,const GhtDimension ** dim)85 ght_attribute_get_dimension(const GhtAttribute *attr, const GhtDimension **dim)
86 {
87     if ( attr->dim )
88     {
89         *dim = attr->dim;
90         return GHT_OK;
91     }
92     *dim = NULL;
93     return GHT_ERROR;
94 }
95 
96 GhtErr
ght_attribute_get_by_dimension(const GhtAttribute * attr,const GhtDimension * dim,GhtAttribute * found)97 ght_attribute_get_by_dimension(const GhtAttribute *attr, const GhtDimension *dim, GhtAttribute *found)
98 {
99     if ( ! attr ) return GHT_ERROR;
100     while ( attr->dim != dim )
101     {
102         if ( ! attr->next ) return GHT_ERROR;
103         attr = attr->next;
104     }
105     memcpy(found, attr, sizeof(GhtAttribute));
106     return GHT_OK;
107 }
108 
109 /** Convert a real value double into a value suitable for storage */
110 static GhtErr
ght_attribute_double_to_storage(const GhtDimension * dim,double * val)111 ght_attribute_double_to_storage(const GhtDimension *dim, double *val)
112 {
113     if ( dim->offset )
114     {
115         *val -= dim->offset;
116     }
117     if ( dim->scale != 1 )
118     {
119         *val /= dim->scale;
120     }
121     return GHT_OK;
122 }
123 
124 /** Convert a real value double into a value suitable for storage */
125 static GhtErr
ght_attribute_storage_to_double(const GhtDimension * dim,double * val)126 ght_attribute_storage_to_double(const GhtDimension *dim, double *val)
127 {
128     if ( dim->scale != 1 )
129     {
130         *val *= dim->scale;
131     }
132     if ( dim->offset )
133     {
134         *val += dim->offset;
135     }
136     return GHT_OK;
137 }
138 
ght_attribute_get_value(const GhtAttribute * attr,double * val)139 GhtErr ght_attribute_get_value(const GhtAttribute *attr, double *val)
140 {
141     const GhtType type = attr->dim->type;
142     size_t size = GhtTypeSizes[type];
143     switch(type)
144     {
145         case GHT_UNKNOWN:
146         {
147             ght_error("%s: unknown attribute type", __func__);
148             return GHT_ERROR;
149         }
150         case GHT_INT8:
151         {
152             int8_t v;
153             memcpy(&v, attr->val, size);
154             *val = v;
155             break;
156         }
157         case GHT_UINT8:
158         {
159             uint8_t v;
160             memcpy(&v, attr->val, size);
161             *val = v;
162             break;
163         }
164         case GHT_INT16:
165         {
166             int16_t v;
167             memcpy(&v, attr->val, size);
168             *val = v;
169             break;
170         }
171         case GHT_UINT16:
172         {
173             uint16_t v;
174             memcpy(&v, attr->val, size);
175             *val = v;
176             break;
177         }
178         case GHT_INT32:
179         {
180             int32_t v;
181             memcpy(&v, attr->val, size);
182             *val = v;
183             break;
184         }
185         case GHT_UINT32:
186         {
187             uint32_t v;
188             memcpy(&v, attr->val, size);
189             *val = v;
190             break;
191         }
192         case GHT_INT64:
193         {
194             int64_t v;
195             memcpy(&v, attr->val, size);
196             *val = v;
197             break;
198         }
199         case GHT_UINT64:
200         {
201             uint64_t v;
202             memcpy(&v, attr->val, size);
203             *val = v;
204             break;
205         }
206         case GHT_DOUBLE:
207         {
208             double v;
209             memcpy(&v, attr->val, size);
210             *val = v;
211             break;
212         }
213         case GHT_FLOAT:
214         {
215             float v;
216             memcpy(&v, attr->val, size);
217             *val = v;
218             break;
219         }
220         default:
221         {
222             ght_error("%s: unknown attribute type %d", __func__, type);
223             return GHT_ERROR;
224         }
225     }
226     GHT_TRY(ght_attribute_storage_to_double(attr->dim, val));
227     return GHT_OK;
228 }
229 
230 
ght_attribute_set_value(GhtAttribute * attr,double val)231 GhtErr ght_attribute_set_value(GhtAttribute *attr, double val)
232 {
233     const GhtType type = attr->dim->type;
234     size_t size = GhtTypeSizes[type];
235     double dv = val;
236 
237     GHT_TRY(ght_attribute_double_to_storage(attr->dim, &dv));
238 
239     switch(type)
240     {
241         case GHT_UNKNOWN:
242         {
243             ght_error("%s: unknown attribute type %d", __func__, type);
244             return GHT_ERROR;
245         }
246         case GHT_INT8:
247         {
248             int8_t v = dv;
249             memcpy(attr->val, &v, size);
250             return GHT_OK;
251         }
252         case GHT_UINT8:
253         {
254             uint8_t v = dv;
255             memcpy(attr->val, &v, size);
256             return GHT_OK;
257         }
258         case GHT_INT16:
259         {
260             int16_t v = dv;
261             memcpy(attr->val, &v, size);
262             return GHT_OK;
263         }
264         case GHT_UINT16:
265         {
266             uint16_t v = dv;
267             memcpy(attr->val, &v, size);
268             return GHT_OK;
269         }
270         case GHT_INT32:
271         {
272             int32_t v = dv;
273             memcpy(attr->val, &v, size);
274             return GHT_OK;
275         }
276         case GHT_UINT32:
277         {
278             uint32_t v = dv;
279             memcpy(attr->val, &v, size);
280             return GHT_OK;
281         }
282         case GHT_INT64:
283         {
284             int64_t v = dv;
285             memcpy(attr->val, &v, size);
286             return GHT_OK;
287         }
288         case GHT_UINT64:
289         {
290             uint64_t v = dv;
291             memcpy(attr->val, &v, size);
292             return GHT_OK;
293         }
294         case GHT_DOUBLE:
295         {
296             double v = dv;
297             memcpy(attr->val, &v, size);
298             return GHT_OK;
299         }
300         case GHT_FLOAT:
301         {
302             float v = dv;
303             memcpy(attr->val, &v, size);
304             return GHT_OK;
305         }
306         default:
307         {
308             ght_error("%s: unknown attribute type %d", __func__, type);
309             return GHT_ERROR;
310         }
311     }
312     return GHT_OK;
313 }
314 
ght_attribute_to_string(const GhtAttribute * attr,stringbuffer_t * sb)315 GhtErr ght_attribute_to_string(const GhtAttribute *attr, stringbuffer_t *sb)
316 {
317     double d;
318     GHT_TRY(ght_attribute_get_value(attr, &d));
319     ght_stringbuffer_aprintf(sb, "%s=%g", attr->dim->name, d);
320     return GHT_OK;
321 }
322 
ght_attribute_get_size(const GhtAttribute * attr,size_t * sz)323 GhtErr ght_attribute_get_size(const GhtAttribute *attr, size_t *sz)
324 {
325     *sz = GhtTypeSizes[attr->dim->type];
326     return GHT_OK;
327 }
328 
ght_attribute_write(const GhtAttribute * attr,GhtWriter * writer)329 GhtErr ght_attribute_write(const GhtAttribute *attr, GhtWriter *writer)
330 {
331     uint8_t position;
332     size_t attrsize;
333     uint8_t buffer[128];
334     uint8_t *ptr = buffer;
335     GHT_TRY(ght_dimension_get_position(attr->dim, &position));
336     GHT_TRY(ght_attribute_get_size(attr, &attrsize));
337 
338     /* Write in dimension position number */
339     memcpy(ptr, &position, 1);
340     ptr++;
341 
342     /* Write in the attribute value */
343     memcpy(ptr, attr->val, attrsize);
344 
345     /* Copy the buffer into the writer */
346     return ght_write(writer, buffer, attrsize + 1);
347 }
348 
ght_attribute_read(GhtReader * reader,GhtAttribute ** attr)349 GhtErr ght_attribute_read(GhtReader *reader, GhtAttribute **attr)
350 {
351     uint8_t dimnum;
352     GhtDimension *dim;
353     GhtAttribute *a;
354     const GhtSchema *schema = reader->schema;
355 
356     ght_read(reader, &dimnum, 1);
357     if ( dimnum >= schema->num_dims )
358     {
359         ght_error("%s: attribute dimension %d does not exist in schema %p", __func__, dimnum, schema);
360         return GHT_ERROR;
361     }
362 
363     dim = schema->dims[dimnum];
364     a = ght_malloc(sizeof(GhtAttribute));
365     if ( ! a ) return GHT_ERROR;
366     memset(a, 0, sizeof(GhtAttribute));
367     a->dim = dim;
368     a->next = NULL;
369     ght_read(reader, a->val, GhtTypeSizes[dim->type]);
370     *attr = a;
371     return GHT_OK;
372 }
373 
374 
ght_attribute_clone(const GhtAttribute * attr,GhtAttribute ** attr_out)375 GhtErr ght_attribute_clone(const GhtAttribute *attr, GhtAttribute **attr_out)
376 {
377     /* Clone attribute and all siblings */
378     GhtAttribute *a;
379 
380     if ( ! attr )
381     {
382         *attr_out = NULL;
383         return GHT_OK;
384     }
385 
386     /* Copy the first one in */
387     a = ght_malloc(sizeof(GhtAttribute));
388     memcpy(a, attr, sizeof(GhtAttribute));
389     a->next = NULL;
390     *attr_out = a;
391 
392     return ght_attribute_clone(attr->next, &((*attr_out)->next));
393 
394 }
395 
396 static GhtErr
ght_attribute_append(GhtAttribute * attr1,GhtAttribute * attr2)397 ght_attribute_append(GhtAttribute *attr1, GhtAttribute *attr2)
398 {
399     while ( attr1->next )
400     {
401         attr1 = attr1->next;
402     }
403 
404     attr1->next = attr2;
405     return GHT_OK;
406 }
407 
408 GhtErr
ght_attribute_union(GhtAttribute * attr1,GhtAttribute * attr2,GhtAttribute ** attr)409 ght_attribute_union(GhtAttribute *attr1, GhtAttribute *attr2, GhtAttribute **attr)
410 {
411     GhtAttribute *a1 = attr1;
412     GhtAttribute *a2 = attr2;
413 
414     /* Null input, null output */
415     if ( ! a1 && ! a2 )
416     {
417         *attr = NULL;
418         return GHT_OK;
419     }
420 
421     if ( ! a1 )
422     {
423         ght_attribute_clone(a2, attr);
424         return GHT_OK;
425     }
426 
427     /* Contents of first list will be starting point */
428     ght_attribute_clone(a1, attr);
429 
430     /* Nothing in second list? Done. */
431     if ( ! a2 ) return GHT_OK;
432 
433     /* For each attribute in the second list... */
434     while ( a2 )
435     {
436         int unique = 1;
437         a1 = attr1;
438         /* Is this attribute in the first list? */
439         while ( a1 )
440         {
441             /* It is. Break. */
442             if ( a2->dim == a1->dim )
443             {
444                 unique = 0;
445                 break;
446             }
447             a1 = a1->next;
448         }
449         /* Unique attribute, add a copy to our output list */
450         if ( unique )
451         {
452             GhtAttribute *a = ght_malloc(sizeof(GhtAttribute));
453             memcpy(a, a2, sizeof(GhtAttribute));
454             a->next = NULL;
455             GHT_TRY(ght_attribute_append(*attr, a));
456         }
457         a2 = a2->next;
458     }
459     return GHT_OK;
460 }