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 }