├── .github └── workflows │ ├── ccpp.yml │ └── js.yml ├── .gitignore ├── CMakeLists.txt ├── COPYING ├── README.md ├── cleanup.sh ├── cmake ├── common.cmake ├── compiler_options.cmake ├── directories.cmake ├── functions.cmake ├── gtest.cmake ├── install.cmake ├── lazperf-config.cmake ├── modules │ ├── CodeCoverage.cmake │ └── FindLASzip.cmake ├── unix_compiler_options.cmake └── win32_compiler_options.cmake ├── cpp ├── CMakeLists.txt ├── benchmarks │ ├── CMakeLists.txt │ ├── brute_point10.cpp │ └── laszip.cpp ├── download-test-sets.sh ├── emscripten │ ├── CMakeLists.txt │ ├── compressed-autzen.bin │ ├── index-comp.html │ ├── index.html │ ├── laz-perf.cpp │ ├── point10.las.laz │ └── run-server.sh ├── examples │ ├── CMakeLists.txt │ ├── point10.cpp │ └── readlaz.cpp ├── lazperf │ ├── Extractor.hpp │ ├── Inserter.hpp │ ├── charbuf.cpp │ ├── charbuf.hpp │ ├── coderbase.hpp │ ├── compressor.hpp │ ├── decoder.hpp │ ├── decompressor.hpp │ ├── detail │ │ ├── field_byte10.cpp │ │ ├── field_byte10.hpp │ │ ├── field_byte14.cpp │ │ ├── field_byte14.hpp │ │ ├── field_gpstime.hpp │ │ ├── field_gpstime10.cpp │ │ ├── field_gpstime10.hpp │ │ ├── field_nir14.cpp │ │ ├── field_nir14.hpp │ │ ├── field_point10.cpp │ │ ├── field_point10.hpp │ │ ├── field_point14.cpp │ │ ├── field_point14.hpp │ │ ├── field_rgb10.cpp │ │ ├── field_rgb10.hpp │ │ ├── field_rgb14.cpp │ │ ├── field_rgb14.hpp │ │ └── field_xyz.hpp │ ├── encoder.hpp │ ├── excepts.hpp │ ├── filestream.cpp │ ├── filestream.hpp │ ├── header.cpp │ ├── header.hpp │ ├── las.hpp │ ├── lazperf.cpp │ ├── lazperf.hpp │ ├── lazperf_base.hpp │ ├── lazperf_user_base.hpp │ ├── model.hpp │ ├── portable_endian.hpp │ ├── readers.cpp │ ├── readers.hpp │ ├── streams.hpp │ ├── utils.hpp │ ├── vlr.cpp │ ├── vlr.hpp │ ├── writers.cpp │ └── writers.hpp ├── support │ ├── brute.html │ └── brute_point10.html ├── test │ ├── CMakeLists.txt │ ├── io_tests.cpp │ ├── lazperf_tests.cpp │ ├── raw-sets │ │ ├── 1815.las │ │ ├── 1815.laz │ │ ├── autzen_trim.las │ │ ├── autzen_trim.laz │ │ ├── classification.txt │ │ ├── extrabytes.las │ │ ├── extrabytes.laz │ │ ├── no-points-1.3.las │ │ ├── no-points-1.3.laz │ │ ├── point-color-time.las │ │ ├── point-color-time.las.laz │ │ ├── point-color.las │ │ ├── point-color.las.laz │ │ ├── point-time-1.4.las.laz │ │ ├── point-time.las │ │ ├── point-time.las.laz │ │ ├── point10-1.0.las │ │ ├── point10-1.0.laz │ │ ├── point10-1.1.las │ │ ├── point10-1.1.laz │ │ ├── point10-1.las.laz.raw │ │ ├── point10-1.las.raw │ │ ├── point10.las │ │ ├── point10.las.laz │ │ └── rand1_6.las │ ├── reader.hpp │ ├── stream_tests.cpp │ ├── test.zsh │ └── test_main.hpp.in └── tools │ ├── CMakeLists.txt │ └── random.cpp ├── hobu-config.bat └── js ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── babel.config.js ├── bundle.sh ├── jest.config.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── index.ts ├── laz-perf.d.ts ├── laz-perf.js ├── laz-perf.wasm └── test │ ├── chunk.test.ts │ ├── file.test.ts │ └── utils.ts ├── tsconfig.json ├── tsconfig.production.json └── wasm.sh /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - '*' 5 | pull_request: 6 | branches: 7 | - '*' 8 | release: 9 | types: 10 | - published 11 | 12 | jobs: 13 | base: 14 | name: Base library ${{ matrix.os }} 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | fail-fast: true 18 | matrix: 19 | os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] 20 | steps: 21 | - uses: actions/checkout@v2 22 | - uses: actions/setup-python@v3 23 | name: Install Python 24 | with: 25 | python-version: '3.10' 26 | - name: Checkout submodules 27 | run: git submodule update --init --recursive 28 | 29 | - uses: ilammy/msvc-dev-cmd@v1 30 | if: matrix.os == 'windows-latest' 31 | 32 | - name: Install CMake and Ninja 33 | run: | 34 | which python 35 | python --version 36 | pip install cmake ninja 37 | - name: Configure 38 | shell: bash -l {0} 39 | run: | 40 | if [ "$RUNNER_OS" == "Windows" ]; then 41 | export CC=cl.exe 42 | export CXX=cl.exe 43 | fi 44 | mkdir build 45 | cd build 46 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -Dgtest_force_shared_crt=ON 47 | - name: Build 48 | shell: bash -l {0} 49 | run: | 50 | cd build 51 | ninja 52 | - name: Test 53 | shell: bash -l {0} 54 | run: | 55 | cd build 56 | ctest 57 | 58 | -------------------------------------------------------------------------------- /.github/workflows/js.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - '*' 5 | pull_request: 6 | branches: 7 | - '*' 8 | release: 9 | types: 10 | - published 11 | 12 | jobs: 13 | test: 14 | runs-on: 'ubuntu-latest' 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | path: laz-perf 20 | - name: Emsdk 21 | run: | 22 | git clone https://github.com/emscripten-core/emsdk.git 23 | cd emsdk 24 | git pull 25 | ./emsdk install latest 26 | ./emsdk activate latest 27 | - name: Wasm 28 | run: | 29 | . emsdk/emsdk_env.sh 30 | cd laz-perf 31 | mkdir build 32 | cd build 33 | cmake \ 34 | -G "Unix Makefiles" \ 35 | -DCMAKE_TOOLCHAIN_FILE="$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" \ 36 | -DCMAKE_BUILD_TYPE=Release \ 37 | .. 38 | $EMSDK/upstream/emscripten/emmake make VERBOSE=1 39 | cp ./cpp/emscripten/laz-perf.* ../js/src/ 40 | - name: Test 41 | run: | 42 | cd laz-perf/js 43 | npm ci 44 | npm test --all 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lazperf/lazperf 2 | *.o 3 | CMakeCache.txt 4 | CMakeFiles/ 5 | cmake_install.cmake 6 | Makefile 7 | install_manifest.txt 8 | test/lazperf_tests 9 | examples/simple 10 | examples/point10 11 | examples/readlaz 12 | examples/dynamic 13 | benchmarks/brute 14 | benchmarks/brute_point10 15 | benchmarks/laszip 16 | .DS_Store 17 | *.js 18 | *.js.map 19 | .vagrant/ 20 | CTestTestfile.cmake 21 | Testing/ 22 | emscripten/autzen.laz 23 | emscripten/haloe.laz 24 | test/raw-sets/SpaceShuttle.laz 25 | test/raw-sets/haloe.laz 26 | cpp/examples/*.wasm 27 | cpp/benchmarks/*.wasm 28 | 29 | # test files we don't need to version control 30 | cpp/test/test_main.hpp 31 | cpp/test/raw-sets/autzen.la? 32 | *.vcxproj 33 | *.filters 34 | *.opensdf 35 | *.sdf 36 | *.sln 37 | *.suo 38 | *.log 39 | *.lastbuildstate 40 | *.tlog 41 | *.exe 42 | *.ilk 43 | *.pdb 44 | *.obj 45 | *.vcxproj.user 46 | *.dll 47 | *.js.mem 48 | build/ 49 | dist/ 50 | wheelhouse 51 | python/lazperf/*.so 52 | python/VERSION.txt 53 | python/lazperf/pylazperfapi.cpp 54 | .eggs/ 55 | *.pyc 56 | lazperf.egg-info 57 | lazperf/*.pyc 58 | lazperf/pylazperfapi.cpp 59 | lazperf/pylazperfapi.so 60 | python/test/*.pyc 61 | python/.eggs/ 62 | *__pycache__* 63 | test/test_main.hpp 64 | x64/Release/ALL_BUILD/ALL_BUILD.vcxprojResolveAssemblyReference.cache 65 | test/gtest/gtest-1.7.0/Release/gtest_main.lib 66 | LAZPERF.VC.VC.opendb 67 | build-js/ 68 | build-wasm/ 69 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(LAZPERF VERSION 3.4.0) 4 | 5 | set(ROOT_DIR ${PROJECT_SOURCE_DIR}) 6 | include(${ROOT_DIR}/cmake/common.cmake NO_POLICY_SCOPE) 7 | include(${ROOT_DIR}/cmake/gtest.cmake) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # Allow advanced users to generate Makefiles printing detailed commands 13 | mark_as_advanced(CMAKE_VERBOSE_MAKEFILE) 14 | 15 | # Path to additional CMake modules 16 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) 17 | 18 | #------------------------------------------------------------------------------ 19 | # general settings 20 | #------------------------------------------------------------------------------ 21 | 22 | # Choose package components 23 | set(WITH_TESTS TRUE CACHE BOOL "Choose if LAZPERF unit tests should be built") 24 | 25 | if (EMSCRIPTEN) 26 | set(WITH_TESTS NO) 27 | else() 28 | include(${LAZPERF_CMAKE_DIR}/install.cmake) 29 | endif() 30 | 31 | if(WITH_TESTS) 32 | enable_testing() 33 | file (DOWNLOAD 34 | "https://github.com/PDAL/data/raw/master/autzen/autzen.laz" 35 | "cpp/test/raw-sets/autzen.laz") 36 | endif() 37 | 38 | # Encourage user to specify a build type (e.g. Release, Debug, etc.), otherwise set it to Release. 39 | if(NOT CMAKE_CONFIGURATION_TYPES) 40 | if(NOT CMAKE_BUILD_TYPE) 41 | message(STATUS "Setting build type to 'Release' as none was specified.") 42 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "Release") 43 | endif() 44 | endif() 45 | 46 | add_subdirectory(cpp) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # What is this? 3 | 4 | LAZperf is an alternative [LAZ](http://laszip.org) implementation. It supports compilation 5 | to WASM via [Emscripten](https://emscripten.org/) so that LAZ data can be decoded in a browser. 6 | 7 | # Building LAZperf for Windows/UNIX 8 | 9 | Previous versions of LAZperf were header-only C++ libraries, so you could simply include the 10 | project header files in your project. Primarily due to licensing issues, this is no longer the 11 | case and LAZperf needs to be built as a library that links with your code. LAZperf uses 12 | CMake as a build system, though it's probably simple to port to another build system as there 13 | are few source files and no dependencies. Assuming you have Git, CMake, make and C++11 compiler 14 | installed, here is the 15 | process on the Unix command line. The process is similar on Windows. 16 | 17 | git clone https://github.com/hobu/laz-perf.git 18 | cd laz-perf 19 | mkdir build 20 | cd build 21 | cmake .. 22 | make 23 | 24 | This should build the library `liblazperf.so` (or similar). You can install this library along 25 | with the supporting header files as follows: 26 | 27 | make install 28 | 29 | # Using LAZperf on Windows/UNIX 30 | 31 | Although the LAZperf library is focused on decoding the LAZ data itself, there is support 32 | for reading a complete LAS or LAZ file. If you have LAZ-compressed data, you can decompress 33 | by creating a decompressor for the right point type and providing a callback that will 34 | provide data from the LAZ source as requested by the decompressor. For example, to read 35 | point format 0 data, you might do the following: 36 | 37 | using namespace lazperf; 38 | 39 | void cb(unsigned char *buf, int len) 40 | { 41 | static unsigned char my_laz_data[] = {...}; 42 | static int idx = 0; 43 | 44 | std::copy(buf, buf + len, my_laz_data + idx); 45 | idx += len; 46 | } 47 | 48 | point_decompressor_0 decompressor(cb); 49 | 50 | char pointbuf[100]; 51 | for (int i = 0; i < num_points; ++i) 52 | { 53 | decompressor(pointbuf); 54 | // Do something with the point data in 'pointbuf' 55 | } 56 | 57 | Compression follows a similar pattern -- see the accompanying examples and tests. 58 | 59 | You can also use LAZperf to read LAZ data from an entire LAZ or LAS file: 60 | 61 | using namespace lazperf; 62 | 63 | reader::named_file f(filename); 64 | 65 | char pointbuf[100]; 66 | for (size_t i = 0; i < f.header().point_count; ++i) 67 | f.readPoint(pointbuf); 68 | 69 | A memory file interface exists If your LAS/LAZ data is internal rather than in a file: 70 | 71 | using namespace lazperf; 72 | 73 | reader::mem_file f(buf, bufsize); 74 | 75 | char pointbuf[100]; 76 | for (size_t i = 0; i < f.header().point_count; ++i) 77 | f.readPoint(pointbuf); 78 | 79 | 80 | # Using LAZperf in JavaScript/TypeScript 81 | 82 | ### Install 83 | LAZperf is available as a UMD module compatible with both NodeJS and browsers, 84 | and includes TypeScript definitions. 85 | ``` 86 | npm install laz-perf 87 | ``` 88 | 89 | ### Usage 90 | ``` 91 | import { createLazPerf } from 'laz-perf' 92 | 93 | const LazPerf = await createLazPerf() 94 | 95 | // File reader API. 96 | const laszip = new LazPerf.LASZip() 97 | laszip.open(filePointer, fileByteLength) 98 | for (let i = 0; i < pointCount; ++i) { 99 | laszip.getPoint(dataPointer) 100 | // Do something with point data. 101 | } 102 | 103 | // Chunk decoder API. 104 | const decoder = new LazPerf.ChunkDecoder() 105 | decoder.open(pointDataRecordFormat, pointDataRecordLength, chunkPointer) 106 | for (let i = 0; i < pointCount; ++i) { 107 | decoder.getPoint(dataPointer) 108 | // Do something with point data. 109 | } 110 | ``` 111 | 112 | See unit tests in `js/src/test` for further details and how to interact with the 113 | Emscripten heap to work with the data. 114 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Clean stuff up 3 | 4 | find . -name cmake_install.cmake -exec rm {} \; 5 | find . -name CMakeCache.txt -exec rm {} \; 6 | find . -name CMakeFiles -exec rm -rf {} \; 7 | find . -name Makefile -exec rm {} \; 8 | -------------------------------------------------------------------------------- /cmake/common.cmake: -------------------------------------------------------------------------------- 1 | include(${CMAKE_CURRENT_LIST_DIR}/directories.cmake) 2 | 3 | include(${CMAKE_CURRENT_LIST_DIR}/functions.cmake) 4 | include(${CMAKE_CURRENT_LIST_DIR}/compiler_options.cmake) 5 | 6 | -------------------------------------------------------------------------------- /cmake/compiler_options.cmake: -------------------------------------------------------------------------------- 1 | if (WIN32) 2 | include (${CMAKE_CURRENT_LIST_DIR}/win32_compiler_options.cmake) 3 | else() 4 | include (${CMAKE_CURRENT_LIST_DIR}/unix_compiler_options.cmake) 5 | endif() 6 | -------------------------------------------------------------------------------- /cmake/directories.cmake: -------------------------------------------------------------------------------- 1 | if (NOT ROOT_DIR) 2 | message(FATAL_ERROR "ROOT_DIR must be set in the top-level CMakeLists.txt") 3 | endif() 4 | set(LAZPERF_CMAKE_DIR ${ROOT_DIR}/cmake) 5 | -------------------------------------------------------------------------------- /cmake/functions.cmake: -------------------------------------------------------------------------------- 1 | function(lazperf_add_library _target _type) 2 | add_library(${_target} ${_type} ${ARGN}) 3 | lazperf_library_compile_settings(${_target} ${_type}) 4 | if (${_type} STREQUAL "SHARED") 5 | lazperf_install_library(${_target}) 6 | endif() 7 | endfunction() 8 | -------------------------------------------------------------------------------- /cmake/gtest.cmake: -------------------------------------------------------------------------------- 1 | # CMake configuration for PROJ unit tests 2 | # External GTest provided by (e.g.) libgtest-dev 3 | 4 | set(MIN_GTest_VERSION "1.8.1") 5 | 6 | if(NOT CMAKE_REQUIRED_QUIET) 7 | # CMake 3.17+ use CHECK_START/CHECK_PASS/CHECK_FAIL 8 | message(STATUS "Looking for GTest") 9 | endif() 10 | find_package(GTest QUIET) 11 | set(USE_EXTERNAL_GTEST_DEFAULT OFF) 12 | if(GTest_FOUND) 13 | if(NOT CMAKE_REQUIRED_QUIET) 14 | message(STATUS "Looking for GTest - found (${GTest_VERSION})") 15 | endif() 16 | if(GTest_VERSION VERSION_LESS MIN_GTest_VERSION) 17 | message(WARNING "External GTest version is too old") 18 | else() 19 | set(USE_EXTERNAL_GTEST_DEFAULT ON) 20 | endif() 21 | else() 22 | if(NOT CMAKE_REQUIRED_QUIET) 23 | message(STATUS "Looking for GTest - not found") 24 | endif() 25 | endif() 26 | 27 | option(USE_EXTERNAL_GTEST 28 | "Compile against external GTest" 29 | ${USE_EXTERNAL_GTEST_DEFAULT} 30 | ) 31 | 32 | if(USE_EXTERNAL_GTEST) 33 | 34 | if(NOT GTest_FOUND) 35 | message(SEND_ERROR "External GTest >= ${MIN_GTest_VERSION} not found, \ 36 | skipping some tests") 37 | # exit the remainder of this file 38 | return() 39 | endif() 40 | message(STATUS "Using external GTest") 41 | 42 | # CMake < 3.20.0 uses GTest::GTest 43 | # CMake >= 3.20 uses GTest::gtest, and deprecates GTest::GTest 44 | # so for older CMake, create an alias from GTest::GTest to GTest::gtest 45 | if(NOT TARGET GTest::gtest) 46 | add_library(GTest::gtest INTERFACE IMPORTED) 47 | set_target_properties(GTest::gtest PROPERTIES 48 | INTERFACE_LINK_LIBRARIES "GTest::GTest") 49 | endif() 50 | 51 | else() 52 | 53 | message(STATUS "Fetching GTest from GitHub ...") 54 | 55 | # Add Google Test 56 | # 57 | # See https://github.com/google/googletest/blob/main/googletest/README.md 58 | 59 | if(POLICY CMP0135) 60 | cmake_policy(SET CMP0135 NEW) # for DOWNLOAD_EXTRACT_TIMESTAMP option 61 | endif() 62 | 63 | set(GTEST_VERSION "1.15.2") 64 | 65 | include(FetchContent) 66 | FetchContent_Declare( 67 | googletest 68 | URL https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.zip 69 | EXCLUDE_FROM_ALL # ignored before CMake 3.28 70 | ) 71 | 72 | # For Windows: Prevent overriding the parent project's compiler/linker settings 73 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 74 | 75 | if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28.0") 76 | FetchContent_MakeAvailable(googletest) 77 | else() 78 | # Pre CMake 3.28 workaround to prevent installing files 79 | FetchContent_GetProperties(googletest) 80 | if(NOT googletest_POPULATED) 81 | FetchContent_Populate(googletest) 82 | add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) 83 | endif() 84 | endif() 85 | endif() 86 | 87 | -------------------------------------------------------------------------------- /cmake/install.cmake: -------------------------------------------------------------------------------- 1 | include(CMakePackageConfigHelpers) 2 | 3 | write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/lazperf-config-version.cmake 4 | VERSION ${LAZPERF_VERSION} 5 | COMPATIBILITY SameMajorVersion 6 | ) 7 | configure_file(${LAZPERF_CMAKE_DIR}/lazperf-config.cmake 8 | ${CMAKE_CURRENT_BINARY_DIR}/lazperf-config.cmake COPYONLY 9 | ) 10 | 11 | function(lazperf_install_library _target) 12 | install( 13 | TARGETS 14 | ${_target} 15 | EXPORT 16 | lazperf-targets 17 | LIBRARY DESTINATION lib 18 | ) 19 | target_include_directories(${_target} INTERFACE $) 20 | endfunction() 21 | 22 | install( 23 | EXPORT 24 | lazperf-targets 25 | FILE 26 | lazperf-targets.cmake 27 | NAMESPACE 28 | LAZPERF:: 29 | DESTINATION 30 | lib/cmake/LAZPERF 31 | ) 32 | 33 | # 34 | # cmake file handling 35 | # 36 | 37 | install( 38 | FILES 39 | ${CMAKE_CURRENT_BINARY_DIR}/lazperf-config.cmake 40 | ${CMAKE_CURRENT_BINARY_DIR}/lazperf-config-version.cmake 41 | DESTINATION 42 | lib/cmake/LAZPERF 43 | ) 44 | -------------------------------------------------------------------------------- /cmake/lazperf-config.cmake: -------------------------------------------------------------------------------- 1 | include(${CMAKE_CURRENT_LIST_DIR}/lazperf-targets.cmake) 2 | -------------------------------------------------------------------------------- /cmake/modules/CodeCoverage.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # 2012-01-31, Lars Bilke 3 | # - Enable Code Coverage 4 | # 5 | # 2013-09-17, Joakim Söderberg 6 | # - Added support for Clang. 7 | # - Some additional usage instructions. 8 | # 9 | # USAGE: 10 | # 1. Copy this file into your cmake modules path. 11 | # 12 | # 2. Add the following line to your CMakeLists.txt: 13 | # INCLUDE(CodeCoverage) 14 | # 15 | # 3. Set compiler flags to turn off optimization and enable coverage: 16 | # SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") 17 | # SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") 18 | # 19 | # 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target 20 | # which runs your test executable and produces a lcov code coverage report: 21 | # Example: 22 | # SETUP_TARGET_FOR_COVERAGE( 23 | # my_coverage_target # Name for custom target. 24 | # test_driver # Name of the test driver executable that runs the tests. 25 | # # NOTE! This should always have a ZERO as exit code 26 | # # otherwise the coverage generation will not complete. 27 | # coverage # Name of output directory. 28 | # ) 29 | # 30 | # 4. Build a Debug build: 31 | # cmake -DCMAKE_BUILD_TYPE=Debug .. 32 | # make 33 | # make my_coverage_target 34 | # 35 | # 36 | 37 | # Check prereqs 38 | FIND_PROGRAM( GCOV_PATH gcov ) 39 | FIND_PROGRAM( LCOV_PATH lcov ) 40 | FIND_PROGRAM( GENHTML_PATH genhtml ) 41 | FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) 42 | 43 | IF(NOT GCOV_PATH) 44 | MESSAGE(FATAL_ERROR "gcov not found! Aborting...") 45 | ENDIF() # NOT GCOV_PATH 46 | 47 | IF(NOT CMAKE_COMPILER_IS_GNUCXX) 48 | # Clang version 3.0.0 and greater now supports gcov as well. 49 | MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") 50 | 51 | IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 52 | MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") 53 | ENDIF() 54 | ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX 55 | 56 | SET(CMAKE_CXX_FLAGS_COVERAGE 57 | "-g -O0 --coverage -fprofile-arcs -ftest-coverage" 58 | CACHE STRING "Flags used by the C++ compiler during coverage builds." 59 | FORCE ) 60 | SET(CMAKE_C_FLAGS_COVERAGE 61 | "-g -O0 --coverage -fprofile-arcs -ftest-coverage" 62 | CACHE STRING "Flags used by the C compiler during coverage builds." 63 | FORCE ) 64 | SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE 65 | "" 66 | CACHE STRING "Flags used for linking binaries during coverage builds." 67 | FORCE ) 68 | SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE 69 | "" 70 | CACHE STRING "Flags used by the shared libraries linker during coverage builds." 71 | FORCE ) 72 | MARK_AS_ADVANCED( 73 | CMAKE_CXX_FLAGS_COVERAGE 74 | CMAKE_C_FLAGS_COVERAGE 75 | CMAKE_EXE_LINKER_FLAGS_COVERAGE 76 | CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) 77 | 78 | IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage")) 79 | MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) 80 | ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" 81 | 82 | 83 | # Param _targetname The name of new the custom make target 84 | # Param _testrunner The name of the target which runs the tests. 85 | # MUST return ZERO always, even on errors. 86 | # If not, no coverage report will be created! 87 | # Param _outputname lcov output is generated as _outputname.info 88 | # HTML report is generated in _outputname/index.html 89 | # Optional fourth parameter is passed as arguments to _testrunner 90 | # Pass them in list form, e.g.: "-j;2" for -j 2 91 | FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname) 92 | 93 | IF(NOT LCOV_PATH) 94 | MESSAGE(FATAL_ERROR "lcov not found! Aborting...") 95 | ENDIF() # NOT LCOV_PATH 96 | 97 | IF(NOT GENHTML_PATH) 98 | MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") 99 | ENDIF() # NOT GENHTML_PATH 100 | 101 | # Setup target 102 | ADD_CUSTOM_TARGET(${_targetname} 103 | 104 | # Cleanup lcov 105 | ${LCOV_PATH} --directory . --zerocounters 106 | 107 | # Run tests 108 | COMMAND ${_testrunner} ${ARGV3} 109 | 110 | # Capturing lcov counters and generating report 111 | COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info 112 | COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned 113 | COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned 114 | COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned 115 | 116 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 117 | COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." 118 | ) 119 | 120 | # Show info where to find the report 121 | ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD 122 | COMMAND ; 123 | COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." 124 | ) 125 | 126 | ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE 127 | 128 | # Param _targetname The name of new the custom make target 129 | # Param _testrunner The name of the target which runs the tests 130 | # Param _outputname cobertura output is generated as _outputname.xml 131 | # Optional fourth parameter is passed as arguments to _testrunner 132 | # Pass them in list form, e.g.: "-j;2" for -j 2 133 | FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) 134 | 135 | IF(NOT PYTHON_EXECUTABLE) 136 | MESSAGE(FATAL_ERROR "Python not found! Aborting...") 137 | ENDIF() # NOT PYTHON_EXECUTABLE 138 | 139 | IF(NOT GCOVR_PATH) 140 | MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") 141 | ENDIF() # NOT GCOVR_PATH 142 | 143 | ADD_CUSTOM_TARGET(${_targetname} 144 | 145 | # Run tests 146 | ${_testrunner} ${ARGV3} 147 | 148 | # Running gcovr 149 | COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml 150 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 151 | COMMENT "Running gcovr to produce Cobertura code coverage report." 152 | ) 153 | 154 | # Show info where to find the report 155 | ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD 156 | COMMAND ; 157 | COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." 158 | ) 159 | 160 | ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA 161 | -------------------------------------------------------------------------------- /cmake/modules/FindLASzip.cmake: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # CMake module to search for LASzip library 4 | # 5 | # On success, the macro sets the following variables: 6 | # LASZIP_FOUND = if the library found 7 | # LASZIP_LIBRARIES = full path to the library 8 | # LASZIP_INCLUDE_DIR = where to find the library headers also defined, 9 | # but not for general use are 10 | # LASZIP_LIBRARY = where to find the PROJ.4 library. 11 | # LASZIP_VERSION = version of library which was found, e.g. "1.2.5" 12 | # 13 | # Copyright (c) 2009 Mateusz Loskot 14 | # 15 | # Module source: http://github.com/mloskot/workshop/tree/master/cmake/ 16 | # 17 | # Redistribution and use is allowed according to the terms of the BSD license. 18 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 19 | # 20 | ############################################################################### 21 | MESSAGE(STATUS "Searching for LASzip ${LASzip_FIND_VERSION}+ library") 22 | 23 | IF(LASZIP_INCLUDE_DIR) 24 | # Already in cache, be silent 25 | SET(LASZIP_FIND_QUIETLY TRUE) 26 | ENDIF() 27 | 28 | IF(WIN32) 29 | SET(OSGEO4W_IMPORT_LIBRARY laszip) 30 | IF(DEFINED ENV{OSGEO4W_ROOT}) 31 | SET(OSGEO4W_ROOT_DIR $ENV{OSGEO4W_ROOT}) 32 | MESSAGE(STATUS "Trying OSGeo4W using environment variable OSGEO4W_ROOT=$ENV{OSGEO4W_ROOT}") 33 | ELSE() 34 | SET(OSGEO4W_ROOT_DIR c:/OSGeo4W) 35 | MESSAGE(STATUS "Trying OSGeo4W using default location OSGEO4W_ROOT=${OSGEO4W_ROOT_DIR}") 36 | ENDIF() 37 | ENDIF() 38 | 39 | 40 | FIND_PATH(LASZIP_INCLUDE_DIR 41 | laszip.hpp 42 | PATH_PREFIXES laszip 43 | PATHS 44 | /usr/include 45 | /usr/local/include 46 | ${OSGEO4W_ROOT_DIR}/include 47 | NO_DEFAULT_PATH) 48 | 49 | SET(LASZIP_NAMES ${OSGEO4W_IMPORT_LIBRARY} laszip) 50 | 51 | FIND_LIBRARY(LASZIP_LIBRARY 52 | NAMES ${LASZIP_NAMES} 53 | PATHS 54 | /usr/lib 55 | /usr/local/lib 56 | ${OSGEO4W_ROOT_DIR}/lib) 57 | 58 | IF(LASZIP_FOUND) 59 | SET(LASZIP_LIBRARIES ${LASZIP_LIBRARY}) 60 | ENDIF() 61 | 62 | IF(LASZIP_INCLUDE_DIR) 63 | SET(LASZIP_VERSION 0) 64 | 65 | SET(LASZIP_VERSION_H "${LASZIP_INCLUDE_DIR}/laszip/laszip.hpp") 66 | FILE(READ ${LASZIP_VERSION_H} LASZIP_VERSION_H_CONTENTS) 67 | 68 | IF (DEFINED LASZIP_VERSION_H_CONTENTS) 69 | string(REGEX REPLACE ".*#define[ \t]LASZIP_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" LASZIP_VERSION_MAJOR "${LASZIP_VERSION_H_CONTENTS}") 70 | string(REGEX REPLACE ".*#define[ \t]LASZIP_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" LASZIP_VERSION_MINOR "${LASZIP_VERSION_H_CONTENTS}") 71 | string(REGEX REPLACE ".*#define[ \t]LASZIP_VERSION_REVISION[ \t]+([0-9]+).*" "\\1" LASZIP_VERSION_REVISION "${LASZIP_VERSION_H_CONTENTS}") 72 | 73 | if(NOT ${LASZIP_VERSION_MAJOR} MATCHES "[0-9]+") 74 | message(FATAL_ERROR "LASzip version parsing failed for LASZIP_VERSION_MAJOR!") 75 | endif() 76 | if(NOT ${LASZIP_VERSION_MINOR} MATCHES "[0-9]+") 77 | message(FATAL_ERROR "LASzip version parsing failed for LASZIP_VERSION_MINOR!") 78 | endif() 79 | if(NOT ${LASZIP_VERSION_REVISION} MATCHES "[0-9]+") 80 | message(FATAL_ERROR "LASzip version parsing failed for LASZIP_VERSION_REVISION!") 81 | endif() 82 | 83 | 84 | SET(LASZIP_VERSION "${LASZIP_VERSION_MAJOR}.${LASZIP_VERSION_MINOR}.${LASZIP_VERSION_REVISION}" 85 | CACHE INTERNAL "The version string for LASzip library") 86 | 87 | IF (LASZIP_VERSION VERSION_EQUAL LASzip_FIND_VERSION OR 88 | LASZIP_VERSION VERSION_GREATER LASzip_FIND_VERSION) 89 | MESSAGE(STATUS "Found LASzip version: ${LASZIP_VERSION}") 90 | ELSE() 91 | MESSAGE(FATAL_ERROR "LASzip version check failed. Version ${LASZIP_VERSION} was found, at least version ${LASzip_FIND_VERSION} is required") 92 | ENDIF() 93 | ELSE() 94 | MESSAGE(FATAL_ERROR "Failed to open ${LASZIP_VERSION_H} file") 95 | ENDIF() 96 | 97 | ENDIF() 98 | 99 | # Handle the QUIETLY and REQUIRED arguments and set LASZIP_FOUND to TRUE 100 | # if all listed variables are TRUE 101 | INCLUDE(FindPackageHandleStandardArgs) 102 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(LASzip DEFAULT_MSG LASZIP_LIBRARY LASZIP_INCLUDE_DIR) 103 | -------------------------------------------------------------------------------- /cmake/unix_compiler_options.cmake: -------------------------------------------------------------------------------- 1 | function(lazperf_target_compile_settings target) 2 | set_property(TARGET ${target} PROPERTY CXX_STANDARD 11) 3 | set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED TRUE) 4 | if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") 5 | # 6 | # VERSION_GREATER_EQUAL doesn't come until cmake 3.7 7 | # 8 | if (NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 7.0) 9 | target_compile_options(${target} PRIVATE 10 | -Wno-implicit-fallthrough 11 | -Wno-int-in-bool-context 12 | -Wno-dangling-else 13 | -Wno-noexcept-type 14 | ) 15 | endif() 16 | set(PDAL_COMPILER_GCC 1) 17 | elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") 18 | set(PDAL_COMPILER_CLANG 1) 19 | else() 20 | message(FATAL_ERROR "Unsupported C++ compiler") 21 | endif() 22 | 23 | target_compile_options(${target} PRIVATE 24 | ${PDAL_CXX_STANDARD} 25 | -Wall 26 | -Wextra 27 | -Wpointer-arith 28 | -Wcast-align 29 | -Wcast-qual 30 | -Wno-error=parentheses 31 | -Wno-error=cast-qual 32 | -Wredundant-decls 33 | 34 | -Wno-unused-parameter 35 | -Wno-unused-variable 36 | -Wno-long-long 37 | -Wno-unknown-pragmas 38 | -Wno-deprecated-declarations 39 | ) 40 | if (PDAL_COMPILER_CLANG) 41 | target_compile_options(${target} PRIVATE 42 | -Wno-unknown-warning-option 43 | ) 44 | endif() 45 | endfunction() 46 | 47 | function(lazperf_library_compile_settings lib type) 48 | lazperf_target_compile_settings(${lib}) 49 | if (${type} STREQUAL "SHARED") 50 | target_compile_options(${lib} PRIVATE 51 | -fvisibility=hidden 52 | -fvisibility-inlines-hidden 53 | ) 54 | endif() 55 | endfunction() 56 | 57 | -------------------------------------------------------------------------------- /cmake/win32_compiler_options.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # We assume you're using MSVC if you're on WIN32. 3 | # 4 | 5 | function(lazperf_target_compile_settings target) 6 | set_property(TARGET ${target} PROPERTY CXX_STANDARD 11) 7 | set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED TRUE) 8 | target_compile_definitions(${target} PRIVATE 9 | -DWIN32_LEAN_AND_MEAN) 10 | if (MSVC) 11 | target_compile_definitions(${target} PRIVATE 12 | -D_CRT_SECURE_NO_DEPRECATE 13 | -D_CRT_SECURE_NO_WARNINGS 14 | -D_CRT_NONSTDC_NO_WARNING 15 | -D_SCL_SECURE_NO_WARNINGS 16 | ) 17 | target_compile_options(${target} PRIVATE 18 | # Yes, we don't understand GCC pragmas 19 | /wd4068 20 | # Windows warns about integer narrowing like crazy and it's 21 | # annoying. In most cases the programmer knows what they're 22 | # doing. A good static analysis tool would be better than 23 | # turning this warning off. 24 | /wd4267 25 | # Annoying warning about function hiding with virtual 26 | # inheritance. 27 | /wd4250 28 | # MSVC doesn't understand bool -> int conversion 29 | /wd4805 30 | # Standard C++-type exception handling. 31 | /EHsc 32 | ) 33 | 34 | include(ProcessorCount) 35 | ProcessorCount(N) 36 | if(NOT N EQUAL 0) 37 | target_compile_options(${target} PRIVATE "/MP${N}") 38 | endif() 39 | 40 | option(PDAL_USE_STATIC_RUNTIME "Use the static runtime" FALSE) 41 | if (PDAL_USE_STATIC_RUNTIME) 42 | target_compile_options(${target} PRIVATE /MT) 43 | endif() 44 | endif() 45 | endfunction() 46 | 47 | function(lazperf_library_compile_settings lib type) 48 | lazperf_target_compile_settings(${lib}) 49 | endfunction() 50 | 51 | # 52 | # Windows htonl and similar are in winsock :( 53 | # 54 | set(WINSOCK_LIBRARY ws2_32) 55 | 56 | -------------------------------------------------------------------------------- /cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | file(GLOB SRCS 3 | lazperf/*.cpp 4 | lazperf/detail/*.cpp 5 | ) 6 | 7 | set (LAZPERF_SHARED_LIB lazperf) 8 | set (LAZPERF_STATIC_LIB lazperf_s) 9 | 10 | if (NOT EMSCRIPTEN) 11 | lazperf_add_library(${LAZPERF_SHARED_LIB} SHARED ${SRCS}) 12 | endif() 13 | lazperf_add_library(${LAZPERF_STATIC_LIB} STATIC ${SRCS}) 14 | 15 | install( 16 | FILES 17 | lazperf/lazperf.hpp 18 | lazperf/filestream.hpp 19 | lazperf/header.hpp 20 | lazperf/readers.hpp 21 | lazperf/vlr.hpp 22 | lazperf/writers.hpp 23 | DESTINATION 24 | include/lazperf 25 | ) 26 | install( 27 | FILES 28 | lazperf/lazperf_user_base.hpp 29 | DESTINATION 30 | include/lazperf 31 | RENAME 32 | lazperf_base.hpp 33 | ) 34 | 35 | add_subdirectory(benchmarks) 36 | add_subdirectory(tools) 37 | if (EMSCRIPTEN) 38 | add_subdirectory(emscripten) 39 | endif() 40 | 41 | if (WITH_TESTS) 42 | enable_testing() 43 | add_subdirectory(test) 44 | add_subdirectory(examples) 45 | endif() 46 | 47 | -------------------------------------------------------------------------------- /cpp/benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(../lazperf) 2 | 3 | if (LASZIP_FOUND) 4 | include_directories(${LASZIP_INCLUDE_DIR}) 5 | add_executable(laszip laszip.cpp) 6 | target_link_libraries(laszip ${ALL_LIBRARIES} ${LASZIP_LIBRARY}) 7 | endif() 8 | -------------------------------------------------------------------------------- /cpp/benchmarks/brute_point10.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: brute.cpp 5 | 6 | CONTENTS: 7 | Brute force benchmarking 8 | 9 | PROGRAMMERS: 10 | 11 | uday.karan@gmail.com - Hobu, Inc. 12 | 13 | COPYRIGHT: 14 | 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | 30 | #include "common/common.hpp" 31 | 32 | #include "compressor.hpp" 33 | #include "decompressor.hpp" 34 | 35 | #include "encoder.hpp" 36 | #include "decoder.hpp" 37 | #include "formats.hpp" 38 | #include "las.hpp" 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | // We need to time operations from within the stream objects itself, may be fast for C++ but we need to know 45 | // their overhead for js 46 | // 47 | struct SuchStream { 48 | SuchStream() : buf(), idx(0), totalTime(0.0f) {} 49 | 50 | void putBytes(const unsigned char* b, size_t len) { 51 | auto tp = common::tick(); 52 | 53 | while(len --) { 54 | buf.push_back(*b++); 55 | } 56 | 57 | totalTime += common::since(tp); 58 | } 59 | 60 | void putByte(const unsigned char b) { 61 | auto tp = common::tick(); 62 | buf.push_back(b); 63 | totalTime += common::since(tp); 64 | } 65 | 66 | unsigned char getByte() { 67 | auto tp = common::tick(); 68 | unsigned char b = buf[idx++]; 69 | totalTime += common::since(tp); 70 | 71 | return b; 72 | } 73 | 74 | void getBytes(unsigned char *b, int len) { 75 | auto tp = common::tick(); 76 | for (int i = 0 ; i < len ; i ++) { 77 | b[i] = getByte(); 78 | } 79 | totalTime += common::since(tp); 80 | } 81 | 82 | std::vector buf; // cuz I'm ze faste 83 | size_t idx; 84 | 85 | float totalTime; 86 | }; 87 | 88 | int main() { 89 | // import namespaces to reduce typing 90 | // 91 | using namespace lazperf; 92 | 93 | // Let's say our record looks something like this: 94 | // 95 | printf("%15s %15s %15s %15s %15s %15s %15s %15s %15s\n", 96 | "Count", 97 | "Comp Init", 98 | "Comp Time", 99 | "Comp Flush", 100 | "Decomp Init", 101 | "Decomp Time", 102 | "Comp OH", 103 | "Decomp OH", 104 | "Total Time"); 105 | 106 | for (int N = 1000 ; N <= 10000000 ; N *= 10) { 107 | auto totalTP = common::tick(); 108 | 109 | float 110 | compressorInitTime = 0.0, 111 | compressTime = 0.0, 112 | comrpressFlushTime = 0.0; 113 | 114 | float 115 | decompInitTime = 0.0, 116 | decompTime = 0.0; 117 | 118 | float encoderStreamOverhead = 0.0, 119 | decoderStreamOverhead = 0.0; 120 | 121 | SuchStream s; 122 | 123 | auto tp = common::tick(); 124 | 125 | record_compressor< 126 | field 127 | > compressor; 128 | 129 | encoders::arithmetic encoder(s); 130 | 131 | compressorInitTime = common::since(tp); 132 | 133 | las::point10 p; 134 | 135 | for (int i = 0 ; i < N; i ++) { 136 | p.x = i; 137 | p.y = i % (1 << 15) ; 138 | p.z = i % (1 << 16); 139 | p.intensity = i % (1 << 15); 140 | 141 | tp = common::tick(); 142 | compressor.compressWith(encoder, (const char*)&p); 143 | compressTime += common::since(tp); 144 | } 145 | 146 | encoderStreamOverhead = s.totalTime; 147 | compressTime -= s.totalTime; // take out all the stream handling time 148 | s.totalTime = 0.0f; 149 | 150 | tp = common::tick(); 151 | encoder.done(); 152 | comrpressFlushTime = common::since(tp) - s.totalTime; 153 | 154 | s.totalTime = 0.0f; 155 | 156 | tp = common::tick(); 157 | 158 | record_decompressor< 159 | field 160 | > decompressor; 161 | 162 | // Create a decoder same way as we did with the encoder 163 | // 164 | decoders::arithmetic decoder(s); 165 | 166 | decompInitTime = common::since(tp); 167 | 168 | // This time we'd read the values out instead and make sure they match what we pushed in 169 | // 170 | for (int i = 0 ; i < N ; i ++) { 171 | // When we decompress data we need to provide where to decode stuff to 172 | // 173 | tp = common::tick(); 174 | decompressor.decompressWith(decoder, (char *)&p); 175 | decompTime += common::since(tp); 176 | 177 | // Finally make sure things match, otherwise bail 178 | if (p.x != i || 179 | p.y != i % (1 << 15) || 180 | p.z != i % (1 << 16) || 181 | p.intensity != i % (1 << 15)) 182 | throw std::runtime_error("Failure!"); 183 | } 184 | 185 | decoderStreamOverhead = s.totalTime; 186 | decompTime -= s.totalTime; 187 | s.totalTime = 0.0f; 188 | 189 | float totalRunTime = common::since(totalTP); 190 | 191 | 192 | // print results from this round 193 | printf("%15d %15.6f %15.6f %15.6f %15.6f %15.6f %15.6f %15.6f %15.6f\n", 194 | N, 195 | compressorInitTime, compressTime, comrpressFlushTime, 196 | decompInitTime, decompTime, 197 | encoderStreamOverhead, decoderStreamOverhead, 198 | totalRunTime); 199 | } 200 | 201 | 202 | printf("\n"); 203 | printf("\tAll times in seconds.\n"); 204 | printf("\tComp = Compressor\n\tDecomp = Decompressor\n\n"); 205 | 206 | return 0; 207 | } 208 | -------------------------------------------------------------------------------- /cpp/download-test-sets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Download and place sets required to run test suites 3 | # 4 | 5 | if [ ! -e test/raw-sets/autzen.laz ] ; then 6 | cd test/raw-sets && \ 7 | curl -O https://github.com/PDAL/data/raw/master/autzen/autzen.laz && \ 8 | las2las autzen.laz autzen.las && \ 9 | cd ../.. 10 | fi 11 | -------------------------------------------------------------------------------- /cpp/emscripten/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(../lazperf) 2 | 3 | if (NOT EMSCRIPTEN) 4 | message(FATAL_ERROR "You should not be including this directory for non emscripten builds") 5 | endif() 6 | 7 | # We need the bind flag to generate bindings. These particular numbers aren't 8 | # terribly important as they can be overridden by the user at runtime. 9 | set(CMAKE_CXX_FLAGS "--bind") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ASSERTIONS=1") 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s INITIAL_MEMORY=262144") 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s TOTAL_STACK=65536") 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ALLOW_MEMORY_GROWTH=1") 14 | 15 | if (NOT WASM EQUAL 0) 16 | set(WASM 1) 17 | endif() 18 | 19 | if (WASM) 20 | message(STATUS "WASM Emscripten output has been enabled") 21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1 -s \"BINARYEN_METHOD='native-wasm'\"") 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s MODULARIZE=1 -s DYNAMIC_EXECUTION=0") 23 | if (ESM) 24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORT_ES6=1") 25 | else (ESM) 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORT_NAME=createLazPerf") 27 | endif() 28 | else (WASM) 29 | message(STATUS "JS Emscripten output has been enabled") 30 | set(CMAKE_CXX_FLAGS "-s WASM=0 ${CMAKE_CXX_FLAGS}") 31 | endif() 32 | 33 | if (ENVIRONMENT AND NOT ${ENVIRONMENT} STREQUAL "all") 34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ENVIRONMENT=${ENVIRONMENT}") 35 | endif() 36 | 37 | message("FLAGS: ${CMAKE_CXX_FLAGS}") 38 | 39 | add_executable(laz-perf laz-perf.cpp) 40 | target_link_libraries(laz-perf ${LAZPERF_STATIC_LIB}) 41 | 42 | if (WASM) 43 | SET_TARGET_PROPERTIES(laz-perf PROPERTIES SUFFIX .js) 44 | else() 45 | SET_TARGET_PROPERTIES(laz-perf PROPERTIES SUFFIX .asm.js) 46 | endif() 47 | -------------------------------------------------------------------------------- /cpp/emscripten/compressed-autzen.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hobuinc/laz-perf/07d925e6d530879adb5299a9c85627e216145b96/cpp/emscripten/compressed-autzen.bin -------------------------------------------------------------------------------- /cpp/emscripten/index-comp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 73 | 74 | -------------------------------------------------------------------------------- /cpp/emscripten/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 54 | 55 | -------------------------------------------------------------------------------- /cpp/emscripten/laz-perf.cpp: -------------------------------------------------------------------------------- 1 | // laz-perf.cpp 2 | // javascript bindings for laz-perf 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include "header.hpp" 9 | #include "readers.hpp" 10 | 11 | using namespace emscripten; 12 | 13 | class LASZip 14 | { 15 | public: 16 | LASZip() 17 | {} 18 | 19 | void open(unsigned int b, size_t len) 20 | { 21 | char *buf = (char*) b; 22 | mem_file_.reset(new lazperf::reader::mem_file(buf, len)); 23 | } 24 | 25 | void getPoint(int buf) 26 | { 27 | char *pbuf = reinterpret_cast(buf); 28 | mem_file_->readPoint(pbuf); 29 | } 30 | 31 | unsigned int getCount() const 32 | { 33 | return static_cast(mem_file_->pointCount()); 34 | } 35 | 36 | unsigned int getPointLength() const 37 | { 38 | return static_cast(mem_file_->header().point_record_length); 39 | } 40 | 41 | unsigned int getPointFormat() const 42 | { 43 | return static_cast(mem_file_->header().point_format_id); 44 | } 45 | 46 | private: 47 | std::shared_ptr mem_file_; 48 | }; 49 | 50 | class ChunkDecoder 51 | { 52 | public: 53 | ChunkDecoder() 54 | {} 55 | 56 | void open(int pdrf, int point_length, unsigned int inputBuf) 57 | { 58 | int ebCount = point_length - lazperf::baseCount(pdrf); 59 | char *buf = reinterpret_cast(inputBuf); 60 | decomp_.reset(new lazperf::reader::chunk_decompressor(pdrf, ebCount, buf)); 61 | } 62 | 63 | void getPoint(unsigned int outBuf) 64 | { 65 | char *buf = reinterpret_cast(outBuf); 66 | decomp_->decompress(buf); 67 | } 68 | 69 | private: 70 | std::shared_ptr decomp_; 71 | }; 72 | 73 | EMSCRIPTEN_BINDINGS(my_module) { 74 | class_("LASZip") 75 | .constructor() 76 | .function("open", &LASZip::open) 77 | .function("getPointLength", &LASZip::getPointLength) 78 | .function("getPointFormat", &LASZip::getPointFormat) 79 | .function("getPoint", &LASZip::getPoint) 80 | .function("getCount", &LASZip::getCount); 81 | 82 | class_("ChunkDecoder") 83 | .constructor() 84 | .function("open", &ChunkDecoder::open) 85 | .function("getPoint", &ChunkDecoder::getPoint); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /cpp/emscripten/point10.las.laz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hobuinc/laz-perf/07d925e6d530879adb5299a9c85627e216145b96/cpp/emscripten/point10.las.laz -------------------------------------------------------------------------------- /cpp/emscripten/run-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | 4 | exec python -m http.server 5 | -------------------------------------------------------------------------------- /cpp/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(point10 point10.cpp) 2 | target_include_directories(point10 3 | PRIVATE 4 | ../lazperf 5 | ) 6 | target_link_libraries(point10 7 | PRIVATE 8 | ${LAZPERF_STATIC_LIB} 9 | ) 10 | lazperf_target_compile_settings(point10) 11 | 12 | add_executable(readlaz readlaz.cpp) 13 | target_include_directories(readlaz 14 | PRIVATE 15 | ../lazperf 16 | ) 17 | target_link_libraries(readlaz 18 | PRIVATE 19 | ${LAZPERF_STATIC_LIB} 20 | ) 21 | lazperf_target_compile_settings(readlaz) 22 | 23 | if (EMSCRIPTEN) 24 | SET_TARGET_PROPERTIES(point10 PROPERTIES SUFFIX .js) 25 | SET_TARGET_PROPERTIES(readlaz PROPERTIES SUFFIX .js) 26 | endif() 27 | -------------------------------------------------------------------------------- /cpp/examples/point10.cpp: -------------------------------------------------------------------------------- 1 | // point10.cpp 2 | // Test point10 stuff 3 | // 4 | 5 | #include "compressor.hpp" 6 | #include "decompressor.hpp" 7 | 8 | #include "las.hpp" 9 | #include "encoder.hpp" 10 | #include "decoder.hpp" 11 | 12 | #include 13 | #include 14 | 15 | lazperf::las::point10 p; // free init to zero :) 16 | 17 | int main() { 18 | // import namespaces to reduce typing 19 | // 20 | using namespace lazperf; 21 | 22 | int N = 1000; 23 | 24 | // Instantiate the arithmetic encoder 25 | // 26 | MemoryStream s; 27 | point_compressor_0 compressor(s.outCb(), 0); 28 | 29 | // Encode some dummy data 30 | // 31 | for (int i = 0 ; i < N; i ++) { 32 | p.x = i; 33 | p.y = i + 1000; 34 | p.z = i + 10000; 35 | 36 | p.intensity = (unsigned short)(i + (1 << 15)); 37 | p.return_number = (i >> 3) & 0x7; 38 | p.number_of_returns_of_given_pulse = i & 0x7; 39 | p.scan_direction_flag = i & 1; 40 | p.edge_of_flight_line = (i+1) & 1; 41 | p.classification = (unsigned char) i % 256; 42 | p.scan_angle_rank = (unsigned char) i % 128; 43 | p.user_data = (i >> 4) % 256; 44 | p.point_source_ID = (i * 30) % (1 << 16); 45 | 46 | // All compressor cares about is your data as a pointer, it will unpack data 47 | // automatically based on the fields that were specified and compress them 48 | // 49 | compressor.compress((const char*)&p); 50 | } 51 | 52 | // Finally terminate the encoder by calling done on it. This will flush out any pending data to output. 53 | // 54 | compressor.done(); 55 | 56 | // Print some fun stuff about compression 57 | // 58 | std::cout << "Points compressed to: " << s.buf.size() << " bytes" << std::endl; 59 | 60 | // Setup record decompressor for point10 61 | // 62 | // Create a decoder same way as we did with the encoder 63 | // 64 | point_decompressor_0 decompressor(s.inCb(), 0); 65 | 66 | // This time we'd read the values out instead and make sure they match what we pushed in 67 | // 68 | for (int i = 0 ; i < N ; i ++) { 69 | // When we decompress data we need to provide where to decode stuff to 70 | // 71 | las::point10 p2; 72 | decompressor.decompress((char *)&p2); 73 | 74 | // Finally make sure things match, otherwise bail 75 | if (p2.x != i || 76 | p2.y != i + 1000 || 77 | p2.z != i + 10000 || 78 | p2.intensity != (unsigned short)(i + (1 << 15)) || 79 | p2.return_number != ((i >> 3) & 0x7) || 80 | p2.number_of_returns_of_given_pulse != (i & 0x7) || 81 | p2.scan_direction_flag != (i & 1) || 82 | p2.edge_of_flight_line != ((i+1) & 1) || 83 | p2.classification != ((unsigned char) i % 256) || 84 | p2.scan_angle_rank != ((unsigned char) i % 128) || 85 | p2.user_data != ((i >> 4) % 256) || 86 | p2.point_source_ID != ((i * 30) % (1 << 16))) 87 | throw std::runtime_error("Not matching"); 88 | } 89 | 90 | // And we're done 91 | std::cout << "Done!" << std::endl; 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /cpp/examples/readlaz.cpp: -------------------------------------------------------------------------------- 1 | // readlaz.cpp 2 | // Read a LAZ file 3 | // 4 | 5 | #include "readers.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #ifdef EMSCRIPTEN_BUILD 11 | #include 12 | #endif 13 | 14 | int main(int argc, char *argv[]) { 15 | if (argc < 2) { 16 | std::cerr << "Usage: readlaz " << std::endl; 17 | return -1; 18 | } 19 | 20 | std::string filename = argv[1]; 21 | 22 | #ifdef EMSCRIPTEN_BUILD 23 | EM_ASM( 24 | FS.mkdir('/files'); 25 | FS.mount(NODEFS, { root: '.' }, '/files'); 26 | ); 27 | 28 | filename = std::string("/files/" + filename); 29 | 30 | std::ifstream file(filename, std::ios::binary); 31 | if (!file.good()) { 32 | std::cerr << "Could not open file for reading: " << filename << std::endl; 33 | std::cerr << strerror(errno) << std::endl; 34 | return -1; 35 | } 36 | #else 37 | std::ifstream file(filename, std::ios::binary); 38 | if (!file.good()) { 39 | std::cerr << "Could not open file for reading: " << filename << std::endl; 40 | std::cerr << strerror(errno) << std::endl; 41 | return -1; 42 | } 43 | #endif 44 | 45 | 46 | lazperf::reader::generic_file f(file); 47 | 48 | size_t count = f.pointCount(); 49 | char buf[256]; // a buffer large enough to hold our point 50 | 51 | for(size_t i = 0 ; i < count ; i ++) 52 | f.readPoint(buf); // read the point out 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /cpp/lazperf/Inserter.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2022, Hobu Inc., info@hobu.co 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following 8 | * conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the 17 | * names of its contributors may be used to endorse or promote 18 | * products derived from this software without specific prior 19 | * written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 | * OF SUCH DAMAGE. 33 | ****************************************************************************/ 34 | #pragma once 35 | 36 | #include 37 | 38 | #include "portable_endian.hpp" 39 | 40 | namespace lazperf 41 | { 42 | 43 | class LeInserter 44 | { 45 | public: 46 | LeInserter(unsigned char *buf, std::size_t size) : m_pbase((char *)buf), 47 | m_epptr((char *)buf + size), m_pptr((char *)buf) 48 | {} 49 | LeInserter(char *buf, std::size_t size) : m_pbase(buf), 50 | m_epptr(buf + size), m_pptr(buf) 51 | {} 52 | 53 | private: 54 | // Base pointer - start of buffer (names taken from std::streambuf). 55 | char *m_pbase; 56 | // End pointer. 57 | char *m_epptr; 58 | // Current position. 59 | char *m_pptr; 60 | 61 | public: 62 | operator bool() const 63 | { return good(); } 64 | bool good() const 65 | { return m_pptr < m_epptr; } 66 | void seek(std::size_t pos) 67 | { m_pptr = m_pbase + pos; } 68 | void put(const std::string& s) 69 | { put(s, s.size()); } 70 | void put(std::string s, size_t len) 71 | { 72 | s.resize(len); 73 | put(s.data(), len); 74 | } 75 | void put(const char *c, size_t len) 76 | { 77 | memcpy(m_pptr, c, len); 78 | m_pptr += len; 79 | } 80 | void put(const unsigned char *c, size_t len) 81 | { 82 | memcpy(m_pptr, c, len); 83 | m_pptr += len; 84 | } 85 | std::size_t position() const 86 | { return m_pptr - m_pbase; } 87 | 88 | LeInserter& operator << (uint8_t v) 89 | { 90 | *m_pptr++ = (char)v; 91 | return *this; 92 | } 93 | 94 | LeInserter& operator << (int8_t v) 95 | { 96 | *m_pptr++ = v; 97 | return *this; 98 | } 99 | 100 | LeInserter& operator << (uint16_t v) 101 | { 102 | v = htole16(v); 103 | memcpy(m_pptr, &v, sizeof(v)); 104 | m_pptr += sizeof(v); 105 | return *this; 106 | } 107 | 108 | LeInserter& operator << (int16_t v) 109 | { 110 | v = (int16_t)htole16((uint16_t)v); 111 | memcpy(m_pptr, &v, sizeof(v)); 112 | m_pptr += sizeof(v); 113 | return *this; 114 | } 115 | 116 | LeInserter& operator << (uint32_t v) 117 | { 118 | v = htole32(v); 119 | memcpy(m_pptr, &v, sizeof(v)); 120 | m_pptr += sizeof(v); 121 | return *this; 122 | } 123 | 124 | LeInserter& operator << (int32_t v) 125 | { 126 | v = (int32_t)htole32((uint32_t)v); 127 | memcpy(m_pptr, &v, sizeof(v)); 128 | m_pptr += sizeof(v); 129 | return *this; 130 | } 131 | 132 | LeInserter& operator << (uint64_t v) 133 | { 134 | v = htole64(v); 135 | memcpy(m_pptr, &v, sizeof(v)); 136 | m_pptr += sizeof(v); 137 | return *this; 138 | } 139 | 140 | LeInserter& operator << (int64_t v) 141 | { 142 | v = (int64_t)htole64((uint64_t)v); 143 | memcpy(m_pptr, &v, sizeof(v)); 144 | m_pptr += sizeof(v); 145 | return *this; 146 | } 147 | 148 | LeInserter& operator << (float v) 149 | { 150 | union 151 | { 152 | float f; 153 | uint32_t u; 154 | } uu; 155 | 156 | uu.f = v; 157 | uu.u = htole32(uu.u); 158 | memcpy(m_pptr, &uu.f, sizeof(uu.f)); 159 | m_pptr += sizeof(uu.f); 160 | return *this; 161 | } 162 | 163 | LeInserter& operator << (double v) 164 | { 165 | union 166 | { 167 | double d; 168 | uint64_t u; 169 | } uu; 170 | 171 | uu.d = v; 172 | uu.u = htole64(uu.u); 173 | memcpy(m_pptr, &uu.d, sizeof(uu.d)); 174 | m_pptr += sizeof(uu.d); 175 | return *this; 176 | } 177 | }; 178 | 179 | } // namespace lazperf 180 | -------------------------------------------------------------------------------- /cpp/lazperf/charbuf.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014, Hobu Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following 8 | * conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the 17 | * names of its contributors may be used to endorse or promote 18 | * products derived from this software without specific prior 19 | * written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 | * OF SUCH DAMAGE. 33 | ****************************************************************************/ 34 | 35 | #include "charbuf.hpp" 36 | 37 | namespace lazperf 38 | { 39 | 40 | void charbuf::initialize(char *buf, size_t count, std::ios::pos_type bufOffset) 41 | { 42 | m_bufOffset = bufOffset; 43 | m_buf = buf; 44 | setg(buf, buf, buf + count); 45 | setp(buf, buf + count); 46 | } 47 | 48 | 49 | std::ios::pos_type charbuf::seekpos(std::ios::pos_type pos, 50 | std::ios_base::openmode which) 51 | { 52 | pos -= m_bufOffset; 53 | if (which & std::ios_base::in) 54 | { 55 | if (pos >= egptr() - eback()) 56 | return -1; 57 | char *cpos = eback() + pos; 58 | setg(eback(), cpos, egptr()); 59 | } 60 | if (which & std::ios_base::out) 61 | { 62 | if (pos > epptr() - m_buf) 63 | return -1; 64 | char *cpos = m_buf + pos; 65 | setp(cpos, epptr()); 66 | } 67 | return pos; 68 | } 69 | 70 | std::ios::pos_type 71 | charbuf::seekoff(std::ios::off_type off, std::ios_base::seekdir dir, 72 | std::ios_base::openmode which) 73 | { 74 | std::ios::pos_type pos; 75 | char *cpos = nullptr; 76 | if (which & std::ios_base::in) 77 | { 78 | switch (dir) 79 | { 80 | case std::ios::beg: 81 | cpos = eback() + off - m_bufOffset; 82 | break; 83 | case std::ios::cur: 84 | cpos = gptr() + off; 85 | break; 86 | case std::ios::end: 87 | cpos = egptr() - off; 88 | break; 89 | default: 90 | break; // Should never happen. 91 | } 92 | if (cpos < eback() || cpos > egptr()) 93 | return -1; 94 | setg(eback(), cpos, egptr()); 95 | pos = cpos - eback(); 96 | } 97 | if (which & std::ios_base::out) 98 | { 99 | switch (dir) 100 | { 101 | case std::ios::beg: 102 | cpos = m_buf + off - m_bufOffset; 103 | break; 104 | case std::ios::cur: 105 | cpos = pptr() + off; 106 | break; 107 | case std::ios::end: 108 | cpos = egptr() - off; 109 | break; 110 | default: 111 | break; // Should never happen. 112 | } 113 | if (cpos < m_buf || cpos > epptr()) 114 | return -1; 115 | setp(cpos, epptr()); 116 | pos = cpos - m_buf; 117 | } 118 | return pos; 119 | } 120 | 121 | } //namespace lazperf 122 | -------------------------------------------------------------------------------- /cpp/lazperf/charbuf.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014, Hobu Inc. 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following 8 | * conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the 17 | * names of its contributors may be used to endorse or promote 18 | * products derived from this software without specific prior 19 | * written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 | * OF SUCH DAMAGE. 33 | ****************************************************************************/ 34 | 35 | #pragma once 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | namespace lazperf 42 | { 43 | 44 | /** 45 | Allow a data buffer to be used at a std::streambuf. 46 | */ 47 | class charbuf : public std::streambuf 48 | { 49 | public: 50 | /** 51 | Construct an empty charbuf. 52 | */ 53 | charbuf() : m_bufOffset(0) 54 | {} 55 | 56 | /** 57 | Construct a charbuf that wraps a byte vector. 58 | 59 | \param v Byte vector to back streambuf. 60 | \param bufOffset Offset in vector (ignore bytes before offset). 61 | */ 62 | charbuf (std::vector& v, pos_type bufOffset = 0) 63 | { initialize(v.data(), v.size(), bufOffset); } 64 | 65 | /** 66 | Construct a charbuf that wraps a byte buffer. 67 | 68 | \param buf Buffer to back streambuf. 69 | \param count Size of buffer. 70 | \param bufOffset Offset in vector (ignore bytes before offset). 71 | */ 72 | charbuf(char *buf, size_t count, pos_type bufOffset = 0) 73 | { initialize(buf, count, bufOffset); } 74 | 75 | /** 76 | Set a buffer to back a charbuf. 77 | 78 | \param buf Buffer to back streambuf. 79 | \param count Size of buffer. 80 | \param bufOffset Offset in vector (ignore bytes before offset). 81 | */ 82 | void initialize(char *buf, size_t count, pos_type bufOffset = 0); 83 | 84 | protected: 85 | /** 86 | Seek to a position in the buffer. 87 | 88 | \param pos Position to seek to. 89 | \param which I/O mode [default: rw] 90 | \return Current position adjusted for buffer offset. 91 | */ 92 | std::ios::pos_type seekpos(std::ios::pos_type pos, 93 | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); 94 | 95 | /** 96 | Seek to a position based on an offset from a position. 97 | 98 | \param off Offset from current position. 99 | \param dir Offset basis (beg, cur or end) 100 | \param which I/O mode [default: rw] 101 | \return Current position adjusted for buffer offset. 102 | */ 103 | std::ios::pos_type seekoff(std::ios::off_type off, 104 | std::ios_base::seekdir dir, 105 | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); 106 | 107 | private: 108 | /** 109 | Offset that allows one to seek to positions not based on the beginning 110 | of the backing vector, but to some other reference point. 111 | */ 112 | std::ios::pos_type m_bufOffset; 113 | 114 | /** 115 | For the put pointer, it seems we need the beginning of the buffer 116 | in order to deal with offsets. 117 | */ 118 | char *m_buf; 119 | }; 120 | 121 | } //namespace lazperf 122 | -------------------------------------------------------------------------------- /cpp/lazperf/coderbase.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma once 4 | 5 | typedef union U32I32F32 6 | { 7 | uint32_t u32; 8 | int32_t i32; 9 | float f32; 10 | } U32I32F32; 11 | 12 | typedef union U64I64F64 13 | { 14 | uint64_t u64; 15 | int64_t i64; 16 | double f64; 17 | } U64I64F64; 18 | 19 | /* this header byte needs to change in case incompatible change happen */ 20 | const int AC_HEADER_BYTE = 2; 21 | const int AC_BUFFER_SIZE = 1024; 22 | 23 | const uint32_t AC__MinLength = 0x01000000U; // threshold for renormalization 24 | const uint32_t AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length 25 | 26 | // Maximum values for binary models 27 | const uint32_t BM__LengthShift = 13; // length bits discarded before mult. 28 | const uint32_t BM__MaxCount = 1 << BM__LengthShift; // for adaptive models 29 | 30 | // Maximum values for general models 31 | const uint32_t DM__LengthShift = 15; // length bits discarded before mult. 32 | const uint32_t DM__MaxCount = 1 << DM__LengthShift; // for adaptive models 33 | -------------------------------------------------------------------------------- /cpp/lazperf/compressor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: compressor.hpp 5 | 6 | CONTENTS: 7 | Integer compressor 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | 32 | #ifndef __compressor_hpp__ 33 | #define __compressor_hpp__ 34 | 35 | #include "model.hpp" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | namespace lazperf 43 | { 44 | namespace compressors 45 | { 46 | 47 | struct integer 48 | { 49 | public: 50 | integer(uint32_t bits = 16, uint32_t contexts = 1) : bits(bits), contexts(contexts) 51 | { 52 | if (bits && bits < 32) 53 | { 54 | corr_bits = bits; 55 | corr_range = 1u << bits; 56 | 57 | // the corrector must fall into this interval 58 | corr_min = -((int32_t)(corr_range/2)); 59 | corr_max = corr_min + corr_range - 1; 60 | } 61 | else 62 | { 63 | corr_bits = 32; 64 | corr_range = 0; 65 | // the corrector must fall into this interval 66 | corr_min = (std::numeric_limits::min)(); 67 | corr_max = (std::numeric_limits::max)(); 68 | } 69 | 70 | k = 0; 71 | } 72 | 73 | ~integer() 74 | { 75 | mBits.clear(); 76 | mCorrector.clear(); 77 | } 78 | 79 | // ABELL - Maybe this is separate so that the compressor can be reused? 80 | // If so, why not called from the ctor? 81 | void init() 82 | { 83 | using models::arithmetic; 84 | using models::arithmetic_bit; 85 | 86 | // maybe create the models 87 | if (mBits.empty()) { 88 | for (uint32_t i = 0; i < contexts; i++) 89 | mBits.push_back(arithmetic(corr_bits+1)); 90 | 91 | // mcorrector0 is already in init state 92 | for (uint32_t i = 1; i <= corr_bits; i++) { 93 | uint32_t v = i <= bits_high ? 1 << i : 1 << bits_high; 94 | mCorrector.push_back(arithmetic(v)); 95 | } 96 | } 97 | } 98 | 99 | unsigned int getK() const 100 | { return k; } 101 | 102 | template 103 | void compress(TEncoder& enc, int32_t pred, int32_t real, uint32_t context) 104 | { 105 | // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] 106 | int32_t corr = real - pred; 107 | // we fold the corrector into the interval [ corr_min ... corr_max ] 108 | if (corr < corr_min) 109 | corr += corr_range; 110 | else if (corr > corr_max) 111 | corr -= corr_range; 112 | writeCorrector(enc, corr, mBits[context]); 113 | } 114 | 115 | template 116 | void writeCorrector(TEncoder& enc, int c, TEntropyModel& mBits) 117 | { 118 | // find the tighest interval [ - (2^k - 1) ... + (2^k) ] that contains c 119 | // do this by checking the absolute value of c (adjusted for the case that c is 2^k) 120 | 121 | uint32_t c1 = (c <= 0 ? -c : c - 1); 122 | // Find the number of bits containing information (32 - # leading 0 bits) 123 | // Tried an intrinsic for this with worse outcome. 124 | for (k = 0; c1; k++) 125 | c1 = c1 >> 1; 126 | 127 | // the number k is between 0 and corr_bits and describes the interval 128 | // the corrector falls into we can compress the exact location of c 129 | // within this interval using k bits 130 | 131 | enc.encodeSymbol(mBits, k); 132 | 133 | if (k) // then c is either smaller than 0 or bigger than 1 134 | { 135 | assert((c != 0) && (c != 1)); 136 | // If k == 32, then the high bit is set, which only happens when the 137 | // value we want to encode is INT_MIN and all the information is in k, 138 | // which has already been encoded above. 139 | if (k == 32) 140 | return; 141 | // translate the corrector c into the k-bit interval [ 0 ... 2^k - 1 ] 142 | if (c < 0) // then c is in the interval [ - (2^k - 1) ... - (2^(k-1)) ] 143 | { 144 | // so we translate c into the interval [ 0 ... + 2^(k-1) - 1 ] 145 | // by adding (2^k - 1) 146 | c += ((1<> k1; 168 | // compress the higher bits using a context table 169 | enc.encodeSymbol(mCorrector[k-1], c); 170 | // store the lower k1 bits raw 171 | enc.writeBits(k1, c1); 172 | } 173 | } 174 | else // then c is 0 or 1 175 | { 176 | assert((c == 0) || (c == 1)); 177 | enc.encodeBit(mCorrector0,c); 178 | } 179 | } 180 | 181 | uint32_t k; 182 | uint32_t bits; 183 | uint32_t contexts; 184 | const uint32_t bits_high {8}; 185 | 186 | uint32_t corr_bits; 187 | uint32_t corr_range; 188 | int32_t corr_min; 189 | int32_t corr_max; 190 | 191 | std::vector mBits; 192 | 193 | models::arithmetic_bit mCorrector0; 194 | std::vector mCorrector; 195 | }; 196 | 197 | } // namespace compressors 198 | } // namespace lazperf 199 | 200 | #endif // __compressor_hpp__ 201 | -------------------------------------------------------------------------------- /cpp/lazperf/decompressor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: decompressor.hpp 5 | 6 | CONTENTS: 7 | Integer decompressor 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | 32 | #ifndef __decompressor_hpp__ 33 | #define __decompressor_hpp__ 34 | 35 | #include "model.hpp" 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | namespace lazperf 42 | { 43 | namespace decompressors 44 | { 45 | struct integer { 46 | integer(uint32_t bits = 16, uint32_t contexts = 1, uint32_t bits_high = 8, uint32_t range = 0): 47 | bits(bits), contexts(contexts), bits_high(bits_high), range(range) { 48 | if (range) { // the corrector's significant bits and range 49 | corr_bits = 0; 50 | corr_range = range; 51 | while (range) 52 | { 53 | range = range >> 1; 54 | corr_bits++; 55 | } 56 | if (corr_range == (1u << (corr_bits-1))) 57 | { 58 | corr_bits--; 59 | } 60 | // the corrector must fall into this interval 61 | corr_min = -((int32_t)(corr_range/2)); 62 | corr_max = corr_min + corr_range - 1; 63 | } 64 | else if (bits && bits < 32) { 65 | corr_bits = bits; 66 | corr_range = 1u << bits; 67 | // the corrector must fall into this interval 68 | corr_min = -((int32_t)(corr_range/2)); 69 | corr_max = corr_min + corr_range - 1; 70 | } 71 | else { 72 | corr_bits = 32; 73 | corr_range = 0; 74 | // the corrector must fall into this interval 75 | corr_min = (std::numeric_limits::min)(); 76 | corr_max = (std::numeric_limits::max)(); 77 | } 78 | 79 | k = 0; 80 | } 81 | 82 | void init() { 83 | using models::arithmetic; 84 | using models::arithmetic_bit; 85 | 86 | uint32_t i; 87 | 88 | // maybe create the models 89 | if (mBits.empty()) { 90 | for (i = 0; i < contexts; i++) 91 | mBits.push_back(arithmetic(corr_bits+1)); 92 | 93 | #ifndef COMPRESS_ONLY_K 94 | // mcorrector0 is already initialized 95 | for (i = 1; i <= corr_bits; i++) { 96 | uint32_t v = i <= bits_high ? 1 << i : 1 << bits_high; 97 | mCorrector.push_back(arithmetic(v)); 98 | } 99 | #endif 100 | } 101 | } 102 | 103 | template< 104 | typename TDecoder 105 | > 106 | int32_t decompress(TDecoder& dec, int32_t pred, uint32_t context) { 107 | int32_t real = pred + readCorrector(dec, mBits[context]); 108 | if (real < 0) real += corr_range; 109 | else if ((uint32_t)(real) >= corr_range) real -= corr_range; 110 | 111 | return real; 112 | } 113 | 114 | inline unsigned int getK() const { return k; } 115 | 116 | template< 117 | typename TDecoder, 118 | typename TEntroyModel 119 | > 120 | int32_t readCorrector(TDecoder& dec, TEntroyModel& mBits) { 121 | int32_t c; 122 | 123 | // decode within which interval the corrector is falling 124 | 125 | k = dec.decodeSymbol(mBits); 126 | 127 | // decode the exact location of the corrector within the interval 128 | 129 | #ifdef COMPRESS_ONLY_K 130 | if (k) // then c is either smaller than 0 or bigger than 1 131 | { 132 | if (k < 32) 133 | { 134 | c = dec.readBits(k); 135 | 136 | if (c >= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ] 137 | { 138 | // so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1 139 | c += 1; 140 | } 141 | else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ] 142 | { 143 | // so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1) 144 | c -= ((1<= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ] 179 | { 180 | // so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1 181 | c += 1; 182 | } 183 | else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ] 184 | { 185 | // so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1) 186 | c -= ((1< mBits; 218 | 219 | models::arithmetic_bit mCorrector0; 220 | std::vector mCorrector; 221 | }; 222 | } // namespace decompressors 223 | } // namespace lazperf 224 | 225 | #endif // __decompressor_hpp__ 226 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_byte10.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_byte10.cpp 5 | 6 | CONTENTS: 7 | 8 | PROGRAMMERS: 9 | 10 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 11 | uday.karan@gmail.com - Hobu, Inc. 12 | andrew.bell.ia@gmail.com - Hobu Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | 18 | This is free software; you can redistribute and/or modify it under the 19 | terms of the Apache Public License 2.0 published by the Apache Software 20 | Foundation. See the COPYING file for more information. 21 | 22 | This software is distributed WITHOUT ANY WARRANTY and without even the 23 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | 25 | CHANGE HISTORY: 26 | 27 | =============================================================================== 28 | */ 29 | 30 | #include "../las.hpp" 31 | 32 | #include 33 | 34 | namespace lazperf 35 | { 36 | namespace detail 37 | { 38 | 39 | Byte10Base::Byte10Base(size_t count) : count_(count), have_last_(false), 40 | lasts_(count), diffs_(count), models_(count, models::arithmetic(256)) 41 | {} 42 | 43 | // COMPRESSOR 44 | 45 | Byte10Compressor::Byte10Compressor(encoders::arithmetic& encoder, size_t count) : 46 | Byte10Base(count), enc_(encoder) 47 | {} 48 | 49 | const char *Byte10Compressor::compress(const char *buf) 50 | { 51 | if (count_ == 0) 52 | return buf; 53 | 54 | auto li = lasts_.begin(); 55 | auto di = diffs_.begin(); 56 | while (di != diffs_.end()) 57 | { 58 | *di = *buf - *li; 59 | *li = *buf; 60 | di++; buf++; li++; 61 | } 62 | 63 | if (!have_last_) 64 | { 65 | enc_.getOutStream().putBytes(lasts_.data(), count_); 66 | have_last_ = true; 67 | } 68 | else 69 | { 70 | di = diffs_.begin(); 71 | auto mi = models_.begin(); 72 | while (di != diffs_.end()) 73 | enc_.encodeSymbol(*mi++, *di++); 74 | } 75 | return buf; 76 | } 77 | 78 | // DECOMPRESSOR 79 | 80 | Byte10Decompressor::Byte10Decompressor(decoders::arithmetic& decoder, size_t count) : 81 | Byte10Base(count), dec_(decoder) 82 | {} 83 | 84 | char *Byte10Decompressor::decompress(char *buf) 85 | { 86 | if (count_ == 0) 87 | return buf; 88 | 89 | if (!have_last_) 90 | { 91 | dec_.getInStream().getBytes((unsigned char *)buf, count_); 92 | std::copy(buf, buf + count_, lasts_.data()); 93 | have_last_ = true; 94 | return buf + count_; 95 | } 96 | // Use the diff vector for our current values. 97 | auto& curs = diffs_; 98 | auto ci = curs.begin(); 99 | auto li = lasts_.begin(); 100 | auto mi = models_.begin(); 101 | while (li != lasts_.end()) 102 | { 103 | *ci = (uint8_t)(*li + dec_.decodeSymbol(*mi)); 104 | *li = *buf = *ci; 105 | li++; buf++; ci++; mi++; 106 | } 107 | return buf; 108 | } 109 | 110 | } // namespace detail 111 | } // namespace lazperf 112 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_byte10.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | andrew.bell.ia@gmail.com - Hobu Inc. 9 | 10 | COPYRIGHT: 11 | 12 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 13 | (c) 2014, Uday Verma, Hobu, Inc. 14 | 15 | This is free software; you can redistribute and/or modify it under the 16 | terms of the Apache Public License 2.0 published by the Apache Software 17 | Foundation. See the COPYING file for more information. 18 | 19 | This software is distributed WITHOUT ANY WARRANTY and without even the 20 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 | 22 | =============================================================================== 23 | */ 24 | 25 | #include 26 | 27 | namespace lazperf 28 | { 29 | namespace detail 30 | { 31 | 32 | class Byte10Base 33 | { 34 | protected: 35 | Byte10Base(size_t count); 36 | 37 | size_t count_; 38 | bool have_last_; 39 | std::vector lasts_; 40 | std::vector diffs_; 41 | std::deque models_; 42 | }; 43 | 44 | class Byte10Compressor : public Byte10Base 45 | { 46 | public: 47 | Byte10Compressor(encoders::arithmetic& encoder, size_t count); 48 | 49 | const char *compress(const char *buf); 50 | 51 | private: 52 | encoders::arithmetic& enc_; 53 | }; 54 | 55 | class Byte10Decompressor : public Byte10Base 56 | { 57 | public: 58 | Byte10Decompressor(decoders::arithmetic& decoder, size_t count); 59 | 60 | char *decompress(char *buf); 61 | 62 | private: 63 | decoders::arithmetic& dec_; 64 | }; 65 | 66 | } // namespace detail 67 | } // namespace lazperf 68 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_byte14.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_byte14.cpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | #include "../las.hpp" 32 | 33 | namespace lazperf 34 | { 35 | namespace detail 36 | { 37 | 38 | Byte14Base::Byte14Base(size_t count) : count_(count), last_channel_(-1), 39 | chan_ctxs_ { count_, count_, count_, count_ } 40 | {} 41 | 42 | size_t Byte14Base::count() const 43 | { 44 | return count_; 45 | } 46 | 47 | // COMPRESSOR 48 | 49 | Byte14Compressor::Byte14Compressor(OutCbStream& stream, size_t count) : 50 | Byte14Base(count), stream_(stream), valid_(count_), 51 | byte_enc_(count, encoders::arithmetic(true)) 52 | {} 53 | 54 | void Byte14Compressor::writeSizes() 55 | { 56 | for (size_t i = 0; i < count_; ++i) 57 | { 58 | if (valid_[i]) 59 | { 60 | byte_enc_[i].done(); 61 | stream_ << byte_enc_[i].num_encoded(); 62 | } 63 | else 64 | stream_ << (uint32_t)0; 65 | } 66 | } 67 | 68 | void Byte14Compressor::writeData() 69 | { 70 | [[maybe_unused]] int32_t total = 0; 71 | for (size_t i = 0; i < count_; ++i) 72 | { 73 | if (valid_[i]) 74 | { 75 | stream_.putBytes(byte_enc_[i].encoded_bytes(), byte_enc_[i].num_encoded()); 76 | total += utils::sum(byte_enc_[i].encoded_bytes(), byte_enc_[i].num_encoded()); 77 | } 78 | } 79 | LAZDEBUG(std::cerr << "BYTE : " << total << "\n"); 80 | } 81 | 82 | const char *Byte14Compressor::compress(const char *buf, int& sc) 83 | { 84 | // don't have the first data yet, just push it to our 85 | // have last stuff and move on 86 | if (last_channel_ == -1) 87 | { 88 | ChannelCtx& c = chan_ctxs_[sc]; 89 | stream_.putBytes((const unsigned char *)buf, count_); 90 | c.last_.assign(buf, buf + count_); 91 | c.have_last_ = true; 92 | last_channel_ = sc; 93 | return buf + count_; 94 | } 95 | ChannelCtx& c = chan_ctxs_[sc]; 96 | las::byte14 *pLastBytes = &chan_ctxs_[last_channel_].last_; 97 | if (!c.have_last_) 98 | { 99 | c.have_last_ = true; 100 | c.last_ = *pLastBytes; 101 | pLastBytes = &c.last_; 102 | } 103 | // This mess is because of the broken-ness of the handling for last in v3, where 104 | // 'last_point' only gets updated on the first context switch in the LASzip code. 105 | las::byte14& lastBytes = *pLastBytes; 106 | 107 | for (size_t i = 0; i < count_; ++i, ++buf) 108 | { 109 | int32_t diff = *(const uint8_t *)buf - lastBytes[i]; 110 | byte_enc_[i].encodeSymbol(c.byte_model_[i], (uint8_t)diff); 111 | if (diff) 112 | { 113 | valid_[i] = true; 114 | lastBytes[i] = *buf; 115 | } 116 | } 117 | 118 | last_channel_ = sc; 119 | return buf + count_; 120 | } 121 | 122 | // DECOMPRESSOR 123 | 124 | Byte14Decompressor::Byte14Decompressor(InCbStream& stream, size_t count) : Byte14Base(count), 125 | stream_(stream), byte_cnt_(count_), byte_dec_(count_, decoders::arithmetic()) 126 | {} 127 | 128 | void Byte14Decompressor::readSizes() 129 | { 130 | for (size_t i = 0; i < count_; ++i) 131 | stream_ >> byte_cnt_[i]; 132 | } 133 | 134 | void Byte14Decompressor::readData() 135 | { 136 | for (size_t i = 0; i < count_; ++i) 137 | byte_dec_[i].initStream(stream_, byte_cnt_[i]); 138 | } 139 | 140 | void Byte14Decompressor::dumpSums() 141 | { 142 | std::cout << "BYTE : " << sumByte.value() << "\n"; 143 | } 144 | 145 | char *Byte14Decompressor::decompress(char *buf, int& sc) 146 | { 147 | if (last_channel_ == -1) 148 | { 149 | ChannelCtx& c = chan_ctxs_[sc]; 150 | stream_.getBytes((unsigned char *)buf, count_); 151 | c.last_.assign(buf, buf + count_); 152 | c.have_last_ = true; 153 | last_channel_ = sc; 154 | return buf + count_; 155 | } 156 | 157 | ChannelCtx& c = chan_ctxs_[sc]; 158 | las::byte14 *pLastByte = &chan_ctxs_[last_channel_].last_; 159 | if (sc != last_channel_) 160 | { 161 | last_channel_ = sc; 162 | if (!c.have_last_) 163 | { 164 | c.have_last_ = true; 165 | c.last_ = *pLastByte; 166 | pLastByte = &chan_ctxs_[last_channel_].last_; 167 | } 168 | } 169 | las::byte14& lastByte = *pLastByte; 170 | 171 | for (size_t i = 0; i < count_; ++i, buf++) 172 | { 173 | if (byte_cnt_[i]) 174 | { 175 | *buf = lastByte[i] + byte_dec_[i].decodeSymbol(c.byte_model_[i]); 176 | lastByte[i] = *buf; 177 | } 178 | else 179 | *buf = lastByte[i]; 180 | } 181 | LAZDEBUG(sumByte.add(lastByte.data(), count_)); 182 | 183 | return buf; 184 | } 185 | 186 | } // namespace detail 187 | } // namespace lazperf 188 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_byte14.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_byte14.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | namespace lazperf 32 | { 33 | namespace detail 34 | { 35 | 36 | class Byte14Base 37 | { 38 | protected: 39 | struct ChannelCtx 40 | { 41 | int have_last_; 42 | las::byte14 last_; 43 | std::vector byte_model_; 44 | 45 | ChannelCtx(size_t count) : have_last_(false), last_(count), 46 | byte_model_(count, models::arithmetic(256)) 47 | {} 48 | }; 49 | 50 | public: 51 | size_t count() const; 52 | 53 | protected: 54 | Byte14Base(size_t count); 55 | 56 | size_t count_; 57 | int last_channel_; 58 | std::array chan_ctxs_; 59 | std::vector> byte_dec_; 60 | }; 61 | 62 | class Byte14Compressor : public Byte14Base 63 | { 64 | public: 65 | Byte14Compressor(OutCbStream& stream, size_t count); 66 | 67 | void writeSizes(); 68 | void writeData(); 69 | const char *compress(const char *buf, int& sc); 70 | 71 | private: 72 | OutCbStream& stream_; 73 | std::vector valid_; 74 | std::vector> byte_enc_; 75 | }; 76 | 77 | class Byte14Decompressor : public Byte14Base 78 | { 79 | public: 80 | Byte14Decompressor(InCbStream& stream, size_t count); 81 | 82 | void dumpSums(); 83 | void readSizes(); 84 | void readData(); 85 | char *decompress(char *buf, int& sc); 86 | 87 | private: 88 | InCbStream& stream_; 89 | std::vector byte_cnt_; 90 | std::vector> byte_dec_; 91 | utils::Summer sumByte; 92 | }; 93 | 94 | } // namespace detail 95 | } // namespace lazperf 96 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_gpstime10.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_gpstime.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | namespace lazperf 32 | { 33 | namespace detail 34 | { 35 | 36 | class Gpstime10Base 37 | { 38 | protected: 39 | Gpstime10Base(); 40 | 41 | bool have_last_; 42 | models::arithmetic m_gpstime_multi, m_gpstime_0diff; 43 | unsigned int last; 44 | unsigned int next; 45 | std::array last_gpstime; 46 | std::array last_gpstime_diff; 47 | std::array multi_extreme_counter; 48 | }; 49 | 50 | class Gpstime10Compressor : public Gpstime10Base 51 | { 52 | public: 53 | Gpstime10Compressor(encoders::arithmetic&); 54 | 55 | const char *compress(const char *c); 56 | 57 | private: 58 | void init(); 59 | 60 | encoders::arithmetic& enc_; 61 | bool compressor_inited_; 62 | compressors::integer ic_gpstime; 63 | }; 64 | 65 | class Gpstime10Decompressor : public Gpstime10Base 66 | { 67 | public: 68 | Gpstime10Decompressor(decoders::arithmetic&); 69 | 70 | char *decompress(char *c); 71 | 72 | private: 73 | void init(); 74 | 75 | decoders::arithmetic& dec_; 76 | bool decompressor_inited_; 77 | decompressors::integer ic_gpstime; 78 | }; 79 | 80 | } // namespace detail 81 | } // namespace lazperf 82 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_nir14.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_nir14.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | #include "../las.hpp" 32 | 33 | namespace lazperf 34 | { 35 | namespace detail 36 | { 37 | 38 | // COMPRESSOR 39 | 40 | void Nir14Compressor::writeSizes() 41 | { 42 | nir_enc_.done(); 43 | stream_ << nir_enc_.num_encoded(); 44 | } 45 | 46 | void Nir14Compressor::writeData() 47 | { 48 | LAZDEBUG(std::cerr << "NIR : " << 49 | utils::sum(nir_enc_.encoded_bytes(), nir_enc_.num_encoded()) << "\n"); 50 | 51 | if (nir_enc_.num_encoded()) 52 | stream_.putBytes(nir_enc_.encoded_bytes(), nir_enc_.num_encoded()); 53 | } 54 | 55 | const char *Nir14Compressor::compress(const char *buf, int& sc) 56 | { 57 | const las::nir14 nir(buf); 58 | 59 | // don't have the first data yet, just push it to our 60 | // have last stuff and move on 61 | if (last_channel_ == -1) 62 | { 63 | ChannelCtx& c = chan_ctxs_[sc]; 64 | stream_.putBytes((const unsigned char*)&nir, sizeof(las::nir14)); 65 | c.last_ = nir; 66 | c.have_last_ = true; 67 | last_channel_ = sc; 68 | return buf + sizeof(las::nir14); 69 | } 70 | 71 | ChannelCtx& c = chan_ctxs_[sc]; 72 | las::nir14 *pLastNir = &chan_ctxs_[last_channel_].last_; 73 | if (!c.have_last_) 74 | { 75 | c.have_last_ = true; 76 | c.last_ = *pLastNir; 77 | pLastNir = &c.last_; 78 | } 79 | // This mess is because of the broken-ness of the handling for last in v3, where 80 | // 'last_point' only gets updated on the first context switch in the LASzip code. 81 | las::nir14& lastNir = *pLastNir; 82 | 83 | bool lowChange = (lastNir.val & 0xFF) != (nir.val & 0xFF); 84 | bool highChange = (lastNir.val & 0xFF00) != (nir.val & 0xFF00); 85 | int32_t sym = (int32_t)lowChange | (highChange << 1); 86 | if (sym) 87 | nir_enc_.makeValid(); 88 | nir_enc_.encodeSymbol(c.used_model_, sym); 89 | 90 | if (lowChange) 91 | { 92 | int32_t diff = (nir.val & 0xFF) - (lastNir.val & 0xFF); 93 | nir_enc_.encodeSymbol(c.diff_model_[0], uint8_t(diff)); 94 | } 95 | if (highChange) 96 | { 97 | int32_t diff = (nir.val >> 8) - (lastNir.val >> 8); 98 | nir_enc_.encodeSymbol(c.diff_model_[1], uint8_t(diff)); 99 | } 100 | 101 | lastNir = nir; 102 | last_channel_ = sc; 103 | return buf + sizeof(las::nir14); 104 | } 105 | 106 | // DECOMPRESSOR 107 | 108 | void Nir14Decompressor::dumpSums() 109 | { 110 | std::cout << "NIR : " << sumNir.value() << "\n"; 111 | } 112 | 113 | void Nir14Decompressor::readSizes() 114 | { 115 | stream_ >> nir_cnt_; 116 | } 117 | 118 | void Nir14Decompressor::readData() 119 | { 120 | nir_dec_.initStream(stream_, nir_cnt_); 121 | } 122 | 123 | char *Nir14Decompressor::decompress(char *buf, int& sc) 124 | { 125 | if (last_channel_ == -1) 126 | { 127 | ChannelCtx& c = chan_ctxs_[sc]; 128 | stream_.getBytes((unsigned char*)buf, sizeof(las::nir14)); 129 | c.last_.unpack(buf); 130 | c.have_last_ = true; 131 | last_channel_ = sc; 132 | return buf + sizeof(las::nir14); 133 | } 134 | if (nir_cnt_ == 0) 135 | { 136 | las::nir14 *nir = reinterpret_cast(buf); 137 | *nir = chan_ctxs_[last_channel_].last_; 138 | return buf + sizeof(las::nir14); 139 | } 140 | 141 | ChannelCtx& c = chan_ctxs_[sc]; 142 | las::nir14 *pLastNir = &chan_ctxs_[last_channel_].last_; 143 | if (sc != last_channel_) 144 | { 145 | last_channel_ = sc; 146 | if (!c.have_last_) 147 | { 148 | c.have_last_ = true; 149 | c.last_ = *pLastNir; 150 | pLastNir = &chan_ctxs_[last_channel_].last_; 151 | } 152 | } 153 | las::nir14& lastNir = *pLastNir; 154 | 155 | uint32_t sym = nir_dec_.decodeSymbol(c.used_model_); 156 | 157 | las::nir14 nir; 158 | 159 | if (sym & (1 << 0)) 160 | { 161 | uint8_t corr = (uint8_t)nir_dec_.decodeSymbol(c.diff_model_[0]); 162 | nir.val = uint8_t(corr + (lastNir.val & 0xFF)); 163 | } 164 | else 165 | nir.val = lastNir.val & 0xFF; 166 | 167 | if (sym & (1 << 1)) 168 | { 169 | uint8_t corr = (uint8_t)nir_dec_.decodeSymbol(c.diff_model_[1]); 170 | nir.val |= (static_cast(uint8_t(corr + (lastNir.val >> 8))) << 8); 171 | } 172 | else 173 | nir.val |= lastNir.val & 0xFF00; 174 | LAZDEBUG(sumNir.add(nir)); 175 | 176 | lastNir = nir; 177 | nir.pack(buf); 178 | return buf + sizeof(las::nir14); 179 | } 180 | 181 | } // namespace detail 182 | } // namespace lazperf 183 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_nir14.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_nir14.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | namespace lazperf 32 | { 33 | namespace detail 34 | { 35 | 36 | class Nir14Base 37 | { 38 | protected: 39 | struct ChannelCtx 40 | { 41 | int have_last_; 42 | las::nir14 last_; 43 | models::arithmetic used_model_; 44 | std::array diff_model_; 45 | 46 | ChannelCtx() : have_last_{false}, used_model_(4), 47 | diff_model_{ models::arithmetic(256), models::arithmetic(256) } 48 | {} 49 | }; 50 | 51 | std::array chan_ctxs_; 52 | int last_channel_ = -1; 53 | }; 54 | 55 | class Nir14Compressor : public Nir14Base 56 | { 57 | public: 58 | Nir14Compressor(OutCbStream& stream) : stream_(stream), nir_enc_(false) 59 | {} 60 | 61 | void writeSizes(); 62 | void writeData(); 63 | const char *compress(const char *buf, int& sc); 64 | 65 | private: 66 | OutCbStream& stream_; 67 | encoders::arithmetic nir_enc_; 68 | }; 69 | 70 | class Nir14Decompressor : public Nir14Base 71 | { 72 | public: 73 | Nir14Decompressor(InCbStream& stream) : stream_(stream) 74 | {} 75 | 76 | void dumpSums(); 77 | void readSizes(); 78 | void readData(); 79 | char *decompress(char *buf, int& sc); 80 | 81 | private: 82 | InCbStream& stream_; 83 | uint32_t nir_cnt_; 84 | decoders::arithmetic nir_dec_; 85 | utils::Summer sumNir; 86 | }; 87 | 88 | } // namespace detail 89 | } // namespace lazperf 90 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_point10.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_point10.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | #include "../compressor.hpp" 32 | #include "../decompressor.hpp" 33 | 34 | namespace lazperf 35 | { 36 | namespace detail 37 | { 38 | 39 | class Point10Base 40 | { 41 | protected: 42 | Point10Base(); 43 | ~Point10Base(); 44 | 45 | las::point10 last_; 46 | std::array last_intensity; 47 | 48 | std::array, 16> last_x_diff_median5; 49 | std::array, 16> last_y_diff_median5; 50 | 51 | std::array last_height; 52 | models::arithmetic m_changed_values; 53 | 54 | // Arithmetic model has no default constructor, so we store they here as raw pointers 55 | std::array m_scan_angle_rank; 56 | std::array m_bit_byte; 57 | std::array m_classification; 58 | std::array m_user_data; 59 | bool have_last_; 60 | }; 61 | 62 | class Point10Compressor : public Point10Base 63 | { 64 | public: 65 | Point10Compressor(encoders::arithmetic&); 66 | 67 | const char *compress(const char *buf); 68 | 69 | private: 70 | void init(); 71 | 72 | encoders::arithmetic& enc_; 73 | compressors::integer ic_intensity; 74 | compressors::integer ic_point_source_ID; 75 | compressors::integer ic_dx; 76 | compressors::integer ic_dy; 77 | compressors::integer ic_z; 78 | bool compressors_inited_; 79 | }; 80 | 81 | class Point10Decompressor : public Point10Base 82 | { 83 | public: 84 | Point10Decompressor(decoders::arithmetic&); 85 | 86 | char *decompress(char *buf); 87 | 88 | private: 89 | void init(); 90 | 91 | decoders::arithmetic& dec_; 92 | decompressors::integer ic_intensity; 93 | decompressors::integer ic_point_source_ID; 94 | decompressors::integer ic_dx; 95 | decompressors::integer ic_dy; 96 | decompressors::integer ic_z; 97 | bool decompressors_inited_; 98 | }; 99 | 100 | } // namespace detail 101 | } // namespace lazperf 102 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_point14.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_point14.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | namespace lazperf 32 | { 33 | namespace detail 34 | { 35 | 36 | class Point14Base 37 | { 38 | protected: 39 | Point14Base(); 40 | 41 | struct ChannelCtx 42 | { 43 | int ctx_num_; //ABELL - For debug. 44 | std::vector changed_values_model_; 45 | models::arithmetic scanner_channel_model_; 46 | models::arithmetic rn_gps_same_model_; 47 | std::vector nr_model_; 48 | std::vector rn_model_; 49 | std::vector class_model_; 50 | std::vector flag_model_; 51 | std::vector user_data_model_; 52 | 53 | models::arithmetic gpstime_multi_model_; 54 | models::arithmetic gpstime_0diff_model_; 55 | 56 | compressors::integer dx_compr_; 57 | compressors::integer dy_compr_; 58 | compressors::integer z_compr_; 59 | compressors::integer intensity_compr_; 60 | compressors::integer scan_angle_compr_; 61 | compressors::integer point_source_id_compr_; 62 | compressors::integer gpstime_compr_; 63 | 64 | decompressors::integer dx_decomp_; 65 | decompressors::integer dy_decomp_; 66 | decompressors::integer z_decomp_; 67 | decompressors::integer intensity_decomp_; 68 | decompressors::integer scan_angle_decomp_; 69 | decompressors::integer point_source_id_decomp_; 70 | decompressors::integer gpstime_decomp_; 71 | 72 | bool have_last_; 73 | las::point14 last_; 74 | std::array last_intensity_; 75 | std::array last_z_; 76 | std::array, 12> last_x_diff_median5_; 77 | std::array, 12> last_y_diff_median5_; 78 | uint32_t last_gps_seq_; 79 | uint32_t next_gps_seq_; 80 | std::array last_gpstime_; 81 | std::array last_gpstime_diff_; 82 | std::array multi_extreme_counter_; 83 | bool gps_time_change_; 84 | 85 | ChannelCtx() : changed_values_model_(8, models::arithmetic(128)), 86 | scanner_channel_model_(3), rn_gps_same_model_(13), 87 | nr_model_(16, models::arithmetic(16)), rn_model_(16, models::arithmetic(16)), 88 | class_model_(64, models::arithmetic(256)), flag_model_(64, models::arithmetic(64)), 89 | user_data_model_(64, models::arithmetic(256)), gpstime_multi_model_(515), 90 | gpstime_0diff_model_(5), 91 | dx_compr_(32, 2), dy_compr_(32, 22), z_compr_(32, 20), intensity_compr_(16, 4), 92 | scan_angle_compr_(16, 2), point_source_id_compr_(16), gpstime_compr_(32, 9), 93 | dx_decomp_(32, 2), dy_decomp_(32, 22), z_decomp_(32, 20), intensity_decomp_(16, 4), 94 | scan_angle_decomp_(16, 2), point_source_id_decomp_(16), gpstime_decomp_(32, 9), 95 | have_last_{false}, last_gps_seq_{0}, next_gps_seq_{0}, 96 | last_gpstime_{}, last_gpstime_diff_{}, multi_extreme_counter_{}, 97 | gps_time_change_{} 98 | { 99 | //ABELL - Move the init into the ctor, I think. 100 | // Also, the encoder should be passed to the ctor. 101 | dx_compr_.init(); 102 | dy_compr_.init(); 103 | z_compr_.init(); 104 | intensity_compr_.init(); 105 | scan_angle_compr_.init(); 106 | point_source_id_compr_.init(); 107 | gpstime_compr_.init(); 108 | 109 | dx_decomp_.init(); 110 | dy_decomp_.init(); 111 | z_decomp_.init(); 112 | intensity_decomp_.init(); 113 | scan_angle_decomp_.init(); 114 | point_source_id_decomp_.init(); 115 | gpstime_decomp_.init(); 116 | 117 | for (auto& xd : last_x_diff_median5_) 118 | xd.init(); 119 | for (auto& yd : last_y_diff_median5_) 120 | yd.init(); 121 | } 122 | }; // ChannelCtx 123 | 124 | std::array chan_ctxs_; 125 | int last_channel_; 126 | }; 127 | 128 | class Point14Compressor : public Point14Base 129 | { 130 | public: 131 | Point14Compressor(OutCbStream& stream) : stream_(stream) 132 | {} 133 | 134 | void writeSizes(); 135 | void writeData(); 136 | const char *compress(const char *buf, int& sc); 137 | 138 | private: 139 | void encodeGpsTime(const las::point14& point, ChannelCtx& c); 140 | 141 | OutCbStream& stream_; 142 | encoders::arithmetic xy_enc_ = true; 143 | encoders::arithmetic z_enc_ = true; 144 | encoders::arithmetic class_enc_ = false; 145 | encoders::arithmetic flags_enc_ = false; 146 | encoders::arithmetic intensity_enc_ = false; 147 | encoders::arithmetic scan_angle_enc_ = false; 148 | encoders::arithmetic user_data_enc_ = false; 149 | encoders::arithmetic point_source_id_enc_ = false; 150 | encoders::arithmetic gpstime_enc_ = false; 151 | }; 152 | 153 | class Point14Decompressor : public Point14Base 154 | { 155 | public: 156 | Point14Decompressor(InCbStream& stream) : stream_(stream) 157 | {} 158 | 159 | void dumpSums(); 160 | void readSizes(); 161 | void readData(); 162 | char *decompress(char *buf, int& sc); 163 | 164 | private: 165 | void decodeGpsTime(ChannelCtx& c); 166 | 167 | InCbStream stream_; 168 | decoders::arithmetic xy_dec_; 169 | decoders::arithmetic z_dec_; 170 | decoders::arithmetic class_dec_; 171 | decoders::arithmetic flags_dec_; 172 | decoders::arithmetic intensity_dec_; 173 | decoders::arithmetic scan_angle_dec_; 174 | decoders::arithmetic user_data_dec_; 175 | decoders::arithmetic point_source_id_dec_; 176 | decoders::arithmetic gpstime_dec_; 177 | std::vector sizes_; 178 | utils::Summer sumChange; 179 | utils::Summer sumReturn; 180 | utils::Summer sumX; 181 | utils::Summer sumY; 182 | utils::Summer sumZ; 183 | utils::Summer sumClass; 184 | utils::Summer sumFlags; 185 | utils::Summer sumIntensity; 186 | utils::Summer sumScanAngle; 187 | utils::Summer sumUserData; 188 | utils::Summer sumPointSourceId; 189 | utils::Summer sumGpsTime; 190 | }; 191 | 192 | } // namespace detail 193 | } // namespace lazperf 194 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_rgb10.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | CHANGE HISTORY: 22 | 23 | =============================================================================== 24 | */ 25 | 26 | #include "../las.hpp" 27 | //#include "../types.hpp" 28 | 29 | namespace lazperf 30 | { 31 | namespace detail 32 | { 33 | 34 | namespace 35 | { 36 | 37 | unsigned int color_diff_bits(const las::rgb& this_val, const las::rgb& last) 38 | { 39 | const las::rgb& a = last; 40 | const las::rgb& b = this_val; 41 | 42 | #define __flag_diff(x,y,f) ((((x) ^ (y)) & (f)) != 0) 43 | unsigned int r = 44 | (__flag_diff(a.r, b.r, 0x00FF) << 0) | 45 | (__flag_diff(a.r, b.r, 0xFF00) << 1) | 46 | (__flag_diff(a.g, b.g, 0x00FF) << 2) | 47 | (__flag_diff(a.g, b.g, 0xFF00) << 3) | 48 | (__flag_diff(a.b, b.b, 0x00FF) << 4) | 49 | (__flag_diff(a.b, b.b, 0xFF00) << 5) | 50 | (__flag_diff(b.r, b.g, 0x00FF) || 51 | __flag_diff(b.r, b.b, 0x00FF) || 52 | __flag_diff(b.r, b.g, 0xFF00) || 53 | __flag_diff(b.r, b.b, 0xFF00)) << 6; 54 | #undef __flag_diff 55 | 56 | return r; 57 | } 58 | 59 | } // unnamed namespace 60 | 61 | Rgb10Base::Rgb10Base() : have_last_(false), last(), m_byte_used(128), m_rgb_diff_0(256), 62 | m_rgb_diff_1(256), m_rgb_diff_2(256), m_rgb_diff_3(256), m_rgb_diff_4(256), 63 | m_rgb_diff_5(256) 64 | {} 65 | 66 | // COMPRESSOR 67 | 68 | Rgb10Compressor::Rgb10Compressor(encoders::arithmetic& encoder) : enc_(encoder) 69 | {} 70 | 71 | const char *Rgb10Compressor::compress(const char *buf) 72 | { 73 | las::rgb this_val(buf); 74 | 75 | if (!have_last_) { 76 | // don't have the first data yet, just push it to our 77 | // have last stuff and move on 78 | have_last_ = true; 79 | last = this_val; 80 | 81 | enc_.getOutStream().putBytes((const unsigned char*)buf, sizeof(las::rgb)); 82 | return buf + sizeof(las::rgb); 83 | } 84 | 85 | // compress color 86 | int diff_l = 0; 87 | int diff_h = 0; 88 | int corr; 89 | 90 | unsigned int sym = detail::color_diff_bits(this_val, last); 91 | 92 | enc_.encodeSymbol(m_byte_used, sym); 93 | 94 | // high and low R 95 | if (sym & (1 << 0)) 96 | { 97 | diff_l = (this_val.r & 0xFF) - (last.r & 0xFF); 98 | enc_.encodeSymbol(m_rgb_diff_0, uint8_t(diff_l)); 99 | } 100 | if (sym & (1 << 1)) 101 | { 102 | diff_h = static_cast(this_val.r >> 8) - (last.r >> 8); 103 | enc_.encodeSymbol(m_rgb_diff_1, uint8_t(diff_h)); 104 | } 105 | 106 | if (sym & (1 << 6)) 107 | { 108 | if (sym & (1 << 2)) 109 | { 110 | corr = static_cast(this_val.g & 0xFF) - 111 | utils::clamp(diff_l + (last.g & 0xFF)); 112 | enc_.encodeSymbol(m_rgb_diff_2, uint8_t(corr)); 113 | } 114 | 115 | if (sym & (1 << 4)) 116 | { 117 | diff_l = (diff_l + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2; 118 | corr = static_cast(this_val.b & 0xFF) - 119 | utils::clamp(diff_l + (last.b & 0xFF)); 120 | enc_.encodeSymbol(m_rgb_diff_4, uint8_t(corr)); 121 | } 122 | 123 | if (sym & (1 << 3)) 124 | { 125 | corr = static_cast(this_val.g >> 8) - 126 | utils::clamp(diff_h + (last.g >> 8)); 127 | enc_.encodeSymbol(m_rgb_diff_3, uint8_t(corr)); 128 | } 129 | 130 | if (sym & (1 << 5)) 131 | { 132 | diff_h = (diff_h + ((this_val.g >> 8)) - (last.g >> 8)) / 2; 133 | corr = static_cast(this_val.b >> 8) - 134 | utils::clamp(diff_h + (last.b >> 8)); 135 | enc_.encodeSymbol(m_rgb_diff_5, uint8_t(corr)); 136 | } 137 | } 138 | 139 | last = this_val; 140 | return buf + sizeof(las::rgb); 141 | } 142 | 143 | // DECOMPRESSOR 144 | 145 | Rgb10Decompressor::Rgb10Decompressor(decoders::arithmetic& decoder) : dec_(decoder) 146 | {} 147 | 148 | char *Rgb10Decompressor::decompress(char *buf) 149 | { 150 | if (!have_last_) { 151 | // don't have the first data yet, read the whole point out of the stream 152 | have_last_ = true; 153 | 154 | dec_.getInStream().getBytes((unsigned char*)buf, sizeof(las::rgb)); 155 | 156 | last.unpack(buf); 157 | return buf + sizeof(las::rgb); 158 | } 159 | 160 | unsigned char corr; 161 | int diff = 0; 162 | unsigned int sym = dec_.decodeSymbol(m_byte_used); 163 | 164 | las::rgb this_val; 165 | 166 | if (sym & (1 << 0)) 167 | { 168 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_0)); 169 | this_val.r = static_cast(uint8_t(corr + (last.r & 0xFF))); 170 | } 171 | else 172 | { 173 | this_val.r = last.r & 0xFF; 174 | } 175 | 176 | if (sym & (1 << 1)) 177 | { 178 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_1)); 179 | this_val.r |= (static_cast(uint8_t(corr + (last.r >> 8))) << 8); 180 | } 181 | else 182 | { 183 | this_val.r |= last.r & 0xFF00; 184 | } 185 | 186 | if (sym & (1 << 6)) 187 | { 188 | diff = (this_val.r & 0xFF) - (last.r & 0xFF); 189 | 190 | if (sym & (1 << 2)) 191 | { 192 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_2)); 193 | this_val.g = static_cast(uint8_t(corr + 194 | utils::clamp(diff + (last.g & 0xFF)))); 195 | } 196 | else 197 | { 198 | this_val.g = last.g & 0xFF; 199 | } 200 | 201 | if (sym & (1 << 4)) 202 | { 203 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_4)); 204 | diff = (diff + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2; 205 | this_val.b = static_cast(uint8_t(corr + 206 | utils::clamp(diff + (last.b & 0xFF)))); 207 | } 208 | else 209 | { 210 | this_val.b = last.b & 0xFF; 211 | } 212 | 213 | diff = (this_val.r >> 8) - (last.r >> 8); 214 | if (sym & (1 << 3)) 215 | { 216 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_3)); 217 | this_val.g |= static_cast(uint8_t(corr + 218 | utils::clamp(diff + (last.g >> 8)))) << 8; 219 | } 220 | else { 221 | this_val.g |= last.g & 0xFF00; 222 | } 223 | 224 | if (sym & (1 << 5)) 225 | { 226 | corr = static_cast(dec_.decodeSymbol(m_rgb_diff_5)); 227 | diff = (diff + (this_val.g >> 8) - (last.g >> 8)) / 2; 228 | 229 | this_val.b |= static_cast(uint8_t(corr + 230 | utils::clamp(diff + (last.b >> 8)))) << 8; 231 | } 232 | else { 233 | this_val.b |= (last.b & 0xFF00); 234 | } 235 | } 236 | else 237 | { 238 | this_val.g = this_val.r; 239 | this_val.b = this_val.r; 240 | } 241 | 242 | last = this_val; 243 | last.pack(buf); 244 | return buf + sizeof(las::rgb); 245 | } 246 | 247 | } // namespace detail 248 | } // namespace lazperf 249 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_rgb10.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | CHANGE HISTORY: 22 | 23 | =============================================================================== 24 | */ 25 | 26 | namespace lazperf 27 | { 28 | namespace detail 29 | { 30 | 31 | class Rgb10Base 32 | { 33 | protected: 34 | Rgb10Base(); 35 | 36 | bool have_last_; 37 | las::rgb last; 38 | 39 | models::arithmetic m_byte_used; 40 | models::arithmetic m_rgb_diff_0; 41 | models::arithmetic m_rgb_diff_1; 42 | models::arithmetic m_rgb_diff_2; 43 | models::arithmetic m_rgb_diff_3; 44 | models::arithmetic m_rgb_diff_4; 45 | models::arithmetic m_rgb_diff_5; 46 | }; 47 | 48 | class Rgb10Compressor : public Rgb10Base 49 | { 50 | public: 51 | Rgb10Compressor(encoders::arithmetic&); 52 | 53 | const char *compress(const char *buf); 54 | 55 | private: 56 | encoders::arithmetic& enc_; 57 | }; 58 | 59 | class Rgb10Decompressor : public Rgb10Base 60 | { 61 | public: 62 | Rgb10Decompressor(decoders::arithmetic&); 63 | 64 | char *decompress(char *buf); 65 | 66 | private: 67 | decoders::arithmetic& dec_; 68 | }; 69 | 70 | } // namespace detail 71 | } // namespace lazperf 72 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_rgb14.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_rgb14.hpp 5 | 6 | CONTENTS: 7 | 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | namespace lazperf 32 | { 33 | namespace detail 34 | { 35 | 36 | class Rgb14Base 37 | { 38 | protected: 39 | struct ChannelCtx 40 | { 41 | int have_last_; 42 | las::rgb14 last_; 43 | models::arithmetic used_model_; 44 | std::array diff_model_; 45 | 46 | ChannelCtx() : have_last_{false}, used_model_(128), 47 | diff_model_{ models::arithmetic(256), models::arithmetic(256), 48 | models::arithmetic(256), models::arithmetic(256), 49 | models::arithmetic(256), models::arithmetic(256) } 50 | {} 51 | }; 52 | 53 | std::array chan_ctxs_; 54 | int last_channel_ = -1; 55 | }; 56 | 57 | class Rgb14Compressor : public Rgb14Base 58 | { 59 | public: 60 | Rgb14Compressor(OutCbStream& stream) : stream_(stream), rgb_enc_(false) 61 | {} 62 | 63 | void writeSizes(); 64 | void writeData(); 65 | const char *compress(const char *buf, int& sc); 66 | 67 | private: 68 | OutCbStream& stream_; 69 | encoders::arithmetic rgb_enc_; 70 | }; 71 | 72 | class Rgb14Decompressor : public Rgb14Base 73 | { 74 | public: 75 | Rgb14Decompressor(InCbStream& stream) : stream_(stream) 76 | {} 77 | 78 | void dumpSums(); 79 | void readSizes(); 80 | void readData(); 81 | char *decompress(char *buf, int& sc); 82 | 83 | private: 84 | InCbStream& stream_; 85 | uint32_t rgb_cnt_; 86 | decoders::arithmetic rgb_dec_; 87 | utils::Summer sumRgb; 88 | }; 89 | 90 | } // namespace detail 91 | } // namespace laszip 92 | -------------------------------------------------------------------------------- /cpp/lazperf/detail/field_xyz.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: field_xyz.hpp 5 | 6 | CONTENTS: 7 | XYZ fields encoder 8 | 9 | 10 | PROGRAMMERS: 11 | 12 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 13 | uday.karan@gmail.com - Hobu, Inc. 14 | 15 | COPYRIGHT: 16 | 17 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 18 | (c) 2014, Uday Verma, Hobu, Inc. 19 | 20 | This is free software; you can redistribute and/or modify it under the 21 | terms of the Apache Public License 2.0 published by the Apache Software 22 | Foundation. See the COPYING file for more information. 23 | 24 | This software is distributed WITHOUT ANY WARRANTY and without even the 25 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 26 | 27 | CHANGE HISTORY: 28 | 29 | =============================================================================== 30 | */ 31 | 32 | #ifndef __las_hpp__ 33 | #error Cannot directly include this file, this is a part of las.hpp 34 | #endif 35 | 36 | namespace laszip { 37 | namespace formats { 38 | // Teach packers how to pack unpack the xyz struct 39 | // 40 | template<> 41 | struct packers { 42 | inline static las::xyz unpack(const char *in) { 43 | // blind casting will cause problems for ARM and Emscripten targets 44 | // 45 | las::xyz p; 46 | 47 | p.x = packers::unpack(in); in += sizeof(int); 48 | p.y = packers::unpack(in); in += sizeof(int); 49 | p.z = packers::unpack(in); 50 | 51 | return p; 52 | } 53 | 54 | inline static void pack(const las::xyz& p, char *buffer) { 55 | packers::pack(p.x, buffer); buffer += sizeof(int); 56 | packers::pack(p.y, buffer); buffer += sizeof(int); 57 | packers::pack(p.z, buffer); 58 | } 59 | }; 60 | 61 | // specialize field to compress point 10 62 | // 63 | template<> 64 | struct field { 65 | typedef las::xyz type; 66 | 67 | field() : compressor_inited_(false), decompressors_inited_(false) { } 68 | 69 | template< 70 | typename TEncoder 71 | > 72 | inline const char *compressWith(TEncoder& enc, const char *buf) 73 | { 74 | if (!compressor_inited_) { 75 | compressors_.init(); 76 | compressor_inited_ = true; 77 | } 78 | 79 | las::xyz this_val = packers::unpack(buf); 80 | if (!common_.have_last_) { 81 | // don't have the first data yet, just push it to our have last stuff and move on 82 | common_.have_last_ = true; 83 | common_.last_ = this_val; 84 | 85 | enc.getOutStream().putBytes((const unsigned char*)buf, 86 | sizeof(las::xyz)); 87 | 88 | // we are done here 89 | return buf + sizeof(las::xyz); 90 | } 91 | 92 | unsigned int k_bits; 93 | int median, diff; 94 | 95 | // compress x coordinate 96 | median = common_.last_x_diff_median5.get(); 97 | diff = this_val.x - common_.last_.x; 98 | compressors_.ic_dx.compress(enc, median, diff, 0); 99 | common_.last_x_diff_median5.add(diff); 100 | 101 | // compress y coordinate 102 | k_bits = compressors_.ic_dx.getK(); 103 | median = common_.last_y_diff_median5.get(); 104 | diff = this_val.y - common_.last_.y; 105 | compressors_.ic_dy.compress(enc, median, diff, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); 106 | common_.last_y_diff_median5.add(diff); 107 | 108 | // compress z coordinate 109 | k_bits = (compressors_.ic_dx.getK() + compressors_.ic_dy.getK()) / 2; 110 | compressors_.ic_z.compress(enc, common_.last_height, this_val.z, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); 111 | common_.last_height = this_val.z; 112 | 113 | common_.last_ = this_val; 114 | return buf + sizeof(las::xyz); 115 | } 116 | 117 | template< 118 | typename TDecoder 119 | > 120 | inline char *decompressWith(TDecoder& dec, char *buf) 121 | { 122 | if (!decompressors_inited_) { 123 | decompressors_.init(); 124 | decompressors_inited_ = true; 125 | } 126 | 127 | if (!common_.have_last_) { 128 | // don't have the first data yet, read the whole point out of the stream 129 | common_.have_last_ = true; 130 | 131 | dec.getInStream().getBytes((unsigned char*)buf, 132 | sizeof(las::xyz)); 133 | 134 | // decode this value 135 | common_.last_ = packers::unpack(buf); 136 | 137 | // we are done here 138 | return buf + sizeof(las::xyz); 139 | } 140 | 141 | unsigned int k_bits; 142 | int median, diff; 143 | 144 | // decompress x coordinate 145 | median = common_.last_x_diff_median5.get(); 146 | 147 | diff = decompressors_.ic_dx.decompress(dec, median, 0); 148 | common_.last_.x += diff; 149 | common_.last_x_diff_median5.add(diff); 150 | 151 | // decompress y coordinate 152 | median = common_.last_y_diff_median5.get(); 153 | k_bits = decompressors_.ic_dx.getK(); 154 | diff = decompressors_.ic_dy.decompress(dec, median, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); 155 | common_.last_.y += diff; 156 | common_.last_y_diff_median5.add(diff); 157 | 158 | // decompress z coordinate 159 | k_bits = (decompressors_.ic_dx.getK() + decompressors_.ic_dy.getK()) / 2; 160 | common_.last_.z = decompressors_.ic_z.decompress(dec, common_.last_height, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); 161 | common_.last_height = common_.last_.z; 162 | 163 | packers::pack(common_.last_, buf); 164 | return buf + sizeof(las::xyz); 165 | } 166 | 167 | // All the things we need to compress a point, group them into structs 168 | // so we don't have too many names flying around 169 | 170 | // Common parts for both a compressor and decompressor go here 171 | struct __common { 172 | type last_; 173 | 174 | utils::streaming_median last_x_diff_median5; 175 | utils::streaming_median last_y_diff_median5; 176 | 177 | int last_height; 178 | bool have_last_; 179 | 180 | __common() : 181 | last_height(0), 182 | have_last_(false) { 183 | } 184 | 185 | ~__common() { 186 | } 187 | } common_; 188 | 189 | // These compressors are specific to a compressor usage, so we keep them separate here 190 | struct __compressors { 191 | compressors::integer ic_dx; 192 | compressors::integer ic_dy; 193 | compressors::integer ic_z; 194 | 195 | __compressors() : 196 | ic_dx(32, 2), 197 | ic_dy(32, 22), 198 | ic_z(32, 20) { } 199 | 200 | void init() { 201 | ic_dx.init(); 202 | ic_dy.init(); 203 | ic_z.init(); 204 | } 205 | } compressors_; 206 | 207 | struct __decompressors { 208 | decompressors::integer ic_dx; 209 | decompressors::integer ic_dy; 210 | decompressors::integer ic_z; 211 | 212 | __decompressors() : 213 | ic_dx(32, 2), 214 | ic_dy(32, 22), 215 | ic_z(32, 20) { } 216 | 217 | void init() { 218 | ic_dx.init(); 219 | ic_dy.init(); 220 | ic_z.init(); 221 | } 222 | } decompressors_; 223 | 224 | bool compressor_inited_; 225 | bool decompressors_inited_; 226 | }; 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /cpp/lazperf/excepts.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: excepts.hpp 5 | 6 | CONTENTS: 7 | Exception types 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | #ifndef __excepts_hpp__ 32 | #define __excepts_hpp__ 33 | 34 | #include 35 | 36 | namespace lazperf 37 | { 38 | 39 | struct error : public std::runtime_error 40 | { 41 | error(const std::string& what) : std::runtime_error(what) 42 | {} 43 | }; 44 | 45 | } // namespace lazperf 46 | 47 | #endif // __excepts_hpp__ 48 | -------------------------------------------------------------------------------- /cpp/lazperf/filestream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: filestream.cpp 5 | 6 | CONTENTS: 7 | Stream abstractions 8 | 9 | PROGRAMMERS: 10 | 11 | uday.karan@gmail.com - Hobu, Inc. 12 | 13 | COPYRIGHT: 14 | 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | #include 30 | 31 | #include "filestream.hpp" 32 | #include "excepts.hpp" 33 | 34 | namespace lazperf 35 | { 36 | 37 | OutFileStream::OutFileStream(std::ostream& out) : f_(out) 38 | {} 39 | 40 | // Should probably write to memory to avoid all these calls to a file that can't 41 | // be seen by the compiler. 42 | void OutFileStream::putBytes(const unsigned char *c, size_t len) 43 | { 44 | f_.write(reinterpret_cast(c), len); 45 | } 46 | 47 | OutputCb OutFileStream::cb() 48 | { 49 | using namespace std::placeholders; 50 | 51 | return std::bind(&OutFileStream::putBytes, this, _1, _2); 52 | } 53 | 54 | // InFileStream 55 | 56 | struct InFileStream::Private 57 | { 58 | // Setting the offset_ to the buffer size will force a fill on the first read. 59 | Private(std::istream& in) : f_(in) 60 | { reset(); } 61 | 62 | void getBytes(unsigned char *buf, size_t request); 63 | size_t fillit(); 64 | void reset() 65 | { 66 | buf_.resize(1 << 20); 67 | offset_ = buf_.size(); 68 | } 69 | 70 | std::istream& f_; 71 | std::vector buf_; 72 | size_t offset_; 73 | }; 74 | 75 | InFileStream::InFileStream(std::istream& in) : p_(new Private(in)) 76 | {} 77 | 78 | InFileStream::~InFileStream() 79 | {} 80 | 81 | // This will force a fill on the next fetch. 82 | void InFileStream::reset() 83 | { 84 | p_->reset(); 85 | } 86 | 87 | InputCb InFileStream::cb() 88 | { 89 | using namespace std::placeholders; 90 | 91 | return std::bind(&InFileStream::Private::getBytes, p_.get(), _1, _2); 92 | } 93 | 94 | void InFileStream::Private::getBytes(unsigned char *buf, size_t request) 95 | { 96 | // Almost all requests are size 1. 97 | if (request == 1) 98 | { 99 | if (offset_ >= buf_.size()) 100 | fillit(); 101 | *buf = buf_[offset_++]; 102 | return; 103 | } 104 | 105 | size_t available = buf_.size() - offset_; 106 | if (request <= available) 107 | { 108 | unsigned char *begin = buf_.data() + offset_; 109 | unsigned char *end = begin + request; 110 | std::copy(begin, end, buf); 111 | offset_ += request; 112 | } 113 | else 114 | { 115 | do 116 | { 117 | size_t bytes = (std::min)(request, available); 118 | unsigned char *begin = buf_.data() + offset_; 119 | unsigned char *end = begin + bytes; 120 | std::copy(begin, end, buf); 121 | offset_ += bytes; 122 | request -= bytes; 123 | if (request == 0) 124 | break; 125 | buf += bytes; 126 | available = fillit(); 127 | } while (true); 128 | } 129 | } 130 | 131 | size_t InFileStream::Private::fillit() 132 | { 133 | offset_ = 0; 134 | f_.read(reinterpret_cast(buf_.data()), buf_.size()); 135 | size_t filled = f_.gcount(); 136 | 137 | if (filled == 0) 138 | throw error("Unexpected end of file."); 139 | buf_.resize(filled); 140 | return filled; 141 | } 142 | 143 | } // namespace lazperf 144 | -------------------------------------------------------------------------------- /cpp/lazperf/filestream.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: filestream.hpp 5 | 6 | CONTENTS: 7 | Stream abstractions 8 | 9 | PROGRAMMERS: 10 | 11 | uday.karan@gmail.com - Hobu, Inc. 12 | 13 | COPYRIGHT: 14 | 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "lazperf.hpp" 34 | 35 | namespace lazperf 36 | { 37 | 38 | // Convenience class 39 | 40 | struct OutFileStream 41 | { 42 | public: 43 | LAZPERF_EXPORT OutFileStream(std::ostream& out); 44 | 45 | LAZPERF_EXPORT void putBytes(const unsigned char *c, size_t len); 46 | LAZPERF_EXPORT OutputCb cb(); 47 | 48 | private: 49 | std::ostream& f_; 50 | }; 51 | 52 | // Convenience class 53 | 54 | struct InFileStream 55 | { 56 | struct Private; 57 | 58 | public: 59 | LAZPERF_EXPORT InFileStream(std::istream& in); 60 | LAZPERF_EXPORT ~InFileStream(); 61 | 62 | // This will force a fill on the next fetch. 63 | LAZPERF_EXPORT void reset(); 64 | LAZPERF_EXPORT InputCb cb(); 65 | 66 | private: 67 | std::unique_ptr p_; 68 | }; 69 | 70 | } // namespace lazperf 71 | 72 | -------------------------------------------------------------------------------- /cpp/lazperf/header.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | CHANGE HISTORY: 22 | 23 | =============================================================================== 24 | */ 25 | 26 | #include 27 | 28 | #include "header.hpp" 29 | #include "Extractor.hpp" 30 | #include "Inserter.hpp" 31 | 32 | namespace lazperf 33 | { 34 | 35 | const size_t header12::Size = 227; 36 | const size_t header13::Size = 235; 37 | const size_t header14::Size = 375; 38 | 39 | int baseCount(int format) 40 | { 41 | // Martin screws with the high bits of the format, so we mask down to the low four bits. 42 | switch (format & 0xF) 43 | { 44 | case 0: 45 | return 20; 46 | case 1: 47 | return 28; 48 | case 2: 49 | return 26; 50 | case 3: 51 | return 34; 52 | case 6: 53 | return 30; 54 | case 7: 55 | return 36; 56 | case 8: 57 | return 38; 58 | default: 59 | return 0; 60 | } 61 | } 62 | 63 | base_header::base_header() 64 | {} 65 | 66 | int base_header::ebCount() const 67 | { 68 | int baseSize = baseCount(point_format_id); 69 | return (baseSize ? point_record_length - baseSize : 0); 70 | } 71 | 72 | // Get the real point format - strip off any silly LAZ encoding bits 73 | int base_header::pointFormat() const 74 | { 75 | return point_format_id & 0x3F; 76 | } 77 | 78 | // Check if the compression bit is set. 79 | bool base_header::compressed() const 80 | { 81 | return point_format_id & 0x80; 82 | } 83 | 84 | size_t base_header::sizeFromVersion() const 85 | { 86 | size_t size = 0; 87 | if (version.minor == 2) 88 | size = header12::Size; 89 | else if (version.minor == 3) 90 | size = header13::Size; 91 | else if (version.minor == 4) 92 | size = header14::Size; 93 | return size; 94 | } 95 | 96 | int base_header::minorVersion(std::istream& in) 97 | { 98 | auto pos = in.tellg(); 99 | in.seekg(25); 100 | int8_t version; 101 | in >> version; 102 | in.seekg(pos); 103 | return (in.good() ? version : 0); 104 | } 105 | 106 | /// 107 | 108 | header12 header12::create(std::istream& in) 109 | { 110 | header12 h; 111 | h.read(in); 112 | return h; 113 | } 114 | 115 | void header12::read(std::istream& in) 116 | { 117 | std::vector buf(header12::Size); 118 | in.read(buf.data(), buf.size()); 119 | LeExtractor s(buf.data(), buf.size()); 120 | 121 | s.get(magic, 4); 122 | s >> file_source_id >> global_encoding; 123 | s.get(guid, 16); 124 | s >> version.major >> version.minor; 125 | 126 | if (version.minor < 2) 127 | { 128 | global_encoding = 0; 129 | if (version.minor == 0) 130 | file_source_id = 0; 131 | } 132 | 133 | s.get(system_identifier, 32); 134 | s.get(generating_software, 32); 135 | s >> creation.day >> creation.year; 136 | s >> header_size >> point_offset >> vlr_count; 137 | s >> point_format_id >> point_record_length; 138 | s >> point_count; 139 | for (int i = 0; i < 5; ++i) 140 | s >> points_by_return[i]; 141 | s >> scale.x >> scale.y >> scale.z; 142 | s >> offset.x >> offset.y >> offset.z; 143 | s >> maxx >> minx >> maxy >> miny >> maxz >> minz; 144 | } 145 | 146 | void header12::write(std::ostream& out) const 147 | { 148 | std::vector buf(header12::Size); 149 | LeInserter s(buf.data(), buf.size()); 150 | 151 | s.put(magic, 4); 152 | s << file_source_id << global_encoding; 153 | s.put(guid, 16); 154 | s << version.major << version.minor; 155 | s.put(system_identifier, 32); 156 | s.put(generating_software, 32); 157 | s << creation.day << creation.year; 158 | s << header_size << point_offset << vlr_count; 159 | s << point_format_id << point_record_length; 160 | s << point_count; 161 | for (int i = 0; i < 5; ++i) 162 | s << points_by_return[i]; 163 | s << scale.x << scale.y << scale.z; 164 | s << offset.x << offset.y << offset.z; 165 | s << maxx << minx << maxy << miny << maxz << minz; 166 | out.write(buf.data(), buf.size()); 167 | } 168 | 169 | /// 170 | 171 | header13 header13::create(std::istream& in) 172 | { 173 | header13 h; 174 | h.read(in); 175 | return h; 176 | } 177 | 178 | void header13::read(std::istream& in) 179 | { 180 | ((header12 *)this)->read(in); 181 | 182 | std::vector buf(header13::Size - header12::Size); 183 | in.read(buf.data(), buf.size()); 184 | LeExtractor s(buf.data(), buf.size()); 185 | 186 | s >> wave_offset; 187 | } 188 | 189 | void header13::write(std::ostream& out) const 190 | { 191 | ((const header12 *)this)->write(out); 192 | 193 | std::vector buf(header13::Size - header12::Size); 194 | LeInserter s(buf.data(), buf.size()); 195 | 196 | s << wave_offset; 197 | 198 | out.write(buf.data(), buf.size()); 199 | } 200 | 201 | /// 202 | 203 | header14 header14::create(std::istream& in) 204 | { 205 | header14 h; 206 | h.read(in); 207 | return h; 208 | } 209 | 210 | void header14::read(std::istream& in) 211 | { 212 | ((header13 *)this)->read(in); 213 | 214 | std::vector buf(header14::Size - header13::Size); 215 | in.read(buf.data(), buf.size()); 216 | LeExtractor s(buf.data(), buf.size()); 217 | 218 | s >> evlr_offset; 219 | s >> evlr_count; 220 | s >> point_count_14; 221 | for (int i = 0; i < 15; ++i) 222 | s >> points_by_return_14[i]; 223 | } 224 | 225 | void header14::write(std::ostream& out) const 226 | { 227 | ((const header13 *)this)->write(out); 228 | 229 | std::vector buf(header14::Size - header13::Size); 230 | LeInserter s(buf.data(), buf.size()); 231 | 232 | s << evlr_offset; 233 | s << evlr_count; 234 | s << point_count_14; 235 | for (int i = 0; i < 15; ++i) 236 | s << points_by_return_14[i]; 237 | 238 | out.write(buf.data(), buf.size()); 239 | } 240 | 241 | } // namespace lazperf 242 | 243 | -------------------------------------------------------------------------------- /cpp/lazperf/header.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | CHANGE HISTORY: 22 | 23 | =============================================================================== 24 | */ 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "lazperf_base.hpp" 35 | 36 | namespace lazperf 37 | { 38 | 39 | class LeInserter; 40 | class LeExtractor; 41 | 42 | const uint32_t DefaultChunkSize = 50000; 43 | const uint32_t VariableChunkSize = (std::numeric_limits::max)(); 44 | 45 | LAZPERF_EXPORT int baseCount(int format); 46 | 47 | struct LAZPERF_EXPORT vector3 48 | { 49 | vector3() : x(0), y(0), z(0) 50 | {} 51 | 52 | vector3(double x, double y, double z) : x(x), y(y), z(z) 53 | {} 54 | 55 | double x; 56 | double y; 57 | double z; 58 | }; 59 | 60 | // We currently export the whole struct because we have virtual functions and the vtable 61 | // doesn't get exported unless you export the struct/class. :( 62 | struct LAZPERF_EXPORT base_header 63 | { 64 | char magic[4] { 'L', 'A', 'S', 'F' }; 65 | uint16_t file_source_id {}; 66 | uint16_t global_encoding {}; 67 | char guid[16] {}; 68 | 69 | struct { 70 | uint8_t major {1}; 71 | uint8_t minor {3}; 72 | } version; 73 | 74 | char system_identifier[32] {}; 75 | char generating_software[32] {}; 76 | 77 | struct { 78 | uint16_t day {}; 79 | uint16_t year {}; 80 | } creation; 81 | 82 | uint16_t header_size {}; 83 | uint32_t point_offset {}; 84 | uint32_t vlr_count {}; 85 | 86 | uint8_t point_format_id {}; 87 | uint16_t point_record_length {}; 88 | 89 | uint32_t point_count {}; 90 | uint32_t points_by_return[5] {}; 91 | 92 | vector3 scale; 93 | vector3 offset; 94 | double maxx { std::numeric_limits::lowest() }; 95 | double minx { (std::numeric_limits::max)() }; 96 | double maxy { std::numeric_limits::lowest() }; 97 | double miny { (std::numeric_limits::max)() }; 98 | double maxz { std::numeric_limits::lowest() }; 99 | double minz { (std::numeric_limits::max)() }; 100 | 101 | size_t sizeFromVersion() const; 102 | int ebCount() const; 103 | int pointFormat() const; 104 | bool compressed() const; 105 | static int minorVersion(std::istream& in); 106 | 107 | protected: 108 | base_header(); 109 | }; 110 | 111 | struct LAZPERF_EXPORT header12 : public base_header 112 | { 113 | header12() 114 | { 115 | version.minor = 2; 116 | } 117 | 118 | static header12 create(std::istream& in); 119 | void read(std::istream& in); 120 | void write(std::ostream& out) const; 121 | static const size_t Size; 122 | }; 123 | 124 | struct LAZPERF_EXPORT header13 : public header12 125 | { 126 | header13() 127 | { 128 | version.minor = 3; 129 | } 130 | 131 | static header13 create(std::istream& in); 132 | void read(std::istream& in); 133 | void write(std::ostream& out) const; 134 | static const size_t Size; 135 | uint64_t wave_offset {0}; 136 | }; 137 | 138 | struct LAZPERF_EXPORT header14 : public header13 139 | { 140 | header14() 141 | { 142 | version.minor = 4; 143 | } 144 | 145 | static header14 create(std::istream& in); 146 | void read(std::istream& in); 147 | void write(std::ostream& out) const; 148 | static const size_t Size; 149 | 150 | uint64_t evlr_offset {0}; 151 | uint32_t evlr_count {0}; 152 | uint64_t point_count_14 {0}; 153 | uint64_t points_by_return_14[15] {}; 154 | }; 155 | 156 | // Note that the values must be converted to 32-bit before encoding. 157 | struct chunk 158 | { 159 | uint64_t count; 160 | uint64_t offset; 161 | }; 162 | 163 | #define FRIEND_TEST(test_case_name, test_name) \ 164 | friend class test_case_name##_##test_name##_Test 165 | 166 | } // namespace lazperf 167 | 168 | -------------------------------------------------------------------------------- /cpp/lazperf/lazperf.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | CONTENTS: 5 | Point formats for LAS 6 | 7 | PROGRAMMERS: 8 | 9 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 10 | uday.karan@gmail.com - Hobu, Inc. 11 | 12 | COPYRIGHT: 13 | 14 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "header.hpp" 36 | #include "lazperf_base.hpp" 37 | 38 | namespace lazperf 39 | { 40 | 41 | // Called when compressed output is to be written. 42 | using OutputCb = std::function; 43 | 44 | // Called when compressed input is to be read. 45 | using InputCb = std::function; 46 | 47 | class LAZPERF_EXPORT las_compressor 48 | { 49 | public: 50 | typedef std::shared_ptr ptr; 51 | 52 | virtual const char *compress(const char *in) = 0; 53 | virtual void done() = 0; 54 | virtual ~las_compressor(); 55 | }; 56 | 57 | class LAZPERF_EXPORT las_decompressor 58 | { 59 | public: 60 | typedef std::shared_ptr ptr; 61 | 62 | virtual char *decompress(char *in) = 0; 63 | virtual ~las_decompressor(); 64 | }; 65 | 66 | class point_compressor_base_1_2 : public las_compressor 67 | { 68 | struct Private; 69 | 70 | public: 71 | LAZPERF_EXPORT void done(); 72 | 73 | protected: 74 | point_compressor_base_1_2(OutputCb cb, size_t ebCount); 75 | virtual ~point_compressor_base_1_2(); 76 | 77 | std::unique_ptr p_; 78 | }; 79 | 80 | class point_compressor_0 final : public point_compressor_base_1_2 81 | { 82 | public: 83 | LAZPERF_EXPORT point_compressor_0(OutputCb cb, size_t ebCount = 0); 84 | LAZPERF_EXPORT ~point_compressor_0(); 85 | 86 | LAZPERF_EXPORT virtual const char *compress(const char *in); 87 | }; 88 | 89 | class point_compressor_1 final : public point_compressor_base_1_2 90 | { 91 | public: 92 | LAZPERF_EXPORT point_compressor_1(OutputCb cb, size_t ebCount = 0); 93 | LAZPERF_EXPORT ~point_compressor_1(); 94 | 95 | LAZPERF_EXPORT virtual const char *compress(const char *in); 96 | }; 97 | 98 | class point_compressor_2 final : public point_compressor_base_1_2 99 | { 100 | public: 101 | LAZPERF_EXPORT point_compressor_2(OutputCb cb, size_t ebCount = 0); 102 | LAZPERF_EXPORT ~point_compressor_2(); 103 | 104 | LAZPERF_EXPORT virtual const char *compress(const char *in); 105 | }; 106 | 107 | class point_compressor_3 final : public point_compressor_base_1_2 108 | { 109 | public: 110 | LAZPERF_EXPORT point_compressor_3(OutputCb cb, size_t ebCount = 0); 111 | LAZPERF_EXPORT ~point_compressor_3(); 112 | 113 | LAZPERF_EXPORT virtual const char *compress(const char *in); 114 | }; 115 | 116 | class point_compressor_base_1_4 : public las_compressor 117 | { 118 | struct Private; 119 | 120 | public: 121 | virtual const char *compress(const char *in) = 0; 122 | 123 | protected: 124 | point_compressor_base_1_4(OutputCb cb, size_t ebCount); 125 | 126 | std::unique_ptr p_; 127 | }; 128 | 129 | 130 | class point_compressor_6 final : public point_compressor_base_1_4 131 | { 132 | public: 133 | LAZPERF_EXPORT point_compressor_6(OutputCb cb, size_t ebCount = 0); 134 | LAZPERF_EXPORT ~point_compressor_6(); 135 | 136 | LAZPERF_EXPORT virtual const char *compress(const char *in); 137 | LAZPERF_EXPORT virtual void done(); 138 | }; 139 | 140 | class point_compressor_7 final : public point_compressor_base_1_4 141 | { 142 | public: 143 | LAZPERF_EXPORT point_compressor_7(OutputCb cb, size_t ebCount = 0); 144 | LAZPERF_EXPORT ~point_compressor_7(); 145 | 146 | LAZPERF_EXPORT virtual const char *compress(const char *in); 147 | LAZPERF_EXPORT virtual void done(); 148 | }; 149 | 150 | class point_compressor_8 final : public point_compressor_base_1_4 151 | { 152 | public: 153 | LAZPERF_EXPORT point_compressor_8(OutputCb cb, size_t ebCount = 0); 154 | LAZPERF_EXPORT ~point_compressor_8(); 155 | 156 | LAZPERF_EXPORT virtual const char *compress(const char *in); 157 | LAZPERF_EXPORT virtual void done(); 158 | }; 159 | 160 | 161 | // Decompressor 162 | 163 | class point_decompressor_base_1_2 : public las_decompressor 164 | { 165 | struct Private; 166 | 167 | public: 168 | virtual char *decompress(char *in) = 0; 169 | virtual ~point_decompressor_base_1_2(); 170 | 171 | protected: 172 | point_decompressor_base_1_2(InputCb cb, size_t ebCount); 173 | void handleFirst(); 174 | 175 | std::unique_ptr p_; 176 | }; 177 | 178 | class point_decompressor_0 final : public point_decompressor_base_1_2 179 | { 180 | public: 181 | LAZPERF_EXPORT point_decompressor_0(InputCb cb, size_t ebCount = 0); 182 | LAZPERF_EXPORT ~point_decompressor_0(); 183 | 184 | LAZPERF_EXPORT virtual char *decompress(char *in); 185 | }; 186 | 187 | class point_decompressor_1 final : public point_decompressor_base_1_2 188 | { 189 | public: 190 | LAZPERF_EXPORT point_decompressor_1(InputCb cb, size_t ebCount = 0); 191 | LAZPERF_EXPORT ~point_decompressor_1(); 192 | 193 | LAZPERF_EXPORT virtual char *decompress(char *out); 194 | }; 195 | 196 | class point_decompressor_2 final : public point_decompressor_base_1_2 197 | { 198 | public: 199 | LAZPERF_EXPORT point_decompressor_2(InputCb cb, size_t ebCount = 0); 200 | LAZPERF_EXPORT ~point_decompressor_2(); 201 | 202 | LAZPERF_EXPORT virtual char *decompress(char *out); 203 | }; 204 | 205 | class point_decompressor_3 final : public point_decompressor_base_1_2 206 | { 207 | public: 208 | LAZPERF_EXPORT point_decompressor_3(InputCb cb, size_t ebCount = 0); 209 | LAZPERF_EXPORT ~point_decompressor_3(); 210 | 211 | LAZPERF_EXPORT virtual char *decompress(char *out); 212 | }; 213 | 214 | class point_decompressor_base_1_4 : public las_decompressor 215 | { 216 | struct Private; 217 | 218 | public: 219 | virtual char *decompress(char *out) = 0; 220 | 221 | protected: 222 | point_decompressor_base_1_4(InputCb cb, size_t ebCount); 223 | 224 | std::unique_ptr p_; 225 | }; 226 | 227 | class point_decompressor_6 final : public point_decompressor_base_1_4 228 | { 229 | public: 230 | LAZPERF_EXPORT point_decompressor_6(InputCb cb, size_t ebCount = 0); 231 | LAZPERF_EXPORT ~point_decompressor_6(); 232 | 233 | LAZPERF_EXPORT virtual char *decompress(char *out); 234 | }; 235 | 236 | class point_decompressor_7 final : public point_decompressor_base_1_4 237 | { 238 | public: 239 | LAZPERF_EXPORT point_decompressor_7(InputCb cb, size_t ebCount = 0); 240 | LAZPERF_EXPORT ~point_decompressor_7(); 241 | 242 | LAZPERF_EXPORT virtual char *decompress(char *out); 243 | }; 244 | 245 | struct point_decompressor_8 final : public point_decompressor_base_1_4 246 | { 247 | public: 248 | LAZPERF_EXPORT ~point_decompressor_8(); 249 | LAZPERF_EXPORT point_decompressor_8(InputCb cb, size_t ebCount = 0); 250 | 251 | LAZPERF_EXPORT virtual char *decompress(char *out); 252 | }; 253 | 254 | // FACTORY 255 | 256 | LAZPERF_EXPORT las_compressor::ptr build_las_compressor(OutputCb, int format, 257 | size_t ebCount = 0); 258 | LAZPERF_EXPORT las_decompressor::ptr build_las_decompressor(InputCb, int format, 259 | size_t ebCount = 0); 260 | 261 | // CHUNK TABLE 262 | 263 | // Note that the chunk values are sizes, rather than offsets. 264 | 265 | // This functions is only for fixed-sized chunks. 266 | LAZPERF_EXPORT void compress_chunk_table(OutputCb cb, const std::vector& chunks); 267 | LAZPERF_EXPORT void compress_chunk_table(OutputCb cb, const std::vector& chunks, 268 | bool variableChunks); 269 | LAZPERF_EXPORT std::vector decompress_chunk_table(InputCb cb, size_t numChunks, 270 | bool variableChunks); 271 | 272 | // Deprecated 273 | LAZPERF_EXPORT std::vector decompress_chunk_table(InputCb cb, size_t numChunks); 274 | 275 | } // namespace lazperf 276 | 277 | -------------------------------------------------------------------------------- /cpp/lazperf/lazperf_base.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define LAZPERF_MAJOR_VERSION 3 5 | #define LAZPERF_MINOR_VERSION 2 6 | #define LAZPERF_REVISION 0 7 | #define LAZPERF_VERSION 3.2.0 8 | 9 | #ifndef LAZPERF_VENDORED 10 | #ifdef _WIN32 11 | #define LAZPERF_EXPORT __declspec(dllexport) 12 | #else 13 | // This may not be necessary. The GCC doc says it take __declspec((dllexport)) 14 | #define LAZPERF_EXPORT __attribute__((visibility ("default"))) 15 | #endif 16 | #else 17 | #define LAZPERF_EXPORT 18 | #endif 19 | -------------------------------------------------------------------------------- /cpp/lazperf/lazperf_user_base.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define LAZPERF_MAJOR_VERSION 1 5 | #define LAZPERF_MINOR_VERSION 3 6 | #define LAZPERF_REVISION 0 7 | #define LAZPERF_VERSION 1.3.0 8 | 9 | // Note that this __declspec(dllimport) is not necessary and you can remove it if you like. 10 | // It allows the compiler to make a potential optimization in calling exported functions 11 | // by using an indirect call rather than a call to a thunk which then calls the exported function. 12 | #ifdef _WIN32 13 | #define LAZPERF_EXPORT __declspec(dllimport) 14 | #else 15 | #define LAZPERF_EXPORT 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /cpp/lazperf/portable_endian.hpp: -------------------------------------------------------------------------------- 1 | // (c) Mathias Panzenböck 2 | // http://github.com/panzi/mathfun/blob/master/examples/portable_endian.h 3 | // 4 | 5 | #pragma once 6 | 7 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) 8 | 9 | # define __WINDOWS__ 10 | 11 | #endif 12 | 13 | // use standard posix style headers for apple emscripten builds as well since emscripten sdk now ships its own 14 | // libc headers 15 | #if defined(__linux__) || defined(__CYGWIN__) || defined(__EMSCRIPTEN__) || defined(__GNU__) 16 | 17 | # include 18 | 19 | #elif defined(__APPLE__) 20 | 21 | # include 22 | # include 23 | 24 | # define htobe16 OSSwapHostToBigInt16 25 | # define htole16 OSSwapHostToLittleInt16 26 | # define be16toh OSSwapBigToHostInt16 27 | # define le16toh OSSwapLittleToHostInt16 28 | 29 | # define htobe32 OSSwapHostToBigInt32 30 | # define htole32 OSSwapHostToLittleInt32 31 | # define be32toh OSSwapBigToHostInt32 32 | # define le32toh OSSwapLittleToHostInt32 33 | 34 | # define htobe64 OSSwapHostToBigInt64 35 | # define htole64 OSSwapHostToLittleInt64 36 | # define be64toh OSSwapBigToHostInt64 37 | # define le64toh OSSwapLittleToHostInt64 38 | 39 | /** 40 | # define __BYTE_ORDER BYTE_ORDER 41 | # define __BIG_ENDIAN BIG_ENDIAN 42 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 43 | # define __PDP_ENDIAN PDP_ENDIAN 44 | **/ 45 | 46 | #elif defined(__OpenBSD__)|| defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) 47 | 48 | # if defined __has_include && __has_include () 49 | # include 50 | # elif defined __has_include && __has_include () 51 | # include 52 | # else 53 | # define be16toh betoh16 54 | # define le16toh letoh16 55 | # define be32toh betoh32 56 | # define le32toh letoh32 57 | # define be64toh betoh64 58 | # define le64toh letoh64 59 | # endif 60 | 61 | #elif defined(__WINDOWS__) 62 | 63 | # include 64 | 65 | # if BYTE_ORDER == LITTLE_ENDIAN 66 | # define htobe16 htons 67 | # define htole16(x) (x) 68 | # define be16toh ntohs 69 | # define le16toh(x) (x) 70 | 71 | # define htobe32 htonl 72 | # define htole32(x) (x) 73 | # define be32toh ntohl 74 | # define le32toh(x) (x) 75 | 76 | # define htole64(x) (x) 77 | # define le64toh(x) (x) 78 | # ifndef __MINGW32__ 79 | # define be64toh ntohll 80 | # define htobe64 htonll 81 | # else 82 | # define be64toh(x) ((((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32))) 83 | # define htobe64(x) ((((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32))) 84 | # endif 85 | 86 | # elif BYTE_ORDER == BIG_ENDIAN 87 | 88 | /* that would be xbox 360 */ 89 | # define htobe16(x) (x) 90 | # define htole16(x) __builtin_bswap16(x) 91 | # define be16toh(x) (x) 92 | # define le16toh(x) __builtin_bswap16(x) 93 | 94 | # define htobe32(x) (x) 95 | # define htole32(x) __builtin_bswap32(x) 96 | # define be32toh(x) (x) 97 | # define le32toh(x) __builtin_bswap32(x) 98 | 99 | # define htobe64(x) (x) 100 | # define htole64(x) __builtin_bswap64(x) 101 | # define be64toh(x) (x) 102 | # define le64toh(x) __builtin_bswap64(x) 103 | 104 | # else 105 | 106 | # error byte order not supported 107 | 108 | # endif 109 | 110 | # define __BYTE_ORDER BYTE_ORDER 111 | # define __BIG_ENDIAN BIG_ENDIAN 112 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 113 | # define __PDP_ENDIAN PDP_ENDIAN 114 | 115 | #else 116 | 117 | # error platform not supported 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /cpp/lazperf/readers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | =============================================================================== 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "header.hpp" 27 | #include "vlr.hpp" 28 | 29 | namespace lazperf 30 | { 31 | namespace reader 32 | { 33 | 34 | class basic_file 35 | { 36 | FRIEND_TEST(io_tests, parses_laszip_vlr_correctly); 37 | struct Private; 38 | 39 | protected: 40 | basic_file(); 41 | ~basic_file(); 42 | 43 | bool open(std::istream& in); 44 | 45 | public: 46 | LAZPERF_EXPORT uint64_t pointCount() const; 47 | LAZPERF_EXPORT const header14& header() const; 48 | LAZPERF_EXPORT void readPoint(char *out); 49 | LAZPERF_EXPORT laz_vlr lazVlr() const; 50 | LAZPERF_EXPORT std::vector vlrData(const std::string& user_id, uint16_t record_id); 51 | 52 | private: 53 | // The file object is not copyable or copy constructible 54 | basic_file(const basic_file&) = delete; 55 | basic_file& operator = (const basic_file&) = delete; 56 | 57 | std::unique_ptr p_; 58 | }; 59 | 60 | class mem_file : public basic_file 61 | { 62 | struct Private; 63 | 64 | public: 65 | LAZPERF_EXPORT mem_file(char *buf, size_t count); 66 | LAZPERF_EXPORT ~mem_file(); 67 | 68 | private: 69 | std::unique_ptr p_; 70 | }; 71 | 72 | class generic_file : public basic_file 73 | { 74 | public: 75 | LAZPERF_EXPORT ~generic_file(); 76 | LAZPERF_EXPORT generic_file(std::istream& in); 77 | }; 78 | 79 | class named_file : public basic_file 80 | { 81 | struct Private; 82 | 83 | public: 84 | LAZPERF_EXPORT named_file(const std::string& filename); 85 | LAZPERF_EXPORT ~named_file(); 86 | 87 | private: 88 | std::unique_ptr p_; 89 | }; 90 | 91 | /// 92 | 93 | class chunk_decompressor 94 | { 95 | struct Private; 96 | public: 97 | LAZPERF_EXPORT chunk_decompressor(int format, int ebCount, const char *srcbuf); 98 | LAZPERF_EXPORT ~chunk_decompressor(); 99 | LAZPERF_EXPORT void decompress(char *outbuf); 100 | 101 | private: 102 | std::unique_ptr p_; 103 | }; 104 | 105 | } // namespace reader 106 | } // namespace lazperf 107 | 108 | -------------------------------------------------------------------------------- /cpp/lazperf/streams.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: streams.hpp 5 | 6 | CONTENTS: 7 | Stream abstractions 8 | 9 | PROGRAMMERS: 10 | 11 | uday.karan@gmail.com - Hobu, Inc. 12 | 13 | COPYRIGHT: 14 | 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | #ifndef __streams_hpp__ 30 | #define __streams_hpp__ 31 | 32 | #include 33 | #include 34 | 35 | #include "lazperf.hpp" 36 | #include "excepts.hpp" 37 | #include "filestream.hpp" 38 | #include "portable_endian.hpp" 39 | 40 | namespace lazperf 41 | { 42 | 43 | struct OutCbStream 44 | { 45 | OutCbStream(OutputCb outCb) : outCb_(outCb) 46 | {} 47 | 48 | void putBytes(const unsigned char *b, size_t len) 49 | { 50 | outCb_(b, len); 51 | } 52 | 53 | void putByte(const unsigned char b) 54 | { 55 | outCb_(&b, 1); 56 | } 57 | 58 | OutputCb outCb_; 59 | }; 60 | 61 | struct InCbStream 62 | { 63 | InCbStream(InputCb inCb) : inCb_(inCb) 64 | {} 65 | 66 | unsigned char getByte() 67 | { 68 | unsigned char c; 69 | inCb_(&c, 1); 70 | return c; 71 | } 72 | 73 | void getBytes(unsigned char *b, size_t len) 74 | { 75 | inCb_(b, len); 76 | } 77 | 78 | InputCb inCb_; 79 | }; 80 | 81 | struct MemoryStream 82 | { 83 | MemoryStream() : buf(), idx(0) 84 | {} 85 | 86 | void putBytes(const unsigned char* b, size_t len) 87 | { 88 | while(len --) 89 | buf.push_back(*b++); 90 | } 91 | 92 | void putByte(const unsigned char b) 93 | { 94 | buf.push_back(b); 95 | } 96 | 97 | OutputCb outCb() 98 | { 99 | using namespace std::placeholders; 100 | 101 | return std::bind(&MemoryStream::putBytes, this, _1, _2); 102 | } 103 | 104 | unsigned char getByte() 105 | { 106 | return buf[idx++]; 107 | } 108 | 109 | void getBytes(unsigned char *b, int len) 110 | { 111 | for (int i = 0 ; i < len ; i ++) 112 | b[i] = getByte(); 113 | } 114 | 115 | InputCb inCb() 116 | { 117 | using namespace std::placeholders; 118 | 119 | return std::bind(&MemoryStream::getBytes, this, _1, _2); 120 | } 121 | 122 | uint32_t numBytesPut() const 123 | { 124 | return buf.size(); 125 | } 126 | 127 | // Copy bytes from the source stream to this stream. 128 | template 129 | void copy(TSrc& in, size_t bytes) 130 | { 131 | buf.resize(bytes); 132 | in.getBytes(buf.data(), bytes); 133 | } 134 | 135 | const uint8_t *data() const 136 | { return buf.data(); } 137 | 138 | const std::vector& buffer() const 139 | { return buf; } 140 | 141 | std::vector& buffer() 142 | { return buf; } 143 | 144 | std::vector buf; // cuz I'm ze faste 145 | size_t idx; 146 | }; 147 | 148 | template 149 | TStream& operator << (TStream& stream, uint32_t u) 150 | { 151 | uint32_t uLe = htole32(u); 152 | stream.putBytes(reinterpret_cast(&uLe), sizeof(uLe)); 153 | return stream; 154 | } 155 | 156 | template 157 | TStream& operator >> (TStream& stream, uint32_t& u) 158 | { 159 | uint32_t uLe; 160 | stream.getBytes(reinterpret_cast(&uLe), sizeof(u)); 161 | u = le32toh(uLe); 162 | return stream; 163 | } 164 | 165 | } // namespace lazperf 166 | 167 | #endif // __streams_hpp__ 168 | -------------------------------------------------------------------------------- /cpp/lazperf/vlr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: vlr.hpp 5 | 6 | CONTENTS: 7 | LAZ vlr 8 | 9 | PROGRAMMERS: 10 | 11 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 12 | uday.karan@gmail.com - Hobu, Inc. 13 | 14 | COPYRIGHT: 15 | 16 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 17 | (c) 2014, Uday Verma, Hobu, Inc. 18 | 19 | This is free software; you can redistribute and/or modify it under the 20 | terms of the Apache Public License 2.0 published by the Apache Software 21 | Foundation. See the COPYING file for more information. 22 | 23 | This software is distributed WITHOUT ANY WARRANTY and without even the 24 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | 26 | CHANGE HISTORY: 27 | 28 | =============================================================================== 29 | */ 30 | 31 | #pragma once 32 | 33 | #include 34 | #include 35 | 36 | #include "lazperf.hpp" 37 | 38 | namespace lazperf 39 | { 40 | 41 | #pragma warning (push) 42 | #pragma warning (disable: 4251) 43 | struct LAZPERF_EXPORT vlr_header 44 | { 45 | uint16_t reserved; 46 | std::string user_id; // 16 chars max 47 | uint16_t record_id; 48 | uint16_t data_length; 49 | std::string description; // 32 chars max 50 | 51 | static vlr_header create(std::istream& in); 52 | void read(std::istream& in); 53 | void write(std::ostream& out) const; 54 | void fill(const char *buf, size_t bufsize); 55 | std::vector data() const; 56 | static const int Size; 57 | }; 58 | 59 | struct LAZPERF_EXPORT evlr_header 60 | { 61 | uint16_t reserved; 62 | std::string user_id; // 16 chars max 63 | uint16_t record_id; 64 | uint64_t data_length; 65 | std::string description; // 32 chars max 66 | 67 | static evlr_header create(std::istream& in); 68 | void read(std::istream& in); 69 | void write(std::ostream& out) const; 70 | void fill(const char *buf, size_t bufsize); 71 | std::vector data() const; 72 | static const int Size; 73 | }; 74 | 75 | struct vlr_index_rec 76 | { 77 | std::string user_id; // 16 chars max 78 | uint16_t record_id; 79 | uint64_t data_length; 80 | std::string description; // 32 chars max 81 | uint64_t byte_offset; 82 | 83 | vlr_index_rec(const vlr_header& h, uint64_t byte_offset); 84 | vlr_index_rec(const evlr_header& h, uint64_t byte_offset); 85 | }; 86 | 87 | struct LAZPERF_EXPORT vlr 88 | { 89 | public: 90 | virtual ~vlr(); 91 | virtual uint64_t size() const = 0; 92 | virtual vlr_header header() const = 0; 93 | virtual evlr_header eheader() const = 0; 94 | }; 95 | 96 | struct LAZPERF_EXPORT laz_vlr : public vlr 97 | { 98 | public: 99 | struct LAZPERF_EXPORT laz_item 100 | { 101 | uint16_t type; 102 | uint16_t size; 103 | uint16_t version; 104 | }; 105 | 106 | uint16_t compressor; 107 | uint16_t coder; 108 | uint8_t ver_major; 109 | uint8_t ver_minor; 110 | uint16_t revision; 111 | uint32_t options; 112 | uint32_t chunk_size; 113 | uint64_t num_points; // This is *not* the number of points. It's garbage. 114 | uint64_t num_bytes; // This is *not* the number of bytes. It's garbage. 115 | std::vector items; 116 | 117 | laz_vlr(); 118 | laz_vlr(int format, int ebCount, uint32_t chunksize); 119 | virtual ~laz_vlr(); 120 | 121 | static laz_vlr create(std::istream& in); 122 | bool valid() const; 123 | void read(std::istream& in); 124 | void write(std::ostream& out) const; 125 | void fill(const char *buf, size_t bufsize); 126 | std::vector data() const; 127 | virtual uint64_t size() const; 128 | virtual vlr_header header() const; 129 | virtual evlr_header eheader() const; 130 | 131 | laz_vlr(const char *vlrdata); 132 | }; 133 | 134 | struct LAZPERF_EXPORT eb_vlr : public vlr 135 | { 136 | public: 137 | struct LAZPERF_EXPORT ebfield 138 | { 139 | uint8_t reserved[2]; 140 | uint8_t data_type; 141 | uint8_t options; 142 | std::string name; 143 | uint8_t unused[4]; 144 | double no_data[3]; 145 | double minval[3]; 146 | double maxval[3]; 147 | double scale[3]; 148 | double offset[3]; 149 | std::string description; 150 | 151 | ebfield(); 152 | }; 153 | 154 | std::vector items; 155 | 156 | eb_vlr(); 157 | [[deprecated]] eb_vlr(int ebCount); 158 | virtual ~eb_vlr(); 159 | 160 | static eb_vlr create(std::istream& in, int byteSize); 161 | void read(std::istream& in, int byteSize); 162 | void write(std::ostream& out) const; 163 | void fill(const char *buf, size_t bufsize); 164 | std::vector data() const; 165 | virtual uint64_t size() const; 166 | virtual vlr_header header() const; 167 | virtual evlr_header eheader() const; 168 | [[deprecated]] void addField(); 169 | void addField(const ebfield& f); 170 | }; 171 | 172 | struct LAZPERF_EXPORT wkt_vlr : public vlr 173 | { 174 | public: 175 | std::string wkt; 176 | 177 | wkt_vlr(); 178 | wkt_vlr(const std::string& s); 179 | virtual ~wkt_vlr(); 180 | 181 | static wkt_vlr create(std::istream& in, int byteSize); 182 | void read(std::istream& in, int byteSize); 183 | void write(std::ostream& out) const; 184 | void fill(const char *buf, size_t bufsize); 185 | std::vector data() const; 186 | virtual uint64_t size() const; 187 | virtual vlr_header header() const; 188 | virtual evlr_header eheader() const; 189 | }; 190 | 191 | struct LAZPERF_EXPORT copc_info_vlr : public vlr 192 | { 193 | public: 194 | double center_x; 195 | double center_y; 196 | double center_z; 197 | double halfsize; 198 | double spacing; 199 | uint64_t root_hier_offset; 200 | uint64_t root_hier_size; 201 | double gpstime_minimum; 202 | double gpstime_maximum; 203 | uint64_t reserved[11] {0}; 204 | 205 | copc_info_vlr(); 206 | virtual ~copc_info_vlr(); 207 | 208 | static copc_info_vlr create(std::istream& in); 209 | void read(std::istream& in); 210 | void write(std::ostream& out) const; 211 | void fill(const char *buf, size_t bufsize); 212 | std::vector data() const; 213 | virtual uint64_t size() const; 214 | virtual vlr_header header() const; 215 | virtual evlr_header eheader() const; 216 | }; 217 | #pragma warning (pop) 218 | 219 | } // namesapce lazperf 220 | 221 | -------------------------------------------------------------------------------- /cpp/lazperf/writers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | PROGRAMMERS: 5 | 6 | martin.isenburg@rapidlasso.com - http://rapidlasso.com 7 | uday.karan@gmail.com - Hobu, Inc. 8 | 9 | COPYRIGHT: 10 | 11 | (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality 12 | (c) 2014, Uday Verma, Hobu, Inc. 13 | 14 | This is free software; you can redistribute and/or modify it under the 15 | terms of the Apache Public License 2.0 published by the Apache Software 16 | Foundation. See the COPYING file for more information. 17 | 18 | This software is distributed WITHOUT ANY WARRANTY and without even the 19 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | 21 | =============================================================================== 22 | */ 23 | 24 | #pragma once 25 | 26 | #include 27 | 28 | #include "header.hpp" 29 | 30 | namespace lazperf 31 | { 32 | namespace writer 33 | { 34 | 35 | class basic_file 36 | { 37 | protected: 38 | struct Private; 39 | 40 | basic_file(); 41 | virtual ~basic_file(); 42 | 43 | public: 44 | LAZPERF_EXPORT bool open(std::ostream& out, const header12& h, uint32_t chunk_size); 45 | LAZPERF_EXPORT void writePoint(const char *p); 46 | LAZPERF_EXPORT void close(); 47 | LAZPERF_EXPORT uint64_t newChunk(); 48 | LAZPERF_EXPORT uint64_t firstChunkOffset() const; 49 | LAZPERF_EXPORT virtual bool compressed() const; 50 | 51 | protected: 52 | std::unique_ptr p_; 53 | }; 54 | 55 | class named_file : public basic_file 56 | { 57 | struct Private; 58 | 59 | public: 60 | struct LAZPERF_EXPORT config 61 | { 62 | public: 63 | vector3 scale; 64 | vector3 offset; 65 | unsigned int chunk_size; 66 | int pdrf; 67 | int minor_version; 68 | int extra_bytes; 69 | 70 | explicit config(); 71 | config(const vector3& scale, const vector3& offset, 72 | unsigned int chunksize = DefaultChunkSize); 73 | config(const header12& header); 74 | 75 | header12 to_header() const; 76 | }; 77 | 78 | LAZPERF_EXPORT named_file(const std::string& filename, const config& c); 79 | LAZPERF_EXPORT virtual ~named_file(); 80 | 81 | LAZPERF_EXPORT void close(); 82 | 83 | private: 84 | std::unique_ptr p_; 85 | }; 86 | 87 | class chunk_compressor 88 | { 89 | struct Private; 90 | public: 91 | LAZPERF_EXPORT chunk_compressor(int format, int ebCount); 92 | LAZPERF_EXPORT ~chunk_compressor(); 93 | LAZPERF_EXPORT void compress(const char *inbuf); 94 | LAZPERF_EXPORT std::vector done(); 95 | 96 | protected: 97 | std::unique_ptr p_; 98 | }; 99 | 100 | } // namespace writer 101 | } // namespace lazperf 102 | 103 | -------------------------------------------------------------------------------- /cpp/support/brute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

