mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-15 00:07:25 -05:00
Embed a copy of laz-perf, and use if system laz-perf is not found
Laz-perf is a relatively "underground" library, and is not packaged for many major distributions. Its also tiny and trivial to include with the other external libraries. This avoids requiring users who want point cloud support to have to compile their own laz-perf
This commit is contained in:
parent
37a0b0e9f7
commit
c7a6e6bd15
@ -391,6 +391,9 @@ IF(WITH_CORE)
|
||||
IF (WITH_EPT) # EPT provider
|
||||
FIND_PACKAGE(ZSTD) # for decompression of point clouds
|
||||
FIND_PACKAGE(LazPerf) # for decompression of point clouds
|
||||
IF (NOT LazPerf_FOUND)
|
||||
MESSAGE(STATUS "Using embedded laz-perf")
|
||||
ENDIF (NOT LazPerf_FOUND)
|
||||
SET(HAVE_EPT TRUE) # used in qgsconfig.h
|
||||
ENDIF (WITH_EPT)
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ FIND_PATH(LazPerf_INCLUDE_DIR
|
||||
"$ENV{INCLUDE}"
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
@ -25,6 +26,4 @@ MARK_AS_ADVANCED(LazPerf_INCLUDE_DIR)
|
||||
|
||||
IF (LazPerf_FOUND)
|
||||
MESSAGE(STATUS "Found laz-perf: ${LazPerf_INCLUDE_DIR}")
|
||||
ELSE (LazPerf_FOUND)
|
||||
MESSAGE(FATAL_ERROR "Could not find laz-perf")
|
||||
ENDIF (LazPerf_FOUND)
|
||||
|
||||
47
external/laz-perf/common/common.hpp
vendored
Normal file
47
external/laz-perf/common/common.hpp
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: common.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace common {
|
||||
inline std::chrono::time_point<std::chrono::high_resolution_clock> tick() {
|
||||
return std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
inline float since(const std::chrono::time_point<std::chrono::high_resolution_clock>& p) {
|
||||
using namespace std::chrono;
|
||||
|
||||
auto now = high_resolution_clock::now();
|
||||
return duration_cast<duration<float> >(now - p).count();
|
||||
}
|
||||
}
|
||||
|
||||
252
external/laz-perf/common/types.hpp
vendored
Normal file
252
external/laz-perf/common/types.hpp
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: mydefs.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
Basic data type definitions and operations to be robust across platforms.
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2005-2013, martin isenburg, rapidlasso - tools to catch reality
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
10 January 2011 -- licensing change for LGPL release and liblas integration
|
||||
13 July 2005 -- created after returning with many mosquito bites from OBX
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
#ifndef MYDEFS_HPP
|
||||
#define MYDEFS_HPP
|
||||
|
||||
typedef char CHAR;
|
||||
|
||||
typedef int I32;
|
||||
typedef short I16;
|
||||
typedef char I8;
|
||||
|
||||
typedef unsigned int U32;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned char U8;
|
||||
|
||||
#if defined(_WIN32) && ! defined (__MINGW32__) // 64 byte integer under Windows
|
||||
typedef unsigned __int64 U64;
|
||||
typedef __int64 I64;
|
||||
#else // 64 byte integer elsewhere ...
|
||||
typedef unsigned long long U64;
|
||||
typedef long long I64;
|
||||
#endif
|
||||
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
typedef int BOOL;
|
||||
#else
|
||||
typedef bool BOOL;
|
||||
#endif
|
||||
|
||||
typedef union U32I32F32 { U32 u32; I32 i32; F32 f32; } U32I32F32;
|
||||
typedef union U64I64F64 { U64 u64; I64 i64; F64 f64; } U64I64F64;
|
||||
|
||||
#define F32_MAX +2.0e+37f
|
||||
#define F32_MIN -2.0e+37f
|
||||
|
||||
#define F64_MAX +2.0e+307
|
||||
#define F64_MIN -2.0e+307
|
||||
|
||||
#define U8_MIN ((U8)0x0) // 0
|
||||
#define U8_MAX ((U8)0xFF) // 255
|
||||
#define U8_MAX_PLUS_ONE 0x0100 // 256
|
||||
|
||||
#define U16_MIN ((U16)0x0) // 0
|
||||
#define U16_MAX ((U16)0xFFFF) // 65535
|
||||
#define U16_MAX_PLUS_ONE 0x00010000 // 65536
|
||||
|
||||
#define U32_MIN ((U32)0x0) // 0
|
||||
#define U32_MAX ((U32)0xFFFFFFFF) // 4294967295
|
||||
#if defined(WIN32) // 64 byte unsigned int constant under Windows
|
||||
#define U32_MAX_PLUS_ONE 0x0000000100000000 // 4294967296
|
||||
#else // 64 byte unsigned int constant elsewhere ...
|
||||
#define U32_MAX_PLUS_ONE 0x0000000100000000ull // 4294967296
|
||||
#endif
|
||||
|
||||
#define I8_MIN ((I8)0x80) // -128
|
||||
#define I8_MAX ((I8)0x7F) // 127
|
||||
|
||||
#define I16_MIN ((I16)0x8000) // -32768
|
||||
#define I16_MAX ((I16)0x7FFF) // 32767
|
||||
|
||||
#define I32_MIN ((I32)0x80000000) // -2147483648
|
||||
#define I32_MAX ((I32)0x7FFFFFFF) // 2147483647
|
||||
|
||||
#define I64_MIN ((I64)0x8000000000000000)
|
||||
#define I64_MAX ((I64)0x7FFFFFFFFFFFFFFF)
|
||||
|
||||
/**
|
||||
#define U8_FOLD(n) (((n) < U8_MIN) ? (n+U8_MAX_PLUS_ONE) : (((n) > U8_MAX) ? (n-U8_MAX_PLUS_ONE) : (n)))
|
||||
**/
|
||||
|
||||
inline uint8_t U8_FOLD(int i)
|
||||
{
|
||||
return uint8_t(i);
|
||||
}
|
||||
|
||||
inline uint8_t u8_fold(int i)
|
||||
{
|
||||
return uint8_t(i);
|
||||
}
|
||||
|
||||
#define I8_CLAMP(n) (((n) <= I8_MIN) ? I8_MIN : (((n) >= I8_MAX) ? I8_MAX : ((I8)(n))))
|
||||
#define U8_CLAMP(n) (((n) <= U8_MIN) ? U8_MIN : (((n) >= U8_MAX) ? U8_MAX : ((U8)(n))))
|
||||
|
||||
#define I16_CLAMP(n) (((n) <= I16_MIN) ? I16_MIN : (((n) >= I16_MAX) ? I16_MAX : ((I16)(n))))
|
||||
#define U16_CLAMP(n) (((n) <= U16_MIN) ? U16_MIN : (((n) >= U16_MAX) ? U16_MAX : ((U16)(n))))
|
||||
|
||||
#define I32_CLAMP(n) (((n) <= I32_MIN) ? I32_MIN : (((n) >= I32_MAX) ? I32_MAX : ((I32)(n))))
|
||||
#define U32_CLAMP(n) (((n) <= U32_MIN) ? U32_MIN : (((n) >= U32_MAX) ? U32_MAX : ((U32)(n))))
|
||||
|
||||
#define I8_QUANTIZE(n) (((n) >= 0) ? (I8)((n)+0.5f) : (I8)((n)-0.5f))
|
||||
#define U8_QUANTIZE(n) (((n) >= 0) ? (U8)((n)+0.5f) : (U8)(0))
|
||||
|
||||
#define I16_QUANTIZE(n) (((n) >= 0) ? (I16)((n)+0.5f) : (I16)((n)-0.5f))
|
||||
#define U16_QUANTIZE(n) (((n) >= 0) ? (U16)((n)+0.5f) : (U16)(0))
|
||||
|
||||
#define I32_QUANTIZE(n) (((n) >= 0) ? (I32)((n)+0.5f) : (I32)((n)-0.5f))
|
||||
#define U32_QUANTIZE(n) (((n) >= 0) ? (U32)((n)+0.5f) : (U32)(0))
|
||||
|
||||
#define I64_QUANTIZE(n) (((n) >= 0) ? (I64)((n)+0.5f) : (I64)((n)-0.5f))
|
||||
#define U64_QUANTIZE(n) (((n) >= 0) ? (U64)((n)+0.5f) : (U64)(0))
|
||||
|
||||
#define I16_FLOOR(n) ((((I16)(n)) > (n)) ? (((I16)(n))-1) : ((I16)(n)))
|
||||
#define I32_FLOOR(n) ((((I32)(n)) > (n)) ? (((I32)(n))-1) : ((I32)(n)))
|
||||
#define I64_FLOOR(n) ((((I64)(n)) > (n)) ? (((I64)(n))-1) : ((I64)(n)))
|
||||
|
||||
#define I16_CEIL(n) ((((I16)(n)) < (n)) ? (((I16)(n))+1) : ((I16)(n)))
|
||||
#define I32_CEIL(n) ((((I32)(n)) < (n)) ? (((I32)(n))+1) : ((I32)(n)))
|
||||
#define I64_CEIL(n) ((((I64)(n)) < (n)) ? (((I64)(n))+1) : ((I64)(n)))
|
||||
|
||||
#define I8_FITS_IN_RANGE(n) (((n) >= I8_MIN) && ((n) <= I8_MAX) ? TRUE : FALSE)
|
||||
#define U8_FITS_IN_RANGE(n) (((n) >= U8_MIN) && ((n) <= U8_MAX) ? TRUE : FALSE)
|
||||
#define I16_FITS_IN_RANGE(n) (((n) >= I16_MIN) && ((n) <= I16_MAX) ? TRUE : FALSE)
|
||||
#define U16_FITS_IN_RANGE(n) (((n) >= U16_MIN) && ((n) <= U16_MAX) ? TRUE : FALSE)
|
||||
|
||||
#define F32_IS_FINITE(n) ((F32_MIN < (n)) && ((n) < F32_MAX))
|
||||
#define F64_IS_FINITE(n) ((F64_MIN < (n)) && ((n) < F64_MAX))
|
||||
|
||||
#define U32_ZERO_BIT_0(n) (((n)&(U32)0xFFFFFFFE))
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define ENDIANSWAP16(n) \
|
||||
( ((((U16) n) << 8) & 0xFF00) | \
|
||||
((((U16) n) >> 8) & 0x00FF) )
|
||||
|
||||
#define ENDIANSWAP32(n) \
|
||||
( ((((U32) n) << 24) & 0xFF000000) | \
|
||||
((((U32) n) << 8) & 0x00FF0000) | \
|
||||
((((U32) n) >> 8) & 0x0000FF00) | \
|
||||
((((U32) n) >> 24) & 0x000000FF) )
|
||||
|
||||
inline void ENDIAN_SWAP_16(U8* field)
|
||||
{
|
||||
U8 help = field[0];
|
||||
field[0] = field[1];
|
||||
field[1] = help;
|
||||
}
|
||||
|
||||
inline void ENDIAN_SWAP_32(U8* field)
|
||||
{
|
||||
U8 help;
|
||||
help = field[0];
|
||||
field[0] = field[3];
|
||||
field[3] = help;
|
||||
help = field[1];
|
||||
field[1] = field[2];
|
||||
field[2] = help;
|
||||
}
|
||||
|
||||
inline void ENDIAN_SWAP_64(U8* field)
|
||||
{
|
||||
U8 help;
|
||||
help = field[0];
|
||||
field[0] = field[7];
|
||||
field[7] = help;
|
||||
help = field[1];
|
||||
field[1] = field[6];
|
||||
field[6] = help;
|
||||
help = field[2];
|
||||
field[2] = field[5];
|
||||
field[5] = help;
|
||||
help = field[3];
|
||||
field[3] = field[4];
|
||||
field[4] = help;
|
||||
}
|
||||
|
||||
inline void ENDIAN_SWAP_16(const U8* from, U8* to)
|
||||
{
|
||||
to[0] = from[1];
|
||||
to[1] = from[0];
|
||||
}
|
||||
|
||||
inline void ENDIAN_SWAP_32(const U8* from, U8* to)
|
||||
{
|
||||
to[0] = from[3];
|
||||
to[1] = from[2];
|
||||
to[2] = from[1];
|
||||
to[3] = from[0];
|
||||
}
|
||||
|
||||
inline void ENDIAN_SWAP_64(const U8* from, U8* to)
|
||||
{
|
||||
to[0] = from[7];
|
||||
to[1] = from[6];
|
||||
to[2] = from[5];
|
||||
to[3] = from[4];
|
||||
to[4] = from[3];
|
||||
to[5] = from[2];
|
||||
to[6] = from[1];
|
||||
to[7] = from[0];
|
||||
}
|
||||
|
||||
|
||||
// Some constants
|
||||
/* this header byte needs to change in case incompatible change happen */
|
||||
#define AC_HEADER_BYTE 2
|
||||
#define AC_BUFFER_SIZE 1024
|
||||
|
||||
const U32 AC__MinLength = 0x01000000U; // threshold for renormalization
|
||||
const U32 AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length
|
||||
|
||||
// Maximum values for binary models
|
||||
const U32 BM__LengthShift = 13; // length bits discarded before mult.
|
||||
const U32 BM__MaxCount = 1 << BM__LengthShift; // for adaptive models
|
||||
|
||||
// Maximum values for general models
|
||||
const U32 DM__LengthShift = 15; // length bits discarded before mult.
|
||||
const U32 DM__MaxCount = 1 << DM__LengthShift; // for adaptive models
|
||||
|
||||
#endif
|
||||
242
external/laz-perf/compressor.hpp
vendored
Normal file
242
external/laz-perf/compressor.hpp
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: compressor.hpp
|
||||
|
||||
CONTENTS:
|
||||
Integer compressor
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __compressor_hpp__
|
||||
#define __compressor_hpp__
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
namespace laszip {
|
||||
namespace compressors {
|
||||
struct integer {
|
||||
integer(U32 bits = 16, U32 contexts = 1, U32 bits_high = 8, U32 range = 0):
|
||||
bits(bits), contexts(contexts), bits_high(bits_high), range(range) {
|
||||
|
||||
if (range) { // the corrector's significant bits and range
|
||||
corr_bits = 0;
|
||||
corr_range = range;
|
||||
while (range)
|
||||
{
|
||||
range = range >> 1;
|
||||
corr_bits++;
|
||||
}
|
||||
if (corr_range == (1u << (corr_bits-1))) {
|
||||
corr_bits--;
|
||||
}
|
||||
|
||||
// the corrector must fall into this interval
|
||||
corr_min = -((I32)(corr_range/2));
|
||||
corr_max = corr_min + corr_range - 1;
|
||||
}
|
||||
else if (bits && bits < 32) {
|
||||
corr_bits = bits;
|
||||
corr_range = 1u << bits;
|
||||
|
||||
// the corrector must fall into this interval
|
||||
corr_min = -((I32)(corr_range/2));
|
||||
corr_max = corr_min + corr_range - 1;
|
||||
}
|
||||
else {
|
||||
corr_bits = 32;
|
||||
corr_range = 0;
|
||||
// the corrector must fall into this interval
|
||||
corr_min = I32_MIN;
|
||||
corr_max = I32_MAX;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
}
|
||||
|
||||
~integer() {
|
||||
mBits.clear();
|
||||
mCorrector.clear();
|
||||
}
|
||||
|
||||
void init() {
|
||||
using laszip::models::arithmetic;
|
||||
using laszip::models::arithmetic_bit;
|
||||
|
||||
U32 i;
|
||||
|
||||
// maybe create the models
|
||||
if (mBits.empty()) {
|
||||
for (i = 0; i < contexts; i++)
|
||||
mBits.push_back(arithmetic(corr_bits+1));
|
||||
|
||||
#ifndef COMPRESS_ONLY_K
|
||||
// mcorrector0 is already in init state
|
||||
for (i = 1; i <= corr_bits; i++) {
|
||||
U32 v = i <= bits_high ? 1 << i : 1 << bits_high;
|
||||
mCorrector.push_back(arithmetic(v));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getK() const { return k; }
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
void compress(TEncoder& enc, I32 pred, I32 real, U32 context) {
|
||||
// the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ]
|
||||
I32 corr = real - pred;
|
||||
// we fold the corrector into the interval [ corr_min ... corr_max ]
|
||||
if (corr < corr_min) corr += corr_range;
|
||||
else if (corr > corr_max) corr -= corr_range;
|
||||
|
||||
writeCorrector(enc, corr, mBits[context]);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TEncoder,
|
||||
typename TEntropyModel
|
||||
>
|
||||
void writeCorrector(TEncoder& enc, int c, TEntropyModel& mBits) {
|
||||
U32 c1;
|
||||
|
||||
// find the tighest interval [ - (2^k - 1) ... + (2^k) ] that contains c
|
||||
|
||||
k = 0;
|
||||
|
||||
// do this by checking the absolute value of c (adjusted for the case that c is 2^k)
|
||||
|
||||
c1 = (c <= 0 ? -c : c-1);
|
||||
|
||||
// this loop could be replaced with more efficient code
|
||||
|
||||
while (c1)
|
||||
{
|
||||
c1 = c1 >> 1;
|
||||
k = k + 1;
|
||||
}
|
||||
|
||||
// the number k is between 0 and corr_bits and describes the interval the corrector falls into
|
||||
// we can compress the exact location of c within this interval using k bits
|
||||
|
||||
enc.encodeSymbol(mBits, k);
|
||||
|
||||
#ifdef COMPRESS_ONLY_K
|
||||
if (k) // then c is either smaller than 0 or bigger than 1
|
||||
{
|
||||
assert((c != 0) && (c != 1));
|
||||
if (k < 32)
|
||||
{
|
||||
// translate the corrector c into the k-bit interval [ 0 ... 2^k - 1 ]
|
||||
if (c < 0) // then c is in the interval [ - (2^k - 1) ... - (2^(k-1)) ]
|
||||
{
|
||||
// so we translate c into the interval [ 0 ... + 2^(k-1) - 1 ] by adding (2^k - 1)
|
||||
enc.writeBits(k, c + ((1<<k) - 1));
|
||||
}
|
||||
else // then c is in the interval [ 2^(k-1) + 1 ... 2^k ]
|
||||
{
|
||||
// so we translate c into the interval [ 2^(k-1) ... + 2^k - 1 ] by subtracting 1
|
||||
enc.writeBits(k, c - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // then c is 0 or 1
|
||||
{
|
||||
assert((c == 0) || (c == 1));
|
||||
enc.writeBit(c);
|
||||
}
|
||||
#else // COMPRESS_ONLY_K
|
||||
if (k) // then c is either smaller than 0 or bigger than 1
|
||||
{
|
||||
assert((c != 0) && (c != 1));
|
||||
if (k < 32)
|
||||
{
|
||||
// translate the corrector c into the k-bit interval [ 0 ... 2^k - 1 ]
|
||||
if (c < 0) // then c is in the interval [ - (2^k - 1) ... - (2^(k-1)) ]
|
||||
{
|
||||
// so we translate c into the interval [ 0 ... + 2^(k-1) - 1 ] by adding (2^k - 1)
|
||||
c += ((1<<k) - 1);
|
||||
}
|
||||
else // then c is in the interval [ 2^(k-1) + 1 ... 2^k ]
|
||||
{
|
||||
// so we translate c into the interval [ 2^(k-1) ... + 2^k - 1 ] by subtracting 1
|
||||
c -= 1;
|
||||
}
|
||||
if (k <= bits_high) // for small k we code the interval in one step
|
||||
{
|
||||
// compress c with the range coder
|
||||
enc.encodeSymbol(mCorrector[k-1], c);
|
||||
}
|
||||
else // for larger k we need to code the interval in two steps
|
||||
{
|
||||
// figure out how many lower bits there are
|
||||
int k1 = k-bits_high;
|
||||
// c1 represents the lowest k-bits_high+1 bits
|
||||
c1 = c & ((1<<k1) - 1);
|
||||
// c represents the highest bits_high bits
|
||||
c = c >> k1;
|
||||
// compress the higher bits using a context table
|
||||
enc.encodeSymbol(mCorrector[k-1], c);
|
||||
// store the lower k1 bits raw
|
||||
enc.writeBits(k1, c1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // then c is 0 or 1
|
||||
{
|
||||
assert((c == 0) || (c == 1));
|
||||
enc.encodeBit(mCorrector0,c);
|
||||
}
|
||||
#endif // COMPRESS_ONLY_K
|
||||
}
|
||||
|
||||
U32 k;
|
||||
|
||||
U32 bits;
|
||||
|
||||
U32 contexts;
|
||||
U32 bits_high;
|
||||
U32 range;
|
||||
|
||||
U32 corr_bits;
|
||||
U32 corr_range;
|
||||
I32 corr_min;
|
||||
I32 corr_max;
|
||||
|
||||
|
||||
std::vector<laszip::models::arithmetic> mBits;
|
||||
|
||||
laszip::models::arithmetic_bit mCorrector0;
|
||||
std::vector<laszip::models::arithmetic> mCorrector;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __compressor_hpp__
|
||||
286
external/laz-perf/decoder.hpp
vendored
Normal file
286
external/laz-perf/decoder.hpp
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: decoder.hpp
|
||||
|
||||
CONTENTS:
|
||||
Decoder stuff
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// **************************** -
|
||||
// ARITHMETIC CODING EXAMPLES -
|
||||
// **************************** -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// Fast arithmetic coding implementation -
|
||||
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// Version 1.00 - April 25, 2004 -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// WARNING -
|
||||
// ========= -
|
||||
// -
|
||||
// The only purpose of this program is to demonstrate the basic principles -
|
||||
// of arithmetic coding. The original version of this code can be found in -
|
||||
// Digital Signal Compression: Principles and Practice -
|
||||
// (Cambridge University Press, 2011, ISBN: 9780511984655) -
|
||||
// -
|
||||
// Copyright (c) 2019 by Amir Said (said@ieee.org) & -
|
||||
// William A. Pearlman (pearlw@ecse.rpi.edu) -
|
||||
// -
|
||||
// Redistribution and use in source and binary forms, with or without -
|
||||
// modification, are permitted provided that the following conditions are -
|
||||
// met: -
|
||||
// -
|
||||
// 1. Redistributions of source code must retain the above copyright notice, -
|
||||
// this list of conditions and the following disclaimer. -
|
||||
// -
|
||||
// 2. Redistributions in binary form must reproduce the above copyright -
|
||||
// notice, this list of conditions and the following disclaimer in the -
|
||||
// documentation and/or other materials provided with the distribution. -
|
||||
// -
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -
|
||||
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -
|
||||
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER -
|
||||
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// A description of the arithmetic coding method used here is available in -
|
||||
// -
|
||||
// Lossless Compression Handbook, ed. K. Sayood -
|
||||
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
|
||||
// -
|
||||
// A. Said, Introduction to Arithetic Coding Theory and Practice -
|
||||
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
#ifndef __decoder_hpp__
|
||||
#define __decoder_hpp__
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "common/types.hpp"
|
||||
|
||||
namespace laszip {
|
||||
namespace decoders {
|
||||
template<
|
||||
typename TInputStream
|
||||
>
|
||||
struct arithmetic {
|
||||
arithmetic(TInputStream& in) :
|
||||
instream(in), value(0) {
|
||||
length = AC__MaxLength;
|
||||
}
|
||||
|
||||
~arithmetic() {
|
||||
}
|
||||
|
||||
void readInitBytes() {
|
||||
value =
|
||||
(instream.getByte() << 24) |
|
||||
(instream.getByte() << 16) |
|
||||
(instream.getByte() << 8) |
|
||||
instream.getByte();
|
||||
}
|
||||
|
||||
template<typename TEntropyModel>
|
||||
U32 decodeBit(TEntropyModel& m) {
|
||||
U32 x = m.bit_0_prob * (length >> BM__LengthShift); // product l x p0
|
||||
U32 sym = (value >= x); // decision
|
||||
// update & shift interval
|
||||
if (sym == 0) {
|
||||
length = x;
|
||||
++m.bit_0_count;
|
||||
}
|
||||
else {
|
||||
value -= x; // shifted interval base = 0
|
||||
length -= x;
|
||||
}
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
if (--m.bits_until_update == 0) m.update(); // periodic model update
|
||||
|
||||
return sym; // return data bit value
|
||||
}
|
||||
|
||||
template<typename TEntropyModel>
|
||||
U32 decodeSymbol(TEntropyModel& m) {
|
||||
U32 n, sym, x, y = length;
|
||||
|
||||
if (m.decoder_table) { // use table look-up for faster decoding
|
||||
unsigned dv = value / (length >>= DM__LengthShift);
|
||||
unsigned t = dv >> m.table_shift;
|
||||
|
||||
sym = m.decoder_table[t]; // initial decision based on table look-up
|
||||
n = m.decoder_table[t+1] + 1;
|
||||
|
||||
while (n > sym + 1) { // finish with bisection search
|
||||
U32 k = (sym + n) >> 1;
|
||||
if (m.distribution[k] > dv) n = k; else sym = k;
|
||||
}
|
||||
|
||||
// compute products
|
||||
x = m.distribution[sym] * length;
|
||||
if (sym != m.last_symbol) y = m.distribution[sym+1] * length;
|
||||
}
|
||||
else { // decode using only multiplications
|
||||
x = sym = 0;
|
||||
length >>= DM__LengthShift;
|
||||
U32 k = (n = m.symbols) >> 1;
|
||||
// decode via bisection search
|
||||
do {
|
||||
U32 z = length * m.distribution[k];
|
||||
if (z > value) {
|
||||
n = k;
|
||||
y = z; // value is smaller
|
||||
}
|
||||
else {
|
||||
sym = k;
|
||||
x = z; // value is larger or equal
|
||||
}
|
||||
} while ((k = (sym + n) >> 1) != sym);
|
||||
}
|
||||
|
||||
value -= x; // update interval
|
||||
length = y - x;
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
|
||||
++m.symbol_count[sym];
|
||||
if (--m.symbols_until_update == 0) m.update(); // periodic model update
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
U32 readBit() {
|
||||
U32 sym = value / (length >>= 1); // decode symbol, change length
|
||||
value -= length * sym; // update interval
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
U32 readBits(U32 bits) {
|
||||
assert(bits && (bits <= 32));
|
||||
|
||||
if (bits > 19) {
|
||||
U32 tmp = readShort();
|
||||
bits = bits - 16;
|
||||
U32 tmp1 = readBits(bits) << 16;
|
||||
return (tmp1|tmp);
|
||||
}
|
||||
|
||||
U32 sym = value / (length >>= bits);// decode symbol, change length
|
||||
value -= length * sym; // update interval
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
return sym;
|
||||
}
|
||||
|
||||
U8 readByte() {
|
||||
U32 sym = value / (length >>= 8); // decode symbol, change length
|
||||
value -= length * sym; // update interval
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
|
||||
assert(sym < (1<<8));
|
||||
|
||||
return (U8)sym;
|
||||
}
|
||||
|
||||
U16 readShort() {
|
||||
U32 sym = value / (length >>= 16); // decode symbol, change length
|
||||
value -= length * sym; // update interval
|
||||
|
||||
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
|
||||
|
||||
assert(sym < (1<<16));
|
||||
|
||||
return (U16)sym;
|
||||
}
|
||||
|
||||
U32 readInt() {
|
||||
U32 lowerInt = readShort();
|
||||
U32 upperInt = readShort();
|
||||
return (upperInt<<16)|lowerInt;
|
||||
}
|
||||
|
||||
F32 readFloat() { /* danger in float reinterpretation */
|
||||
U32I32F32 u32i32f32;
|
||||
u32i32f32.u32 = readInt();
|
||||
return u32i32f32.f32;
|
||||
}
|
||||
|
||||
U64 readInt64() {
|
||||
U64 lowerInt = readInt();
|
||||
U64 upperInt = readInt();
|
||||
return (upperInt<<32)|lowerInt;
|
||||
}
|
||||
|
||||
F64 readDouble() { /* danger in float reinterpretation */
|
||||
U64I64F64 u64i64f64;
|
||||
u64i64f64.u64 = readInt64();
|
||||
return u64i64f64.f64;
|
||||
}
|
||||
|
||||
TInputStream& getInStream() {
|
||||
return instream;
|
||||
}
|
||||
|
||||
|
||||
arithmetic<TInputStream>(const arithmetic<TInputStream>&) = delete;
|
||||
arithmetic<TInputStream>& operator = (const arithmetic<TInputStream>&) = delete;
|
||||
|
||||
private:
|
||||
void renorm_dec_interval() {
|
||||
do { // read least-significant byte
|
||||
value = (value << 8) | instream.getByte();
|
||||
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
|
||||
}
|
||||
|
||||
TInputStream& instream;
|
||||
U32 value, length;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __decoder_hpp__
|
||||
223
external/laz-perf/decompressor.hpp
vendored
Normal file
223
external/laz-perf/decompressor.hpp
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: decompressor.hpp
|
||||
|
||||
CONTENTS:
|
||||
Integer decompressor
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __decompressor_hpp__
|
||||
#define __decompressor_hpp__
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
namespace laszip {
|
||||
namespace decompressors {
|
||||
struct integer {
|
||||
integer(U32 bits = 16, U32 contexts = 1, U32 bits_high = 8, U32 range = 0):
|
||||
bits(bits), contexts(contexts), bits_high(bits_high), range(range) {
|
||||
if (range) { // the corrector's significant bits and range
|
||||
corr_bits = 0;
|
||||
corr_range = range;
|
||||
while (range)
|
||||
{
|
||||
range = range >> 1;
|
||||
corr_bits++;
|
||||
}
|
||||
if (corr_range == (1u << (corr_bits-1)))
|
||||
{
|
||||
corr_bits--;
|
||||
}
|
||||
// the corrector must fall into this interval
|
||||
corr_min = -((I32)(corr_range/2));
|
||||
corr_max = corr_min + corr_range - 1;
|
||||
}
|
||||
else if (bits && bits < 32) {
|
||||
corr_bits = bits;
|
||||
corr_range = 1u << bits;
|
||||
// the corrector must fall into this interval
|
||||
corr_min = -((I32)(corr_range/2));
|
||||
corr_max = corr_min + corr_range - 1;
|
||||
}
|
||||
else {
|
||||
corr_bits = 32;
|
||||
corr_range = 0;
|
||||
// the corrector must fall into this interval
|
||||
corr_min = I32_MIN;
|
||||
corr_max = I32_MAX;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
}
|
||||
|
||||
void init() {
|
||||
using laszip::models::arithmetic;
|
||||
using laszip::models::arithmetic_bit;
|
||||
|
||||
U32 i;
|
||||
|
||||
// maybe create the models
|
||||
if (mBits.empty()) {
|
||||
for (i = 0; i < contexts; i++)
|
||||
mBits.push_back(arithmetic(corr_bits+1));
|
||||
|
||||
#ifndef COMPRESS_ONLY_K
|
||||
// mcorrector0 is already initialized
|
||||
for (i = 1; i <= corr_bits; i++) {
|
||||
U32 v = i <= bits_high ? 1 << i : 1 << bits_high;
|
||||
mCorrector.push_back(arithmetic(v));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
I32 decompress(TDecoder& dec, I32 pred, U32 context) {
|
||||
I32 real = pred + readCorrector(dec, mBits[context]);
|
||||
if (real < 0) real += corr_range;
|
||||
else if ((U32)(real) >= corr_range) real -= corr_range;
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
inline unsigned int getK() const { return k; }
|
||||
|
||||
template<
|
||||
typename TDecoder,
|
||||
typename TEntroyModel
|
||||
>
|
||||
I32 readCorrector(TDecoder& dec, TEntroyModel& mBits) {
|
||||
I32 c;
|
||||
|
||||
// decode within which interval the corrector is falling
|
||||
|
||||
k = dec.decodeSymbol(mBits);
|
||||
|
||||
// decode the exact location of the corrector within the interval
|
||||
|
||||
#ifdef COMPRESS_ONLY_K
|
||||
if (k) // then c is either smaller than 0 or bigger than 1
|
||||
{
|
||||
if (k < 32)
|
||||
{
|
||||
c = dec.readBits(k);
|
||||
|
||||
if (c >= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ]
|
||||
{
|
||||
// so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1
|
||||
c += 1;
|
||||
}
|
||||
else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ]
|
||||
{
|
||||
// so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1)
|
||||
c -= ((1<<k) - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c = corr_min;
|
||||
}
|
||||
}
|
||||
else // then c is either 0 or 1
|
||||
{
|
||||
c = dec.readBit();
|
||||
}
|
||||
#else // COMPRESS_ONLY_K
|
||||
if (k) // then c is either smaller than 0 or bigger than 1
|
||||
{
|
||||
if (k < 32)
|
||||
{
|
||||
if (k <= bits_high) // for small k we can do this in one step
|
||||
{
|
||||
// decompress c with the range coder
|
||||
c = dec.decodeSymbol(mCorrector[k-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for larger k we need to do this in two steps
|
||||
int k1 = k-bits_high;
|
||||
// decompress higher bits with table
|
||||
c = dec.decodeSymbol(mCorrector[k-1]);
|
||||
// read lower bits raw
|
||||
int c1 = dec.readBits(k1);
|
||||
// put the corrector back together
|
||||
c = (c << k1) | c1;
|
||||
}
|
||||
// translate c back into its correct interval
|
||||
if (c >= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ]
|
||||
{
|
||||
// so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1
|
||||
c += 1;
|
||||
}
|
||||
else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ]
|
||||
{
|
||||
// so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1)
|
||||
c -= ((1<<k) - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c = corr_min;
|
||||
}
|
||||
}
|
||||
else // then c is either 0 or 1
|
||||
{
|
||||
c = dec.decodeBit(mCorrector0);
|
||||
}
|
||||
#endif // COMPRESS_ONLY_K
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
U32 k;
|
||||
|
||||
U32 bits;
|
||||
|
||||
U32 contexts;
|
||||
U32 bits_high;
|
||||
U32 range;
|
||||
|
||||
U32 corr_bits;
|
||||
U32 corr_range;
|
||||
I32 corr_min;
|
||||
I32 corr_max;
|
||||
|
||||
|
||||
std::vector<laszip::models::arithmetic> mBits;
|
||||
|
||||
laszip::models::arithmetic_bit mCorrector0;
|
||||
std::vector<laszip::models::arithmetic> mCorrector;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __decompressor_hpp__
|
||||
108
external/laz-perf/detail/field_extrabytes.hpp
vendored
Normal file
108
external/laz-perf/detail/field_extrabytes.hpp
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: field_extrabytes.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
andrew.bell.ia@gmail.com - Hobu Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#error Cannot directly include this file, this is a part of las.hpp
|
||||
#endif
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
|
||||
template<>
|
||||
struct field<las::extrabytes> {
|
||||
typedef las::extrabytes type;
|
||||
|
||||
size_t count_;
|
||||
bool have_last_;
|
||||
std::vector<uint8_t> lasts_;
|
||||
std::vector<uint8_t> diffs_;
|
||||
std::deque<models::arithmetic> models_;
|
||||
|
||||
field(size_t count) :
|
||||
count_(count), have_last_(false), lasts_(count), diffs_(count),
|
||||
models_(count, models::arithmetic(256))
|
||||
{}
|
||||
|
||||
template<typename TEncoder>
|
||||
inline const char *compressWith(TEncoder& enc, const char *buf)
|
||||
{
|
||||
auto li = lasts_.begin();
|
||||
auto di = diffs_.begin();
|
||||
while (di != diffs_.end())
|
||||
{
|
||||
*di = *buf - *li;
|
||||
*li = *buf;
|
||||
di++; buf++; li++;
|
||||
}
|
||||
|
||||
if (!have_last_)
|
||||
{
|
||||
enc.getOutStream().putBytes(lasts_.data(), count_);
|
||||
have_last_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
di = diffs_.begin();
|
||||
auto mi = models_.begin();
|
||||
while (di != diffs_.end())
|
||||
enc.encodeSymbol(*mi++, *di++);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<typename TDecoder>
|
||||
inline char *decompressWith(TDecoder& dec, char *buf)
|
||||
{
|
||||
if (!have_last_)
|
||||
{
|
||||
dec.getInStream().getBytes((unsigned char *)buf, count_);
|
||||
std::copy(buf, buf + count_, lasts_.data());
|
||||
have_last_ = true;
|
||||
return buf + count_;
|
||||
}
|
||||
// Use the diff vector for our current values.
|
||||
auto& curs = diffs_;
|
||||
auto ci = curs.begin();
|
||||
auto li = lasts_.begin();
|
||||
auto mi = models_.begin();
|
||||
while (li != lasts_.end())
|
||||
{
|
||||
*ci = u8_fold(*li + dec.decodeSymbol(*mi));
|
||||
*li = *buf = *ci;
|
||||
li++; buf++; ci++; mi++;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
446
external/laz-perf/detail/field_gpstime.hpp
vendored
Normal file
446
external/laz-perf/detail/field_gpstime.hpp
vendored
Normal file
@ -0,0 +1,446 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: field_gpstime.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#error Cannot directly include this file, this is a part of las.hpp
|
||||
#endif
|
||||
|
||||
#define LASZIP_GPSTIME_MULTI 500
|
||||
#define LASZIP_GPSTIME_MULTI_MINUS -10
|
||||
#define LASZIP_GPSTIME_MULTI_UNCHANGED (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1)
|
||||
#define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 2)
|
||||
|
||||
#define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 6)
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
// Teach packers how to pack and unpack gps time
|
||||
//
|
||||
template<>
|
||||
struct packers<las::gpstime> {
|
||||
inline static las::gpstime unpack(const char *in) {
|
||||
uint64_t lower = packers<unsigned int>::unpack(in),
|
||||
upper = packers<unsigned int>::unpack(in + 4);
|
||||
|
||||
return las::gpstime((upper << 32) | lower);
|
||||
}
|
||||
|
||||
inline static void pack(const las::gpstime& t, char *buffer) {
|
||||
packers<unsigned int>::pack(t.value & 0xFFFFFFFF, buffer);
|
||||
packers<unsigned int>::pack(t.value >> 32, buffer + 4);
|
||||
}
|
||||
};
|
||||
|
||||
// Figure how to compress and decompress GPS time fields
|
||||
//
|
||||
template<>
|
||||
struct field<las::gpstime> {
|
||||
typedef las::gpstime type;
|
||||
|
||||
field() : compressor_inited_(false), decompressor_inited_(false) {}
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& enc, const char *buf)
|
||||
{
|
||||
las::gpstime this_val = packers<las::gpstime>::unpack(buf);
|
||||
|
||||
if (!compressor_inited_) {
|
||||
compressors_.init();
|
||||
compressor_inited_ = true;
|
||||
}
|
||||
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, just push it to our have last stuff and move on
|
||||
common_.have_last_ = true;
|
||||
common_.last_gpstime[0] = this_val;
|
||||
|
||||
// write this out to the encoder as it is
|
||||
enc.getOutStream().putBytes((const unsigned char*)buf,
|
||||
sizeof(las::gpstime));
|
||||
buf += sizeof(las::gpstime);
|
||||
|
||||
// we are done here
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (common_.last_gpstime_diff[common_.last] == 0) { // if last integer different was 0
|
||||
if (this_val.value == common_.last_gpstime[common_.last].value) {
|
||||
enc.encodeSymbol(common_.m_gpstime_0diff, 0);
|
||||
}
|
||||
else {
|
||||
// calculate the difference between the two doubles as an integer
|
||||
//
|
||||
int64_t curr_gpstime_diff_64 = this_val.value - common_.last_gpstime[common_.last].value;
|
||||
int curr_gpstime_diff = static_cast<int>(curr_gpstime_diff_64);
|
||||
|
||||
if (curr_gpstime_diff_64 == static_cast<int64_t>(curr_gpstime_diff)) {
|
||||
// this difference is small enough to be represented with 32 bits
|
||||
enc.encodeSymbol(common_.m_gpstime_0diff, 1);
|
||||
compressors_.ic_gpstime.compress(enc, 0, curr_gpstime_diff, 0);
|
||||
common_.last_gpstime_diff[common_.last] = curr_gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else { // the difference is huge
|
||||
U32 i;
|
||||
|
||||
// maybe the double belongs to another time sequence
|
||||
//
|
||||
for (i = 1; i < 4; i++) {
|
||||
int64_t other_gpstime_diff_64 = this_val.value -
|
||||
common_.last_gpstime[(common_.last+i)&3].value;
|
||||
int other_gpstime_diff = static_cast<int>(other_gpstime_diff_64);
|
||||
|
||||
if (other_gpstime_diff_64 == static_cast<int64_t>(other_gpstime_diff)) {
|
||||
enc.encodeSymbol(common_.m_gpstime_0diff, i+2); // it belongs to another sequence
|
||||
common_.last = (common_.last+i)&3;
|
||||
return compressWith(enc, buf);
|
||||
}
|
||||
}
|
||||
|
||||
// no other sequence found. start new sequence.
|
||||
enc.encodeSymbol(common_.m_gpstime_0diff, 2);
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
static_cast<int>(common_.last_gpstime[common_.last].value >> 32),
|
||||
static_cast<int>(this_val.value >> 32), 8);
|
||||
|
||||
enc.writeInt(static_cast<unsigned int>(this_val.value));
|
||||
|
||||
common_.next = (common_.next+1)&3;
|
||||
common_.last = common_.next;
|
||||
common_.last_gpstime_diff[common_.last] = 0;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
common_.last_gpstime[common_.last] = this_val;
|
||||
}
|
||||
}
|
||||
else { // the last integer difference was *not* zero
|
||||
if (this_val.value == common_.last_gpstime[common_.last].value) {
|
||||
// if the doubles have not changed use a special symbol
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI_UNCHANGED);
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate the difference between the two doubles as an integer
|
||||
int64_t curr_gpstime_diff_64 = this_val.value -
|
||||
common_.last_gpstime[common_.last].value;
|
||||
int curr_gpstime_diff = static_cast<int>(curr_gpstime_diff_64);
|
||||
|
||||
// if the current gpstime difference can be represented with 32 bits
|
||||
if (curr_gpstime_diff_64 == static_cast<int64_t>(curr_gpstime_diff)) {
|
||||
// compute multiplier between current and last integer difference
|
||||
float multi_f = (float)curr_gpstime_diff /
|
||||
(float)(common_.last_gpstime_diff[common_.last]);
|
||||
int multi = I32_QUANTIZE(multi_f);
|
||||
|
||||
// compress the residual curr_gpstime_diff in dependance on the multiplier
|
||||
if (multi == 1) {
|
||||
// this is the case we assume we get most often for regular spaced pulses
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, 1);
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
common_.last_gpstime_diff[common_.last], curr_gpstime_diff, 1);
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else if (multi > 0) {
|
||||
if (multi < LASZIP_GPSTIME_MULTI) {
|
||||
// positive multipliers up to LASZIP_GPSTIME_MULTI are compressed directly
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, multi);
|
||||
if (multi < 10)
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
multi*common_.last_gpstime_diff[common_.last],
|
||||
curr_gpstime_diff, 2);
|
||||
else
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
multi*common_.last_gpstime_diff[common_.last],
|
||||
curr_gpstime_diff, 3);
|
||||
}
|
||||
else {
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI);
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
LASZIP_GPSTIME_MULTI*common_.last_gpstime_diff[common_.last],
|
||||
curr_gpstime_diff, 4);
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
|
||||
if (common_.multi_extreme_counter[common_.last] > 3) {
|
||||
common_.last_gpstime_diff[common_.last] = curr_gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (multi < 0) {
|
||||
if (multi > LASZIP_GPSTIME_MULTI_MINUS) {
|
||||
// negative multipliers larger than LASZIP_GPSTIME_MULTI_MINUS are compressed directly
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI - multi);
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
multi*common_.last_gpstime_diff[common_.last],
|
||||
curr_gpstime_diff, 5);
|
||||
}
|
||||
else {
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS);
|
||||
compressors_.ic_gpstime.compress(enc,
|
||||
LASZIP_GPSTIME_MULTI_MINUS*common_.last_gpstime_diff[common_.last],
|
||||
curr_gpstime_diff, 6);
|
||||
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
if (common_.multi_extreme_counter[common_.last] > 3)
|
||||
{
|
||||
common_.last_gpstime_diff[common_.last] = curr_gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, 0);
|
||||
compressors_.ic_gpstime.compress(enc, 0, curr_gpstime_diff, 7);
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
if (common_.multi_extreme_counter[common_.last] > 3)
|
||||
{
|
||||
common_.last_gpstime_diff[common_.last] = curr_gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // the difference is huge
|
||||
int i;
|
||||
// maybe the double belongs to another time sequence
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
int64_t other_gpstime_diff_64 = this_val.value - common_.last_gpstime[(common_.last+i)&3].value;
|
||||
int other_gpstime_diff = static_cast<int>(other_gpstime_diff_64);
|
||||
|
||||
if (other_gpstime_diff_64 == static_cast<int64_t>(other_gpstime_diff)) {
|
||||
// it belongs to this sequence
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL+i);
|
||||
common_.last = (common_.last+i)&3;
|
||||
return compressWith(enc, buf);
|
||||
}
|
||||
}
|
||||
|
||||
// no other sequence found. start new sequence.
|
||||
enc.encodeSymbol(common_.m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL);
|
||||
compressors_.ic_gpstime.compress(
|
||||
enc,
|
||||
static_cast<int>(common_.last_gpstime[common_.last].value >> 32),
|
||||
static_cast<int>(this_val.value >> 32), 8);
|
||||
enc.writeInt(static_cast<unsigned int>(this_val.value));
|
||||
common_.next = (common_.next+1)&3;
|
||||
common_.last = common_.next;
|
||||
common_.last_gpstime_diff[common_.last] = 0;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
|
||||
common_.last_gpstime[common_.last] = this_val;
|
||||
}
|
||||
}
|
||||
return buf + sizeof(las::gpstime);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& dec, char *buf) {
|
||||
if (!decompressor_inited_) {
|
||||
decompressors_.init();
|
||||
decompressor_inited_ = true;
|
||||
}
|
||||
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, read the whole point out of the stream
|
||||
common_.have_last_ = true;
|
||||
|
||||
dec.getInStream().getBytes((unsigned char*)buf,
|
||||
sizeof(las::gpstime));
|
||||
// decode this value
|
||||
common_.last_gpstime[0] = packers<las::gpstime>::unpack(buf);
|
||||
|
||||
// we are done here
|
||||
return buf + sizeof(las::gpstime);
|
||||
}
|
||||
|
||||
int multi;
|
||||
if (common_.last_gpstime_diff[common_.last] == 0) { // if the last integer difference was zero
|
||||
multi = dec.decodeSymbol(common_.m_gpstime_0diff);
|
||||
|
||||
if (multi == 1) { // the difference can be represented with 32 bits
|
||||
common_.last_gpstime_diff[common_.last] = decompressors_.ic_gpstime.decompress(dec, 0, 0);
|
||||
common_.last_gpstime[common_.last].value += common_.last_gpstime_diff[common_.last];
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else if (multi == 2) { // the difference is huge
|
||||
common_.next = (common_.next+1)&3;
|
||||
common_.last_gpstime[common_.next].value = decompressors_.ic_gpstime.decompress(
|
||||
dec,
|
||||
(common_.last_gpstime[common_.last].value >> 32), 8);
|
||||
common_.last_gpstime[common_.next].value = common_.last_gpstime[common_.next].value << 32;
|
||||
common_.last_gpstime[common_.next].value |= dec.readInt();
|
||||
common_.last = common_.next;
|
||||
common_.last_gpstime_diff[common_.last] = 0;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else if (multi > 2) { // we switch to another sequence
|
||||
common_.last = (common_.last+multi-2)&3;
|
||||
|
||||
decompressWith(dec, buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
multi = dec.decodeSymbol(common_.m_gpstime_multi);
|
||||
if (multi == 1) {
|
||||
common_.last_gpstime[common_.last].value += decompressors_.ic_gpstime.decompress(
|
||||
dec,
|
||||
common_.last_gpstime_diff[common_.last], 1);
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else if (multi < LASZIP_GPSTIME_MULTI_UNCHANGED) {
|
||||
int gpstime_diff;
|
||||
if (multi == 0) {
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(dec, 0, 7);
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
if (common_.multi_extreme_counter[common_.last] > 3) { common_.last_gpstime_diff[common_.last] = gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
else if (multi < LASZIP_GPSTIME_MULTI) {
|
||||
if (multi < 10)
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(dec,
|
||||
multi*common_.last_gpstime_diff[common_.last], 2);
|
||||
else
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(dec,
|
||||
multi*common_.last_gpstime_diff[common_.last], 3);
|
||||
}
|
||||
else if (multi == LASZIP_GPSTIME_MULTI) {
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(
|
||||
dec,
|
||||
LASZIP_GPSTIME_MULTI*common_.last_gpstime_diff[common_.last], 4);
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
if (common_.multi_extreme_counter[common_.last] > 3) {
|
||||
common_.last_gpstime_diff[common_.last] = gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
multi = LASZIP_GPSTIME_MULTI - multi;
|
||||
if (multi > LASZIP_GPSTIME_MULTI_MINUS) {
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(
|
||||
dec,
|
||||
multi*common_.last_gpstime_diff[common_.last], 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpstime_diff = decompressors_.ic_gpstime.decompress(
|
||||
dec,
|
||||
LASZIP_GPSTIME_MULTI_MINUS*common_.last_gpstime_diff[common_.last], 6);
|
||||
common_.multi_extreme_counter[common_.last]++;
|
||||
if (common_.multi_extreme_counter[common_.last] > 3) {
|
||||
common_.last_gpstime_diff[common_.last] = gpstime_diff;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
common_.last_gpstime[common_.last].value += gpstime_diff;
|
||||
}
|
||||
else if (multi == LASZIP_GPSTIME_MULTI_CODE_FULL) {
|
||||
common_.next = (common_.next+1)&3;
|
||||
common_.last_gpstime[common_.next].value = decompressors_.ic_gpstime.decompress(
|
||||
dec, static_cast<int>(common_.last_gpstime[common_.last].value >> 32), 8);
|
||||
common_.last_gpstime[common_.next].value = common_.last_gpstime[common_.next].value << 32;
|
||||
common_.last_gpstime[common_.next].value |= dec.readInt();
|
||||
common_.last = common_.next;
|
||||
common_.last_gpstime_diff[common_.last] = 0;
|
||||
common_.multi_extreme_counter[common_.last] = 0;
|
||||
}
|
||||
else if (multi >= LASZIP_GPSTIME_MULTI_CODE_FULL) {
|
||||
common_.last = (common_.last+multi-LASZIP_GPSTIME_MULTI_CODE_FULL)&3;
|
||||
|
||||
decompressWith(dec, buf);
|
||||
}
|
||||
}
|
||||
packers<las::gpstime>::pack(common_.last_gpstime[common_.last],
|
||||
buf);
|
||||
return buf + sizeof(las::gpstime);
|
||||
}
|
||||
|
||||
// All the things we need to compress a point, group them into structs
|
||||
// so we don't have too many names flying around
|
||||
|
||||
// Common parts for both a compressor and decompressor go here
|
||||
struct __common {
|
||||
bool have_last_;
|
||||
models::arithmetic m_gpstime_multi, m_gpstime_0diff;
|
||||
unsigned int last, next;
|
||||
std::array<las::gpstime, 4> last_gpstime;
|
||||
std::array<int, 4> last_gpstime_diff;
|
||||
std::array<int, 4> multi_extreme_counter;
|
||||
|
||||
__common() :
|
||||
have_last_(false),
|
||||
m_gpstime_multi(LASZIP_GPSTIME_MULTI_TOTAL),
|
||||
m_gpstime_0diff(6),
|
||||
last(0), next(0) {
|
||||
|
||||
last_gpstime.fill(las::gpstime());
|
||||
last_gpstime_diff.fill(0);
|
||||
multi_extreme_counter.fill(0);
|
||||
}
|
||||
|
||||
|
||||
~__common() {
|
||||
}
|
||||
} common_;
|
||||
|
||||
// These compressors are specific to a compressor usage, so we keep them separate here
|
||||
struct __compressors {
|
||||
compressors::integer ic_gpstime;
|
||||
|
||||
__compressors() :
|
||||
ic_gpstime(32, 9) {}
|
||||
|
||||
void init() {
|
||||
ic_gpstime.init();
|
||||
}
|
||||
} compressors_;
|
||||
|
||||
struct __decompressors {
|
||||
decompressors::integer ic_gpstime;
|
||||
|
||||
__decompressors() :
|
||||
ic_gpstime(32, 9) {}
|
||||
|
||||
void init() {
|
||||
ic_gpstime.init();
|
||||
}
|
||||
} decompressors_;
|
||||
|
||||
bool compressor_inited_;
|
||||
bool decompressor_inited_;
|
||||
};
|
||||
}
|
||||
}
|
||||
463
external/laz-perf/detail/field_point10.hpp
vendored
Normal file
463
external/laz-perf/detail/field_point10.hpp
vendored
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: field_point10.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#error Cannot directly include this file, this is a part of las.hpp
|
||||
#endif
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
namespace detail {
|
||||
inline int changed_values(const las::point10& this_val, const las::point10& last, unsigned short last_intensity) {
|
||||
// This logic here constructs a 5-bit changed value which is basically a bit map of what has changed
|
||||
// since the last point, not considering the x, y and z values
|
||||
int bitfields_changed = (
|
||||
(last.return_number ^ this_val.return_number) |
|
||||
(last.number_of_returns_of_given_pulse ^ this_val.number_of_returns_of_given_pulse) |
|
||||
(last.scan_direction_flag ^ this_val.scan_direction_flag) |
|
||||
(last.edge_of_flight_line ^ this_val.edge_of_flight_line)) != 0;
|
||||
|
||||
// last intensity is not checked with last point, but the passed in
|
||||
// last intensity value
|
||||
int intensity_changed =
|
||||
(last_intensity ^ this_val.intensity) != 0;
|
||||
|
||||
int classification_changed =
|
||||
(last.classification ^ this_val.classification) != 0;
|
||||
|
||||
int scan_angle_rank_changed =
|
||||
(last.scan_angle_rank ^ this_val.scan_angle_rank) != 0;
|
||||
|
||||
int user_data_changed =
|
||||
(last.user_data ^ this_val.user_data) != 0;
|
||||
|
||||
int point_source_changed =
|
||||
(last.point_source_ID ^ this_val.point_source_ID) != 0;
|
||||
|
||||
return
|
||||
(bitfields_changed << 5) |
|
||||
(intensity_changed << 4) |
|
||||
(classification_changed << 3) |
|
||||
(scan_angle_rank_changed << 2) |
|
||||
(user_data_changed << 1) |
|
||||
(point_source_changed);
|
||||
}
|
||||
|
||||
inline unsigned char bitfields_to_char(const las::point10& p) {
|
||||
unsigned char a = p.return_number,
|
||||
b = p.number_of_returns_of_given_pulse,
|
||||
c = p.scan_direction_flag,
|
||||
d = p.edge_of_flight_line;
|
||||
|
||||
return
|
||||
((d & 0x1) << 7) |
|
||||
((c & 0x1) << 6) |
|
||||
((b & 0x7) << 3) |
|
||||
(a & 0x7);
|
||||
}
|
||||
|
||||
inline void char_to_bitfields(unsigned char d, las::point10& p) {
|
||||
p.return_number = d & 0x7;
|
||||
p.number_of_returns_of_given_pulse = (d >> 3) & 0x7;
|
||||
p.scan_direction_flag = (d >> 6) & 0x1;
|
||||
p.edge_of_flight_line = (d >> 7) & 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
// Teach packers how to pack unpack the point10 struct
|
||||
//
|
||||
template<>
|
||||
struct packers<las::point10> {
|
||||
inline static las::point10 unpack(const char *in) {
|
||||
// blind casting will cause problems for ARM and Emscripten targets
|
||||
//
|
||||
las::point10 p;
|
||||
|
||||
p.x = packers<int>::unpack(in); in += sizeof(int);
|
||||
p.y = packers<int>::unpack(in); in += sizeof(int);
|
||||
p.z = packers<int>::unpack(in); in += sizeof(int);
|
||||
p.intensity = packers<unsigned short>::unpack(in); in += sizeof(unsigned short);
|
||||
|
||||
unsigned char d =
|
||||
packers<unsigned char>::unpack(in); in += sizeof(unsigned char);
|
||||
|
||||
// unpack read bitfields into p
|
||||
detail::char_to_bitfields(d, p);
|
||||
|
||||
p.classification =
|
||||
packers<unsigned char>::unpack(in); in += sizeof(unsigned char);
|
||||
|
||||
p.scan_angle_rank = packers<char>::unpack(in); in += sizeof(char);
|
||||
p.user_data = packers<char>::unpack(in); in += sizeof(char);
|
||||
p.point_source_ID =
|
||||
packers<unsigned short>::unpack(in);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
inline static void pack(const las::point10& p, char *buffer) {
|
||||
packers<int>::pack(p.x, buffer); buffer += sizeof(int);
|
||||
packers<int>::pack(p.y, buffer); buffer += sizeof(int);
|
||||
packers<int>::pack(p.z, buffer); buffer += sizeof(int);
|
||||
|
||||
packers<unsigned short>::pack(p.intensity, buffer); buffer += sizeof(unsigned short);
|
||||
|
||||
// pack bitfields into a char
|
||||
unsigned char e = detail::bitfields_to_char(p);
|
||||
|
||||
packers<unsigned char>::pack(e, buffer); buffer += sizeof(unsigned char);
|
||||
packers<unsigned char>::pack(
|
||||
p.classification, buffer); buffer += sizeof(unsigned char);
|
||||
|
||||
packers<char>::pack(p.scan_angle_rank, buffer); buffer += sizeof(char);
|
||||
packers<char>::pack(p.user_data, buffer); buffer += sizeof(char);
|
||||
packers<unsigned short>::pack(
|
||||
p.point_source_ID, buffer);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// specialize field to compress point 10
|
||||
//
|
||||
template<>
|
||||
struct field<las::point10> {
|
||||
typedef las::point10 type;
|
||||
|
||||
field() : compressor_inited_(false), decompressors_inited_(false) { }
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& enc, const char *buf)
|
||||
{
|
||||
|
||||
las::point10 this_val;
|
||||
this_val = packers<las::point10>::unpack(buf);
|
||||
|
||||
if (!compressor_inited_) {
|
||||
compressors_.init();
|
||||
compressor_inited_ = true;
|
||||
}
|
||||
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, just push it to our have last stuff and move on
|
||||
common_.have_last_ = true;
|
||||
common_.last_ = this_val;
|
||||
|
||||
// write this out to the encoder as it is
|
||||
enc.getOutStream().putBytes((const unsigned char*)buf,
|
||||
sizeof(las::point10));
|
||||
return buf + sizeof(las::point10);
|
||||
}
|
||||
|
||||
// this is not the first point we're trying to compress, do crazy things
|
||||
//
|
||||
unsigned int r = this_val.return_number,
|
||||
n = this_val.number_of_returns_of_given_pulse,
|
||||
m = utils::number_return_map[n][r],
|
||||
l = utils::number_return_level[n][r];
|
||||
|
||||
unsigned int k_bits;
|
||||
int median, diff;
|
||||
|
||||
// compress which other values have changed
|
||||
int changed_values = detail::changed_values(this_val, common_.last_, common_.last_intensity[m]);
|
||||
|
||||
enc.encodeSymbol(common_.m_changed_values, changed_values);
|
||||
|
||||
// if any of the bit fields changed, compress them
|
||||
if (changed_values & (1 << 5)) {
|
||||
unsigned char b = detail::bitfields_to_char(this_val),
|
||||
last_b = detail::bitfields_to_char(common_.last_);
|
||||
enc.encodeSymbol(*common_.m_bit_byte[last_b], b);
|
||||
}
|
||||
|
||||
// if the intensity changed, compress it
|
||||
if (changed_values & (1 << 4)) {
|
||||
compressors_.ic_intensity.compress(enc, common_.last_intensity[m], this_val.intensity, (m < 3 ? m : 3));
|
||||
common_.last_intensity[m] = this_val.intensity;
|
||||
}
|
||||
|
||||
// if the classification has changed, compress it
|
||||
if (changed_values & (1 << 3)) {
|
||||
enc.encodeSymbol(*common_.m_classification[common_.last_.classification], this_val.classification);
|
||||
}
|
||||
|
||||
// if the scan angle rank has changed, compress it
|
||||
if (changed_values & (1 << 2)) {
|
||||
enc.encodeSymbol(*common_.m_scan_angle_rank[this_val.scan_direction_flag],
|
||||
U8_FOLD(this_val.scan_angle_rank - common_.last_.scan_angle_rank));
|
||||
}
|
||||
|
||||
// encode user data if changed
|
||||
if (changed_values & (1 << 1)) {
|
||||
enc.encodeSymbol(*common_.m_user_data[common_.last_.user_data], this_val.user_data);
|
||||
}
|
||||
|
||||
// if the point source id was changed, compress it
|
||||
if (changed_values & 1) {
|
||||
compressors_.ic_point_source_ID.compress(enc, common_.last_.point_source_ID, this_val.point_source_ID, 0);
|
||||
}
|
||||
|
||||
// compress x coordinate
|
||||
median = common_.last_x_diff_median5[m].get();
|
||||
diff = this_val.x - common_.last_.x;
|
||||
compressors_.ic_dx.compress(enc, median, diff, n == 1);
|
||||
common_.last_x_diff_median5[m].add(diff);
|
||||
|
||||
// compress y coordinate
|
||||
k_bits = compressors_.ic_dx.getK();
|
||||
median = common_.last_y_diff_median5[m].get();
|
||||
diff = this_val.y - common_.last_.y;
|
||||
compressors_.ic_dy.compress(enc, median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
|
||||
common_.last_y_diff_median5[m].add(diff);
|
||||
|
||||
// compress z coordinate
|
||||
k_bits = (compressors_.ic_dx.getK() + compressors_.ic_dy.getK()) / 2;
|
||||
compressors_.ic_z.compress(enc, common_.last_height[l], this_val.z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
|
||||
common_.last_height[l] = this_val.z;
|
||||
|
||||
common_.last_ = this_val;
|
||||
return buf + sizeof(las::point10);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& dec, char *buf)
|
||||
{
|
||||
if (!decompressors_inited_) {
|
||||
decompressors_.init();
|
||||
decompressors_inited_ = true;
|
||||
}
|
||||
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, read the whole point out of the stream
|
||||
common_.have_last_ = true;
|
||||
|
||||
dec.getInStream().getBytes((unsigned char*)buf,
|
||||
sizeof(las::point10));
|
||||
// decode this value
|
||||
common_.last_ = packers<las::point10>::unpack(buf);
|
||||
// we are done here
|
||||
|
||||
common_.last_.intensity = 0;
|
||||
return buf + sizeof(las::point10);
|
||||
}
|
||||
|
||||
unsigned int r, n, m, l, k_bits;
|
||||
int median, diff;
|
||||
|
||||
// decompress which other values have changed
|
||||
int changed_values = dec.decodeSymbol(common_.m_changed_values);
|
||||
if (changed_values) {
|
||||
// there was some change in one of the fields (other than x, y and z)
|
||||
|
||||
// decode bit fields if they have changed
|
||||
if (changed_values & (1 << 5)) {
|
||||
unsigned char b = detail::bitfields_to_char(common_.last_);
|
||||
b = (unsigned char)dec.decodeSymbol(*common_.m_bit_byte[b]);
|
||||
detail::char_to_bitfields(b, common_.last_);
|
||||
}
|
||||
|
||||
r = common_.last_.return_number;
|
||||
n = common_.last_.number_of_returns_of_given_pulse;
|
||||
m = utils::number_return_map[n][r];
|
||||
l = utils::number_return_level[n][r];
|
||||
|
||||
// decompress the intensity if it has changed
|
||||
if (changed_values & (1 << 4)) {
|
||||
common_.last_.intensity = static_cast<unsigned short>(decompressors_.ic_intensity.decompress(dec, common_.last_intensity[m], (m < 3 ? m : 3)));
|
||||
common_.last_intensity[m] = common_.last_.intensity;
|
||||
}
|
||||
else {
|
||||
common_.last_.intensity = common_.last_intensity[m];
|
||||
}
|
||||
|
||||
// decompress the classification ... if it has changed
|
||||
if (changed_values & (1 << 3)) {
|
||||
common_.last_.classification =
|
||||
(unsigned char)dec.decodeSymbol(*common_.m_classification[common_.last_.classification]);
|
||||
}
|
||||
|
||||
// decompress the scan angle rank if needed
|
||||
if (changed_values & (1 << 2)) {
|
||||
int val = dec.decodeSymbol(*common_.m_scan_angle_rank[common_.last_.scan_direction_flag]);
|
||||
common_.last_.scan_angle_rank = static_cast<unsigned char>(U8_FOLD(val + common_.last_.scan_angle_rank));
|
||||
}
|
||||
|
||||
// decompress the user data
|
||||
if (changed_values & (1 << 1)) {
|
||||
common_.last_.user_data = (unsigned char)dec.decodeSymbol(*common_.m_user_data[common_.last_.user_data]);
|
||||
}
|
||||
|
||||
// decompress the point source ID
|
||||
if (changed_values & 1) {
|
||||
common_.last_.point_source_ID = (unsigned short)decompressors_.ic_point_source_ID.decompress(dec,
|
||||
common_.last_.point_source_ID, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
r = common_.last_.return_number;
|
||||
n = common_.last_.number_of_returns_of_given_pulse;
|
||||
m = utils::number_return_map[n][r];
|
||||
l = utils::number_return_level[n][r];
|
||||
}
|
||||
|
||||
// decompress x coordinate
|
||||
median = common_.last_x_diff_median5[m].get();
|
||||
|
||||
diff = decompressors_.ic_dx.decompress(dec, median, n==1);
|
||||
common_.last_.x += diff;
|
||||
common_.last_x_diff_median5[m].add(diff);
|
||||
|
||||
// decompress y coordinate
|
||||
median = common_.last_y_diff_median5[m].get();
|
||||
k_bits = decompressors_.ic_dx.getK();
|
||||
diff = decompressors_.ic_dy.decompress(dec, median, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
|
||||
common_.last_.y += diff;
|
||||
common_.last_y_diff_median5[m].add(diff);
|
||||
|
||||
// decompress z coordinate
|
||||
k_bits = (decompressors_.ic_dx.getK() + decompressors_.ic_dy.getK()) / 2;
|
||||
common_.last_.z = decompressors_.ic_z.decompress(dec, common_.last_height[l], (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
|
||||
common_.last_height[l] = common_.last_.z;
|
||||
|
||||
packers<las::point10>::pack(common_.last_, buf);
|
||||
return buf + sizeof(las::point10);
|
||||
}
|
||||
|
||||
// All the things we need to compress a point, group them into structs
|
||||
// so we don't have too many names flying around
|
||||
|
||||
// Common parts for both a compressor and decompressor go here
|
||||
struct __common {
|
||||
las::point10 last_;
|
||||
|
||||
std::array<unsigned short, 16> last_intensity;
|
||||
|
||||
std::array<utils::streaming_median<int>, 16> last_x_diff_median5;
|
||||
std::array<utils::streaming_median<int>, 16> last_y_diff_median5;
|
||||
|
||||
std::array<int, 8> last_height;
|
||||
|
||||
models::arithmetic m_changed_values;
|
||||
|
||||
// Arithmetic model has no default constructor, so we store they here as raw pointers
|
||||
//
|
||||
std::array<models::arithmetic*, 2> m_scan_angle_rank;
|
||||
std::array<models::arithmetic*, 256> m_bit_byte;
|
||||
std::array<models::arithmetic*, 256> m_classification;
|
||||
std::array<models::arithmetic*, 256> m_user_data;
|
||||
|
||||
bool have_last_;
|
||||
|
||||
__common() :
|
||||
m_changed_values(64),
|
||||
have_last_(false) {
|
||||
last_intensity.fill(0);
|
||||
|
||||
m_scan_angle_rank[0] = new models::arithmetic(256);
|
||||
m_scan_angle_rank[1] = new models::arithmetic(256);
|
||||
|
||||
last_height.fill(0);
|
||||
|
||||
for (int i = 0 ; i < 256 ; i ++) {
|
||||
m_bit_byte[i] = new models::arithmetic(256);
|
||||
m_classification[i] = new models::arithmetic(256);
|
||||
m_user_data[i] = new models::arithmetic(256);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~__common() {
|
||||
delete m_scan_angle_rank[0];
|
||||
delete m_scan_angle_rank[1];
|
||||
|
||||
for (int i = 0 ; i < 256 ; i ++) {
|
||||
delete m_bit_byte[i];
|
||||
delete m_classification[i];
|
||||
delete m_user_data[i];
|
||||
}
|
||||
}
|
||||
} common_;
|
||||
|
||||
// These compressors are specific to a compressor usage, so we keep them separate here
|
||||
struct __compressors {
|
||||
compressors::integer ic_intensity;
|
||||
compressors::integer ic_point_source_ID;
|
||||
compressors::integer ic_dx;
|
||||
compressors::integer ic_dy;
|
||||
compressors::integer ic_z;
|
||||
|
||||
__compressors() :
|
||||
ic_intensity(16, 4),
|
||||
ic_point_source_ID(16),
|
||||
ic_dx(32, 2),
|
||||
ic_dy(32, 22),
|
||||
ic_z(32, 20) { }
|
||||
|
||||
void init() {
|
||||
ic_intensity.init();
|
||||
ic_point_source_ID.init();
|
||||
ic_dx.init();
|
||||
ic_dy.init();
|
||||
ic_z.init();
|
||||
}
|
||||
} compressors_;
|
||||
|
||||
struct __decompressors {
|
||||
decompressors::integer ic_intensity;
|
||||
decompressors::integer ic_point_source_ID;
|
||||
decompressors::integer ic_dx;
|
||||
decompressors::integer ic_dy;
|
||||
decompressors::integer ic_z;
|
||||
|
||||
__decompressors() :
|
||||
ic_intensity(16, 4),
|
||||
ic_point_source_ID(16),
|
||||
ic_dx(32, 2),
|
||||
ic_dy(32, 22),
|
||||
ic_z(32, 20) { }
|
||||
|
||||
void init() {
|
||||
ic_intensity.init();
|
||||
ic_point_source_ID.init();
|
||||
ic_dx.init();
|
||||
ic_dy.init();
|
||||
ic_z.init();
|
||||
}
|
||||
} decompressors_;
|
||||
|
||||
bool compressor_inited_;
|
||||
bool decompressors_inited_;
|
||||
};
|
||||
}
|
||||
}
|
||||
269
external/laz-perf/detail/field_rgb.hpp
vendored
Normal file
269
external/laz-perf/detail/field_rgb.hpp
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: field_rgb.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#error Cannot directly include this file, this is a part of las.hpp
|
||||
#endif
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
// Teach packers how to pack and unpack rgb
|
||||
//
|
||||
template<>
|
||||
struct packers<las::rgb> {
|
||||
inline static las::rgb unpack(const char *in) {
|
||||
return las::rgb(packers<uint16_t>::unpack(in),
|
||||
packers<uint16_t>::unpack(in+2),
|
||||
packers<uint16_t>::unpack(in+4));
|
||||
|
||||
}
|
||||
|
||||
inline static void pack(const las::rgb& c, char *buffer) {
|
||||
packers<uint16_t>::pack(c.r, buffer);
|
||||
packers<uint16_t>::pack(c.g, buffer+2);
|
||||
packers<uint16_t>::pack(c.b, buffer+4);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
static inline unsigned int color_diff_bits(const las::rgb& this_val, const las::rgb& last) {
|
||||
|
||||
const las::rgb& a = last,
|
||||
b = this_val;
|
||||
|
||||
#define __flag_diff(x,y,f) ((((x) ^ (y)) & (f)) != 0)
|
||||
unsigned int r =
|
||||
(__flag_diff(a.r, b.r, 0x00FF) << 0) |
|
||||
(__flag_diff(a.r, b.r, 0xFF00) << 1) |
|
||||
(__flag_diff(a.g, b.g, 0x00FF) << 2) |
|
||||
(__flag_diff(a.g, b.g, 0xFF00) << 3) |
|
||||
(__flag_diff(a.b, b.b, 0x00FF) << 4) |
|
||||
(__flag_diff(a.b, b.b, 0xFF00) << 5) |
|
||||
(__flag_diff(b.r, b.g, 0x00FF) |
|
||||
__flag_diff(b.r, b.b, 0x00FF) |
|
||||
__flag_diff(b.r, b.g, 0xFF00) |
|
||||
__flag_diff(b.r, b.b, 0xFF00)) << 6;
|
||||
#undef __flag_diff
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure how to compress and decompress GPS time fields
|
||||
//
|
||||
template<>
|
||||
struct field<las::rgb> {
|
||||
typedef las::rgb type;
|
||||
|
||||
field():
|
||||
have_last_(false),
|
||||
last(),
|
||||
m_byte_used(128),
|
||||
m_rgb_diff_0(256),
|
||||
m_rgb_diff_1(256),
|
||||
m_rgb_diff_2(256),
|
||||
m_rgb_diff_3(256),
|
||||
m_rgb_diff_4(256),
|
||||
m_rgb_diff_5(256) {}
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& enc, const char *buf)
|
||||
{
|
||||
las::rgb this_val;
|
||||
|
||||
this_val = packers<las::rgb>::unpack(buf);
|
||||
if (!have_last_) {
|
||||
// don't have the first data yet, just push it to our
|
||||
// have last stuff and move on
|
||||
have_last_ = true;
|
||||
last = this_val;
|
||||
|
||||
enc.getOutStream().putBytes((const unsigned char*)buf,
|
||||
sizeof(las::rgb));
|
||||
|
||||
return buf + sizeof(las::rgb);
|
||||
}
|
||||
|
||||
// compress color
|
||||
int diff_l = 0;
|
||||
int diff_h = 0;
|
||||
int corr;
|
||||
|
||||
unsigned int sym = detail::color_diff_bits(this_val, last);
|
||||
|
||||
enc.encodeSymbol(m_byte_used, sym);
|
||||
|
||||
// high and low R
|
||||
if (sym & (1 << 0)) {
|
||||
diff_l = (this_val.r & 0xFF) - (last.r & 0xFF);
|
||||
enc.encodeSymbol(m_rgb_diff_0, U8_FOLD(diff_l));
|
||||
}
|
||||
if (sym & (1 << 1)) {
|
||||
diff_h = static_cast<int>(this_val.r >> 8) - (last.r >> 8);
|
||||
enc.encodeSymbol(m_rgb_diff_1, U8_FOLD(diff_h));
|
||||
}
|
||||
|
||||
if (sym & (1 << 6)) {
|
||||
if (sym & (1 << 2)) {
|
||||
corr = static_cast<int>(this_val.g & 0xFF) - U8_CLAMP(diff_l + (last.g & 0xFF));
|
||||
enc.encodeSymbol(m_rgb_diff_2, U8_FOLD(corr));
|
||||
}
|
||||
|
||||
if (sym & (1 << 4)) {
|
||||
diff_l = (diff_l + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2;
|
||||
corr = static_cast<int>(this_val.b & 0xFF) - U8_CLAMP(diff_l + (last.b & 0xFF));
|
||||
enc.encodeSymbol(m_rgb_diff_4, U8_FOLD(corr));
|
||||
}
|
||||
|
||||
if (sym & (1 << 3)) {
|
||||
corr = static_cast<int>(this_val.g >> 8) - U8_CLAMP(diff_h + (last.g >> 8));
|
||||
enc.encodeSymbol(m_rgb_diff_3, U8_FOLD(corr));
|
||||
}
|
||||
|
||||
if (sym & (1 << 5)) {
|
||||
diff_h = (diff_h + ((this_val.g >> 8)) - (last.g >> 8)) / 2;
|
||||
corr = static_cast<int>(this_val.b >> 8) - U8_CLAMP(diff_h + (last.b >> 8));
|
||||
enc.encodeSymbol(m_rgb_diff_5, U8_FOLD(corr));
|
||||
}
|
||||
}
|
||||
|
||||
last = this_val;
|
||||
return buf + sizeof(las::rgb);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& dec, char *buf)
|
||||
{
|
||||
if (!have_last_) {
|
||||
// don't have the first data yet, read the whole point out of the stream
|
||||
have_last_ = true;
|
||||
|
||||
dec.getInStream().getBytes((unsigned char*)buf,
|
||||
sizeof(las::rgb));
|
||||
|
||||
last = packers<las::rgb>::unpack(buf);
|
||||
return buf + sizeof(las::rgb);
|
||||
}
|
||||
|
||||
unsigned char corr;
|
||||
int diff = 0;
|
||||
unsigned int sym = dec.decodeSymbol(m_byte_used);
|
||||
|
||||
las::rgb this_val;
|
||||
|
||||
if (sym & (1 << 0)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_0));
|
||||
this_val.r = static_cast<unsigned short>(U8_FOLD(corr + (last.r & 0xFF)));
|
||||
}
|
||||
else {
|
||||
this_val.r = last.r & 0xFF;
|
||||
}
|
||||
|
||||
if (sym & (1 << 1)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_1));
|
||||
this_val.r |= (static_cast<unsigned short>(U8_FOLD(corr + (last.r >> 8))) << 8);
|
||||
}
|
||||
else {
|
||||
this_val.r |= last.r & 0xFF00;
|
||||
}
|
||||
|
||||
if (sym & (1 << 6)) {
|
||||
diff = (this_val.r & 0xFF) - (last.r & 0xFF);
|
||||
|
||||
if (sym & (1 << 2)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_2));
|
||||
this_val.g = static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.g & 0xFF))));
|
||||
}
|
||||
else {
|
||||
this_val.g = last.g & 0xFF;
|
||||
}
|
||||
|
||||
if (sym & (1 << 4)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_4));
|
||||
diff = (diff + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2;
|
||||
this_val.b = static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff+(last.b & 0xFF))));
|
||||
}
|
||||
else {
|
||||
this_val.b = last.b & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
diff = (this_val.r >> 8) - (last.r >> 8);
|
||||
if (sym & (1 << 3)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_3));
|
||||
this_val.g |= static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.g >> 8)))) << 8;
|
||||
}
|
||||
else {
|
||||
this_val.g |= last.g & 0xFF00;
|
||||
}
|
||||
|
||||
|
||||
if (sym & (1 << 5)) {
|
||||
corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_5));
|
||||
diff = (diff + (this_val.g >> 8) - (last.g >> 8)) / 2;
|
||||
|
||||
this_val.b |= static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.b >> 8)))) << 8;
|
||||
}
|
||||
else {
|
||||
this_val.b |= (last.b & 0xFF00);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this_val.g = this_val.r;
|
||||
this_val.b = this_val.r;
|
||||
}
|
||||
|
||||
last = this_val;
|
||||
packers<las::rgb>::pack(last, buf);
|
||||
return buf + sizeof(las::rgb);
|
||||
}
|
||||
|
||||
// All the things we need to compress a point, group them into structs
|
||||
// so we don't have too many names flying around
|
||||
|
||||
// Common parts for both a compressor and decompressor go here
|
||||
bool have_last_;
|
||||
las::rgb last;
|
||||
|
||||
models::arithmetic m_byte_used;
|
||||
models::arithmetic m_rgb_diff_0,
|
||||
m_rgb_diff_1,
|
||||
m_rgb_diff_2,
|
||||
m_rgb_diff_3,
|
||||
m_rgb_diff_4,
|
||||
m_rgb_diff_5;
|
||||
};
|
||||
}
|
||||
}
|
||||
228
external/laz-perf/detail/field_xyz.hpp
vendored
Normal file
228
external/laz-perf/detail/field_xyz.hpp
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: field_xyz.hpp
|
||||
|
||||
CONTENTS:
|
||||
XYZ fields encoder
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#error Cannot directly include this file, this is a part of las.hpp
|
||||
#endif
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
// Teach packers how to pack unpack the xyz struct
|
||||
//
|
||||
template<>
|
||||
struct packers<las::xyz> {
|
||||
inline static las::xyz unpack(const char *in) {
|
||||
// blind casting will cause problems for ARM and Emscripten targets
|
||||
//
|
||||
las::xyz p;
|
||||
|
||||
p.x = packers<int>::unpack(in); in += sizeof(int);
|
||||
p.y = packers<int>::unpack(in); in += sizeof(int);
|
||||
p.z = packers<int>::unpack(in);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
inline static void pack(const las::xyz& p, char *buffer) {
|
||||
packers<int>::pack(p.x, buffer); buffer += sizeof(int);
|
||||
packers<int>::pack(p.y, buffer); buffer += sizeof(int);
|
||||
packers<int>::pack(p.z, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
// specialize field to compress point 10
|
||||
//
|
||||
template<>
|
||||
struct field<las::xyz> {
|
||||
typedef las::xyz type;
|
||||
|
||||
field() : compressor_inited_(false), decompressors_inited_(false) { }
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& enc, const char *buf)
|
||||
{
|
||||
if (!compressor_inited_) {
|
||||
compressors_.init();
|
||||
compressor_inited_ = true;
|
||||
}
|
||||
|
||||
las::xyz this_val = packers<las::xyz>::unpack(buf);
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, just push it to our have last stuff and move on
|
||||
common_.have_last_ = true;
|
||||
common_.last_ = this_val;
|
||||
|
||||
enc.getOutStream().putBytes((const unsigned char*)buf,
|
||||
sizeof(las::xyz));
|
||||
|
||||
// we are done here
|
||||
return buf + sizeof(las::xyz);
|
||||
}
|
||||
|
||||
unsigned int k_bits;
|
||||
int median, diff;
|
||||
|
||||
// compress x coordinate
|
||||
median = common_.last_x_diff_median5.get();
|
||||
diff = this_val.x - common_.last_.x;
|
||||
compressors_.ic_dx.compress(enc, median, diff, 0);
|
||||
common_.last_x_diff_median5.add(diff);
|
||||
|
||||
// compress y coordinate
|
||||
k_bits = compressors_.ic_dx.getK();
|
||||
median = common_.last_y_diff_median5.get();
|
||||
diff = this_val.y - common_.last_.y;
|
||||
compressors_.ic_dy.compress(enc, median, diff, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
|
||||
common_.last_y_diff_median5.add(diff);
|
||||
|
||||
// compress z coordinate
|
||||
k_bits = (compressors_.ic_dx.getK() + compressors_.ic_dy.getK()) / 2;
|
||||
compressors_.ic_z.compress(enc, common_.last_height, this_val.z, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
|
||||
common_.last_height = this_val.z;
|
||||
|
||||
common_.last_ = this_val;
|
||||
return buf + sizeof(las::xyz);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& dec, char *buf)
|
||||
{
|
||||
if (!decompressors_inited_) {
|
||||
decompressors_.init();
|
||||
decompressors_inited_ = true;
|
||||
}
|
||||
|
||||
if (!common_.have_last_) {
|
||||
// don't have the first data yet, read the whole point out of the stream
|
||||
common_.have_last_ = true;
|
||||
|
||||
dec.getInStream().getBytes((unsigned char*)buf,
|
||||
sizeof(las::xyz));
|
||||
|
||||
// decode this value
|
||||
common_.last_ = packers<las::xyz>::unpack(buf);
|
||||
|
||||
// we are done here
|
||||
return buf + sizeof(las::xyz);
|
||||
}
|
||||
|
||||
unsigned int k_bits;
|
||||
int median, diff;
|
||||
|
||||
// decompress x coordinate
|
||||
median = common_.last_x_diff_median5.get();
|
||||
|
||||
diff = decompressors_.ic_dx.decompress(dec, median, 0);
|
||||
common_.last_.x += diff;
|
||||
common_.last_x_diff_median5.add(diff);
|
||||
|
||||
// decompress y coordinate
|
||||
median = common_.last_y_diff_median5.get();
|
||||
k_bits = decompressors_.ic_dx.getK();
|
||||
diff = decompressors_.ic_dy.decompress(dec, median, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
|
||||
common_.last_.y += diff;
|
||||
common_.last_y_diff_median5.add(diff);
|
||||
|
||||
// decompress z coordinate
|
||||
k_bits = (decompressors_.ic_dx.getK() + decompressors_.ic_dy.getK()) / 2;
|
||||
common_.last_.z = decompressors_.ic_z.decompress(dec, common_.last_height, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
|
||||
common_.last_height = common_.last_.z;
|
||||
|
||||
packers<las::xyz>::pack(common_.last_, buf);
|
||||
return buf + sizeof(las::xyz);
|
||||
}
|
||||
|
||||
// All the things we need to compress a point, group them into structs
|
||||
// so we don't have too many names flying around
|
||||
|
||||
// Common parts for both a compressor and decompressor go here
|
||||
struct __common {
|
||||
type last_;
|
||||
|
||||
utils::streaming_median<int> last_x_diff_median5;
|
||||
utils::streaming_median<int> last_y_diff_median5;
|
||||
|
||||
int last_height;
|
||||
bool have_last_;
|
||||
|
||||
__common() :
|
||||
last_height(0),
|
||||
have_last_(false) {
|
||||
}
|
||||
|
||||
~__common() {
|
||||
}
|
||||
} common_;
|
||||
|
||||
// These compressors are specific to a compressor usage, so we keep them separate here
|
||||
struct __compressors {
|
||||
compressors::integer ic_dx;
|
||||
compressors::integer ic_dy;
|
||||
compressors::integer ic_z;
|
||||
|
||||
__compressors() :
|
||||
ic_dx(32, 2),
|
||||
ic_dy(32, 22),
|
||||
ic_z(32, 20) { }
|
||||
|
||||
void init() {
|
||||
ic_dx.init();
|
||||
ic_dy.init();
|
||||
ic_z.init();
|
||||
}
|
||||
} compressors_;
|
||||
|
||||
struct __decompressors {
|
||||
decompressors::integer ic_dx;
|
||||
decompressors::integer ic_dy;
|
||||
decompressors::integer ic_z;
|
||||
|
||||
__decompressors() :
|
||||
ic_dx(32, 2),
|
||||
ic_dy(32, 22),
|
||||
ic_z(32, 20) { }
|
||||
|
||||
void init() {
|
||||
ic_dx.init();
|
||||
ic_dy.init();
|
||||
ic_z.init();
|
||||
}
|
||||
} decompressors_;
|
||||
|
||||
bool compressor_inited_;
|
||||
bool decompressors_inited_;
|
||||
};
|
||||
}
|
||||
}
|
||||
329
external/laz-perf/encoder.hpp
vendored
Normal file
329
external/laz-perf/encoder.hpp
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: encoder.hpp
|
||||
|
||||
CONTENTS:
|
||||
Encoder stuff
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// **************************** -
|
||||
// ARITHMETIC CODING EXAMPLES -
|
||||
// **************************** -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// Fast arithmetic coding implementation -
|
||||
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// Version 1.00 - April 25, 2004 -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// WARNING -
|
||||
// ========= -
|
||||
// -
|
||||
// The only purpose of this program is to demonstrate the basic principles -
|
||||
// of arithmetic coding. The original version of this code can be found in -
|
||||
// Digital Signal Compression: Principles and Practice -
|
||||
// (Cambridge University Press, 2011, ISBN: 9780511984655) -
|
||||
// -
|
||||
// Copyright (c) 2019 by Amir Said (said@ieee.org) & -
|
||||
// William A. Pearlman (pearlw@ecse.rpi.edu) -
|
||||
// -
|
||||
// Redistribution and use in source and binary forms, with or without -
|
||||
// modification, are permitted provided that the following conditions are -
|
||||
// met: -
|
||||
// -
|
||||
// 1. Redistributions of source code must retain the above copyright notice, -
|
||||
// this list of conditions and the following disclaimer. -
|
||||
// -
|
||||
// 2. Redistributions in binary form must reproduce the above copyright -
|
||||
// notice, this list of conditions and the following disclaimer in the -
|
||||
// documentation and/or other materials provided with the distribution. -
|
||||
// -
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -
|
||||
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -
|
||||
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER -
|
||||
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// -
|
||||
// A description of the arithmetic coding method used here is available in -
|
||||
// -
|
||||
// Lossless Compression Handbook, ed. K. Sayood -
|
||||
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
|
||||
// -
|
||||
// A. Said, Introduction to Arithetic Coding Theory and Practice -
|
||||
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
|
||||
// -
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
#ifndef __encoder_hpp__
|
||||
#define __encoder_hpp__
|
||||
|
||||
#include "common/types.hpp"
|
||||
|
||||
namespace laszip {
|
||||
namespace encoders {
|
||||
template<
|
||||
typename TOutStream
|
||||
>
|
||||
struct arithmetic {
|
||||
arithmetic(TOutStream& out) :
|
||||
outstream(out) {
|
||||
outbuffer = new U8[2*AC_BUFFER_SIZE];
|
||||
endbuffer = outbuffer + 2 * AC_BUFFER_SIZE;
|
||||
|
||||
base = 0;
|
||||
length = AC__MaxLength;
|
||||
outbyte = outbuffer;
|
||||
endbyte = endbuffer;
|
||||
}
|
||||
|
||||
~arithmetic() {
|
||||
delete [] outbuffer;
|
||||
}
|
||||
|
||||
void done() {
|
||||
U32 init_base = base; // done encoding: set final data bytes
|
||||
BOOL another_byte = TRUE;
|
||||
|
||||
if (length > 2 * AC__MinLength) {
|
||||
base += AC__MinLength; // base offset
|
||||
length = AC__MinLength >> 1; // set new length for 1 more byte
|
||||
}
|
||||
else {
|
||||
base += AC__MinLength >> 1; // base offset
|
||||
length = AC__MinLength >> 9; // set new length for 2 more bytes
|
||||
another_byte = FALSE;
|
||||
}
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
renorm_enc_interval(); // renormalization = output last bytes
|
||||
|
||||
if (endbyte != endbuffer)
|
||||
{
|
||||
assert(outbyte < outbuffer + AC_BUFFER_SIZE);
|
||||
outstream.putBytes(outbuffer + AC_BUFFER_SIZE, AC_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
I64 buffer_size = outbyte - outbuffer;
|
||||
if (buffer_size) outstream.putBytes(outbuffer, (U32)buffer_size);
|
||||
|
||||
// write two or three zero bytes to be in sync with the decoder's byte reads
|
||||
outstream.putByte(0);
|
||||
outstream.putByte(0);
|
||||
|
||||
if (another_byte) outstream.putByte(0);
|
||||
}
|
||||
|
||||
/* Encode a bit with modelling */
|
||||
template<typename EntropyModel>
|
||||
void encodeBit(EntropyModel& m, U32 sym) {
|
||||
assert(sym <= 1);
|
||||
|
||||
U32 x = m.bit_0_prob * (length >> BM__LengthShift); // product l x p0
|
||||
// update interval
|
||||
if (sym == 0) {
|
||||
length = x;
|
||||
++m.bit_0_count;
|
||||
}
|
||||
else {
|
||||
U32 init_base = base;
|
||||
base += x;
|
||||
length -= x;
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
}
|
||||
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
if (--m.bits_until_update == 0) m.update(); // periodic model update
|
||||
}
|
||||
|
||||
/* Encode a symbol with modelling */
|
||||
template <typename EntropyModel>
|
||||
void encodeSymbol(EntropyModel& m, U32 sym) {
|
||||
assert(sym <= m.last_symbol);
|
||||
|
||||
U32 x, init_base = base;
|
||||
// compute products
|
||||
if (sym == m.last_symbol) {
|
||||
x = m.distribution[sym] * (length >> DM__LengthShift);
|
||||
base += x; // update interval
|
||||
length -= x; // no product needed
|
||||
}
|
||||
else {
|
||||
x = m.distribution[sym] * (length >>= DM__LengthShift);
|
||||
base += x; // update interval
|
||||
length = m.distribution[sym+1] * length - x;
|
||||
}
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
|
||||
++m.symbol_count[sym];
|
||||
if (--m.symbols_until_update == 0) m.update(); // periodic model update
|
||||
}
|
||||
|
||||
/* Encode a bit without modelling */
|
||||
void writeBit(U32 sym) {
|
||||
assert(sym < 2);
|
||||
|
||||
U32 init_base = base;
|
||||
base += sym * (length >>= 1); // new interval base and length
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
}
|
||||
|
||||
void writeBits(U32 bits, U32 sym) {
|
||||
assert(bits && (bits <= 32) && (sym < (1u<<bits)));
|
||||
|
||||
if (bits > 19)
|
||||
{
|
||||
writeShort(sym&U16_MAX);
|
||||
sym = sym >> 16;
|
||||
bits = bits - 16;
|
||||
}
|
||||
|
||||
U32 init_base = base;
|
||||
base += sym * (length >>= bits); // new interval base and length
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
}
|
||||
|
||||
void writeByte(U8 sym) {
|
||||
U32 init_base = base;
|
||||
base += (U32)(sym) * (length >>= 8); // new interval base and length
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
}
|
||||
|
||||
void writeShort(U16 sym) {
|
||||
U32 init_base = base;
|
||||
base += (U32)(sym) * (length >>= 16); // new interval base and length
|
||||
|
||||
if (init_base > base) propagate_carry(); // overflow = carry
|
||||
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
|
||||
}
|
||||
|
||||
void writeInt(U32 sym) {
|
||||
writeShort((U16)(sym & 0xFFFF)); // lower 16 bits
|
||||
writeShort((U16)(sym >> 16)); // UPPER 16 bits
|
||||
}
|
||||
|
||||
void writeFloat(F32 sym) /* danger in float reinterpretation */ {
|
||||
U32I32F32 u32i32f32;
|
||||
u32i32f32.f32 = sym;
|
||||
|
||||
writeInt(u32i32f32.u32);
|
||||
}
|
||||
|
||||
void writeInt64(U64 sym) {
|
||||
writeInt((U32)(sym & 0xFFFFFFFF)); // lower 32 bits
|
||||
writeInt((U32)(sym >> 32)); // UPPER 32 bits
|
||||
}
|
||||
|
||||
void writeDouble(F64 sym) /* danger in float reinterpretation */ {
|
||||
U64I64F64 u64i64f64;
|
||||
u64i64f64.f64 = sym;
|
||||
|
||||
writeInt64(u64i64f64.u64);
|
||||
}
|
||||
|
||||
TOutStream& getOutStream() {
|
||||
return outstream;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void propagate_carry() {
|
||||
U8 * b;
|
||||
if (outbyte == outbuffer)
|
||||
b = endbuffer - 1;
|
||||
else
|
||||
b = outbyte - 1;
|
||||
while (*b== 0xFFU)
|
||||
{
|
||||
*b = 0;
|
||||
if (b == outbuffer)
|
||||
b= endbuffer - 1;
|
||||
else
|
||||
b--;
|
||||
assert(outbuffer <= b);
|
||||
assert(b < endbuffer);
|
||||
assert(outbyte < endbuffer);
|
||||
}
|
||||
++*b;
|
||||
}
|
||||
|
||||
void renorm_enc_interval() {
|
||||
do { // output and discard top byte
|
||||
assert(outbuffer <= outbyte);
|
||||
assert(outbyte < endbuffer);
|
||||
assert(outbyte < endbyte);
|
||||
*outbyte++ = (U8)(base >> 24);
|
||||
if (outbyte == endbyte) manage_outbuffer();
|
||||
base <<= 8;
|
||||
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
|
||||
}
|
||||
|
||||
void manage_outbuffer() {
|
||||
if (outbyte == endbuffer) outbyte = outbuffer;
|
||||
outstream.putBytes(outbyte, AC_BUFFER_SIZE);
|
||||
endbyte = outbyte + AC_BUFFER_SIZE;
|
||||
assert(endbyte > outbyte);
|
||||
assert(outbyte < endbuffer);
|
||||
}
|
||||
|
||||
arithmetic<TOutStream>(const arithmetic<TOutStream>&) = delete;
|
||||
arithmetic<TOutStream>& operator = (const arithmetic<TOutStream>&) = delete;
|
||||
|
||||
private:
|
||||
U8* outbuffer;
|
||||
U8* endbuffer;
|
||||
U8* outbyte;
|
||||
U8* endbyte;
|
||||
U32 base, value, length;
|
||||
|
||||
TOutStream& outstream;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __encoder_hpp__
|
||||
66
external/laz-perf/excepts.hpp
vendored
Normal file
66
external/laz-perf/excepts.hpp
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: excepts.hpp
|
||||
|
||||
CONTENTS:
|
||||
Exception types
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __excepts_hpp__
|
||||
#define __excepts_hpp__
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace laszip {
|
||||
#define __make_exception_class(name,msg) \
|
||||
struct name : public std::runtime_error { name() : std::runtime_error(msg) {} }
|
||||
|
||||
__make_exception_class(file_not_found, "The specified file was not found");
|
||||
__make_exception_class(invalid_magic, "File magic is not valid");
|
||||
__make_exception_class(old_style_compression, "The file seems to have old style compression which is not supported");
|
||||
__make_exception_class(not_compressed, "The file doesn't seem to be compressed");
|
||||
|
||||
__make_exception_class(invalid_header_request, "Cannot request for headers while the file state in invalid");
|
||||
|
||||
__make_exception_class(no_laszip_vlr, "No LASzip VLR was found in the VLRs section");
|
||||
__make_exception_class(laszip_format_unsupported, "Only LASzip POINTWISE CHUNKED decompressor is supported");
|
||||
|
||||
__make_exception_class(chunk_table_read_error, "There was a problem reading the chunk table");
|
||||
__make_exception_class(unknown_chunk_table_format, "The chunk table version number is unknown");
|
||||
|
||||
__make_exception_class(unknown_schema_type, "The LAZ schema is not recognized");
|
||||
__make_exception_class(unknown_record_item_type, "The record item type is not supported");
|
||||
|
||||
__make_exception_class(write_open_failed, "Could not open file for writing");
|
||||
|
||||
__make_exception_class(end_of_file, "Reached End of file");
|
||||
|
||||
|
||||
struct not_supported : public std::runtime_error {
|
||||
not_supported(const char *msg) : std::runtime_error(msg) { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __excepts_hpp__
|
||||
274
external/laz-perf/factory.hpp
vendored
Normal file
274
external/laz-perf/factory.hpp
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: factory.hpp
|
||||
|
||||
CONTENTS:
|
||||
Factory to create dynamic compressors and decompressors
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __factory_hpp__
|
||||
#define __factory_hpp__
|
||||
|
||||
#include "formats.hpp"
|
||||
#include "excepts.hpp"
|
||||
#include "las.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace laszip {
|
||||
namespace factory {
|
||||
struct record_item {
|
||||
enum {
|
||||
BYTE = 0,
|
||||
POINT10 = 6,
|
||||
GPSTIME = 7,
|
||||
RGB12 = 8
|
||||
};
|
||||
|
||||
int type, size, version;
|
||||
record_item(int t, int s, int v) :
|
||||
type(t), size(s), version(v) {}
|
||||
|
||||
bool operator == (const record_item& other) const
|
||||
{
|
||||
return (type == other.type &&
|
||||
version == other.version &&
|
||||
size == other.size);
|
||||
}
|
||||
|
||||
bool operator != (const record_item& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static const record_item& point()
|
||||
{
|
||||
static record_item item(POINT10, 20, 2);
|
||||
return item;
|
||||
}
|
||||
|
||||
static const record_item& gpstime()
|
||||
{
|
||||
static record_item item(GPSTIME, 8, 2);
|
||||
return item;
|
||||
}
|
||||
|
||||
static const record_item& rgb()
|
||||
{
|
||||
static record_item item(RGB12, 6, 2);
|
||||
return item;
|
||||
}
|
||||
|
||||
static const record_item eb(size_t count)
|
||||
{
|
||||
return record_item(BYTE, count, 2);
|
||||
}
|
||||
};
|
||||
|
||||
struct record_schema {
|
||||
record_schema() : records() { }
|
||||
|
||||
void push(const record_item& item) {
|
||||
records.push_back(item);
|
||||
}
|
||||
|
||||
// This is backward compatible support. Remove.
|
||||
#ifdef _WIN32
|
||||
__declspec(deprecated) void push(int t)
|
||||
#else
|
||||
void push(int t) __attribute__ ((deprecated))
|
||||
#endif
|
||||
{
|
||||
if (t == record_item::POINT10)
|
||||
push(record_item::point());
|
||||
else if (t == record_item::GPSTIME)
|
||||
push(record_item::gpstime());
|
||||
else if (t == record_item::RGB12)
|
||||
push(record_item::rgb());
|
||||
else
|
||||
throw unknown_schema_type();
|
||||
}
|
||||
|
||||
record_schema& operator () (const record_item& i) {
|
||||
push(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int size_in_bytes() const {
|
||||
int sum = 0;
|
||||
for (auto i : records)
|
||||
sum += i.size;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
int format() const
|
||||
{
|
||||
size_t count = records.size();
|
||||
if (count == 0)
|
||||
return -1;
|
||||
|
||||
// Ignore extrabytes record that should be at the end.
|
||||
if (extrabytes())
|
||||
count--;
|
||||
|
||||
if (count == 0 || records[0] != record_item::point())
|
||||
return -1;
|
||||
|
||||
if (count == 1)
|
||||
return 0;
|
||||
if (count == 2)
|
||||
{
|
||||
if (records[1] == record_item::gpstime())
|
||||
return 1;
|
||||
else if (records[1] == record_item::rgb())
|
||||
return 2;
|
||||
}
|
||||
if (count == 3 && records[1] == record_item::gpstime() &&
|
||||
records[2] == record_item::rgb())
|
||||
return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t extrabytes() const
|
||||
{
|
||||
if (records.size())
|
||||
{
|
||||
auto ri = records.rbegin();
|
||||
if (ri->type == record_item::BYTE && ri->version == 2)
|
||||
return ri->size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<record_item> records;
|
||||
};
|
||||
|
||||
|
||||
template<typename TDecoder>
|
||||
formats::dynamic_decompressor::ptr build_decompressor(TDecoder& decoder,
|
||||
const record_schema& schema)
|
||||
{
|
||||
using namespace formats;
|
||||
|
||||
int format = schema.format();
|
||||
if (format == -1)
|
||||
throw unknown_schema_type();
|
||||
size_t ebCount = schema.extrabytes();
|
||||
if (ebCount)
|
||||
{
|
||||
auto decompressor = make_dynamic_decompressor(decoder);
|
||||
decompressor->template add_field<las::point10>();
|
||||
if (format == 1 || format == 3)
|
||||
decompressor->template add_field<las::gpstime>();
|
||||
if (format == 2 || format == 3)
|
||||
decompressor->template add_field<las::rgb>();
|
||||
decompressor->add_field(field<las::extrabytes>(ebCount));
|
||||
return decompressor;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0:
|
||||
return make_dynamic_decompressor(decoder,
|
||||
new formats::record_decompressor<
|
||||
field<las::point10>>());
|
||||
case 1:
|
||||
return make_dynamic_decompressor(decoder,
|
||||
new formats::record_decompressor<
|
||||
field<las::point10>,
|
||||
field<las::gpstime>>());
|
||||
case 2:
|
||||
return make_dynamic_decompressor(decoder,
|
||||
new formats::record_decompressor<
|
||||
field<las::point10>,
|
||||
field<las::rgb>>());
|
||||
case 3:
|
||||
return make_dynamic_decompressor(decoder,
|
||||
new formats::record_decompressor<
|
||||
field<las::point10>,
|
||||
field<las::gpstime>,
|
||||
field<las::rgb>>());
|
||||
}
|
||||
}
|
||||
return dynamic_decompressor::ptr();
|
||||
}
|
||||
|
||||
template<typename TEncoder>
|
||||
formats::dynamic_compressor::ptr build_compressor(TEncoder& encoder,
|
||||
const record_schema& schema)
|
||||
{
|
||||
using namespace formats;
|
||||
|
||||
int format = schema.format();
|
||||
if (format == -1)
|
||||
throw unknown_schema_type();
|
||||
size_t ebCount = schema.extrabytes();
|
||||
if (ebCount)
|
||||
{
|
||||
auto compressor = make_dynamic_compressor(encoder);
|
||||
compressor->template add_field<las::point10>();
|
||||
if (format == 1 || format == 3)
|
||||
compressor->template add_field<las::gpstime>();
|
||||
if (format == 2 || format == 3)
|
||||
compressor->template add_field<las::rgb>();
|
||||
compressor->add_field(field<las::extrabytes>(ebCount));
|
||||
return compressor;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0:
|
||||
return make_dynamic_compressor(encoder,
|
||||
new formats::record_compressor<
|
||||
field<las::point10>>());
|
||||
case 1:
|
||||
return make_dynamic_compressor(encoder,
|
||||
new formats::record_compressor<
|
||||
field<las::point10>,
|
||||
field<las::gpstime>>());
|
||||
case 2:
|
||||
return make_dynamic_compressor(encoder,
|
||||
new formats::record_compressor<
|
||||
field<las::point10>,
|
||||
field<las::rgb>>());
|
||||
case 3:
|
||||
return make_dynamic_compressor(encoder,
|
||||
new formats::record_compressor<
|
||||
field<las::point10>,
|
||||
field<las::gpstime>,
|
||||
field<las::rgb>>());
|
||||
}
|
||||
}
|
||||
return dynamic_compressor::ptr();
|
||||
}
|
||||
|
||||
} // namespace factory
|
||||
} // namespace laszip
|
||||
|
||||
#endif // __factory_hpp__
|
||||
546
external/laz-perf/formats.hpp
vendored
Normal file
546
external/laz-perf/formats.hpp
vendored
Normal file
@ -0,0 +1,546 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: formats.hpp
|
||||
|
||||
CONTENTS:
|
||||
Format support
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
#ifndef __formats_hpp__
|
||||
#define __formats_hpp__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include "compressor.hpp"
|
||||
#include "decompressor.hpp"
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
template<typename T>
|
||||
struct packers {
|
||||
static_assert(sizeof(T) == 0,
|
||||
"Only specialized instances of packers should be used");
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<uint32_t> {
|
||||
static unsigned int unpack(const char *in) {
|
||||
uint32_t b1 = in[0],
|
||||
b2 = in[1],
|
||||
b3 = in[2],
|
||||
b4 = in[3];
|
||||
|
||||
return (b4 << 24) |
|
||||
((b3 & 0xFF) << 16) |
|
||||
((b2 & 0xFF) << 8) |
|
||||
(b1 & 0xFF);
|
||||
}
|
||||
|
||||
static void pack(uint32_t v, char *out) {
|
||||
out[3] = (v >> 24) & 0xFF;
|
||||
out[2] = (v >> 16) & 0xFF;
|
||||
out[1] = (v >> 8) & 0xFF;
|
||||
out[0] = v & 0xFF;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<uint16_t> {
|
||||
static unsigned short unpack(const char *in) {
|
||||
uint16_t b1 = in[0],
|
||||
b2 = in[1];
|
||||
|
||||
return (((b2 & 0xFF) << 8) | (b1 & 0xFF));
|
||||
}
|
||||
|
||||
static void pack(uint16_t v, char *out) {
|
||||
out[1] = (v >> 8) & 0xFF;
|
||||
out[0] = v & 0xFF;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<uint8_t> {
|
||||
static unsigned char unpack(const char *in) {
|
||||
return static_cast<uint8_t>(in[0]);
|
||||
}
|
||||
|
||||
static void pack(uint8_t c, char *out) {
|
||||
out[0] = static_cast<char>(c);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<int32_t> {
|
||||
static int unpack(const char *in) {
|
||||
return static_cast<int32_t>(packers<uint32_t>::unpack(in));
|
||||
}
|
||||
|
||||
static void pack(int32_t t, char *out) {
|
||||
packers<uint32_t>::pack(static_cast<uint32_t>(t), out);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<int16_t> {
|
||||
static short unpack(const char *in) {
|
||||
return static_cast<int16_t>(packers<uint16_t>::unpack(in));
|
||||
}
|
||||
|
||||
static void pack(int16_t t, char *out) {
|
||||
packers<uint16_t>::pack(static_cast<uint16_t>(t), out);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct packers<int8_t> {
|
||||
static int8_t unpack(const char *in) {
|
||||
return in[0];
|
||||
}
|
||||
|
||||
static void pack(int8_t t, char *out) {
|
||||
out[0] = t;
|
||||
}
|
||||
};
|
||||
|
||||
// Char is neither signed char nor unsigned char.
|
||||
template<>
|
||||
struct packers<char> {
|
||||
static char unpack(const char *in) {
|
||||
return in[0];
|
||||
}
|
||||
|
||||
static void pack(char t, char *out) {
|
||||
out[0] = t;
|
||||
}
|
||||
};
|
||||
|
||||
/** A simple strategy which returns simple diffs */
|
||||
template<typename T>
|
||||
struct standard_diff_method {
|
||||
standard_diff_method<T>()
|
||||
: have_value_(false) {}
|
||||
|
||||
inline void push(const T& v) {
|
||||
if (!have_value_)
|
||||
have_value_ = true;
|
||||
|
||||
value = v;
|
||||
}
|
||||
|
||||
inline bool have_value() const {
|
||||
return have_value_;
|
||||
}
|
||||
|
||||
T value;
|
||||
bool have_value_;
|
||||
};
|
||||
|
||||
struct base_field {
|
||||
typedef std::shared_ptr<base_field> ptr;
|
||||
|
||||
virtual ~base_field() {
|
||||
// hello 1996
|
||||
}
|
||||
|
||||
virtual const char *compressRaw(const char *buf)
|
||||
{ return buf; }
|
||||
virtual char *decompressRaw(char *buf)
|
||||
{ return buf; }
|
||||
};
|
||||
|
||||
template<typename T, typename TDiffMethod = standard_diff_method<T> >
|
||||
struct field {
|
||||
static_assert(std::is_integral<T>::value,
|
||||
"Default implementation for field only handles integral types");
|
||||
|
||||
typedef T type;
|
||||
|
||||
field() :
|
||||
compressor_(sizeof(T) * 8),
|
||||
decompressor_(sizeof(T) * 8),
|
||||
compressor_inited_(false),
|
||||
decompressor_inited_(false) { }
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& encoder,
|
||||
const char *buf)
|
||||
{
|
||||
T this_val = packers<type>::unpack(buf);
|
||||
if (!compressor_inited_)
|
||||
compressor_.init();
|
||||
|
||||
// Let the differ decide what values we're going to push
|
||||
//
|
||||
if (differ_.have_value()) {
|
||||
compressor_.compress(encoder, differ_.value, this_val, 0);
|
||||
}
|
||||
else {
|
||||
// differ is not ready for us to start encoding values
|
||||
// for us, so we need to write raw into
|
||||
// the outputstream
|
||||
//
|
||||
encoder.getOutStream().putBytes((const unsigned char*)buf,
|
||||
sizeof(T));
|
||||
}
|
||||
differ_.push(this_val);
|
||||
return buf + sizeof(T);
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& decoder, char *buffer)
|
||||
{
|
||||
if (!decompressor_inited_)
|
||||
decompressor_.init();
|
||||
|
||||
T r;
|
||||
if (differ_.have_value()) {
|
||||
r = static_cast<T>(decompressor_.decompress(decoder, differ_.value, 0));
|
||||
packers<T>::pack(r, buffer);
|
||||
}
|
||||
else {
|
||||
// this is probably the first time we're reading stuff, read the record as is
|
||||
decoder.getInStream().getBytes((unsigned char*)buffer, sizeof(T));
|
||||
|
||||
r = packers<T>::unpack(buffer);
|
||||
}
|
||||
buffer += sizeof(T);
|
||||
|
||||
differ_.push(r);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
laszip::compressors::integer compressor_;
|
||||
laszip::decompressors::integer decompressor_;
|
||||
|
||||
bool compressor_inited_, decompressor_inited_;
|
||||
|
||||
TDiffMethod differ_;
|
||||
};
|
||||
|
||||
template<typename... TS>
|
||||
struct record_compressor;
|
||||
|
||||
template<typename... TS>
|
||||
struct record_decompressor;
|
||||
|
||||
template<>
|
||||
struct record_compressor<> {
|
||||
record_compressor() {}
|
||||
template<
|
||||
typename T
|
||||
>
|
||||
inline const char *compressWith(T&, const char *buf)
|
||||
{ return buf; }
|
||||
};
|
||||
|
||||
template<typename T, typename... TS>
|
||||
struct record_compressor<T, TS...> {
|
||||
record_compressor() {}
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
inline const char *compressWith(TEncoder& encoder,
|
||||
const char *buffer)
|
||||
{
|
||||
buffer = field_.compressWith(encoder, buffer);
|
||||
|
||||
// Move on to the next field
|
||||
return next_.compressWith(encoder, buffer);
|
||||
}
|
||||
|
||||
// The field that we handle
|
||||
T field_;
|
||||
|
||||
// Our default strategy right now is to just encode diffs,
|
||||
// but we would employ more advanced techniques soon
|
||||
record_compressor<TS...> next_;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct record_decompressor<> {
|
||||
record_decompressor() : firstDecompress(true) {}
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& decoder, char *buf) {
|
||||
if (firstDecompress) {
|
||||
decoder.readInitBytes();
|
||||
firstDecompress = false;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool firstDecompress;
|
||||
};
|
||||
|
||||
template<typename T, typename... TS>
|
||||
struct record_decompressor<T, TS...> {
|
||||
record_decompressor() {}
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
inline char *decompressWith(TDecoder& decoder, char *buf) {
|
||||
buf = field_.decompressWith(decoder, buf);
|
||||
|
||||
// Move on to the next field
|
||||
return next_.decompressWith(decoder, buf);
|
||||
}
|
||||
|
||||
// The field that we handle
|
||||
T field_;
|
||||
|
||||
// Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
|
||||
record_decompressor<TS...> next_;
|
||||
};
|
||||
|
||||
struct dynamic_compressor {
|
||||
typedef std::shared_ptr<dynamic_compressor> ptr;
|
||||
|
||||
virtual const char *compress(const char *in) = 0;
|
||||
virtual ~dynamic_compressor() {}
|
||||
};
|
||||
|
||||
struct dynamic_decompressor {
|
||||
typedef std::shared_ptr<dynamic_decompressor> ptr;
|
||||
|
||||
virtual char *decompress(char *in) = 0;
|
||||
virtual ~dynamic_decompressor() {}
|
||||
};
|
||||
|
||||
template<
|
||||
typename TEncoder,
|
||||
typename TRecordCompressor
|
||||
>
|
||||
struct dynamic_compressor1 : public dynamic_compressor {
|
||||
dynamic_compressor1(TEncoder& enc, TRecordCompressor* compressor) :
|
||||
enc_(enc), compressor_(compressor) {}
|
||||
|
||||
virtual const char *compress(const char *in) {
|
||||
return compressor_->compressWith(enc_, in);
|
||||
}
|
||||
|
||||
dynamic_compressor1(const dynamic_compressor1<TEncoder , TRecordCompressor>&) = delete;
|
||||
dynamic_compressor1<TEncoder, TRecordCompressor>& operator=(dynamic_compressor1<TEncoder, TRecordCompressor>&) = delete;
|
||||
|
||||
TEncoder& enc_;
|
||||
std::unique_ptr<TRecordCompressor> compressor_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename TEncoder,
|
||||
typename TRecordCompressor
|
||||
>
|
||||
static dynamic_compressor::ptr make_dynamic_compressor(TEncoder& encoder, TRecordCompressor* compressor) {
|
||||
return dynamic_compressor::ptr(
|
||||
new dynamic_compressor1<TEncoder, TRecordCompressor>(encoder, compressor));
|
||||
}
|
||||
|
||||
template<
|
||||
typename TDecoder,
|
||||
typename TRecordDecompressor
|
||||
>
|
||||
struct dynamic_decompressor1 : public dynamic_decompressor {
|
||||
dynamic_decompressor1(TDecoder& dec, TRecordDecompressor* decompressor) :
|
||||
dec_(dec), decompressor_(decompressor) {}
|
||||
|
||||
virtual char *decompress(char *in)
|
||||
{
|
||||
return decompressor_->decompressWith(dec_, in);
|
||||
}
|
||||
|
||||
dynamic_decompressor1(const dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
|
||||
dynamic_decompressor1<TDecoder, TRecordDecompressor>& operator=(dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
|
||||
|
||||
TDecoder& dec_;
|
||||
std::unique_ptr<TRecordDecompressor> decompressor_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename TDecoder,
|
||||
typename TRecordDecompressor
|
||||
>
|
||||
static dynamic_decompressor::ptr make_dynamic_decompressor(TDecoder& decoder, TRecordDecompressor* decompressor) {
|
||||
return dynamic_decompressor::ptr(
|
||||
new dynamic_decompressor1<TDecoder, TRecordDecompressor>(decoder, decompressor));
|
||||
}
|
||||
|
||||
// type-erasure stuff for fields
|
||||
template<
|
||||
typename TEncoderDecoder,
|
||||
typename TField
|
||||
>
|
||||
struct dynamic_compressor_field : base_field {
|
||||
dynamic_compressor_field(TEncoderDecoder& encdec) :
|
||||
encdec_(encdec), field_()
|
||||
{}
|
||||
|
||||
dynamic_compressor_field(TEncoderDecoder& encdec, const TField& f) :
|
||||
encdec_(encdec), field_(f)
|
||||
{}
|
||||
|
||||
virtual const char *compressRaw(const char *in) {
|
||||
return field_.compressWith(encdec_, in);
|
||||
}
|
||||
|
||||
TEncoderDecoder& encdec_;
|
||||
TField field_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename TEncoderDecoder,
|
||||
typename TField
|
||||
>
|
||||
struct dynamic_decompressor_field : base_field {
|
||||
dynamic_decompressor_field(TEncoderDecoder& encdec) :
|
||||
encdec_(encdec), field_()
|
||||
{}
|
||||
|
||||
dynamic_decompressor_field(TEncoderDecoder& encdec,
|
||||
const TField& f) : encdec_(encdec), field_(f)
|
||||
{}
|
||||
|
||||
virtual char *decompressRaw(char *buf) {
|
||||
return field_.decompressWith(encdec_, buf);
|
||||
}
|
||||
|
||||
TEncoderDecoder& encdec_;
|
||||
TField field_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
struct dynamic_field_compressor: dynamic_compressor {
|
||||
typedef dynamic_field_compressor<TEncoder> this_type;
|
||||
typedef std::shared_ptr<this_type> ptr;
|
||||
|
||||
dynamic_field_compressor(TEncoder& encoder) :
|
||||
enc_(encoder), fields_()
|
||||
{}
|
||||
|
||||
template<typename TFieldType>
|
||||
void add_field()
|
||||
{
|
||||
using TField = field<TFieldType>;
|
||||
|
||||
fields_.push_back(base_field::ptr(new
|
||||
dynamic_compressor_field<TEncoder, TField>(enc_)));
|
||||
}
|
||||
|
||||
template<typename TField>
|
||||
void add_field(const TField& f)
|
||||
{
|
||||
fields_.push_back(base_field::ptr(new
|
||||
dynamic_compressor_field<TEncoder, TField>(enc_, f)));
|
||||
}
|
||||
|
||||
virtual const char *compress(const char *in)
|
||||
{
|
||||
for (auto f: fields_)
|
||||
in = f->compressRaw(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
TEncoder& enc_;
|
||||
std::vector<base_field::ptr> fields_;
|
||||
};
|
||||
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
struct dynamic_field_decompressor : dynamic_decompressor {
|
||||
typedef dynamic_field_decompressor<TDecoder> this_type;
|
||||
typedef std::shared_ptr<this_type> ptr;
|
||||
|
||||
dynamic_field_decompressor(TDecoder& decoder) :
|
||||
dec_(decoder), fields_(), first_decomp_(true)
|
||||
{}
|
||||
|
||||
template<typename TFieldType>
|
||||
void add_field()
|
||||
{
|
||||
using TField = field<TFieldType>;
|
||||
|
||||
fields_.push_back(base_field::ptr(new
|
||||
dynamic_decompressor_field<TDecoder, TField>(dec_)));
|
||||
}
|
||||
|
||||
template<typename TField>
|
||||
void add_field(const TField& f)
|
||||
{
|
||||
fields_.push_back(base_field::ptr(new
|
||||
dynamic_decompressor_field<TDecoder, TField>(dec_, f)));
|
||||
}
|
||||
|
||||
|
||||
virtual char *decompress(char *out)
|
||||
{
|
||||
for (auto f: fields_)
|
||||
out = f->decompressRaw(out);
|
||||
|
||||
// the decoder needs to be told that it should read the
|
||||
// init bytes after the first record has been read
|
||||
//
|
||||
if (first_decomp_) {
|
||||
first_decomp_ = false;
|
||||
dec_.readInitBytes();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
TDecoder& dec_;
|
||||
std::vector<base_field::ptr> fields_;
|
||||
bool first_decomp_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename TEncoder
|
||||
>
|
||||
static typename dynamic_field_compressor<TEncoder>::ptr make_dynamic_compressor(TEncoder& encoder) {
|
||||
typedef typename dynamic_field_compressor<TEncoder>::ptr ptr;
|
||||
return ptr(new dynamic_field_compressor<TEncoder>(encoder));
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename TDecoder
|
||||
>
|
||||
static typename dynamic_field_decompressor<TDecoder>::ptr make_dynamic_decompressor(TDecoder& decoder) {
|
||||
typedef typename dynamic_field_decompressor<TDecoder>::ptr ptr;
|
||||
return ptr(new dynamic_field_decompressor<TDecoder>(decoder));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __formats_hpp__
|
||||
1055
external/laz-perf/io.hpp
vendored
Normal file
1055
external/laz-perf/io.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
100
external/laz-perf/las.hpp
vendored
Normal file
100
external/laz-perf/las.hpp
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: las.hpp
|
||||
|
||||
CONTENTS:
|
||||
Point formats for LAS
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __las_hpp__
|
||||
#define __las_hpp__
|
||||
|
||||
#include "formats.hpp"
|
||||
#include "model.hpp"
|
||||
#include "compressor.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace laszip {
|
||||
namespace formats {
|
||||
namespace las {
|
||||
#pragma pack(push, 1)
|
||||
struct point10 {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
unsigned short intensity;
|
||||
unsigned char return_number : 3;
|
||||
unsigned char number_of_returns_of_given_pulse : 3;
|
||||
unsigned char scan_direction_flag : 1;
|
||||
unsigned char edge_of_flight_line : 1;
|
||||
unsigned char classification;
|
||||
char scan_angle_rank;
|
||||
unsigned char user_data;
|
||||
unsigned short point_source_ID;
|
||||
|
||||
point10() : x(0), y(0), intensity(0), return_number(0),
|
||||
number_of_returns_of_given_pulse(0), scan_direction_flag(0),
|
||||
edge_of_flight_line(0), classification(0),
|
||||
scan_angle_rank(0), user_data(0), point_source_ID(0)
|
||||
{}
|
||||
};
|
||||
|
||||
struct gpstime {
|
||||
int64_t value;
|
||||
|
||||
gpstime() : value(0) {}
|
||||
gpstime(int64_t v) : value(v) {}
|
||||
};
|
||||
|
||||
struct rgb {
|
||||
unsigned short r, g, b;
|
||||
|
||||
rgb(): r(0), g(0), b(0) {}
|
||||
rgb(unsigned short _r, unsigned short _g, unsigned short _b) :
|
||||
r(_r), g(_g), b(_b) {}
|
||||
};
|
||||
|
||||
// just the XYZ fields out of the POINT10 struct
|
||||
struct xyz {
|
||||
int x, y, z;
|
||||
|
||||
xyz() : x(0), y(0), z(0)
|
||||
{}
|
||||
};
|
||||
|
||||
struct extrabytes : public std::vector<uint8_t>
|
||||
{};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "detail/field_extrabytes.hpp"
|
||||
#include "detail/field_point10.hpp"
|
||||
#include "detail/field_gpstime.hpp"
|
||||
#include "detail/field_rgb.hpp"
|
||||
#include "detail/field_xyz.hpp"
|
||||
|
||||
#endif // __las_hpp__
|
||||
127
external/laz-perf/main.cpp
vendored
Normal file
127
external/laz-perf/main.cpp
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: main.cpp
|
||||
|
||||
CONTENTS:
|
||||
Run templatized LASzip
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#include "../common/common.hpp"
|
||||
#include "compressor.hpp"
|
||||
#include "decompressor.hpp"
|
||||
|
||||
#include "encoder.hpp"
|
||||
#include "decoder.hpp"
|
||||
#include "formats.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
struct SuchStream {
|
||||
SuchStream() : buf(), idx(0) {}
|
||||
|
||||
void putBytes(const unsigned char* b, size_t len) {
|
||||
while(len --) {
|
||||
buf.push_back(*b++);
|
||||
}
|
||||
}
|
||||
|
||||
void putByte(const unsigned char b) {
|
||||
buf.push_back(b);
|
||||
}
|
||||
|
||||
unsigned char getByte() {
|
||||
return buf[idx++];
|
||||
}
|
||||
|
||||
void getBytes(unsigned char *b, int len) {
|
||||
for (int i = 0 ; i < len ; i ++) {
|
||||
b[i] = getByte();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buf; // cuz I'm ze faste
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
void runEncoderDecoder() {
|
||||
using namespace laszip;
|
||||
using namespace laszip::formats;
|
||||
|
||||
auto start = common::tick();
|
||||
std::cout << common::since(start) << std::endl;
|
||||
|
||||
record_compressor<
|
||||
field<int>,
|
||||
field<short>,
|
||||
field<unsigned short>,
|
||||
field<unsigned int> > compressor;
|
||||
|
||||
// Throw stuff down at the coder and capture the output
|
||||
SuchStream s;
|
||||
|
||||
encoders::arithmetic<SuchStream> encoder(s);
|
||||
struct {
|
||||
int a;
|
||||
short b;
|
||||
unsigned short c;
|
||||
unsigned int d;
|
||||
} data;
|
||||
|
||||
|
||||
for (int i = 0 ; i < 10; i ++) {
|
||||
data.a = i;
|
||||
data.b = i + 10;
|
||||
data.c = i + 40000;
|
||||
data.d = i + (1 << 31);
|
||||
|
||||
compressor.compressWith(encoder, (const char*)&data);
|
||||
}
|
||||
encoder.done();
|
||||
|
||||
std::cout << "Points compressed to: " << s.buf.size() << " bytes" << std::endl;
|
||||
|
||||
record_decompressor<
|
||||
field<int>,
|
||||
field<short>,
|
||||
field<unsigned short>,
|
||||
field<unsigned int> > decompressor;
|
||||
|
||||
decoders::arithmetic<SuchStream> decoder(s);
|
||||
|
||||
for (int i = 0 ; i < 10 ; i ++) {
|
||||
decompressor.decompressWith(decoder, (char *)&data);
|
||||
|
||||
if (data.a != i ||
|
||||
data.b != i + 10 ||
|
||||
data.c != i + 40000 ||
|
||||
data.d != i + (1 << 31))
|
||||
throw std::runtime_error("Failure!");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
runEncoderDecoder();
|
||||
|
||||
return 0;
|
||||
}
|
||||
250
external/laz-perf/model.hpp
vendored
Normal file
250
external/laz-perf/model.hpp
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: model.hpp
|
||||
|
||||
CONTENTS:
|
||||
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __model_hpp__
|
||||
#define __model_hpp__
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace laszip {
|
||||
namespace models {
|
||||
struct arithmetic {
|
||||
arithmetic(U32 syms, bool com = false, U32 *initTable = nullptr) :
|
||||
symbols(syms), compress(com),
|
||||
distribution(nullptr), symbol_count(nullptr), decoder_table(nullptr) {
|
||||
if ( (symbols < 2) || (symbols > (1 << 11)) ) {
|
||||
throw std::runtime_error("Invalid number of symbols");
|
||||
}
|
||||
|
||||
last_symbol = symbols - 1;
|
||||
if ((!compress) && (symbols > 16)) {
|
||||
U32 table_bits = 3;
|
||||
while (symbols > (1U << (table_bits + 2))) ++table_bits;
|
||||
table_size = 1 << table_bits;
|
||||
table_shift = DM__LengthShift - table_bits;
|
||||
decoder_table = reinterpret_cast<U32*>(utils::aligned_malloc(sizeof(U32) * (table_size + 2)));
|
||||
}
|
||||
else { // small alphabet: no table needed
|
||||
decoder_table = 0;
|
||||
table_size = table_shift = 0;
|
||||
}
|
||||
|
||||
distribution = reinterpret_cast<U32*>(utils::aligned_malloc(symbols * sizeof(U32)));
|
||||
symbol_count = reinterpret_cast<U32*>(utils::aligned_malloc(symbols * sizeof(U32)));
|
||||
|
||||
total_count = 0;
|
||||
update_cycle = symbols;
|
||||
|
||||
if (initTable)
|
||||
for (U32 k = 0; k < symbols; k++) symbol_count[k] = initTable[k];
|
||||
else
|
||||
for (U32 k = 0; k < symbols; k++) symbol_count[k] = 1;
|
||||
|
||||
update();
|
||||
symbols_until_update = update_cycle = (symbols + 6) >> 1;
|
||||
}
|
||||
|
||||
~arithmetic() {
|
||||
if (distribution) utils::aligned_free(distribution);
|
||||
if (symbol_count) utils::aligned_free(symbol_count);
|
||||
if (decoder_table) utils::aligned_free(decoder_table);
|
||||
}
|
||||
|
||||
arithmetic(const arithmetic& other)
|
||||
: symbols(other.symbols), compress(other.compress),
|
||||
total_count(other.total_count), update_cycle(other.update_cycle),
|
||||
symbols_until_update(other.symbols_until_update), last_symbol(other.last_symbol),
|
||||
table_size(other.table_size), table_shift(other.table_shift)
|
||||
{
|
||||
size_t size(symbols * sizeof(U32));
|
||||
distribution = reinterpret_cast<U32*>(utils::aligned_malloc(size));
|
||||
std::copy(other.distribution, other.distribution + symbols, distribution);
|
||||
|
||||
symbol_count = reinterpret_cast<U32*>(utils::aligned_malloc(size));
|
||||
std::copy(other.symbol_count, other.symbol_count + symbols, symbol_count);
|
||||
|
||||
if (table_size)
|
||||
{
|
||||
size = (table_size + 2) * sizeof(U32);
|
||||
decoder_table = reinterpret_cast<U32*>(utils::aligned_malloc(size));
|
||||
std::copy(other.decoder_table, other.decoder_table + (table_size + 2), decoder_table);
|
||||
}
|
||||
else
|
||||
decoder_table = nullptr;
|
||||
}
|
||||
|
||||
arithmetic(arithmetic&& other) : symbols(other.symbols), compress(other.compress),
|
||||
distribution(other.distribution), symbol_count(other.symbol_count),
|
||||
decoder_table(other.decoder_table),
|
||||
total_count(other.total_count), update_cycle(other.update_cycle),
|
||||
symbols_until_update(other.symbols_until_update), last_symbol(other.last_symbol),
|
||||
table_size(other.table_size), table_shift(other.table_shift)
|
||||
{
|
||||
other.distribution = other.decoder_table = other.symbol_count = NULL;
|
||||
other.symbol_count = 0;
|
||||
}
|
||||
|
||||
arithmetic& operator = (arithmetic&& other) {
|
||||
if (this != &other) {
|
||||
if (distribution) utils::aligned_free(distribution);
|
||||
if (symbol_count) utils::aligned_free(symbol_count);
|
||||
if (decoder_table) utils::aligned_free(decoder_table);
|
||||
|
||||
symbols = other.symbols;
|
||||
compress = other.compress;
|
||||
|
||||
distribution = other.distribution;
|
||||
symbol_count = other.symbol_count;
|
||||
decoder_table = other.decoder_table;
|
||||
|
||||
total_count = other.total_count;
|
||||
update_cycle = other.update_cycle;
|
||||
symbols_until_update = other.symbols_until_update;
|
||||
last_symbol = other.last_symbol;
|
||||
table_size = other.table_size;
|
||||
table_shift = other.table_shift;
|
||||
|
||||
other.distribution = other.symbol_count = other.decoder_table = nullptr;
|
||||
other.total_count = other.update_cycle = other.symbols_until_update =
|
||||
other.last_symbol = other.table_size = other.table_shift = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void update() {
|
||||
// halve counts when a threshold is reached
|
||||
if ((total_count += update_cycle) > DM__MaxCount) {
|
||||
total_count = 0;
|
||||
for (U32 n = 0; n < symbols; n++)
|
||||
{
|
||||
total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
// compute cumulative distribution, decoder table
|
||||
U32 k, sum = 0, s = 0;
|
||||
U32 scale = 0x80000000U / total_count;
|
||||
|
||||
if (compress || (table_size == 0)) {
|
||||
for (k = 0; k < symbols; k++)
|
||||
{
|
||||
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
|
||||
sum += symbol_count[k];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (k = 0; k < symbols; k++)
|
||||
{
|
||||
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
|
||||
sum += symbol_count[k];
|
||||
U32 w = distribution[k] >> table_shift;
|
||||
while (s < w) decoder_table[++s] = k - 1;
|
||||
}
|
||||
decoder_table[0] = 0;
|
||||
while (s <= table_size) decoder_table[++s] = symbols - 1;
|
||||
}
|
||||
|
||||
// set frequency of model updates
|
||||
update_cycle = (5 * update_cycle) >> 2;
|
||||
U32 max_cycle = (symbols + 6) << 3;
|
||||
|
||||
if (update_cycle > max_cycle) update_cycle = max_cycle;
|
||||
symbols_until_update = update_cycle;
|
||||
}
|
||||
|
||||
U32 symbols;
|
||||
bool compress;
|
||||
|
||||
U32 * distribution, * symbol_count, * decoder_table;
|
||||
|
||||
U32 total_count, update_cycle, symbols_until_update;
|
||||
U32 last_symbol, table_size, table_shift;
|
||||
};
|
||||
|
||||
struct arithmetic_bit {
|
||||
arithmetic_bit() {
|
||||
// initialization to equiprobable model
|
||||
bit_0_count = 1;
|
||||
bit_count = 2;
|
||||
bit_0_prob = 1U << (BM__LengthShift - 1);
|
||||
// start with frequent updates
|
||||
update_cycle = bits_until_update = 4;
|
||||
}
|
||||
|
||||
arithmetic_bit(arithmetic_bit&& other):
|
||||
update_cycle(other.update_cycle), bits_until_update(other.bits_until_update),
|
||||
bit_0_prob(other.bit_0_prob), bit_0_count(other.bit_0_count), bit_count(other.bit_count) {
|
||||
}
|
||||
|
||||
arithmetic_bit& operator = (arithmetic_bit&& other) {
|
||||
if (this != &other) {
|
||||
update_cycle = other.update_cycle;
|
||||
bits_until_update = other.bits_until_update;
|
||||
bit_0_prob = other.bit_0_prob;
|
||||
bit_0_count = other.bit_0_count;
|
||||
bit_count = other.bit_count;
|
||||
|
||||
other.update_cycle = other.bits_until_update =
|
||||
other.bit_0_prob = other.bit_0_count = other.bit_count = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void update() {
|
||||
// halve counts when a threshold is reached
|
||||
if ((bit_count += update_cycle) > BM__MaxCount)
|
||||
{
|
||||
bit_count = (bit_count + 1) >> 1;
|
||||
bit_0_count = (bit_0_count + 1) >> 1;
|
||||
if (bit_0_count == bit_count) ++bit_count;
|
||||
}
|
||||
|
||||
// compute scaled bit 0 probability
|
||||
U32 scale = 0x80000000U / bit_count;
|
||||
bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);
|
||||
|
||||
// set frequency of model updates
|
||||
update_cycle = (5 * update_cycle) >> 2;
|
||||
if (update_cycle > 64) update_cycle = 64;
|
||||
bits_until_update = update_cycle;
|
||||
}
|
||||
|
||||
U32 update_cycle, bits_until_update;
|
||||
U32 bit_0_prob, bit_0_count, bit_count;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __model_hpp__
|
||||
115
external/laz-perf/portable_endian.hpp
vendored
Normal file
115
external/laz-perf/portable_endian.hpp
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// (c) Mathias Panzenböck
|
||||
// http://github.com/panzi/mathfun/blob/master/examples/portable_endian.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
||||
|
||||
# define __WINDOWS__
|
||||
|
||||
#endif
|
||||
|
||||
// use standard posix style headers for apple emscripten builds as well since emscripten sdk now ships its own
|
||||
// libc headers
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(__EMSCRIPTEN__)
|
||||
|
||||
# include <endian.h>
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
# include <machine/endian.h>
|
||||
# include <libkern/OSByteOrder.h>
|
||||
|
||||
# define htobe16 OSSwapHostToBigInt16
|
||||
# define htole16 OSSwapHostToLittleInt16
|
||||
# define be16toh OSSwapBigToHostInt16
|
||||
# define le16toh OSSwapLittleToHostInt16
|
||||
|
||||
# define htobe32 OSSwapHostToBigInt32
|
||||
# define htole32 OSSwapHostToLittleInt32
|
||||
# define be32toh OSSwapBigToHostInt32
|
||||
# define le32toh OSSwapLittleToHostInt32
|
||||
|
||||
# define htobe64 OSSwapHostToBigInt64
|
||||
# define htole64 OSSwapHostToLittleInt64
|
||||
# define be64toh OSSwapBigToHostInt64
|
||||
# define le64toh OSSwapLittleToHostInt64
|
||||
|
||||
/**
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __PDP_ENDIAN PDP_ENDIAN
|
||||
**/
|
||||
|
||||
#elif defined(__OpenBSD__)|| defined(__FreeBSD__)
|
||||
|
||||
# include <sys/endian.h>
|
||||
|
||||
#elif defined(__NetBSD__) || defined(__DragonFly__)
|
||||
|
||||
# define be16toh betoh16
|
||||
# define le16toh letoh16
|
||||
|
||||
# define be32toh betoh32
|
||||
# define le32toh letoh32
|
||||
|
||||
# define be64toh betoh64
|
||||
# define le64toh letoh64
|
||||
|
||||
#elif defined(__WINDOWS__)
|
||||
|
||||
# include <winsock2.h>
|
||||
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
# define htobe16 htons
|
||||
# define htole16(x) (x)
|
||||
# define be16toh ntohs
|
||||
# define le16toh(x) (x)
|
||||
|
||||
# define htobe32 htonl
|
||||
# define htole32(x) (x)
|
||||
# define be32toh ntohl
|
||||
# define le32toh(x) (x)
|
||||
|
||||
# define htobe64 htonll
|
||||
# define htole64(x) (x)
|
||||
# define be64toh ntohll
|
||||
# define le64toh(x) (x)
|
||||
|
||||
# elif BYTE_ORDER == BIG_ENDIAN
|
||||
|
||||
/* that would be xbox 360 */
|
||||
# define htobe16(x) (x)
|
||||
# define htole16(x) __builtin_bswap16(x)
|
||||
# define be16toh(x) (x)
|
||||
# define le16toh(x) __builtin_bswap16(x)
|
||||
|
||||
# define htobe32(x) (x)
|
||||
# define htole32(x) __builtin_bswap32(x)
|
||||
# define be32toh(x) (x)
|
||||
# define le32toh(x) __builtin_bswap32(x)
|
||||
|
||||
# define htobe64(x) (x)
|
||||
# define htole64(x) __builtin_bswap64(x)
|
||||
# define be64toh(x) (x)
|
||||
# define le64toh(x) __builtin_bswap64(x)
|
||||
|
||||
# else
|
||||
|
||||
# error byte order not supported
|
||||
|
||||
# endif
|
||||
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __PDP_ENDIAN PDP_ENDIAN
|
||||
|
||||
#else
|
||||
|
||||
# error platform not supported
|
||||
|
||||
#endif
|
||||
114
external/laz-perf/streams.hpp
vendored
Normal file
114
external/laz-perf/streams.hpp
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: streams.hpp
|
||||
|
||||
CONTENTS:
|
||||
Stream abstractions
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __streams_hpp__
|
||||
#define __streams_hpp__
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace laszip {
|
||||
namespace streams {
|
||||
struct memory_stream {
|
||||
memory_stream(const char *buf, std::streamsize len) :
|
||||
buf_(buf), len_(len), offset_(0),
|
||||
is_bad_(false), is_eof_(false), last_read_count_(0) {
|
||||
}
|
||||
|
||||
void read(char *into, std::streamsize size) {
|
||||
if (is_eof_) {
|
||||
is_bad_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::streamsize to_read = (std::min)(size, len_ - offset_);
|
||||
std::copy(buf_ + offset_, buf_ + offset_ + to_read, into);
|
||||
offset_ += to_read;
|
||||
last_read_count_ = to_read;
|
||||
|
||||
if (offset_ >= len_)
|
||||
is_eof_ = true;
|
||||
}
|
||||
|
||||
bool eof() {
|
||||
return is_eof_;
|
||||
}
|
||||
|
||||
std::streamsize gcount() {
|
||||
return last_read_count_;
|
||||
}
|
||||
|
||||
bool good() {
|
||||
bool b = is_bad_;
|
||||
is_bad_ = false;
|
||||
return !b;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
is_bad_ = false;
|
||||
is_eof_ = false;
|
||||
}
|
||||
|
||||
std::streamsize tellg() {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
void seekg(std::ios::pos_type p) {
|
||||
if (p >= len_)
|
||||
is_bad_ = true;
|
||||
else
|
||||
offset_ = p;
|
||||
}
|
||||
|
||||
void seekg(std::ios::off_type p, std::ios_base::seekdir dir) {
|
||||
std::streamoff new_offset_ = 0;
|
||||
switch(dir) {
|
||||
case std::ios::beg: new_offset_ = p; break;
|
||||
case std::ios::end: new_offset_ = len_ + p - 1; break;
|
||||
case std::ios::cur: new_offset_ = offset_ + p; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (new_offset_ >= len_ || new_offset_ < 0)
|
||||
is_bad_ = true;
|
||||
else {
|
||||
is_bad_ = false;
|
||||
offset_ = new_offset_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *buf_;
|
||||
std::streamsize len_, offset_;
|
||||
bool is_bad_, is_eof_;
|
||||
std::streamsize last_read_count_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __streams_hpp__
|
||||
192
external/laz-perf/util.hpp
vendored
Normal file
192
external/laz-perf/util.hpp
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE: util.hpp
|
||||
|
||||
CONTENTS:
|
||||
Utility classes
|
||||
|
||||
PROGRAMMERS:
|
||||
|
||||
martin.isenburg@rapidlasso.com - http://rapidlasso.com
|
||||
uday.karan@gmail.com - Hobu, Inc.
|
||||
|
||||
COPYRIGHT:
|
||||
|
||||
(c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
|
||||
(c) 2014, Uday Verma, Hobu, Inc.
|
||||
|
||||
This is free software; you can redistribute and/or modify it under the
|
||||
terms of the GNU Lesser General Licence as published by the Free Software
|
||||
Foundation. See the COPYING file for more information.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY and without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
CHANGE HISTORY:
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __util_hpp__
|
||||
#define __util_hpp__
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace laszip {
|
||||
namespace utils {
|
||||
#define ALIGN 64
|
||||
|
||||
static inline void *aligned_malloc(int size) {
|
||||
void *mem = malloc(size+ALIGN+sizeof(void*));
|
||||
void **ptr = (void**)(( ((uintptr_t)mem)+ALIGN+sizeof(void*) ) & ~(uintptr_t)(ALIGN-1) );
|
||||
ptr[-1] = mem;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void aligned_free(void *ptr) {
|
||||
free(((void**)ptr)[-1]);
|
||||
}
|
||||
|
||||
template<
|
||||
typename T
|
||||
>
|
||||
class streaming_median {
|
||||
public:
|
||||
std::array<T, 5> values;
|
||||
BOOL high;
|
||||
|
||||
void init() {
|
||||
values.fill(T(0));
|
||||
high = true;
|
||||
}
|
||||
|
||||
inline void add(const T& v) {
|
||||
if (high) {
|
||||
if (v < values[2]) {
|
||||
values[4] = values[3];
|
||||
values[3] = values[2];
|
||||
if (v < values[0]) {
|
||||
values[2] = values[1];
|
||||
values[1] = values[0];
|
||||
values[0] = v;
|
||||
}
|
||||
else if (v < values[1]) {
|
||||
values[2] = values[1];
|
||||
values[1] = v;
|
||||
}
|
||||
else {
|
||||
values[2] = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (v < values[3]) {
|
||||
values[4] = values[3];
|
||||
values[3] = v;
|
||||
}
|
||||
else {
|
||||
values[4] = v;
|
||||
}
|
||||
high = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (values[2] < v) {
|
||||
values[0] = values[1];
|
||||
values[1] = values[2];
|
||||
if (values[4] < v) {
|
||||
values[2] = values[3];
|
||||
values[3] = values[4];
|
||||
values[4] = v;
|
||||
}
|
||||
else if (values[3] < v) {
|
||||
values[2] = values[3];
|
||||
values[3] = v;
|
||||
}
|
||||
else {
|
||||
values[2] = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (values[1] < v) {
|
||||
values[0] = values[1];
|
||||
values[1] = v;
|
||||
}
|
||||
else {
|
||||
values[0] = v;
|
||||
}
|
||||
high = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline T get() const {
|
||||
return values[2];
|
||||
}
|
||||
|
||||
streaming_median() {
|
||||
init();
|
||||
}
|
||||
};
|
||||
|
||||
// for LAS files with the return (r) and the number (n) of
|
||||
// returns field correctly populated the mapping should really
|
||||
// be only the following.
|
||||
// { 15, 15, 15, 15, 15, 15, 15, 15 },
|
||||
// { 15, 0, 15, 15, 15, 15, 15, 15 },
|
||||
// { 15, 1, 2, 15, 15, 15, 15, 15 },
|
||||
// { 15, 3, 4, 5, 15, 15, 15, 15 },
|
||||
// { 15, 6, 7, 8, 9, 15, 15, 15 },
|
||||
// { 15, 10, 11, 12, 13, 14, 15, 15 },
|
||||
// { 15, 15, 15, 15, 15, 15, 15, 15 },
|
||||
// { 15, 15, 15, 15, 15, 15, 15, 15 }
|
||||
// however, some files start the numbering of r and n with 0,
|
||||
// only have return counts r, or only have number of return
|
||||
// counts n, or mix up the position of r and n. we therefore
|
||||
// "complete" the table to also map those "undesired" r & n
|
||||
// combinations to different contexts
|
||||
const unsigned char number_return_map[8][8] =
|
||||
{
|
||||
{ 15, 14, 13, 12, 11, 10, 9, 8 },
|
||||
{ 14, 0, 1, 3, 6, 10, 10, 9 },
|
||||
{ 13, 1, 2, 4, 7, 11, 11, 10 },
|
||||
{ 12, 3, 4, 5, 8, 12, 12, 11 },
|
||||
{ 11, 6, 7, 8, 9, 13, 13, 12 },
|
||||
{ 10, 10, 11, 12, 13, 14, 14, 13 },
|
||||
{ 9, 10, 11, 12, 13, 14, 15, 14 },
|
||||
{ 8, 9, 10, 11, 12, 13, 14, 15 }
|
||||
};
|
||||
|
||||
// for LAS files with the return (r) and the number (n) of
|
||||
// returns field correctly populated the mapping should really
|
||||
// be only the following.
|
||||
// { 0, 7, 7, 7, 7, 7, 7, 7 },
|
||||
// { 7, 0, 7, 7, 7, 7, 7, 7 },
|
||||
// { 7, 1, 0, 7, 7, 7, 7, 7 },
|
||||
// { 7, 2, 1, 0, 7, 7, 7, 7 },
|
||||
// { 7, 3, 2, 1, 0, 7, 7, 7 },
|
||||
// { 7, 4, 3, 2, 1, 0, 7, 7 },
|
||||
// { 7, 5, 4, 3, 2, 1, 0, 7 },
|
||||
// { 7, 6, 5, 4, 3, 2, 1, 0 }
|
||||
// however, some files start the numbering of r and n with 0,
|
||||
// only have return counts r, or only have number of return
|
||||
// counts n, or mix up the position of r and n. we therefore
|
||||
// "complete" the table to also map those "undesired" r & n
|
||||
// combinations to different contexts
|
||||
const unsigned char number_return_level[8][8] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 1, 0, 1, 2, 3, 4, 5, 6 },
|
||||
{ 2, 1, 0, 1, 2, 3, 4, 5 },
|
||||
{ 3, 2, 1, 0, 1, 2, 3, 4 },
|
||||
{ 4, 3, 2, 1, 0, 1, 2, 3 },
|
||||
{ 5, 4, 3, 2, 1, 0, 1, 2 },
|
||||
{ 6, 5, 4, 3, 2, 1, 0, 1 },
|
||||
{ 7, 6, 5, 4, 3, 2, 1, 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __util_hpp__
|
||||
@ -105,7 +105,7 @@ astyleit() {
|
||||
|
||||
for f in "$@"; do
|
||||
case "$f" in
|
||||
src/plugins/grass/qtermwidget/*|external/qwt*|external/o2/*|external/qt-unix-signals/*|external/rtree/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|external/meshOptimizer/*|external/mapbox-vector-tile/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*)
|
||||
src/plugins/grass/qtermwidget/*|external/qwt*|external/o2/*|external/qt-unix-signals/*|external/rtree/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|external/laz-perf/*|external/meshOptimizer/*|external/mapbox-vector-tile/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*)
|
||||
echo -ne "$f skipped $elcr"
|
||||
continue
|
||||
;;
|
||||
|
||||
@ -1656,9 +1656,20 @@ IF (WITH_EPT)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
${ZSTD_INCLUDE_DIR}
|
||||
${LazPerf_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
IF (LazPerf_FOUND)
|
||||
# Use sytem laz-perf
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
${LazPerf_INCLUDE_DIR}
|
||||
)
|
||||
ELSE (LazPerf_FOUND)
|
||||
# Use embedded laz-perf from external/laz-perf
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
${CMAKE_SOURCE_DIR}/external
|
||||
)
|
||||
ENDIF (LazPerf_FOUND)
|
||||
|
||||
SET(QGIS_CORE_SRCS ${QGIS_CORE_SRCS}
|
||||
providers/ept/qgseptdataitems.cpp
|
||||
providers/ept/qgseptprovider.cpp
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user