UNPKG

gis-tools-ts

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

1,094 lines 71.2 kB
// import { BufferReader } from '../..'; // import { // ArithmeticDecoder, // ArithmeticModel, // IntegerCompressor, // LASWavePacket13, // LASZIP_DECOMPRESS_SELECTIVE_ALL, // LASZIP_DECOMPRESS_SELECTIVE_BYTE0, // LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION, // LASZIP_DECOMPRESS_SELECTIVE_FLAGS, // LASZIP_DECOMPRESS_SELECTIVE_GPS_TIME, // LASZIP_DECOMPRESS_SELECTIVE_INTENSITY, // LASZIP_DECOMPRESS_SELECTIVE_NIR, // LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE, // LASZIP_DECOMPRESS_SELECTIVE_RGB, // LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE, // LASZIP_DECOMPRESS_SELECTIVE_USER_DATA, // LASZIP_DECOMPRESS_SELECTIVE_WAVEPACKET, // LASZIP_DECOMPRESS_SELECTIVE_Z, // LASpoint14, // LASrgbaNir, // number_return_level_8ctx, // number_return_map_6ctx, // } from '.'; // import { // LAScontextBYTE14, // LAScontextPOINT14, // LAScontextRGB14, // LAScontextRGBNIR14, // LAScontextWAVEPACKET14, // } from './v3'; // import { i16Quantize, i8Clamp, u32ZeroBit0, u8Clamp, u8Fold } from '../util'; export {}; // import type { Reader } from '../..'; // import { ItemReader, LASrgba, LAZContext } from '.'; // const LASZIP_GPSTIME_MULTI = 500; // const LASZIP_GPSTIME_MULTI_MINUS = -10; // const LASZIP_GPSTIME_MULTI_CODE_FULL = LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1; // const LASZIP_GPSTIME_MULTI_TOTAL = LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 5; // /** Parse LAZ Point 1.4v4 */ // export class LAZPoint14v4Reader implements ItemReader { // // readers // instreamChannelReturnsXY?: Reader; // instreamZ?: Reader; // instreamClassification?: Reader; // instreamFlags?: Reader; // instreamIntensity?: Reader; // instreamScanAngle?: Reader; // instreamUserData?: Reader; // instreamPointSource?: Reader; // instreamGpsTime?: Reader; // // decoders // decChannelReturnsXY?: ArithmeticDecoder; // decZ?: ArithmeticDecoder; // decClassification?: ArithmeticDecoder; // decFlags?: ArithmeticDecoder; // decIntensity?: ArithmeticDecoder; // decScanAngle?: ArithmeticDecoder; // decUserData?: ArithmeticDecoder; // decPointSource?: ArithmeticDecoder; // decGpsTime?: ArithmeticDecoder; // // states // changedZ = false; // changedClassification = false; // changedFlags = false; // changedIntensity = false; // changedScanAngle = false; // changedUserData = false; // changedPointSource = false; // changedGpsTime = false; // // num bytes values // numBytesChannelReturnsXY = 0; // U32 // numBytesZ = 0; // U32 // numBytesClassification = 0; // U32 // numBytesFlags = 0; // U32 // numBytesIntensity = 0; // U32 // numBytesScanAngle = 0; // U32 // numBytesUserData = 0; // U32 // numBytesPointSource = 0; // U32 // numBytesGpsTime = 0; // U32 // // request states // requestedZ = false; // requestedClassification = false; // requestedFlags = false; // requestedIntensity = false; // requestedScanAngle = false; // requestedUserData = false; // requestedPointSource = false; // requestedGpsTime = false; // bytes?: DataView; // numBytesAllocated = 0; // U32 // currentContext = 0; // U32 // contexts = [ // new LAScontextPOINT14(), // new LAScontextPOINT14(), // new LAScontextPOINT14(), // new LAScontextPOINT14(), // ]; // /** // * @param dec - the arithmetic decoder // * @param decompressSelective - which fields to decompress // */ // constructor( // readonly dec: ArithmeticDecoder, // readonly decompressSelective = LASZIP_DECOMPRESS_SELECTIVE_ALL, // ) { // for (let c = 0; c < 4; c++) this.contexts[c].mChangedValues[0] = undefined; // this.requestedZ = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_Z); // this.requestedClassification = Boolean( // decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION, // ); // this.requestedFlags = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_FLAGS); // this.requestedIntensity = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_INTENSITY); // this.requestedScanAngle = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE); // this.requestedUserData = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_USER_DATA); // this.requestedPointSource = Boolean( // decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE, // ); // this.requestedGpsTime = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_GPS_TIME); // } // /** // * Read in chunk sizes // * @param reader - the full data store // */ // chunkSizes(reader: Reader): void { // this.numBytesChannelReturnsXY = reader.getUint32(undefined, true); // this.numBytesZ = reader.getUint32(undefined, true); // this.numBytesClassification = reader.getUint32(undefined, true); // this.numBytesFlags = reader.getUint32(undefined, true); // this.numBytesIntensity = reader.getUint32(undefined, true); // this.numBytesScanAngle = reader.getUint32(undefined, true); // this.numBytesUserData = reader.getUint32(undefined, true); // this.numBytesPointSource = reader.getUint32(undefined, true); // this.numBytesGpsTime = reader.getUint32(undefined, true); // } // /** // * @param item - the current item to be read into // * @param context - the current context // */ // init(item: DataView, context: LAZContext): void { // const { reader } = this.dec; // /* on the first init create instreams and decoders */ // if (this.instreamChannelReturnsXY === undefined) { // /* create decoders */ // this.decChannelReturnsXY = new ArithmeticDecoder(reader); // this.decZ = new ArithmeticDecoder(reader); // this.decClassification = new ArithmeticDecoder(reader); // this.decFlags = new ArithmeticDecoder(reader); // this.decIntensity = new ArithmeticDecoder(reader); // this.decScanAngle = new ArithmeticDecoder(reader); // this.decUserData = new ArithmeticDecoder(reader); // this.decPointSource = new ArithmeticDecoder(reader); // this.decGpsTime = new ArithmeticDecoder(reader); // } // /* how many bytes do we need to read */ // let numBytes = this.numBytesChannelReturnsXY; // U32 // if (this.requestedZ) numBytes += this.numBytesZ; // if (this.requestedClassification) numBytes += this.numBytesClassification; // if (this.requestedFlags) numBytes += this.numBytesFlags; // if (this.requestedIntensity) numBytes += this.numBytesIntensity; // if (this.requestedScanAngle) numBytes += this.numBytesScanAngle; // if (this.requestedUserData) numBytes += this.numBytesUserData; // if (this.requestedPointSource) numBytes += this.numBytesPointSource; // if (this.requestedGpsTime) numBytes += this.numBytesGpsTime; // /* make sure the buffer is sufficiently large */ // if (numBytes > this.numBytesAllocated) this.numBytesAllocated = numBytes; // /* load the requested bytes and init the corresponding instreams and decoders */ // numBytes = 0; // this.bytes = reader.seekSlice(this.numBytesChannelReturnsXY); // this.instreamChannelReturnsXY = new BufferReader(this.bytes.buffer); // this.decChannelReturnsXY = new ArithmeticDecoder(this.instreamChannelReturnsXY); // this.decChannelReturnsXY.init(); // numBytes += this.numBytesChannelReturnsXY; // if (this.requestedZ) { // if (this.numBytesZ !== 0) { // this.bytes = reader.seekSlice(this.numBytesZ); // this.instreamZ = new BufferReader(this.bytes.buffer); // this.decZ = new ArithmeticDecoder(this.instreamZ); // this.decZ.init(); // numBytes += this.numBytesZ; // this.changedZ = true; // } else { // this.instreamZ = undefined; // this.changedZ = false; // } // } else { // if (this.numBytesZ !== 0) { // reader.seek(reader.tell() + this.numBytesZ); // } // this.changedZ = false; // } // if (this.requestedClassification) { // if (this.numBytesClassification !== 0) { // this.bytes = reader.seekSlice(this.numBytesClassification); // this.instreamClassification = new BufferReader(this.bytes.buffer); // this.decClassification = new ArithmeticDecoder(this.instreamClassification); // this.decClassification.init(); // numBytes += this.numBytesClassification; // this.changedClassification = true; // } else { // this.instreamClassification = undefined; // this.changedClassification = false; // } // } else { // if (this.numBytesClassification !== 0) { // reader.seek(reader.tell() + this.numBytesClassification); // } // this.changedClassification = false; // } // if (this.requestedFlags) { // if (this.numBytesFlags !== 0) { // this.bytes = reader.seekSlice(this.numBytesFlags); // this.instreamFlags = new BufferReader(this.bytes.buffer); // this.decFlags = new ArithmeticDecoder(this.instreamFlags); // this.decFlags.init(); // numBytes += this.numBytesFlags; // this.changedFlags = true; // } else { // this.instreamFlags = undefined; // this.changedFlags = false; // } // } else { // if (this.numBytesFlags !== 0) { // reader.seek(reader.tell() + this.numBytesFlags); // } // this.changedFlags = false; // } // if (this.requestedIntensity) { // if (this.numBytesIntensity !== 0) { // this.bytes = reader.seekSlice(this.numBytesIntensity); // this.instreamIntensity = new BufferReader(this.bytes.buffer); // this.decIntensity = new ArithmeticDecoder(this.instreamIntensity); // this.decIntensity.init(); // numBytes += this.numBytesIntensity; // this.changedIntensity = true; // } else { // this.instreamIntensity = undefined; // this.changedIntensity = false; // } // } else { // if (this.numBytesIntensity !== 0) { // reader.seek(reader.tell() + this.numBytesIntensity); // } // this.changedIntensity = false; // } // if (this.requestedScanAngle) { // if (this.numBytesScanAngle !== 0) { // this.bytes = reader.seekSlice(this.numBytesScanAngle); // this.instreamScanAngle = new BufferReader(this.bytes.buffer); // this.decScanAngle = new ArithmeticDecoder(this.instreamScanAngle); // this.decScanAngle.init(); // numBytes += this.numBytesScanAngle; // this.changedScanAngle = true; // } else { // this.instreamScanAngle = undefined; // this.changedScanAngle = false; // } // } else { // if (this.numBytesScanAngle !== 0) { // reader.seek(reader.tell() + this.numBytesScanAngle); // } // this.changedScanAngle = false; // } // if (this.requestedUserData) { // if (this.numBytesUserData !== 0) { // this.bytes = reader.seekSlice(this.numBytesUserData); // this.instreamUserData = new BufferReader(this.bytes.buffer); // this.decUserData = new ArithmeticDecoder(this.instreamUserData); // this.decUserData.init(); // numBytes += this.numBytesUserData; // this.changedUserData = true; // } else { // this.instreamUserData = undefined; // this.changedUserData = false; // } // } else { // if (this.numBytesUserData !== 0) { // reader.seek(reader.tell() + this.numBytesUserData); // } // this.changedUserData = false; // } // if (this.requestedPointSource) { // if (this.numBytesPointSource !== 0) { // this.bytes = reader.seekSlice(this.numBytesPointSource); // this.instreamPointSource = new BufferReader(this.bytes.buffer); // this.decPointSource = new ArithmeticDecoder(this.instreamPointSource); // this.decPointSource.init(); // numBytes += this.numBytesPointSource; // this.changedPointSource = true; // } else { // this.instreamPointSource = undefined; // this.changedPointSource = false; // } // } else { // if (this.numBytesPointSource !== 0) { // reader.seek(reader.tell() + this.numBytesPointSource); // } // this.changedPointSource = false; // } // if (this.requestedGpsTime) { // if (this.numBytesGpsTime !== 0) { // this.bytes = reader.seekSlice(this.numBytesGpsTime); // this.instreamGpsTime = new BufferReader(this.bytes.buffer); // this.decGpsTime = new ArithmeticDecoder(this.instreamGpsTime); // this.decGpsTime.init(); // numBytes += this.numBytesGpsTime; // this.changedGpsTime = true; // } else { // this.instreamGpsTime = undefined; // this.changedGpsTime = false; // } // } else { // if (this.numBytesGpsTime !== 0) { // reader.seek(reader.tell() + this.numBytesGpsTime); // } // this.changedGpsTime = false; // } // /* mark the four scanner channel contexts as unused */ // for (let c = 0; c < 4; c++) { // this.contexts[c].unused = true; // } // /* set scanner channel as current context */ // const currItem = new LASpoint14(item); // this.currentContext = currItem.scannerChannel; // context.value = this.currentContext; // the POINT14 reader sets context for all other items // /* create and init models and decompressors */ // this.#createAndInitModelsAndDecompressors(this.currentContext, currItem); // } // /** // * @param item - the current item to be read into // * @param context - the current context // */ // read(item: DataView, context: LAZContext): void { // const { contexts } = this; // // get last // let lastItem = new LASpoint14(contexts[this.currentContext].lastItem); // //////////////////////////////////////// // // decompress returnsXY layer // //////////////////////////////////////// // // create single (3) / first (1) / last (2) / intermediate (0) context from last point return // let lpr = lastItem.returnNumber === 1 ? 1 : 0; // (I32) first? // lpr += lastItem.returnNumber >= lastItem.numberOfReturns ? 2 : 0; // last? // // add info whether the GPS time changed in the last return to the context // lpr += lastItem.gpsTimeChange !== 0 ? 4 : 0; // // decompress which values have changed with last point return context (I32) // const changedValues = this.decChannelReturnsXY!.decodeSymbol( // contexts[this.currentContext].mChangedValues[lpr]!, // ); // // if scanner channel has changed // if ((changedValues & (1 << 6)) !== 0) { // const diff = this.decChannelReturnsXY!.decodeSymbol( // contexts[this.currentContext].mScannerChannel!, // ); // (U32) curr = last + (sym + 1) // const scannerChannel = (this.currentContext + diff + 1) % 4; // U32 // // maybe create and init entropy models and integer compressors // if (contexts[scannerChannel].unused) { // // create and init entropy models and integer decompressors // this.#createAndInitModelsAndDecompressors( // scannerChannel, // new LASpoint14(contexts[this.currentContext].lastItem), // ); // } // // switch context to current scanner channel // this.currentContext = scannerChannel; // // get last for new context // lastItem = new LASpoint14(contexts[this.currentContext].lastItem); // lastItem.scannerChannel = scannerChannel; // } // context.value = this.currentContext; // the POINT14 reader sets context for all other items // // determine changed attributes // const pointSourceChange = Boolean(changedValues & (1 << 5)); // const gpsTimeChange = Boolean(changedValues & (1 << 4)); // const scanAngleChange = Boolean(changedValues & (1 << 3)); // // get last return counts // const lastN = lastItem.numberOfReturns; // U32 // const lastR = lastItem.returnNumber; // U32 // // if number of returns is different we decompress it // let n: number; // if ((changedValues & (1 << 2)) !== 0) { // if (contexts[this.currentContext].mNumberOfReturns[lastN] === undefined) { // contexts[this.currentContext].mNumberOfReturns[lastN] = new ArithmeticModel(16); // contexts[this.currentContext].mNumberOfReturns[lastN]!.init(); // } // n = this.decChannelReturnsXY!.decodeSymbol( // contexts[this.currentContext].mNumberOfReturns[lastN]!, // ); // lastItem.numberOfReturns = n; // } else { // n = lastN; // } // // how is the return number different // let r: number; // if ((changedValues & 3) === 0) { // // same return number // r = lastR; // } else if ((changedValues & 3) === 1) { // // return number plus 1 mod 16 // r = (lastR + 1) % 16; // lastItem.returnNumber = r; // } else if ((changedValues & 3) === 2) { // // return number minus 1 mod 16 // r = (lastR + 15) % 16; // lastItem.returnNumber = r; // } else { // // the return number difference is bigger than +1 / -1 so we decompress how it is different // if (gpsTimeChange) { // // if the GPS time has changed // if (contexts[this.currentContext].mReturnNumber[lastR] === undefined) { // contexts[this.currentContext].mReturnNumber[lastR] = new ArithmeticModel(16); // contexts[this.currentContext].mReturnNumber[lastR]!.init(); // } // r = this.decChannelReturnsXY!.decodeSymbol( // contexts[this.currentContext].mReturnNumber[lastR]!, // ); // } // if the GPS time has not changed // else { // // I32 // const sym = this.decChannelReturnsXY!.decodeSymbol( // contexts[this.currentContext].mReturnNumberGpsSame!, // ); // r = (lastR + (sym + 2)) % 16; // } // lastItem.returnNumber = r; // } // // set legacy return counts and number of returns // if (n > 7) { // if (r > 6) { // if (r >= n) { // lastItem.legacyReturnNumber = 7; // } else { // lastItem.legacyReturnNumber = 6; // } // } else { // lastItem.legacyReturnNumber = r; // } // lastItem.legacyNumberOfReturns = 7; // } else { // lastItem.legacyReturnNumber = r; // lastItem.legacyNumberOfReturns = n; // } // // get return map m and return level l context for current point // const m = number_return_map_6ctx[n][r]; // U32 // const l = number_return_level_8ctx[n][r]; // U32 // // create single (3) / first (1) / last (2) / intermediate (0) return context for current point // let cpr = r === 1 ? 2 : 0; // first ? (I32) // cpr += r >= n ? 1 : 0; // last ? // let kBits: number; // U32 // let median, diff; // I32 // // decompress X coordinate // median = // contexts[this.currentContext].lastXDiffMedian5[(m << 1) | Number(gpsTimeChange)]!.get(); // diff = contexts[this.currentContext].icdX!.decompress(median, { value: Number(n === 1) }); // lastItem.x += diff; // contexts[this.currentContext].lastXDiffMedian5[(m << 1) | Number(gpsTimeChange)]!.add(diff); // // decompress Y coordinate // median = // contexts[this.currentContext].lastYDiffMedian5[(m << 1) | Number(gpsTimeChange)]!.get(); // kBits = contexts[this.currentContext].icdX!.getK(); // diff = contexts[this.currentContext].icdY!.decompress(median, { // value: Number(n === 1) + (kBits < 20 ? u32ZeroBit0(kBits) : 20), // }); // lastItem.y += diff; // contexts[this.currentContext].lastYDiffMedian5[(m << 1) | Number(gpsTimeChange)]!.add(diff); // //////////////////////////////////////// // // decompress Z layer (if changed and requested) // //////////////////////////////////////// // if (this.changedZ) { // // if the Z coordinate should be decompressed and changes within this chunk // kBits = // (contexts[this.currentContext].icdX!.getK() + contexts[this.currentContext].icdY!.getK()) / // 2; // lastItem.z = contexts[this.currentContext].icZ!.decompress( // contexts[this.currentContext].lastZ[l], // { value: Number(n === 1) + (kBits < 18 ? u32ZeroBit0(kBits) : 18) }, // ); // contexts[this.currentContext].lastZ[l] = lastItem.z; // } // //////////////////////////////////////// // // decompress classifications layer (if changed and requested) // //////////////////////////////////////// // if (this.changedClassification) { // // if the classification should be decompressed and changes within this chunk // const last_classification = lastItem.classification; // U32 // const ccc = ((last_classification & 0x1f) << 1) + (cpr === 3 ? 1 : 0); // I32 // if (contexts[this.currentContext].mClassification[ccc] === undefined) { // contexts[this.currentContext].mClassification[ccc] = new ArithmeticModel(256); // contexts[this.currentContext].mClassification[ccc]!.init(); // } // lastItem.classification = this.decClassification!.decodeSymbol( // contexts[this.currentContext].mClassification[ccc]!, // ); // // update the legacy copy // if (lastItem.classification < 32) { // lastItem.legacyClassification = lastItem.classification; // } else { // lastItem.legacyClassification = 0; // } // } // //////////////////////////////////////// // // decompress flags layer (if changed and requested) // //////////////////////////////////////// // if (this.changedFlags) { // // if the flags should be decompressed and change within this chunk // // U32 // const lastFlags = // (lastItem.edgeOfFlightLine << 5) | // (lastItem.scanDirectionFlag << 4) | // lastItem.classificationFlags; // if (contexts[this.currentContext].mFlags[lastFlags] === undefined) { // contexts[this.currentContext].mFlags[lastFlags] = new ArithmeticModel(64); // contexts[this.currentContext].mFlags[lastFlags]!.init(); // } // const flags = this.decFlags!.decodeSymbol(contexts[this.currentContext].mFlags[lastFlags]!); // lastItem.edgeOfFlightLine = (flags & (1 << 5)) !== 0 ? 1 : 0; // lastItem.scanDirectionFlag = (flags & (1 << 4)) !== 0 ? 1 : 0; // lastItem.classificationFlags = flags & 0x0f; // // legacy copies // lastItem.legacyFlags = flags & 0x07; // } // //////////////////////////////////////// // // decompress intensity layer (if changed and requested) // //////////////////////////////////////// // if (this.changedIntensity) { // // if the intensity should be decompressed and changes within this chunk // // U16 // const intensity = contexts[this.currentContext].icIntensity!.decompress( // contexts[this.currentContext].lastIntensity[(cpr << 1) | Number(gpsTimeChange)], // { value: cpr }, // ); // contexts[this.currentContext].lastIntensity[(cpr << 1) | Number(gpsTimeChange)] = intensity; // lastItem.intensity = intensity; // } // //////////////////////////////////////// // // decompress scanAngle layer (if changed and requested) // //////////////////////////////////////// // if (this.changedScanAngle) { // // if the scan angle should be decompressed and changes within this chunk // if (scanAngleChange) { // // if the scan angle has actually changed // lastItem.scanAngle = contexts[this.currentContext].icScanAngle!.decompress( // lastItem.scanAngle, // { value: Number(gpsTimeChange) }, // ); // if the GPS time has changed // lastItem.legacyScanAngleRank = i8Clamp(i16Quantize(0.006 * lastItem.scanAngle)); // } // } // //////////////////////////////////////// // // decompress userData layer (if changed and requested) // //////////////////////////////////////// // if (this.changedUserData) { // // if the user data should be decompressed and changes within this chunk // const index = Math.trunc(lastItem.userData / 4); // if (contexts[this.currentContext].mUserData![index] === undefined) { // contexts[this.currentContext].mUserData[index] = new ArithmeticModel(256); // contexts[this.currentContext].mUserData[index]!.init(); // } // lastItem.userData = this.decUserData!.decodeSymbol( // contexts[this.currentContext].mUserData[index]!, // ); // } // //////////////////////////////////////// // // decompress point_source layer (if changed and requested) // //////////////////////////////////////// // if (this.changedPointSource) { // // if the point source ID should be decompressed and changes within this chunk // if (pointSourceChange) { // // if the point source ID has actually changed // lastItem.pointSourceID = contexts[this.currentContext].icPointSourceID!.decompress( // lastItem.pointSourceID, // ); // } // } // //////////////////////////////////////// // // decompress gpsTime layer (if changed and requested) // //////////////////////////////////////// // if (this.changedGpsTime) { // // if the GPS time should be decompressed and changes within this chunk // if (gpsTimeChange) { // // if the GPS time has actually changed // this.#readGpsTime(); // lastItem.gpsTime = // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].f64; // } // } // // copy the last item // lastItem.copyTo(item, 45); // // remember if the last point had a gpsTimeChange // lastItem.gpsTimeChange = Number(gpsTimeChange); // } // /** Read the GPS Time */ // #readGpsTime(): void { // const { contexts } = this; // let multi: number; // I32 // if (contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] === 0) { // // if the last integer difference was zero // multi = this.decGpsTime!.decodeSymbol(contexts[this.currentContext].mGpstime0diff!); // if (multi === 0) { // // the difference can be represented with 32 bits // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = // contexts[this.currentContext].icGpstime!.decompress(0, { value: 0 }); // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].i64 += BigInt( // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // ); // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = 0; // } else if (multi === 1) { // // the difference is huge // contexts[this.currentContext].next = (contexts[this.currentContext].next + 1) & 3; // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 = // contexts[this.currentContext].icGpstime!.decompress( // Number( // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].u64 >> // 32n, // ), // { value: 8 }, // ); // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 = // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 << 32n; // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 |= BigInt( // this.decGpsTime!.readInt(), // ); // contexts[this.currentContext].last = contexts[this.currentContext].next; // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = 0; // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = 0; // } // we switch to another sequence // else { // contexts[this.currentContext].last = (contexts[this.currentContext].last + multi - 1) & 3; // this.#readGpsTime(); // } // } else { // multi = this.decGpsTime!.decodeSymbol(contexts[this.currentContext].mGpstimeMulti!); // if (multi === 1) { // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].i64 += BigInt( // contexts[this.currentContext].icGpstime!.decompress( // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 1 }, // ), // ); // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = 0; // } else if (multi < LASZIP_GPSTIME_MULTI_CODE_FULL) { // let gpstimeDiff: number; // I32 // if (multi === 0) { // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress(0, { value: 7 }); // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last]++; // if ( // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] > // 3 // ) { // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = // gpstimeDiff; // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = // 0; // } // } else if (multi < LASZIP_GPSTIME_MULTI) { // if (multi < 10) // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress( // multi * // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 2 }, // ); // else // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress( // multi * // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 3 }, // ); // } else if (multi === LASZIP_GPSTIME_MULTI) { // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress( // LASZIP_GPSTIME_MULTI * // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 4 }, // ); // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last]++; // if ( // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] > // 3 // ) { // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = // gpstimeDiff; // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = // 0; // } // } else { // multi = LASZIP_GPSTIME_MULTI - multi; // if (multi > LASZIP_GPSTIME_MULTI_MINUS) { // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress( // multi * // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 5 }, // ); // } else { // gpstimeDiff = contexts[this.currentContext].icGpstime!.decompress( // LASZIP_GPSTIME_MULTI_MINUS * // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last], // { value: 6 }, // ); // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last]++; // if ( // contexts[this.currentContext].multiExtremeCounter[ // contexts[this.currentContext].last // ] > 3 // ) { // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = // gpstimeDiff; // contexts[this.currentContext].multiExtremeCounter[ // contexts[this.currentContext].last // ] = 0; // } // } // } // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].i64 += // BigInt(gpstimeDiff); // } else if (multi === LASZIP_GPSTIME_MULTI_CODE_FULL) { // contexts[this.currentContext].next = (contexts[this.currentContext].next + 1) & 3; // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 = // contexts[this.currentContext].icGpstime!.decompress( // Number( // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].last].u64 >> // 32n, // ), // { value: 8 }, // ); // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 = // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 << 32n; // contexts[this.currentContext].lastGpstime[contexts[this.currentContext].next].u64 |= BigInt( // this.decGpsTime!.readInt(), // ); // contexts[this.currentContext].last = contexts[this.currentContext].next; // contexts[this.currentContext].lastGpstimeDiff[contexts[this.currentContext].last] = 0; // contexts[this.currentContext].multiExtremeCounter[contexts[this.currentContext].last] = 0; // } else if (multi >= LASZIP_GPSTIME_MULTI_CODE_FULL) { // contexts[this.currentContext].last = // (contexts[this.currentContext].last + multi - LASZIP_GPSTIME_MULTI_CODE_FULL) & 3; // this.#readGpsTime(); // } // } // } // /** // * @param context - the current context // * @param item - the current item to be read from // */ // #createAndInitModelsAndDecompressors(context: number, item: LASpoint14) { // const { contexts } = this; // let i: number; // I32 // /* first create all entropy models and integer decompressors (if needed) */ // if (contexts[context].mChangedValues[0] === undefined) { // /* for the channelReturnsXY layer */ // contexts[context].mChangedValues[0] = new ArithmeticModel(128); // contexts[context].mChangedValues[1] = new ArithmeticModel(128); // contexts[context].mChangedValues[2] = new ArithmeticModel(128); // contexts[context].mChangedValues[3] = new ArithmeticModel(128); // contexts[context].mChangedValues[4] = new ArithmeticModel(128); // contexts[context].mChangedValues[5] = new ArithmeticModel(128); // contexts[context].mChangedValues[6] = new ArithmeticModel(128); // contexts[context].mChangedValues[7] = new ArithmeticModel(128); // contexts[context].mScannerChannel = new ArithmeticModel(3); // for (i = 0; i < 16; i++) { // contexts[context].mNumberOfReturns[i] = undefined; // contexts[context].mReturnNumber[i] = undefined; // } // contexts[context].mReturnNumberGpsSame = new ArithmeticModel(13); // contexts[context].icdX = new IntegerCompressor(this.decChannelReturnsXY!, 32, 2); // 32 bits, 2 context // contexts[context].icdY = new IntegerCompressor(this.decChannelReturnsXY!, 32, 22); // 32 bits, 22 contexts // /* for the Z layer */ // contexts[context].icZ = new IntegerCompressor(this.decZ!, 32, 20); // 32 bits, 20 contexts // /* for the classification layer */ // /* for the flags layer */ // /* for the userData layer */ // for (i = 0; i < 64; i++) { // contexts[context].mClassification[i] = undefined; // contexts[context].mFlags[i] = undefined; // contexts[context].mUserData[i] = undefined; // } // /* for the intensity layer */ // contexts[context].icIntensity = new IntegerCompressor(this.decIntensity!, 16, 4); // /* for the scanAngle layer */ // contexts[context].icScanAngle = new IntegerCompressor(this.decScanAngle!, 16, 2); // /* for the pointSourceID layer */ // contexts[context].icPointSourceID = new IntegerCompressor(this.decPointSource!, 16); // /* for the gpsTime layer */ // contexts[context].mGpstimeMulti = new ArithmeticModel(LASZIP_GPSTIME_MULTI_TOTAL); // contexts[context].mGpstime0diff = new ArithmeticModel(5); // contexts[context].icGpstime = new IntegerCompressor(this.decGpsTime!, 32, 9); // 32 bits, 9 contexts // } // /* then init entropy models and integer compressors */ // /* for the channelReturnsXY layer */ // contexts[context].mChangedValues[0]!.init(); // contexts[context].mChangedValues[1]!.init(); // contexts[context].mChangedValues[2]!.init(); // contexts[context].mChangedValues[3]!.init(); // contexts[context].mChangedValues[4]!.init(); // contexts[context].mChangedValues[5]!.init(); // contexts[context].mChangedValues[6]!.init(); // contexts[context].mChangedValues[7]!.init(); // contexts[context].mScannerChannel!.init(); // for (i = 0; i < 16; i++) { // if (contexts[context].mNumberOfReturns[i] !== undefined) // contexts[context].mNumberOfReturns[i]!.init(); // if (contexts[context].mReturnNumber[i] !== undefined) // contexts[context].mReturnNumber[i]!.init(); // } // contexts[context].mReturnNumberGpsSame!.init(); // contexts[context].icdX!.initDecompressor(); // contexts[context].icdY!.initDecompressor(); // for (i = 0; i < 12; i++) { // contexts[context].lastXDiffMedian5[i]!.init(); // contexts[context].lastYDiffMedian5[i]!.init(); // } // /* for the Z layer */ // contexts[context].icZ!.initDecompressor(); // for (i = 0; i < 8; i++) { // contexts[context].lastZ[i] = item.z; // } // /* for the classification layer, flags layer, and userData layer */ // for (i = 0; i < 64; i++) { // if (contexts[context].mClassification[i] !== undefined) // contexts[context].mClassification[i]!.init(); // if (contexts[context].mFlags[i] !== undefined) contexts[context].mFlags[i]!.init(); // if (contexts[context].mUserData[i] !== undefined) contexts[context].mUserData[i]!.init(); // } // /* for the intensity layer */ // contexts[context].icIntensity!.initDecompressor(); // for (i = 0; i < 8; i++) { // contexts[context].lastIntensity[i] = item.intensity; // } // /* for the scanAngle layer */ // contexts[context].icScanAngle!.initDecompressor(); // /* for the pointSourceID layer */ // contexts[context].icPointSourceID!.initDecompressor(); // /* for the gpsTime layer */ // contexts[context].mGpstimeMulti!.init(); // contexts[context].mGpstime0diff!.init(); // contexts[context].icGpstime!.initDecompressor(); // contexts[context].last = 0; // contexts[context].next = 0; // contexts[context].lastGpstimeDiff[0] = 0; // contexts[context].lastGpstimeDiff[1] = 0; // contexts[context].lastGpstimeDiff[2] = 0; // contexts[context].lastGpstimeDiff[3] = 0; // contexts[context].multiExtremeCounter[0] = 0; // contexts[context].multiExtremeCounter[1] = 0; // contexts[context].multiExtremeCounter[2] = 0; // contexts[context].multiExtremeCounter[3] = 0; // contexts[context].lastGpstime[0].f64 = item.gpsTime; // contexts[context].lastGpstime[1].u64 = 0; // contexts[context].lastGpstime[2].u64 = 0; // contexts[context].lastGpstime[3].u64 = 0; // /* init current context from last item */ // item.copyTo(contexts[context].lastItem, 45); // new LASpoint14(contexts[context].lastItem).gpsTimeChange = 0; // contexts[context].unused = false; // } // } // /** Parse LAZ RGB 1.4v4 */ // export class LAZrgb14v4Reader implements ItemReader { // instreamRGB?: Reader; // decRGB?: ArithmeticDecoder; // changedRGB = false; // numBytesRGB = 0; // U32 // requestedRGB: boolean; // bytes?: DataView; // numBytesAllocated = 0; // U32 // currentContext = 0; // U32 // contexts = [ // new LAScontextRGB14(), // new LAScontextRGB14(), // new LAScontextRGB14(), // new LAScontextRGB14(), // ]; // /** // * @param dec - the arithmetic decoder // * @param decompressSelective - which fields to decompress // */ // constructor( // readonly dec: ArithmeticDecoder, // readonly decompressSelective = LASZIP_DECOMPRESS_SELECTIVE_ALL, // ) { // this.requestedRGB = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_RGB); // for (let c = 0; c < 4; c++) this.contexts[c].mByteUsed = undefined; // } // /** // * Read in the chunk size // * @param reader - the data block to read from // */ // chunkSizes(reader: Reader): void { // this.numBytesRGB = reader.getUint32(undefined, true); // } // /** // * @param item - the current item // * @param context - the current context // */ // init(item: DataView, context: LAZContext): void { // const { reader } = this.dec; // /* on the first init create instreams and decoders */ // if (this.instreamRGB === undefined) { // /* create decoders */ // this.decRGB = new ArithmeticDecoder(reader); // } // /* make sure the buffer is sufficiently large */ // if (this.numBytesRGB > this.numBytesAllocated) { // this.numBytesAllocated = this.numBytesRGB; // } // /* load the requested bytes and init the corresponding instreams an decoders */ // if (this.requestedRGB) { // if (this.numBytesRGB !== 0) { // this.bytes = reader.seekSlice(this.numBytesRGB); // this.instreamRGB = new BufferReader(this.bytes.buffer); // this.decRGB = new ArithmeticDecoder(this.instreamRGB); // this.decRGB.init(); // this.changedRGB = true; // } else { // this.instreamRGB = undefined; // this.changedRGB = false; // } // } else { // if (this.numBytesRGB !== 0) { // reader.seek(reader.tell() + this.numBytesRGB); // } // this.changedRGB = false; // } // /* mark the four scanner channel contexts as unused */ // for (let c = 0; c < 4; c++) this.contexts[c].unused = true; // /* set scanner channel as current context */ // this.currentContext = context.value; // all other items use context set by POINT14 reader // /* create and init models and decompressors */ // this.#createAndInitModelsAndDecompressors(this.currentContext, new LASrgba(item)); // } // /** // * @param item - the current item // * @param context - the current context // */ // read(item: DataView, context: LAZContext): void { // const { contexts } = this; // const curItem = new LASrgba(item); // let lastItem = new LASrgba(contexts[this.currentContext].lastItem); // // check for context switch // if (this.currentContext !== context.value) { // this.currentContext = context.value; // all other items use context set by POINT14 reader // if (contexts[this.currentContext].unused) { // this.#createAndInitModelsAndDecompressors(this.currentContext, lastItem); // } // lastItem = new LASrgba(contexts[this.currentContext].lastItem); // } // // decompress // if (this.changedRGB) { // let corr: number; // U8 // let diff = 0; // I32 // const sym = this.decRGB!.decodeSymbol(contexts[this.currentContext].mByteUsed!); // U32 // if ((sym & (1 << 0)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff0!); // curItem.r = u8Fold(corr + (lastItem.r & 255)); // } else { // curItem.r = lastItem.r & 0xff; // } // if ((sym & (1 << 1)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff1!); // curItem.r |= u8Fold(corr + (lastItem.r >> 8)) << 8; // } else { // curItem.r |= lastItem.r & 0xff00; // } // if ((sym & (1 << 6)) !== 0) { // diff = (curItem.r & 0x00ff) - (lastItem.r & 0x00ff); // if ((sym & (1 << 2)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff2!); // curItem.g = u8Fold(corr + u8Clamp(diff + (lastItem.g & 255))); // } else { // curItem.g = lastItem.g & 0xff; // } // if ((sym & (1 << 4)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff4!); // diff = Math.trunc((diff + ((curItem.g & 0x00ff) - (lastItem.g & 0x00ff))) / 2); // curItem.b = u8Fold(corr + u8Clamp(diff + (lastItem.b & 255))); // } else { // curItem.b = lastItem.b & 0xff; // } // diff = (curItem.r >> 8) - (lastItem.r >> 8); // if ((sym & (1 << 3)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff3!); // curItem.g |= u8Fold(corr + u8Clamp(diff + (lastItem.g >> 8))) << 8; // } else { // curItem.g |= lastItem.g & 0xff00; // } // if ((sym & (1 << 5)) !== 0) { // corr = this.decRGB!.decodeSymbol(contexts[this.currentContext].mRgbDiff5!); // diff = Math.trunc((diff + ((curItem.g >> 8) - (lastItem.g >> 8))) / 2); // curItem.b |= u8Fold(corr + u8Clamp(diff + (lastItem.b >> 8))) << 8; // } else { // curItem.b |= lastItem.b & 0xff00; // } // } else { // curItem.g = curItem.r; // curItem.b = curItem.r; // } // curItem.copyTo(lastItem.data, 6); // } else { // lastItem.copyTo(curItem.data, 6); // } // } // /** // * @param context - the current context // * @param item - the current item to be read from // */ // #createAndInitModelsAndDecompressors(context: number, item: LASrgba): void { // const { contexts } = this; // /* first create all entropy models (if needed) */ // if (contexts[context].mByteUsed === undefined) { // contexts[context].mByteUsed = new ArithmeticModel(128); // contexts[context].mRgbDiff0 = new ArithmeticModel(256); // contexts[context].mRgbDiff1 = new ArithmeticModel(256); // contexts[context].mRgbDiff2 = new ArithmeticModel(256); // contexts[context].mRgbDiff3 = new ArithmeticModel(256); // contexts[context].mRgbDiff4 = new ArithmeticModel(256); // contexts[context].mRgbDiff5 = new ArithmeticModel(256); // } // /* then init entropy models */ // contexts[context].mByteUsed!.init(); // contexts[context].mRgbDiff0!.init(); // contexts[context].mRgbDiff1!.init(); // contexts[context].mRgbDiff2!.init(); // contexts[context].mRgbDiff3!.init(); // contexts[context].mRgbDiff4!.init(); // contexts[context].mRgbDiff5!.init(); // /* init current context from item */ // item.copyTo(contexts[context].lastItem, 6); // contexts[context].unused = false; // } // } // /** Parse LAZ RGB NIR 1.4v3 */ // export class LAZrgbNir14v4Reader implements ItemReader { // instreamRGB?: Reader; // instreamNIR?: Reader; // decRGB?: ArithmeticDecoder; // decNIR?: ArithmeticDecoder; // changedRGB = false; // changedNIR = false; // numBytesRGB = 0; // U32 // numBytesNIR = 0; // U32 // requestedRGB: boolean; // requestedNIR: boolean; // bytes?: DataView; // numBytesAllocated = 0; // U32 // currentContext = 0; // U32 // contexts = [ // new LAScontextRGBNIR14(), // new LAScontextRGBNIR14(), // new LAScontextRGBNIR14(), // new LAScontextRGBNIR14(), // ]; // /** // * @param dec - the arithmetic decoder // * @param decompressSelective - the decompress selective // */ // constructor( // readonly dec: ArithmeticDecoder, // readonly decompressSelective = LASZIP_DECOMPRESS_SELECTIVE_ALL, // ) { // this.requestedRGB = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_RGB); // this.requestedNIR = Boolean(decompressSelective & LASZIP_DECOMPRESS_SELECTIVE_NIR); // /* mark the four scanner channel contexts as uninitialized */ // for (let c = 0; c < 4; c++) { // this.contexts[c].mRgbBytesUsed = undefined; // this.contexts[c].mNirBytesUsed = undefined; // } // } // /** @param reader - the data block to read from */ // chunkSizes(reader: Reader): void { // /* read bytes per layer */ // this.numBytesRGB = reader.getUint32(undefined, true); // this.numBytesNIR = reader.getUint32(undefined, true); // } // /** // * @param item - the current item // * @param context - the current context // */ // init(item: DataView, context: LAZContext): void { // const { reader } = this.dec; // if (this.instreamRGB === undefined) { // /* create decoders */ // this.decRGB = new ArithmeticDecoder(reader); // this.decNIR = new ArithmeticDecoder(reader); // } // /* how many bytes do we need to read */ // let numBytes = 0; // U32 // if (this.requestedRGB) numBytes += this.numBytesRGB; // if (this.requestedNIR) numBytes += this.numBytesNIR; // /* make sure the buffer is sufficiently large */ // if (numBytes > this.numBytesAllocated) this.numBytesAllocated = numBytes; // /* load the requested bytes and init the corresponding instreams an decoders */ // numBytes = 0; // if (this.requestedRGB) { // if (this.numBytesRGB !== 0) { // this.bytes = reader.seekSlice(this.numBytesRGB); // numBytes += this.numBytesRGB; // this.instreamRGB = new BufferReader(this.bytes.buffer); // this.decRGB = new ArithmeticDecoder(this.instreamRGB