/* * Copyright 2007-2014, martin isenburg, rapidlasso - fast 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 LICENSE.txt 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. */ package com.revolsys.elevation.cloud.las.zip; import static java.lang.Integer.compareUnsigned; public class IntegerCompressor { private final int bitsHigh; private final int contexts; private int correctorBits; private int correctorMax; private int correctorMin; private int correctorRange; private final ArithmeticDecoder decoder; private final ArithmeticEncoder encoder; private int k; private ArithmeticModel[] bits; private ArithmeticModel[] corrector; private ArithmeticBitModel corrector0; public IntegerCompressor(final ArithmeticDecoder decoder, final int bits) { this(decoder, bits, 1); } public IntegerCompressor(final ArithmeticDecoder decoder, final int bits, final int contexts) { this(decoder, bits, contexts, 8, 0); } IntegerCompressor(final ArithmeticDecoder decoder, final int bits, final int contexts, final int bitsHigh, int range) { assert decoder != null; this.encoder = null; this.decoder = decoder; this.contexts = contexts; this.bitsHigh = bitsHigh; if (range != 0) // the corrector's significant bits and range { this.correctorBits = 0; this.correctorRange = range; while (range != 0) { range = range >>> 1; this.correctorBits++; } if (this.correctorRange == 1 << this.correctorBits - 1) { this.correctorBits--; } // the corrector must fall into this interval this.correctorMin = -Integer.divideUnsigned(this.correctorRange, 2); this.correctorMax = this.correctorMin + this.correctorRange - 1; } else if (bits != 0 && compareUnsigned(bits, 32) < 0) { this.correctorBits = bits; this.correctorRange = 1 << bits; // the corrector must fall into this interval this.correctorMin = -Integer.divideUnsigned(this.correctorRange, 2); this.correctorMax = this.correctorMin + this.correctorRange - 1; } else { this.correctorBits = 32; this.correctorRange = 0; // the corrector must fall into this interval this.correctorMin = Integer.MIN_VALUE; this.correctorMax = Integer.MAX_VALUE; } this.k = 0; this.bits = null; this.corrector = null; } public IntegerCompressor(final ArithmeticEncoder encoder, final int bits) { this(encoder, bits, 1, 8, 0); } IntegerCompressor(final ArithmeticEncoder encoder, final int bits, final int contexts, final int bitsHigh, int range) { assert encoder != null; this.encoder = encoder; this.decoder = null; this.contexts = contexts; this.bitsHigh = bitsHigh; if (range != 0) // the corrector's significant bits and range { this.correctorBits = 0; this.correctorRange = range; while (range != 0) { range = range >>> 1; this.correctorBits++; } if (this.correctorRange == 1 << this.correctorBits - 1) { this.correctorBits--; } // the corrector must fall into this interval this.correctorMin = -Integer.divideUnsigned(this.correctorRange, 2); this.correctorMax = this.correctorMin + this.correctorRange - 1; } else if (bits != 0 && compareUnsigned(bits, 32) < 0) { this.correctorBits = bits; this.correctorRange = 1 << bits; // the corrector must fall into this interval this.correctorMin = -Integer.divideUnsigned(this.correctorRange, 2); this.correctorMax = this.correctorMin + this.correctorRange - 1; } else { this.correctorBits = 32; this.correctorRange = 0; // the corrector must fall into this interval this.correctorMin = Integer.MIN_VALUE; this.correctorMax = Integer.MAX_VALUE; } this.k = 0; this.bits = null; this.corrector = null; } public void compress(final int pred, final int real) { compress(pred, real, 0); } void compress(final int pred, final int real, final int context) { assert this.encoder != null; // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] int corr = real - pred; // we fold the corrector into the interval [ corr_min ... corr_max ] if (corr < this.correctorMin) { corr += this.correctorRange; } else if (corr > this.correctorMax) { corr -= this.correctorRange; } writeCorrector(corr, this.bits[context]); } public int decompress(final int pred) { return decompress(pred, 0); } public int decompress(final int pred, final int context) { int real = pred + readCorrector(this.bits[context]); if (real < 0) { real += this.correctorRange; } else if (compareUnsigned(real, this.correctorRange) >= 0) { real -= this.correctorRange; } return real; } public int getK() { return this.k; } public void initCompressor() { int i; assert this.encoder != null; // maybe create the models if (this.bits == null) { this.bits = new ArithmeticModel[this.contexts]; for (i = 0; i < this.contexts; i++) { this.bits[i] = this.encoder.createSymbolModel(this.correctorBits + 1); } this.corrector = new ArithmeticModel[this.correctorBits + 1]; this.corrector0 = this.encoder.createBitModel(); for (i = 1; i <= this.correctorBits; i++) { if (i <= this.bitsHigh) { this.corrector[i] = this.encoder.createSymbolModel(1 << i); } else { this.corrector[i] = this.encoder.createSymbolModel(1 << this.bitsHigh); } } } // certainly init the models for (i = 0; i < this.contexts; i++) { this.encoder.initSymbolModel(this.bits[i]); } this.encoder.initBitModel(this.corrector0); for (i = 1; i <= this.correctorBits; i++) { this.encoder.initSymbolModel(this.corrector[i]); } } public void initDecompressor() { int i; // maybe create the models if (this.bits == null) { this.bits = new ArithmeticModel[this.contexts]; for (i = 0; i < this.contexts; i++) { this.bits[i] = ArithmeticDecoder.createSymbolModel(this.correctorBits + 1); } this.corrector = new ArithmeticModel[this.correctorBits + 1]; this.corrector0 = ArithmeticDecoder.createBitModel(); for (i = 1; i <= this.correctorBits; i++) { if (i <= this.bitsHigh) { this.corrector[i] = ArithmeticDecoder.createSymbolModel(1 << i); } else { this.corrector[i] = ArithmeticDecoder.createSymbolModel(1 << this.bitsHigh); } } } // certainly init the models for (i = 0; i < this.contexts; i++) { ArithmeticModel.initSymbolModel(this.bits[i]); } ArithmeticDecoder.initBitModel(this.corrector0); for (i = 1; i <= this.correctorBits; i++) { ArithmeticModel.initSymbolModel(this.corrector[i]); } } int readCorrector(final ArithmeticModel model) { final ArithmeticDecoder decoder = this.decoder; // decode within which interval the corrector is falling final int k = decoder.decodeSymbol(model); this.k = k; // decode the exact location of the corrector within the interval // TODO: original code: if (k) // TODO: how can k be zero or one? int corrector; if (k == 0) { // then c is either 0 or 1 corrector = decoder.decodeBit(this.corrector0); } else { // then c is either smaller than 0 or bigger than 1 if (k < 32) { corrector = decoder.decodeSymbol(this.corrector[k]); final int bitsHigh = this.bitsHigh; if (k > bitsHigh) { // for larger k we need to do this in two steps final int k1 = k - bitsHigh; // read lower bits raw final int c1 = decoder.getBits(k1); // put the corrector back together corrector = corrector << k1 | c1; } // translate c back into its correct interval if (corrector >= 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 corrector += 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) corrector -= (1 << k) - 1; } } else { corrector = this.correctorMin; } } return corrector; } void writeCorrector(int c, final ArithmeticModel mBits) { int c1; // find the tighest interval [ - (2^k - 1) ... + (2^k) ] that contains c this.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 != 0) { c1 = c1 >>> 1; this.k = this.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 this.encoder.encodeSymbol(mBits, this.k); if (this.k != 0) // then c is either smaller than 0 or bigger than 1 { assert c != 0 && c != 1; if (compareUnsigned(this.k, 32) < 0) { // 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 << this.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 (this.k <= this.bitsHigh) // for small k we code the interval in one step { // compress c with the range coder this.encoder.encodeSymbol(this.corrector[this.k], c); } else // for larger k we need to code the interval in two steps { // figure out how many lower bits there are final int k1 = this.k - this.bitsHigh; // c1 represents the lowest k-bitsHigh+1 bits c1 = c & (1 << k1) - 1; // c represents the highest bitsHigh bits c = c >> k1; // compress the higher bits using a context table this.encoder.encodeSymbol(this.corrector[this.k], c); // store the lower k1 bits raw this.encoder.writeBits(k1, c1); } } } else // then c is 0 or 1 { assert c == 0 || c == 1; this.encoder.encodeBit(this.corrector0, c); } } }