lasreadpoint.cpp
Go to the documentation of this file.
1 /*
2 ===============================================================================
3 
4  FILE: lasreadpoint.cpp
5 
6  CONTENTS:
7 
8  see corresponding header file
9 
10  PROGRAMMERS:
11 
12  martin.isenburg@gmail.com
13 
14  COPYRIGHT:
15 
16  (c) 2011, Martin Isenburg, LASSO - tools to catch reality
17 
18  This is free software; you can redistribute and/or modify it under the
19  terms of the GNU Lesser General Licence as published by the Free Software
20  Foundation. See the COPYING file for more information.
21 
22  This software is distributed WITHOUT ANY WARRANTY and without even the
23  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 
25  CHANGE HISTORY:
26 
27  see corresponding header file
28 
29 ===============================================================================
30 */
31 
32 #include "lasreadpoint.hpp"
33 
34 #include "arithmeticdecoder.hpp"
35 #include "lasreaditemraw.hpp"
38 
39 #include <stdlib.h>
40 #include <string.h>
41 
43 {
44  point_size = 0;
45  instream = 0;
46  num_readers = 0;
47  readers = 0;
48  readers_raw = 0;
50  dec = 0;
51  // used for chunking
53  chunk_count = 0;
54  current_chunk = 0;
55  number_chunks = 0;
56  tabled_chunks = 0;
57  chunk_totals = 0;
58  chunk_starts = 0;
59  // used for seeking
60  point_start = 0;
61  seek_point = 0;
62 }
63 
64 BOOL LASreadPoint::setup(U32 num_items, const LASitem* items, const LASzip* laszip)
65 {
66  U32 i;
67 
68  // is laszip exists then we must use its items
69  if (laszip)
70  {
71  if (num_items != laszip->num_items) return FALSE;
72  if (items != laszip->items) return FALSE;
73  }
74 
75  // create entropy decoder (if requested)
76  dec = 0;
77  if (laszip && laszip->compressor)
78  {
79  switch (laszip->coder)
80  {
82  dec = new ArithmeticDecoder();
83  break;
84  default:
85  // entropy decoder not supported
86  return FALSE;
87  }
88  }
89 
90  // initizalize the readers
91  readers = 0;
92  num_readers = num_items;
93 
94  // disable chunking
96 
97  // always create the raw readers
99  for (i = 0; i < num_readers; i++)
100  {
101  switch (items[i].type)
102  {
103  case LASitem::POINT10:
104  if (IS_LITTLE_ENDIAN())
106  else
108  break;
109  case LASitem::GPSTIME11:
110  if (IS_LITTLE_ENDIAN())
112  else
114  break;
115  case LASitem::RGB12:
116  if (IS_LITTLE_ENDIAN())
118  else
120  break;
122  if (IS_LITTLE_ENDIAN())
124  else
126  break;
127  case LASitem::BYTE:
128  readers_raw[i] = new LASreadItemRaw_BYTE(items[i].size);
129  break;
130  case LASitem::POINT14:
131  if (IS_LITTLE_ENDIAN())
133  else
134  return FALSE;
135  break;
136  case LASitem::RGBNIR14:
137  if (IS_LITTLE_ENDIAN())
139  else
141  break;
142  default:
143  return FALSE;
144  }
145  point_size += items[i].size;
146  }
147 
148  if (dec)
149  {
151  // seeks with compressed data need a seek point
152  if (seek_point)
153  {
154  delete [] seek_point[0];
155  delete [] seek_point;
156  }
157  seek_point = new U8*[num_items];
158  if (!seek_point) return FALSE;
159  seek_point[0] = new U8[point_size];
160  if (!seek_point[0]) return FALSE;
161  for (i = 0; i < num_readers; i++)
162  {
163  switch (items[i].type)
164  {
165  case LASitem::POINT10:
166  if (items[i].version == 1)
168  else if (items[i].version == 2)
170  else
171  return FALSE;
172  break;
173  case LASitem::GPSTIME11:
174  if (items[i].version == 1)
176  else if (items[i].version == 2)
178  else
179  return FALSE;
180  break;
181  case LASitem::RGB12:
182  if (items[i].version == 1)
184  else if (items[i].version == 2)
186  else
187  return FALSE;
188  break;
190  if (items[i].version == 1)
192  else
193  return FALSE;
194  break;
195  case LASitem::BYTE:
196  if (items[i].version == 1)
197  readers_compressed[i] = new LASreadItemCompressed_BYTE_v1(dec, items[i].size);
198  else if (items[i].version == 2)
199  readers_compressed[i] = new LASreadItemCompressed_BYTE_v2(dec, items[i].size);
200  else
201  return FALSE;
202  break;
203  default:
204  return FALSE;
205  }
206  if (i) seek_point[i] = seek_point[i-1]+items[i-1].size;
207  }
209  {
210  if (laszip->chunk_size) chunk_size = laszip->chunk_size;
212  }
213  }
214  return TRUE;
215 }
216 
218 {
219  if (!instream) return FALSE;
220  this->instream = instream;
221 
222  // on very first init with chunking enabled
223  if (number_chunks == U32_MAX)
224  {
225  if (!read_chunk_table())
226  {
227  return FALSE;
228  }
229  current_chunk = 0;
231  }
232 
233  point_start = instream->tell();
234 
235  U32 i;
236  for (i = 0; i < num_readers; i++)
237  {
238  ((LASreadItemRaw*)(readers_raw[i]))->init(instream);
239  }
240 
241  if (dec)
242  {
243  readers = 0;
244  }
245  else
246  {
248  }
249 
250  return TRUE;
251 }
252 
253 BOOL LASreadPoint::seek(const U32 current, const U32 target)
254 {
255  if (!instream->isSeekable()) return FALSE;
256  U32 delta = 0;
257  if (dec)
258  {
259  if (chunk_starts)
260  {
261  U32 target_chunk;
262  if (chunk_totals)
263  {
264  target_chunk = search_chunk_table(target, 0, number_chunks);
265  chunk_size = chunk_totals[target_chunk+1]-chunk_totals[target_chunk];
266  delta = target - chunk_totals[target_chunk];
267  }
268  else
269  {
270  target_chunk = target/chunk_size;
271  delta = target%chunk_size;
272  }
273  if (target_chunk >= tabled_chunks)
274  {
275  if (current_chunk < (tabled_chunks-1))
276  {
277  dec->done();
280  init(instream);
281  chunk_count = 0;
282  }
283  delta += (chunk_size*(target_chunk-current_chunk) - chunk_count);
284  }
285  else if (current_chunk != target_chunk || current > target)
286  {
287  dec->done();
288  current_chunk = target_chunk;
290  init(instream);
291  chunk_count = 0;
292  }
293  else
294  {
295  delta = target - current;
296  }
297  }
298  else if (current > target)
299  {
300  dec->done();
302  init(instream);
303  delta = target;
304  }
305  else if (current < target)
306  {
307  delta = target - current;
308  }
309  while (delta)
310  {
311  read(seek_point);
312  delta--;
313  }
314  }
315  else
316  {
317  if (current != target)
318  {
320  }
321  }
322  return TRUE;
323 }
324 
325 BOOL LASreadPoint::read(U8* const * point)
326 {
327  U32 i;
328 
329  try
330  {
331  if (dec)
332  {
333  if (chunk_count == chunk_size)
334  {
335  current_chunk++;
336  dec->done();
337  init(instream);
338  if (tabled_chunks == current_chunk) // no or incomplete chunk table?
339  {
341  {
342  number_chunks += 256;
343  chunk_starts = (I64*)realloc(chunk_starts, sizeof(I64)*number_chunks);
344  }
345  chunk_starts[tabled_chunks] = point_start; // needs fixing
346  tabled_chunks++;
347  }
348  else if (chunk_totals) // variable sized chunks?
349  {
351  }
352  chunk_count = 0;
353  }
354  chunk_count++;
355 
356  if (readers)
357  {
358  for (i = 0; i < num_readers; i++)
359  {
360  readers[i]->read(point[i]);
361  }
362  }
363  else
364  {
365  for (i = 0; i < num_readers; i++)
366  {
367  readers_raw[i]->read(point[i]);
368  ((LASreadItemCompressed*)(readers_compressed[i]))->init(point[i]);
369  }
371  dec->init(instream);
372  }
373  }
374  else
375  {
376  for (i = 0; i < num_readers; i++)
377  {
378  readers[i]->read(point[i]);
379  }
380  }
381  }
382  catch (...)
383  {
384  return FALSE;
385  }
386  return TRUE;
387 }
388 
390 {
392  {
393  if (dec) dec->done();
394  }
395  return TRUE;
396 }
397 
399 {
400  // read the 8 bytes that store the location of the chunk table
401  I64 chunk_table_start_position;
402  try { instream->get64bitsLE((U8*)&chunk_table_start_position); } catch(...)
403  {
404  return FALSE;
405  }
406 
407  // this is where the chunks start
408  I64 chunks_start = instream->tell();
409 
410  if ((chunk_table_start_position + 8) == chunks_start)
411  {
412  // then compressor was interrupted before getting a chance to write the chunk table
413  number_chunks = 256;
414  chunk_starts = (I64*)malloc(sizeof(I64)*number_chunks);
415  if (chunk_starts == 0)
416  {
417  return FALSE;
418  }
419  chunk_starts[0] = chunks_start;
420  tabled_chunks = 1;
421  return TRUE;
422  }
423 
424  if (!instream->isSeekable())
425  {
426  // if the stream is not seekable we cannot seek to the chunk table but won't need it anyways
427  tabled_chunks = 0;
428  return TRUE;
429  }
430 
431  if (chunk_table_start_position == -1)
432  {
433  // the compressor was writing to a non-seekable stream and wrote the chunk table start at the end
434  if (!instream->seekEnd(8))
435  {
436  return FALSE;
437  }
438  try { instream->get64bitsLE((U8*)&chunk_table_start_position); } catch(...)
439  {
440  return FALSE;
441  }
442  }
443 
444  // read the chunk table
445  try
446  {
447  instream->seek(chunk_table_start_position);
448  U32 version;
449  instream->get32bitsLE((U8*)&version);
450  if (version != 0)
451  {
452  throw;
453  }
455  if (chunk_totals) delete [] chunk_totals;
456  chunk_totals = 0;
457  if (chunk_starts) free(chunk_starts);
458  chunk_starts = 0;
459  if (chunk_size == U32_MAX)
460  {
461  chunk_totals = new U32[number_chunks+1];
462  if (chunk_totals == 0)
463  {
464  throw;
465  }
466  chunk_totals[0] = 0;
467  }
468  chunk_starts = (I64*)malloc(sizeof(I64)*(number_chunks+1));
469  if (chunk_starts == 0)
470  {
471  throw;
472  }
473  chunk_starts[0] = chunks_start;
474  tabled_chunks = 1;
475  if (number_chunks > 0)
476  {
477  U32 i;
478  dec->init(instream);
479  IntegerCompressor ic(dec, 32, 2);
480  ic.initDecompressor();
481  for (i = 1; i <= number_chunks; i++)
482  {
483  if (chunk_size == U32_MAX) chunk_totals[i] = ic.decompress((i>1 ? chunk_totals[i-1] : 0), 0);
484  chunk_starts[i] = ic.decompress((i>1 ? (U32)(chunk_starts[i-1]) : 0), 1);
485  tabled_chunks++;
486  }
487  dec->done();
488  for (i = 1; i <= number_chunks; i++)
489  {
490  if (chunk_size == U32_MAX) chunk_totals[i] += chunk_totals[i-1];
491  chunk_starts[i] += chunk_starts[i-1];
492  }
493  }
494  }
495  catch (...)
496  {
497  // something went wrong while reading the chunk table
498  if (chunk_totals) delete [] chunk_totals;
499  chunk_totals = 0;
500  // fix as many additional chunk_starts as possible
501  U32 i;
502  for (i = 1; i < tabled_chunks; i++)
503  {
504  chunk_starts[i] += chunk_starts[i-1];
505  }
506  }
507  if (!instream->seek(chunks_start))
508  {
509  return FALSE;
510  }
511  return TRUE;
512 }
513 
514 U32 LASreadPoint::search_chunk_table(const U32 index, const U32 lower, const U32 upper)
515 {
516  if (lower + 1 == upper) return lower;
517  U32 mid = (lower+upper)/2;
518  if (index >= chunk_totals[mid])
519  return search_chunk_table(index, mid, upper);
520  else
521  return search_chunk_table(index, lower, mid);
522 }
523 
525 {
526  U32 i;
527 
528  if (readers_raw)
529  {
530  for (i = 0; i < num_readers; i++)
531  {
532  delete readers_raw[i];
533  }
534  delete [] readers_raw;
535  }
536 
537  if (readers_compressed)
538  {
539  for (i = 0; i < num_readers; i++)
540  {
541  delete readers_compressed[i];
542  }
543  delete [] readers_compressed;
544  }
545 
546  if (dec)
547  {
548  delete dec;
549  }
550 
551  if (chunk_totals) delete [] chunk_totals;
552  if (chunk_starts) delete [] chunk_starts;
553 
554  if (seek_point)
555  {
556  delete [] seek_point[0];
557  delete [] seek_point;
558  }
559 }
BOOL IS_LITTLE_ENDIAN()
Definition: mydefs.hpp:144
I32 decompress(I32 iPred, U32 context=0)
int BOOL
Definition: mydefs.hpp:57
ByteStreamIn * instream
#define FALSE
Definition: mydefs.hpp:133
LASreadItem ** readers_raw
EntropyDecoder * dec
virtual I64 tell() const =0
#define LASZIP_CODER_ARITHMETIC
Definition: laszip.hpp:63
U32 * chunk_totals
unsigned int chunk_size
Definition: laszip.hpp:117
virtual BOOL isSeekable() const =0
unsigned int U32
Definition: mydefs.hpp:39
unsigned short compressor
Definition: laszip.hpp:111
BOOL setup(const U32 num_items, const LASitem *items, const LASzip *laszip=0)
virtual BOOL seek(const I64 position)=0
virtual void read(U8 *item)=0
virtual void done()=0
long long I64
Definition: mydefs.hpp:48
BOOL read_chunk_table()
unsigned short coder
Definition: laszip.hpp:112
unsigned char U8
Definition: mydefs.hpp:41
I64 * chunk_starts
LASreadItem ** readers_compressed
BOOL read(U8 *const *point)
BOOL seek(const U32 current, const U32 target)
unsigned short size
Definition: laszip.hpp:74
#define U32_MAX
Definition: mydefs.hpp:75
virtual void get64bitsLE(U8 *bytes)=0
virtual BOOL init(ByteStreamIn *instream)=0
LASitem * items
Definition: laszip.hpp:121
U32 search_chunk_table(const U32 index, const U32 lower, const U32 upper)
virtual void get32bitsLE(U8 *bytes)=0
unsigned short num_items
Definition: laszip.hpp:120
#define TRUE
Definition: mydefs.hpp:137
LASreadItem ** readers
BOOL init(ByteStreamIn *instream)
virtual BOOL seekEnd(const I64 distance=0)=0
#define LASZIP_COMPRESSOR_POINTWISE_CHUNKED
Definition: laszip.hpp:55


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Mon Feb 28 2022 22:46:07