/*
* Copyright 2007-2012, 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 com.revolsys.elevation.cloud.las.zip.StreamingMedian5.newStreamingMedian5;
import com.revolsys.elevation.cloud.las.LasPointCloud;
import com.revolsys.elevation.cloud.las.pointformat.LasPoint;
public class LazDecompressPoint10V2 extends LazDecompressPoint10 {
private final ArithmeticModel decompressScanAngleRankFalse = ArithmeticDecoder
.createSymbolModel(256);
private final ArithmeticModel decompressScanAngleRankTrue = ArithmeticDecoder
.createSymbolModel(256);
private final int[] last_height = new int[8]; // signed
private final int[] lastIntensity = new int[16];
private final StreamingMedian5[] lastXDiffMedian5 = newStreamingMedian5(16);
private final StreamingMedian5[] lastYDiffMedian5 = newStreamingMedian5(16);
public LazDecompressPoint10V2(final LasPointCloud pointCloud, final ArithmeticDecoder decoder) {
super(pointCloud, decoder);
this.decompressDeltaX = new IntegerCompressor(decoder, 32, 2);
this.decompressDeltaY = new IntegerCompressor(decoder, 32, 22);
this.decompressZ = new IntegerCompressor(decoder, 32, 20);
this.decompressIntensity = new IntegerCompressor(decoder, 16, 4);
this.decompressPointSourceId = new IntegerCompressor(decoder, 16);
}
@Override
public void init(final LasPoint point) {
super.init(point);
for (int i = 0; i < 16; i++) {
this.lastXDiffMedian5[i].init();
this.lastYDiffMedian5[i].init();
this.lastIntensity[i] = 0;
this.last_height[i / 2] = 0;
}
ArithmeticModel.initSymbolModel(this.decompressScanAngleRankFalse);
ArithmeticModel.initSymbolModel(this.decompressScanAngleRankTrue);
this.intensity = 0;
}
@Override
public void read(final LasPoint point) {
final int changedValues = this.decoder.decodeSymbol(this.decompressChangedValues);
final int m;
int returnNumber;
int returnCount;
final int l;
if (changedValues == 0) {
returnNumber = this.returnByte & 0b111;
returnCount = this.returnByte >> 3 & 0b111;
m = Common_v2.NUMBER_RETURN_MAP[returnCount][returnNumber];
l = Common_v2.NUMBER_RETURN_LEVEL[returnCount][returnNumber];
} else {
// decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed
if ((changedValues & 32) != 0) {
this.returnByte = read(this.decompressBitByte, this.returnByte);
}
returnNumber = this.returnByte & 0b111;
returnCount = this.returnByte >> 3 & 0b111;
m = Common_v2.NUMBER_RETURN_MAP[returnCount][returnNumber];
l = Common_v2.NUMBER_RETURN_LEVEL[returnCount][returnNumber];
// decompress the intensity if it has changed
if ((changedValues & 16) != 0) {
this.intensity = this.decompressIntensity.decompress(this.lastIntensity[m], m < 3 ? m : 3);
this.lastIntensity[m] = this.intensity;
} else {
this.intensity = this.lastIntensity[m];
}
if ((changedValues & 8) != 0) {
this.classificationByte = read(this.decompressClassification, this.classificationByte);
}
// decompress the scan_angle_rank ... if it has changed
if ((changedValues & 4) != 0) {
ArithmeticModel model;
if (this.scanDirectionFlag) {
model = this.decompressScanAngleRankTrue;
} else {
model = this.decompressScanAngleRankFalse;
}
final int val = this.decoder.decodeSymbol(model);
this.scanAngleRank = (byte)Byte.toUnsignedInt(MyDefs.U8_FOLD(val + this.scanAngleRank));
}
if ((changedValues & 2) != 0) {
this.userData = read(this.decompressUserData, this.userData);
}
// decompress the point_source_ID ... if it has changed
if ((changedValues & 1) != 0) {
this.pointSourceId = this.decompressPointSourceId.decompress(this.pointSourceId);
}
}
// decompress x coordinate
final int medianX = this.lastXDiffMedian5[m].get();
final int diffX = this.decompressDeltaX.decompress(medianX, returnCount == 1 ? 1 : 0);
this.x += diffX;
this.lastXDiffMedian5[m].add(diffX);
// decompress y coordinate
final int medianY = this.lastYDiffMedian5[m].get();
final int kBitsY = this.decompressDeltaX.getK();
final int diffY = this.decompressDeltaY.decompress(medianY,
(returnCount == 1 ? 1 : 0) + (kBitsY < 20 ? MyDefs.U32_ZERO_BIT_0(kBitsY) : 20));
this.y += diffY;
this.lastYDiffMedian5[m].add(diffY);
// decompress z coordinate
final int kBitsZ = (this.decompressDeltaX.getK() + this.decompressDeltaY.getK()) / 2;
this.z = this.decompressZ.decompress(this.last_height[l],
(returnCount == 1 ? 1 : 0) + (kBitsZ < 18 ? MyDefs.U32_ZERO_BIT_0(kBitsZ) : 18));
this.last_height[l] = this.z;
postRead(point);
this.scanDirectionFlag = point.isScanDirectionFlag();
}
}