Check console, running benchmark.

7 | 8 | 2 | 3 | 4 | 5 | 6 |

Check console, running benchmark.

7 | 8 | (f_.get()); 71 | } 72 | 73 | void record(char *b) { // make sure you pass enough memory 74 | f_.read(b, size_); 75 | } 76 | 77 | std::ifstream f_; 78 | unsigned short size_; 79 | unsigned int count_; 80 | }; 81 | 82 | } // namespace test 83 | } // namespace lazperf 84 | 85 | #endif // __reader_hpp__ 86 | -------------------------------------------------------------------------------- /cpp/test/stream_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | 4 | FILE: stream_tests.cpp 5 | 6 | CONTENTS: 7 | Factory to create dynamic compressors and decompressors 8 | 9 | PROGRAMMERS: 10 | 11 | uday.karan@gmail.com - Hobu, Inc. 12 | 13 | COPYRIGHT: 14 | 15 | (c) 2014, Uday Verma, Hobu, Inc. 16 | 17 | This is free software; you can redistribute and/or modify it under the 18 | terms of the Apache Public License 2.0 published by the Apache Software 19 | Foundation. See the COPYING file for more information. 20 | 21 | This software is distributed WITHOUT ANY WARRANTY and without even the 22 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | CHANGE HISTORY: 25 | 26 | =============================================================================== 27 | */ 28 | 29 | #include "test_main.hpp" 30 | 31 | #include 32 | 33 | /** 34 | TEST(stream_tests, streams_are_sane) { 35 | using namespace laszip::streams; 36 | 37 | char buf[1024]; 38 | 39 | memory_stream s(buf, sizeof(buf)); 40 | 41 | EXPECT_EQ(s.good(), true); 42 | EXPECT_EQ(s.eof(), false); 43 | EXPECT_EQ(s.gcount(), 0); 44 | 45 | s.seekg(1024); 46 | 47 | EXPECT_EQ(s.good(), false); 48 | EXPECT_EQ(s.eof(), false); 49 | EXPECT_EQ(s.tellg(), 0); 50 | 51 | s.seekg(512); 52 | EXPECT_EQ(s.good(), true); 53 | EXPECT_EQ(s.eof(), false); 54 | EXPECT_EQ(s.tellg(), 512); 55 | 56 | char b[64]; 57 | 58 | s.read(b, 64); 59 | 60 | EXPECT_EQ(s.good(), true); 61 | EXPECT_EQ(s.eof(), false); 62 | EXPECT_EQ(s.tellg(), 512+64); 63 | EXPECT_EQ(s.gcount(), 64); 64 | 65 | 66 | char c[512]; 67 | s.read(c, 512); 68 | 69 | EXPECT_EQ(s.good(), true); 70 | EXPECT_EQ(s.eof(), true); 71 | EXPECT_EQ(s.tellg(), 1024); 72 | EXPECT_EQ(s.gcount(), 512 - 64); 73 | 74 | s.clear(); 75 | 76 | EXPECT_EQ(s.good(), true); 77 | EXPECT_EQ(s.eof(), false); 78 | EXPECT_EQ(s.tellg(), 1024); 79 | 80 | s.read(c, 64); 81 | 82 | 83 | EXPECT_EQ(s.good(), true); 84 | EXPECT_EQ(s.eof(), true); 85 | EXPECT_EQ(s.gcount(), 0); 86 | EXPECT_EQ(s.tellg(), 1024); 87 | 88 | s.seekg(0); 89 | 90 | EXPECT_EQ(s.good(), true); 91 | EXPECT_EQ(s.eof(), true); // seek should not clear eof flag 92 | EXPECT_EQ(s.tellg(), 0); 93 | 94 | s.clear(); 95 | 96 | EXPECT_EQ(s.eof(), false); 97 | 98 | s.seekg(2048); 99 | 100 | EXPECT_EQ(s.good(), false); 101 | EXPECT_EQ(s.good(), true); // only report last status 102 | EXPECT_EQ(s.tellg(), 0); 103 | 104 | s.seekg(1024); 105 | EXPECT_EQ(s.good(), false); 106 | EXPECT_EQ(s.good(), true); // only report last status 107 | EXPECT_EQ(s.tellg(), 0); 108 | 109 | s.seekg(0, std::ios::end); 110 | EXPECT_EQ(s.good(), true); 111 | EXPECT_EQ(s.tellg(), 1023); 112 | 113 | s.seekg(-10, std::ios::end); 114 | EXPECT_EQ(s.good(), true); 115 | EXPECT_EQ(s.tellg(), 1013); 116 | 117 | s.seekg(10, std::ios::end); 118 | EXPECT_EQ(s.good(), false); 119 | EXPECT_EQ(s.tellg(), 1013); 120 | 121 | s.seekg(512); 122 | s.seekg(10, std::ios::cur); 123 | EXPECT_EQ(s.good(), true); 124 | EXPECT_EQ(s.tellg(), 522); 125 | 126 | s.seekg(1000, std::ios::cur); 127 | EXPECT_EQ(s.good(), false); 128 | EXPECT_EQ(s.tellg(), 522); 129 | 130 | s.seekg(-10, std::ios::cur); 131 | EXPECT_EQ(s.good(), true); 132 | EXPECT_EQ(s.tellg(), 512); 133 | 134 | s.seekg(0, std::ios::beg); 135 | EXPECT_EQ(s.good(), true); 136 | EXPECT_EQ(s.tellg(), 0); 137 | 138 | s.seekg(10, std::ios::beg); 139 | EXPECT_EQ(s.good(), true); 140 | EXPECT_EQ(s.tellg(), 10); 141 | 142 | s.seekg(0); 143 | s.seekg(-10, std::ios::beg); 144 | EXPECT_EQ(s.good(), false); 145 | EXPECT_EQ(s.tellg(), 0); 146 | } 147 | **/ 148 | -------------------------------------------------------------------------------- /cpp/test/test.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | pdal=/Users/acbell/pdal/build/bin/pdal 4 | percent=1 5 | format=7 6 | eb=3 7 | count=0 8 | 9 | while [ 1 ] 10 | do 11 | echo $count 12 | ((count++)) 13 | rm -f lazperf.laz laszip.laz lazperf.las laszip.las foo.1 foo.2 14 | 15 | if [[ $format == 0 ]] 16 | then 17 | pointsize=20 18 | elif [[ $format == 1 ]] 19 | then 20 | pointsize=28 21 | elif [[ $format == 2 ]] 22 | then 23 | pointsize=26 24 | elif [[ $format == 3 ]] 25 | then 26 | pointsize=34 27 | elif [[ $format == 6 ]] 28 | then 29 | pointsize=30 30 | elif [[ $format == 7 ]] 31 | then 32 | pointsize=36 33 | elif [[ $format == 8 ]] 34 | then 35 | pointsize=38 36 | else 37 | echo "Bad format $format" 38 | break; 39 | fi 40 | (( pointsize+=eb )) 41 | 42 | /Users/acbell/lazperf/build/tools/random foo.las $format/$eb $percent 43 | (( percent++ )) 44 | if (( percent > 20 )) 45 | then 46 | percent=1 47 | fi 48 | 49 | $pdal translate --writers.las.minor_version=4 --writers.las.dataformat_id=$format --writers.las.extra_dims=all --writers.las.compression=lazperf foo.las lazperf.laz --writers.las.forward=all 50 | $pdal translate --writers.las.minor_version=4 --writers.las.dataformat_id=$format --writers.las.extra_dims=all --writers.las.compression=laszip foo.las laszip.laz --writers.las.forward=all 51 | diff lazperf.laz laszip.laz 52 | res=$? 53 | if [[ $res != 0 ]] 54 | then 55 | echo "Bad encoding" 56 | break 57 | fi 58 | # 59 | $pdal translate --writers.las.minor_version=4 --writers.las.dataformat_id=$format --writers.las.extra_dims=all --readers.las.compression=lazperf laszip.laz lazperf.las --writers.las.forward=all 60 | $pdal translate --writers.las.minor_version=4 --writers.las.dataformat_id=$format --writers.las.extra_dims=all --readers.las.compression=laszip laszip.laz laszip.las --writers.las.forward=all 61 | diff lazperf.las laszip.las 62 | res=$? 63 | if [[ $res != 0 ]] 64 | then 65 | echo "Bad decoding" 66 | break 67 | fi 68 | # 69 | (( fullsize=50000 * pointsize )) 70 | tail -c $fullsize foo.las > foo.1 71 | tail -c $fullsize laszip.las > foo.2 72 | diff foo.1 foo.2 73 | res=$? 74 | if [[ $res != 0 ]] 75 | then 76 | echo "Bad comparison" 77 | break 78 | fi 79 | done 80 | -------------------------------------------------------------------------------- /cpp/test/test_main.hpp.in: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | GTEST_API_ int main(int argc, char **argv) { 4 | testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | 8 | std::string testFile(const std::string& filename) 9 | { 10 | return std::string("@CMAKE_SOURCE_DIR@/cpp/test/raw-sets/") + filename; 11 | } 12 | -------------------------------------------------------------------------------- /cpp/tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(random random.cpp) 3 | 4 | target_include_directories(random PRIVATE ../lazperf) 5 | lazperf_target_compile_settings(random) 6 | target_link_libraries(random PRIVATE ${LAZPERF_STATIC_LIB}) 7 | 8 | -------------------------------------------------------------------------------- /hobu-config.bat: -------------------------------------------------------------------------------- 1 | @echo on 2 | 3 | set GENERATOR="Ninja" 4 | set BUILD_TYPE=Release 5 | 6 | del /s /q %CONDA_DEFAULT_ENV% 7 | mkdir %CONDA_DEFAULT_ENV% 8 | cd %CONDA_DEFAULT_ENV% 9 | 10 | 11 | cmake -G %GENERATOR% ^ 12 | -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX% ^ 13 | -DCMAKE_BUILD_TYPE=Release -Dgtest_force_shared_crt=ON ^ 14 | -DCMAKE_VERBOSE_MAKEFILE=OFF ^ 15 | .. 16 | 17 | 18 | ninja -------------------------------------------------------------------------------- /js/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | lib/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /js/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !package.json 3 | !lib/** 4 | -------------------------------------------------------------------------------- /js/.prettierignore: -------------------------------------------------------------------------------- 1 | * 2 | !/src/ 3 | !/src/** 4 | /src/laz-perf.js 5 | -------------------------------------------------------------------------------- /js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /js/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ["@babel/preset-env", { targets: { node: "current" } }], 4 | "@babel/preset-typescript", 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /js/bundle.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | cd "$(dirname "$0")" 5 | 6 | mkdir -p lib/ 7 | 8 | npx tsc --project tsconfig.production.json 9 | 10 | cp src/laz-perf.wasm lib/ 11 | cp src/laz-perf.d.ts lib/ 12 | cp src/laz-perf.js lib/ 13 | 14 | function bundle () { 15 | ENVIRONMENT="$1" 16 | 17 | # The laz-perf.js file with the bootstrapping code for each specific 18 | # environment must already exist so we don't need to account for that here. 19 | # The rest of these files are exactly the same for all environments, so 20 | # simply copy them into the directory for this environment. 21 | cp lib/index.js lib/${ENVIRONMENT} 22 | cp lib/index.d.ts lib/${ENVIRONMENT} 23 | cp lib/laz-perf.wasm lib/${ENVIRONMENT} 24 | cp lib/laz-perf.d.ts lib/${ENVIRONMENT} 25 | } 26 | 27 | bundle node 28 | bundle web 29 | bundle worker 30 | -------------------------------------------------------------------------------- /js/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | }; -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laz-perf", 3 | "version": "0.0.7", 4 | "description": "LAZ implementation compiled to WASM via Emscripten for LAZ support in a browser", 5 | "main": "lib/node/index.js", 6 | "browser": "lib/web/index.js", 7 | "homepage": "https://github.com/hobuinc/laz-perf", 8 | "keywords": [ 9 | "3d", 10 | "laz", 11 | "laszip", 12 | "point cloud", 13 | "lidar", 14 | "gis" 15 | ], 16 | "scripts": { 17 | "build": "./bundle.sh", 18 | "wasm": "./wasm.sh", 19 | "prepare": "npm run wasm && npm run build", 20 | "test": "jest" 21 | }, 22 | "license": "Apache-2.0", 23 | "devDependencies": { 24 | "@types/emscripten": "^1.39.6", 25 | "@types/jest": "^28.1.4", 26 | "jest": "^28.1.2", 27 | "prettier": "^2.7.1", 28 | "ts-jest": "^28.0.5", 29 | "tslib": "^2.3.1", 30 | "typescript": "^4.5.5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /js/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from "@rollup/plugin-commonjs"; 2 | import copy from "rollup-plugin-copy"; 3 | import includePaths from "rollup-plugin-includepaths"; 4 | import typescript from "@rollup/plugin-typescript"; 5 | 6 | export default { 7 | input: "src/index.ts", 8 | output: { 9 | file: "lib/index.js", 10 | format: "umd", 11 | name: "LazPerf", 12 | globals: { fs: "fs", path: "path" }, 13 | }, 14 | external: ["fs", "path"], 15 | plugins: [ 16 | commonjs({ include: "src/laz-perf.js" }), 17 | typescript({ 18 | tsconfig: "./tsconfig.production.json", 19 | // Put declarations at the top level of the output dir. 20 | // declarationDir: ".", 21 | }), 22 | includePaths({ paths: "src", extensions: [".ts", ".js"] }), 23 | copy({ 24 | targets: [ 25 | { src: "src/laz-perf.wasm", dest: "lib" }, 26 | { src: "src/laz-perf.d.ts", dest: "lib" }, 27 | ], 28 | }), 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /js/src/index.ts: -------------------------------------------------------------------------------- 1 | import createLazPerf from './laz-perf.js' 2 | export { createLazPerf } 3 | export const create = createLazPerf 4 | 5 | export type LazPerf = Awaited> 6 | export const LazPerf = { create: createLazPerf } 7 | -------------------------------------------------------------------------------- /js/src/laz-perf.d.ts: -------------------------------------------------------------------------------- 1 | type Pointer = number 2 | 3 | declare class LASZip { 4 | constructor() 5 | delete(): void 6 | 7 | open(data: Pointer, length: number): void 8 | getPoint(dest: Pointer): void 9 | getCount(): number 10 | getPointLength(): number 11 | getPointFormat(): number 12 | } 13 | 14 | declare class ChunkDecoder { 15 | constructor() 16 | delete(): void 17 | 18 | open( 19 | pointDataRecordFormat: number, 20 | pointDataRecordLength: number, 21 | pointer: Pointer 22 | ): void 23 | 24 | getPoint(pointer: Pointer): void 25 | } 26 | 27 | export declare interface LazPerf extends EmscriptenModule { 28 | LASZip: typeof LASZip 29 | ChunkDecoder: typeof ChunkDecoder 30 | } 31 | 32 | declare const createLazPerf: EmscriptenModuleFactory 33 | export default createLazPerf 34 | -------------------------------------------------------------------------------- /js/src/laz-perf.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hobuinc/laz-perf/07d925e6d530879adb5299a9c85627e216145b96/js/src/laz-perf.wasm -------------------------------------------------------------------------------- /js/src/test/chunk.test.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs' 2 | import { join } from 'path' 3 | 4 | import { createLazPerf } from '..' 5 | import { parseHeader } from './utils' 6 | 7 | const testdatadir = join(__dirname, '../../../cpp/test/raw-sets') 8 | 9 | test('chunk decoder', async () => { 10 | const file = await fs.readFile(join(testdatadir, 'autzen_trim.laz')) 11 | 12 | const { 13 | pointDataRecordFormat, 14 | pointDataRecordLength, 15 | pointDataOffset, 16 | pointCount, 17 | scale, 18 | offset, 19 | min, 20 | max, 21 | } = parseHeader(file) 22 | 23 | expect(pointDataRecordFormat).toEqual(3) 24 | expect(pointDataRecordLength).toEqual(34) 25 | expect(pointCount).toBeGreaterThanOrEqual(2) 26 | expect(scale).toEqual([0.01, 0.01, 0.01]) 27 | expect(min.every((v, i) => v < max[i])).toBe(true) 28 | 29 | // Create our Emscripten module. 30 | const LazPerf = await createLazPerf() 31 | const decoder = new LazPerf.ChunkDecoder() 32 | 33 | // To make it clear that we are only operating on the compressed data chunk 34 | // rather than a full LAZ file, strip off the header/VLRs here. The magic 35 | // offset of 8 is to skip past the chunk table offset. We are only going to 36 | // decompress 2 points here so we don't have to worry about potential resets 37 | // of the chunk table, so our only assumption here will be that points 0 and 1 38 | // are in the same chunk. 39 | const chunk = file.subarray(pointDataOffset + 8) 40 | 41 | // Allocate our memory in the Emscripten heap: a filePtr buffer for our 42 | // compressed content and a single point's worth of bytes for our output. 43 | const dataPtr = LazPerf._malloc(pointDataRecordLength) 44 | const chunkPtr = LazPerf._malloc(chunk.byteLength) 45 | 46 | // Copy our chunk into the Emscripten heap. 47 | LazPerf.HEAPU8.set( 48 | new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength), 49 | chunkPtr 50 | ) 51 | 52 | try { 53 | decoder.open(pointDataRecordFormat, pointDataRecordLength, chunkPtr) 54 | 55 | for (let i = 0; i < 2; ++i) { 56 | decoder.getPoint(dataPtr) 57 | 58 | // Now our dataPtr (in the Emscripten heap) contains our point data, copy 59 | // it out into our own Buffer. 60 | const pointbuffer = Buffer.from( 61 | LazPerf.HEAPU8.buffer, 62 | dataPtr, 63 | pointDataRecordLength 64 | ) 65 | 66 | // Grab the scaled/offset XYZ values and reverse the scale/offset to get 67 | // their absolute positions. It would be possible to add checks for 68 | // attributes other than XYZ here - our pointbuffer contains an entire 69 | // point whose format corresponds to the pointDataRecordFormat above. 70 | const point = [ 71 | pointbuffer.readInt32LE(0), 72 | pointbuffer.readInt32LE(4), 73 | pointbuffer.readInt32LE(8), 74 | ].map((v, i) => v * scale[i] + offset[i]) 75 | 76 | // Doing 6 expect(point[n]).toBeGreaterThanOrEqual(min[n]) style checks in 77 | // this tight loop slows down the test by 50x, so do a quicker check. 78 | if (point.some((v, i) => v < min[i] || v > max[i])) { 79 | console.error(i, point, min, max) 80 | throw new Error(`Point ${i} out of expected range`) 81 | } 82 | } 83 | } finally { 84 | LazPerf._free(chunkPtr) 85 | LazPerf._free(dataPtr) 86 | decoder.delete() 87 | } 88 | }) 89 | -------------------------------------------------------------------------------- /js/src/test/file.test.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs' 2 | import { join } from 'path' 3 | 4 | import { createLazPerf } from '..' 5 | import { parseHeader } from './utils' 6 | 7 | const testdatadir = join(__dirname, '../../../cpp/test/raw-sets') 8 | 9 | test('file reader', async () => { 10 | const file = await fs.readFile(join(testdatadir, 'autzen_trim.laz')) 11 | 12 | const { 13 | pointDataRecordFormat, 14 | pointDataRecordLength, 15 | pointCount, 16 | scale, 17 | offset, 18 | min, 19 | max, 20 | } = parseHeader(file) 21 | 22 | // Check some header values for sanity, for example we want to make sure we 23 | // don't get a pointCount of 0 and then not perform any data checks. 24 | expect(pointDataRecordFormat).toEqual(3) 25 | expect(pointDataRecordLength).toEqual(34) 26 | expect(pointCount).toEqual(110_000) 27 | expect(scale).toEqual([0.01, 0.01, 0.01]) 28 | expect(min.every((v, i) => v < max[i])).toBe(true) 29 | 30 | // Create our Emscripten module. 31 | const LazPerf = await createLazPerf() 32 | const laszip = new LazPerf.LASZip() 33 | 34 | // Allocate our memory in the Emscripten heap: a filePtr buffer for our 35 | // compressed content and a single point's worth of bytes for our output. 36 | const dataPtr = LazPerf._malloc(pointDataRecordLength) 37 | const filePtr = LazPerf._malloc(file.byteLength) 38 | 39 | // Copy our data into the Emscripten heap so we can point at it in getPoint(). 40 | LazPerf.HEAPU8.set( 41 | new Uint8Array(file.buffer, file.byteOffset, file.byteLength), 42 | filePtr 43 | ) 44 | 45 | try { 46 | laszip.open(filePtr, file.byteLength) 47 | 48 | for (let i = 0; i < pointCount; ++i) { 49 | laszip.getPoint(dataPtr) 50 | 51 | // Now our dataPtr (in the Emscripten heap) contains our point data, copy 52 | // it out into our own Buffer. 53 | const pointbuffer = Buffer.from( 54 | LazPerf.HEAPU8.buffer, 55 | dataPtr, 56 | pointDataRecordLength 57 | ) 58 | 59 | // Grab the scaled/offset XYZ values and reverse the scale/offset to get 60 | // their absolute positions. It would be possible to add checks for 61 | // attributes other than XYZ here - our pointbuffer contains an entire 62 | // point whose format corresponds to the pointDataRecordFormat above. 63 | const point = [ 64 | pointbuffer.readInt32LE(0), 65 | pointbuffer.readInt32LE(4), 66 | pointbuffer.readInt32LE(8), 67 | ].map((v, i) => v * scale[i] + offset[i]) 68 | 69 | // Doing 6 expect(point[n]).toBeGreaterThanOrEqual(min[n]) style checks in 70 | // this tight loop slows down the test by 50x, so do a quicker check. 71 | if (point.some((v, i) => v < min[i] || v > max[i])) { 72 | console.error(i, point, min, max) 73 | throw new Error(`Point ${i} out of expected range`) 74 | } 75 | } 76 | } finally { 77 | LazPerf._free(filePtr) 78 | LazPerf._free(dataPtr) 79 | laszip.delete() 80 | } 81 | }) 82 | 83 | test('not legacy point count', async () => { 84 | const file = await fs.readFile(join(testdatadir, 'point-time-1.4.las.laz')) 85 | 86 | // Overwrite the legacy point count with a zero value. In our 87 | // laszip.pointCount() below, we should still get the right value from the 88 | // non-legacy field. 89 | file.writeUint32LE(0, 107) 90 | 91 | const { pointDataRecordLength } = parseHeader(file) 92 | 93 | const LazPerf = await createLazPerf() 94 | const laszip = new LazPerf.LASZip() 95 | 96 | // Allocate our memory in the Emscripten heap: a filePtr buffer for our 97 | // compressed content and a single point's worth of bytes for our output. 98 | const dataPtr = LazPerf._malloc(pointDataRecordLength) 99 | const filePtr = LazPerf._malloc(file.byteLength) 100 | 101 | // Copy our data into the Emscripten heap so we can point at it in getPoint(). 102 | LazPerf.HEAPU8.set( 103 | new Uint8Array(file.buffer, file.byteOffset, file.byteLength), 104 | filePtr 105 | ) 106 | 107 | try { 108 | laszip.open(filePtr, file.byteLength) 109 | expect(laszip.getCount()).toEqual(1065) 110 | } finally { 111 | LazPerf._free(filePtr) 112 | LazPerf._free(dataPtr) 113 | laszip.delete() 114 | } 115 | }) 116 | -------------------------------------------------------------------------------- /js/src/test/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Parse out a small subset of the LAS header that we will use to verify point 3 | * data contents. 4 | */ 5 | export function parseHeader(file: Buffer) { 6 | if (file.byteLength < 227) throw new Error('Invalid file length') 7 | 8 | const pointDataRecordFormat = file.readUint8(104) & 0b1111 9 | const pointDataRecordLength = file.readUint16LE(105) 10 | const pointDataOffset = file.readUint32LE(96) 11 | const pointCount = file.readUint32LE(107) 12 | 13 | const scale = [ 14 | file.readDoubleLE(131), 15 | file.readDoubleLE(139), 16 | file.readDoubleLE(147), 17 | ] 18 | const offset = [ 19 | file.readDoubleLE(155), 20 | file.readDoubleLE(163), 21 | file.readDoubleLE(171), 22 | ] 23 | const min = [ 24 | file.readDoubleLE(187), 25 | file.readDoubleLE(203), 26 | file.readDoubleLE(219), 27 | ] 28 | const max = [ 29 | file.readDoubleLE(179), 30 | file.readDoubleLE(195), 31 | file.readDoubleLE(211), 32 | ] 33 | return { 34 | pointDataRecordFormat, 35 | pointDataRecordLength, 36 | pointDataOffset, 37 | pointCount, 38 | scale, 39 | offset, 40 | min, 41 | max, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src"], 3 | "exclude": [], 4 | "compilerOptions": { 5 | "baseUrl": "src", 6 | "rootDir": "src", 7 | "outDir": "lib", 8 | "declarationDir": "lib", 9 | 10 | "target": "es2019", 11 | "module": "commonjs", 12 | 13 | "lib": ["es2020", "dom"], 14 | "declaration": true, 15 | 16 | "moduleResolution": "node", 17 | "allowSyntheticDefaultImports": true, 18 | "strict": true, 19 | "noImplicitAny": true, 20 | "esModuleInterop": true, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /js/tsconfig.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["src/test"] 4 | } 5 | -------------------------------------------------------------------------------- /js/wasm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script generates: 4 | # The actual WASM: 5 | # src/laz-perf.wasm 6 | # 7 | # The bootstrapping JS built for all environments: 8 | # src/laz-perf.js 9 | # 10 | # And the bootstrapping JS built for specific environments: 11 | # lib/node/laz-perf.js 12 | # lib/web/laz-perf.js 13 | # lib/worker/laz-perf.js 14 | 15 | set -e 16 | cd "$(dirname "$0")/.." 17 | CMAKE_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake 18 | 19 | mkdir -p ./js/build 20 | function build () { 21 | ENVIRONMENT="$1" 22 | printf "\n\nBuilding for environment: ${ENVIRONMENT}\n" 23 | docker run --rm -v $(pwd):/src emscripten/emsdk:3.1.20 bash -c \ 24 | " 25 | cd js/build && \ 26 | cmake \ 27 | -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN_FILE}" \ 28 | -DCMAKE_BUILD_TYPE=Release \ 29 | -DENVIRONMENT=${ENVIRONMENT} \ 30 | ../.. && \ 31 | emmake make VERBOSE=1 32 | " 33 | 34 | # This one is a generic build intended for use in all environments. 35 | # Note that the generated WASM will be the same for all of these builds, 36 | # only the JS bootstrapping code will vary based on the environment. 37 | if [ "$ENVIRONMENT" = "all" ]; then 38 | cp ./js/build/cpp/emscripten/laz-perf.js ./js/src/ 39 | cp ./js/build/cpp/emscripten/laz-perf.wasm ./js/src/ 40 | # And these are the individual bootstrappers for the various environments. 41 | else 42 | mkdir -p ./js/lib/${ENVIRONMENT} 43 | cp ./js/build/cpp/emscripten/laz-perf.js ./js/lib/${ENVIRONMENT}/ 44 | fi 45 | } 46 | 47 | build all 48 | build node 49 | build web 50 | build worker 51 | --------------------------------------------------------------------------------