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:
Nyall Dawson 2020-11-07 08:55:36 +10:00 committed by Peter Petrik
parent 37a0b0e9f7
commit c7a6e6bd15
25 changed files with 5749 additions and 4 deletions

View File

@ -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)

View File

@ -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
View 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
View 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
View 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
View 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
View 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__

View 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;
}
};
}
}

View 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_;
};
}
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

100
external/laz-perf/las.hpp vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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__

View File

@ -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
;;

View File

@ -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