pax_global_header00006660000000000000000000000064135623421710014516gustar00rootroot0000000000000052 comment=1ab671e42ff1f086e29d5b7e300a5026e7b8d69b LASzip-3.4.3/000077500000000000000000000000001356234217100126675ustar00rootroot00000000000000LASzip-3.4.3/.gitignore000066400000000000000000000002721356234217100146600ustar00rootroot00000000000000CMakeFiles/ CMakeCache.txt include/laszip/laszip_api_version.h bin/ Makefile* cmake_install* CPackConfig.cmake CPackSourceConfig.cmake *.gz *.bz2 _CPack_Packages/ install_mainifest.txt LASzip-3.4.3/.travis.yml000066400000000000000000000023461356234217100150050ustar00rootroot00000000000000# .travis.yml # Configure Travis CI service for http://github.com/LASzip language: cpp sudo: required services: docker dist: trusty env: global: - secure: "ZxsNFzAy3sDCrN6cBiMlBsIh2NYYIBuFxbPK48IAIkXiiUFkXUrh8snmduzCrwuE0vgsHKlER8RvHKA3OPZjOCiBUiFgXLEiwBJgChGoX4hk88b84hpfR4W4tGeiqAORJzwmj/DdSbX9OW1Gh4HxH76H5obE+fWI4qW+7LcX7II=" - secure: "ApVmY9Duy9/B3sOC37Fwh1utlyWe5GvGXal1eKcT0uHk2fKJIYSJVBh5sv5Qe/dF8vamaqAcakqo0z3D9sQmiQRbvs1swNtz9Pf6GwPL4D0dSc7K9Rc1rWmEwSXsNX4OV7BD/DlzJqkB1RBOIdb70k1uOld21WtZJs0l5SFFE4c=" compiler: - g++ - clang after_success: - echo "secure travis:" "$TRAVIS_SECURE_ENV_VARS" - sh -c 'if test "$TRAVIS_SECURE_ENV_VARS" = "true" -a "$TRAVIS_BRANCH" = "master" -a "$CXX" = "g++"; then echo "publish website"; ./scripts/ci/build_docs.sh; ./scripts/ci/add_deploy_key.sh; ./scripts/ci/deploy_website.sh $TRAVIS_BUILD_DIR/docs/build /tmp; fi' before_install: ./scripts/ci/docker.sh script: ./scripts/ci/script.sh notifications: on_success: always # [always|never|change] # default: change on_failure: always # [always|never|change] # default: always irc: "chat.freenode.net#pdal" # Uncomment and edit below for notifications by e-mail #email: # recipients: # - howard@hobu.co LASzip-3.4.3/AUTHORS000066400000000000000000000001571356234217100137420ustar00rootroot00000000000000Martin Isenburg martin.isenburg@rapidlasso.com Howard Butler howard@hobu.co Michael P. Gerlek mpg@flaxen.com LASzip-3.4.3/CHANGES.txt000066400000000000000000000112361356234217100145030ustar00rootroot00000000000000 9 November 2019 -- upped version to 3.4 revision 3 for selective decompression extra bytes fix 9 November 2019 -- fix for selective decompression of more than 16 extra bytes in new point types 6 or higher 9 November 2019 -- moved UTF8toUTF16() function from laszip.hpp to mydefs.hpp and added new mydefs.cpp 16 October 2019 -- unicode support added for Windows LASzip.dll via in new UTF8toUTF16() function 11 August 2019 -- added CMake for DLL build and minor fixes to allow 64 bit Windows compile of LASzip.dll 11 April 2019 -- increase AC_BUFFER_SIZE from 1024 to 4096 to lower chance of ultra-rare propagate_carry() overflow 10 April 2019 -- fix potential memory leaks found by Connor Manning using valgrind 31 March 2019 -- better license terms for core arithmetic coder thanks to Amir Said. upgrade to version 3.4 rev 0 20 March 2019 -- upped to 3.3 r1 for checking consistent legacy and extended classification for new point types 19 March 2019 -- bug fix when decompressing new point types: zero "legacy classification" if "classification" > 31 7 March 2019 -- upped to 3.3 r0 because hobu was suggesting it for the next release 21 February 2019 -- bug fix when writing 4,294,967,296 or more points uncompressed to LAS 28 December 2018 -- fix for LASzip v4 decompression of WavePacket part of PRDF 9 and 10 27 December 2018 -- upped to 3.2 r9 for bug fix in multi-channel NIR decompression 7 November 2018 -- laszip DLL: upped to 3.2 r8 for identical legacy and extended flags check 20 October 2018 -- fixed rare bug in LASinterval::merge_intervals() 5 October 2018 -- laszip DLL: upped to 3.2 r6 for corrected 'is_empty' return value in laszip_inside_rectangle() 28 September 2018 -- laszip DLL: tiny bug fix for writing extended classifications via DLL and updated examples 17 September 2018 -- laszip DLL: no more support for deprecated LASattributes (aka "extra bytes") with dimensions 2 or 3 30 July 2018 -- bug fix in selective decompression of "extra_bytes" for point types 6 and higher 29 March 2018 -- add LASlib only fields to some structs to avoid future mix-up for "native" LAS 1.4 9 February 2018 -- minor version increment to 3.2 as POINT14_v4 fixes context inefficiency bug 28 December 2017 -- prepare to correct 'context switch' bug reported by Wanwannodao on some future date 15 September 2017 -- new C++ istream / ostream interface completed and released 22 August 2017 -- new C++ istream / ostream interface 18 July 2017 -- bug fix for spatially-indexed reading from native compressed LAS 1.4 files 28 May 2017 -- support for "selective decompression" of compressed LAS 1.4 points added into DLL API 25 April 2017 -- enable "native LAS 1.4 extension" in LASzip DLL via 'request_native_extension' 30 March 2017 -- alpha-release of "native LAS 1.4 extension" for LASzip compression 11 January 2017 -- new DLL/API function 'laszip_set_chunk_size()' to change chunk size 8 January 2017 -- changed file names from "laszip_dll.h" to "laszip_api.h" for hobu 7 January 2017 -- set reserved field in LASzip VLR from 0xAABB to 0x0 7 January 2017 -- make scan angle quantization in compatibility mode consistent with LASlib 7 January 2017 -- compatibility mode *decompression* fix for points with waveforms 23 September 2015 -- correct update of bounding box and counters from inventory on closing 23 September 2015 -- correct update of bounding box and counters from inventory on closing 22 September 2015 -- bug fix for not overwriting description of pre-existing "extra bytes" 5 September 201 -- the "LAS 1.4 compatibility mode" now allows pre-existing "extra bytes" 31 July 2015 -- new DLL (incompatible with prior version) supports "LAS 1.4 compatibility mode" 4 April 2015 -- added DLL functions for creation and exploitation of spatial indexing LAX files 3 April 2015 -- moved spatial indexing (LAX file generation) from LASlib to LASzip 16 November 2014 -- improved detection & reporting of file truncation and/or LAZ bit-errors 6 September 2014 -- removal of (unused) EntropyEncoder and EntropyDecoder purely virtual classes 24 August 2014 -- when reading LAZ chunk table read is delayed until first read() or seek() is called 18 September 2013 -- fixed small memory leak 24 August 2013 -- fixed bug with explicit cast from LASitem:type to unsigned short and vice versa 11 August 2013 -- laszipdllexample: new EXAMPLE_THREE shows export of geo-referenced LAZ 8 August 2013 -- LASzip: new DLL calls laszip_get_coordinates() and laszip_set_coordinates() 6 August 2013 -- LASzip: new DLL calls laszip_auto_offset() and laszip_check_for_integer_overflow() 1 August 2013 -- LASzip: new DLL calls unload_dll() and get_point_count() for FUSION integration 29 July 2013 -- LASzip: created an easy-to-use DLL interface for LASzip integration LASzip-3.4.3/CMakeLists.txt000066400000000000000000000100451356234217100154270ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.11) project(LASZIP CXX C) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) set(ROOT_DIR "${PROJECT_SOURCE_DIR}") # the next line is the ONLY place in the entire laszip system where # the version info is hard-coded set(LASZIP_API_VERSION_STRING "3.4.3" CACHE STRING "LASzip version" FORCE) include (CheckIncludeFileCXX) include(${ROOT_DIR}/cmake/common.cmake NO_POLICY_SCOPE) include(${ROOT_DIR}/cmake/cpack.cmake NO_POLICY_SCOPE) #------------------------------------------------------------------------------ # internal cmake settings #------------------------------------------------------------------------------ set(CMAKE_COLOR_MAKEFILE ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON) include(FeatureSummary) # Allow advanced users to generate Makefiles printing detailed commands mark_as_advanced(CMAKE_VERBOSE_MAKEFILE) #------------------------------------------------------------------------------ # LASZIP general settings #------------------------------------------------------------------------------ # # Extract the pieces of the version info from the version string above. DISSECT_VERSION() GET_OS_INFO() SET_INSTALL_DIRS() set(LASZIP_API_VERSION ${LASZIP_API_VERSION_MAJOR}.${LASZIP_API_VERSION_MINOR}.${LASZIP_API_VERSION_PATCH}) # libtool SO version naming # 8.0.0 for 3.2.1 # 9.0.0 for 4.0+ set(LASZIP_SO_VERSION "8.0.5") set(LASZIP_COMPATIBILITY_VERSION 8) check_include_file_cxx ("unordered_map" HAVE_UNORDERED_MAP) ############################################################################### # Main CMake configuration file for laszip # # Author: Mateusz Loskot # # ############################################################################### # laszip general settings set(LASZIP_API_VERSION_H ${CMAKE_CURRENT_BINARY_DIR}/include/laszip/laszip_api_version.h) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/laszip_api_version.h.in ${LASZIP_API_VERSION_H}) set(LASZIP_BASE_LIB_NAME laszip) set(LASZIP_API_LIB_NAME laszip_api) if(WIN32) set(LASZIP_BASE_LIB_NAME "${LASZIP_BASE_LIB_NAME}${LASZIP_API_VERSION_MAJOR}") set(LASZIP_API_LIB_NAME "${LASZIP_API_LIB_NAME}${LASZIP_API_VERSION_MAJOR}") endif() set(LASZIP_OUTPUT_LIB_DIR "${LASZIP_BINARY_DIR}/${LASZIP_LIB_INSTALL_DIR}") set(LASZIP_OUTPUT_BIN_DIR "${LASZIP_BINARY_DIR}/${LASZIP_BIN_INSTALL_DIR}") set(LASZIP_PLUGIN_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/${LASZIP_LIB_INSTALL_DIR}") file(MAKE_DIRECTORY "${LASZIP_OUTPUT_LIB_DIR}") file(MAKE_DIRECTORY "${LASZIP_OUTPUT_BIN_DIR}") # per http://www.cmake.org/Wiki/CMake_RPATH_handling SET(CMAKE_SKIP_BUILD_RPATH FALSE) SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) IF (APPLE) SET(MACOSX_RPATH ON) endif() LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${LASZIP_LIB_INSTALL_DIR}" isSystemDir) IF("${isSystemDir}" STREQUAL "-1") SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LASZIP_LIB_INSTALL_DIR}") ENDIF("${isSystemDir}" STREQUAL "-1") # wipe lib/ drectory on clean. It will have plugins that could be out of date # in the next build set_directory_properties(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${LASZIP_OUTPUT_LIB_DIR}/*") if(WIN32) add_definitions("-DLASZIP_DLL_EXPORT=1") foreach(config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${config} CONFIG) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG} "${LASZIP_OUTPUT_LIB_DIR}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG} "${LASZIP_OUTPUT_BIN_DIR}") # ---[ Windows requires DLLs (shared libraries) to be installed in the same directory as executables set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG} "${LASZIP_OUTPUT_BIN_DIR}") endforeach(config) else(WIN32) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${LASZIP_OUTPUT_LIB_DIR}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${LASZIP_OUTPUT_BIN_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${LASZIP_OUTPUT_LIB_DIR}") endif(WIN32) set(LASZIP_HEADERS_DIR "${PROJECT_SOURCE_DIR}/include/laszip") add_subdirectory(src) add_subdirectory(dll) # add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) LASzip-3.4.3/COPYING000066400000000000000000000636421356234217100137350ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! LASzip-3.4.3/ChangeLog000066400000000000000000001672121356234217100144520ustar00rootroot000000000000002018-03-22 * Howard Butler call vcvars (03:41:11) * Howard Butler Merge branch 'master' of github.com:LASzip/LASzip (03:39:49) * Howard Butler VC vars (03:39:11) 2018-03-21 * Howard Butler use laszip3 as DLL name for new builds on windows (08:34:15) * Howard Butler fix doc version (08:29:18) * Howard Butler point to 3.2.0 release (08:25:52) * Howard Butler fix LASZIP_VERSION_BUILD_DATE (08:21:21) * Howard Butler configure environment (07:51:08) * Howard Butler whitespace normalization (07:49:14) * Howard Butler use 2017 for appveyor builds (07:48:06) * Howard Butler remove matrix (06:04:53) * Howard Butler appveyor builds (06:01:40) * Howard Butler set version to 3.2.0 (06:01:30) * Howard Butler Create README.rst (05:31:12) 2018-03-19 * Howard Butler make sure to compile lasreaditemcompressed_v4.cpp laswriteitemcompressed_v4.cpp too (11:10:47) 2018-02-09 * Martin Isenburg version increment to 3.2 (can read v4 compressed items) (03:56:42) * Martin Isenburg prepare to correct 'context switch' bug reported by Wanwannodao (03:45:51) * Martin Isenburg better WARNINGS and fix for MSVC2013 C4258 warning about shadowed 'i' value (03:35:20) * Martin Isenburg small fix in set_extended_classification() (03:27:38) * Martin Isenburg define fixes for std::unordered_map by Evon (03:26:09) 2018-01-29 * Howard Butler Merge pull request #41 from pblottiere/fix_install (09:51:34) * Blottiere Paul Fix install of laszip_api_version.h (08:03:55) 2018-01-12 * Howard Butler Merge pull request #38 from hobu/laszip-4.0-work-ticket (09:47:10) 2018-01-02 * Howard Butler another include install path attempt (10:54:31) * Howard Butler bump version to 4.0.0 (10:43:22) * Howard Butler include install location broken (10:43:15) 2017-10-19 * Howard Butler Merge pull request #33 from gadomski/load-dll-on-debian (13:02:11) * Pete Gadomski Load .so dll on non-apple (12:06:55) 2017-10-10 * Howard Butler download link for release (14:24:34) * Howard Butler increment versions for 3.1.1 release (14:04:35) * Howard Butler ChangeLog refresh (13:47:49) 2017-10-09 * Howard Butler Merge pull request #31 from kbevers/dk-lidar (09:38:12) * Kristian Evers Moved link to Danish LiDAR to LAZ section of data providers and updated link (09:35:22) 2017-10-02 * Martin Isenburg found 2 more softwares with LAZ support at INTERGEO (06:15:28) 2017-09-27 * Martin Isenburg found 6 new software with LAZ support at INTERGEO (03:14:28) 2017-09-26 * Martin Isenburg updates based on Kirk's 2nd email (another fix) (15:22:25) * Martin Isenburg updates based on Kirk's 2nd email (15:11:13) 2017-09-22 * Martin Isenburg updates based on Kirk's email (21:31:12) 2017-09-14 * Martin Isenburg NOAA now platinum sponsor (11:57:35) * Howard Butler make sure to install binary directory laszip_version_api.h (08:49:52) 2017-09-13 * Howard Butler fix download links (21:38:07) * Howard Butler update doc ver (16:51:47) * Howard Butler point to 3.1.0 release (15:36:06) * Howard Butler define version near top of CMakeLists.txt (15:34:26) * Howard Butler package creation stuff (15:13:34) * Howard Butler check for unordered_map at configure-time and define HAVE_UNORDERED_MAP for the compilation to use it (14:41:07) * Howard Butler cpack stuff for making distribution (14:12:51) * Howard Butler Mergenstall branch 'master' of github.com:LASzip/LASzip (13:03:07) * Howard Butler Merge pull request #27 from abellgithub/master (13:01:11) * Andrew Bell Fix memcpy. (12:58:54) * Howard Butler Merge branch 'master' of github.com:LASzip/LASzip (11:43:42) * Martin Isenburg moved '#include ' from laszip_api.h to laszip_dll.cpp (11:38:00) * Howard Butler -DUNORDERED (11:36:54) * Howard Butler cpack (11:36:47) * Howard Butler fix memcpy call (11:36:34) * Howard Butler put back hash_map (11:36:20) * Martin Isenburg fixed bug in memcpy call (?). uniform API interface: always pointers (11:34:43) * Martin Isenburg compile switch for hash_map vs unordered_map for MSVC60 (11:16:47) * Howard Butler no iostream, no std::copy (08:20:47) 2017-09-12 * Howard Butler no -DUNORDERED (21:09:23) * Howard Butler wrong install path (21:05:16) * Howard Butler check before fclose() (21:04:54) * Howard Butler Merge remote-tracking branch 'andrew/master' into release-prep (13:08:28) * Andrew Bell Keep memory allocation/deallocation in the DLL. (12:15:26) 2017-09-11 * Howard Butler release 3.1.0 preparation (17:14:36) * Howard Butler dos2unix some config (16:06:50) 2017-09-02 * Martin Isenburg new #define LASZIP_API_VERSION keeps include out of my build (11:21:05) 2017-08-30 * Martin Isenburg undoing senseless change (once I thought about it) (20:02:04) * Martin Isenburg completing stream-based writing (with writing LAS header) (19:51:02) 2017-08-28 * Martin Isenburg LASzip for LAS 1.4 fix in set_classification() (16:43:33) * Martin Isenburg LAS 1.4 fixes for flags: copy_to(), copy_from(), set_xxxx_flag() functions (14:05:04) * Martin Isenburg proper 'context' variable instead of development hack (14:02:59) * Martin Isenburg Merge pull request #26 from abellgithub/master (10:30:58) 2017-08-24 * Andrew Bell Remove dead code. (10:38:54) * Andrew Bell Fixes to allow detection of version 1.1. Remove dead build code. (10:35:15) 2017-08-23 * Martin Isenburg minor version increment (also for turning on 'native LAS 1.4 extension' by default) and tiny bug fixes (02:51:44) * Martin Isenburg minor version increment (also for turning on 'native LAS 1.4 extension' by default (02:49:52) 2017-08-22 * Martin Isenburg Merge pull request #24 from abellgithub/master (09:58:43) 2017-08-11 * Andrew Bell Fix output stream for VLR header fields. (13:44:49) * Andrew Bell Merge branch 'zip4' (13:44:20) 2017-08-07 * Andrew Bell Allow compilation on clang. (09:40:34) 2017-08-03 * Martin Isenburg new 'laszip_set_point_type_and_size()' as minimal setup for ostream writer (12:18:12) * Martin Isenburg simplify C++ interface by removing point format and size from arguments (09:20:46) * Martin Isenburg simplify C++ interface by removing point format and size from arguments (09:18:54) * Martin Isenburg reuse new 'setup_laszip_items()' in C code writer (08:13:52) * Martin Isenburg added to history in header comments (05:05:19) * Martin Isenburg reuse new 'write_laszip_vlr_header()' and 'write_laszip_vlr_payload()' in C code (05:04:24) * Martin Isenburg reuse new 'laszip_vrl_payload_size()' in C code (04:52:37) * Martin Isenburg new 'laszip_create_laszip_vlr' C++ interface (for PDAL) (04:06:10) * Martin Isenburg new 'laszip_create_laszip_vlr' C++ interface (for PDAL) (04:03:41) 2017-08-01 * Martin Isenburg use same 'laszip_read_header' when reading from file_name or istream (07:18:23) 2017-07-29 * Martin Isenburg minimal C++ iostream interface (11:57:57) * Martin Isenburg revision increment for minimal C++ iostream interface (11:52:58) * Martin Isenburg minimal C++ iostream interface (11:51:02) * Martin Isenburg removal of blanks (from Andrew Bell) (04:23:03) * Martin Isenburg new '#ifdef CREATE_HISTOGRAMS' and removal of blanks (from Andrew Bell) (04:22:52) * Martin Isenburg removal of unused variable and blanks (from Andrew Bell) (04:22:40) * Martin Isenburg removal of unused variable and blanks (from Andrew Bell) (04:22:29) * Martin Isenburg ifdef NULL check (from Andrew Bell) (04:09:57) * Martin Isenburg support for selective decompression via DLL interface (03:54:57) * Martin Isenburg support for selective decompression via DLL interface (03:50:54) * Martin Isenburg support for selective decompression via DLL interface (03:45:01) * Martin Isenburg revision increment due for selective decompression and seeking bug fix (03:42:06) * Martin Isenburg tiny re-spelling of constant for consistency (03:39:05) * Martin Isenburg bug fix for seeking in compressed LAS 1.4 files and fixing spelling error in variable name (03:36:34) * Martin Isenburg tiny re-spelling of constant for consistency (03:33:43) * Martin Isenburg portability fix suggested by Marc Espie and better verbose output (03:31:04) * Martin Isenburg portability fix suggested by Marc Espie (03:29:09) 2017-06-20 * Martin Isenburg (U16) casting fix (02:28:40) 2017-04-26 * Martin Isenburg new function to enable *writing* of new LAS 1.4 point types with new native extension (20:31:44) * Martin Isenburg changes for adding native LAS 1.4 extension (20:26:30) * Martin Isenburg defines for selective LAS 1.4 decompression (20:15:21) * Martin Isenburg common defines for v3 item readers and writers (20:14:37) * Martin Isenburg new cases for native LAS 1.4 extension (if requested) (20:12:36) * Martin Isenburg new cases for native LAS 1.4 extension (if requested) (20:10:41) * Martin Isenburg added missing BigEndian function (20:07:47) * Martin Isenburg native LAS1.4 extension item writers (20:06:38) * Martin Isenburg native LAS1.4 extension item readers (20:05:45) * Martin Isenburg added missing BigEndian function (20:04:15) * Martin Isenburg fix in copy_from() and copy_to() for new point types (20:03:06) * Martin Isenburg generic function for setting the no_data value (19:58:07) * Martin Isenburg new function for 'skipping' bytes in the stream (19:54:21) 2017-04-01 * Martin Isenburg description of compression for NIR layer (08:28:49) * Martin Isenburg Compression of RGB, Wavepacketsm and Extra Bytes layers (08:16:56) * Martin Isenburg complete for compression of POINT14 layer(s) (07:46:08) 2017-03-31 * Martin Isenburg details for compression of classification/flags/intensity layers (17:09:51) * Martin Isenburg added actually used tables for map and level (10:25:48) * Martin Isenburg updating to released alpha (10:16:13) 2017-02-27 * Martin Isenburg Mapworks has LAZ support (22:17:27) 2017-01-15 * Martin Isenburg version 2.5.2 (up from 2.5.1) includes new DLL/API function to change chunk size (with tiny fix) (05:18:16) 2017-01-11 * Martin Isenburg version 2.5.2 (up from 2.5.1) includes new DLL/API function to change chunk size (10:13:16) 2017-01-08 * Martin Isenburg no side-effect name changes to prepare for native LAS 1.4 compression (13:08:58) * Martin Isenburg can be used as init dummy by native LAS 1.4 compressor (12:49:05) * Martin Isenburg new functionality used by native LAS 1.4 compressor (12:37:58) * Martin Isenburg no side-effect name changes to prepare for native LAS 1.4 compression (11:53:17) * Martin Isenburg extended_scan_angle is I16 not U16 (11:24:17) * Martin Isenburg new MACRO used for native LAS 1.4 compression (11:24:07) * Martin Isenburg minor version increment 2.5. always writing start_of_waveform_data_packet_record as zero. (08:38:27) * Martin Isenburg removing debug error fprintf (08:01:15) * Martin Isenburg new convenience macro (07:41:59) * Martin Isenburg minor version increment 2.5. fixing NIR and scanner channel copy. (07:41:30) * Martin Isenburg minor version increment 2.5. fixing large I64 seek. (07:40:43) * Martin Isenburg minor version increment 2.5. small fixs. sync laszip_dll with laszip_api for hobu (07:28:10) 2016-10-29 * Martin Isenburg INTERGEO: 3 more companies support LAZ (22:51:19) 2016-06-29 * Martin Isenburg intro update (14:37:51) * Martin Isenburg Update specification.rst (14:27:11) * Martin Isenburg Update blueprint.rst (14:18:41) * Martin Isenburg update to what is happening now (14:17:47) * Martin Isenburg added detail about how the GPS time is encoded (14:06:57) * Martin Isenburg Update specification.rst (10:11:55) * Martin Isenburg some detail on compression of X and Y coordinates (10:06:47) * Martin Isenburg Adding detail about return map and return level (09:49:05) * Martin Isenburg create more layers for more efficient decompression (09:18:42) 2016-06-21 * Martin Isenburg exploit correlation between scan angle and GPS time changes (09:51:03) 2016-06-19 * Martin Isenburg compressing point source ID seperate makes rarely sense (09:32:41) 2016-06-17 * Martin Isenburg Update specification.rst (10:59:44) 2016-06-16 * Martin Isenburg starting to refine the compression scheme (09:29:35) 2016-05-22 * Howard Butler Fix #22 -- get autotools in shape again (17:33:41) 2016-04-18 * Howard Butler Build and deploy website docs when 'master' branch is built (15:18:20) 2016-03-08 * Howard Butler Merge pull request #21 from micahcochran/patch-1 (13:27:24) * Micah Cochran Switch Travis to Trusty 14.04. (09:41:02) 2016-02-29 * Howard Butler Merge branch 'master' of github.com:LASzip/LASzip (10:45:19) 2016-02-27 * Martin Isenburg forgot to deletenow undefined LASZIP_DLL (21:08:49) * Howard Butler remove LASzipper/LASUnzipper, catch up to LASzip DLL (13:04:09) 2016-02-25 * Howard Butler remove pnacl stuff which is not used (09:32:45) * Martin Isenburg updated (08:55:35) * Martin Isenburg moves from tools to example directory (08:50:33) * Martin Isenburg moves from tools to example directory (08:49:03) * Martin Isenburg moves from tools to example directory (08:48:06) * Martin Isenburg no more laszip\include directory (08:45:49) * Martin Isenburg depreciating old libLAS laszipper/lasunzipper binding (08:30:11) * Martin Isenburg moving laszippertest to example (08:26:49) * Martin Isenburg upgrading to LAS 1.4 compatibility mode (08:23:40) * Martin Isenburg depreciating old libLAS laszipper/lasunzipper binding (08:20:15) * Martin Isenburg depreciating old libLAS laszipper/lasunzipper binding (08:19:06) * Martin Isenburg depreciating old libLAS laszipper/lasunzipper binding (08:12:17) * Martin Isenburg depreciating old libLAS laszipper/lasunzipper binding (08:11:19) * Martin Isenburg zipper and unzipper now only used by laszippertest (07:59:11) * Martin Isenburg zipper and unzipper now only used by laszippertest (07:57:15) * Martin Isenburg syncing laszip.org with latest LASzip 2.4.1 (07:53:56) 2016-02-23 * Martin Isenburg Update specification.rst (04:43:27) * Martin Isenburg Update specification.rst (04:41:59) * Martin Isenburg Update specification.rst (04:41:03) * Martin Isenburg Update specification.rst (04:39:22) * Martin Isenburg Update specification.rst (04:38:46) * Martin Isenburg Update specification.rst (04:34:26) * Martin Isenburg Update specification.rst (04:12:53) 2016-02-22 * Martin Isenburg coarse outline to get started (06:57:07) * Martin Isenburg Update specification.rst (03:31:07) * Martin Isenburg specification document for "native LAS 1.4 compression" (03:09:41) 2016-01-22 * Martin Isenburg SceneMark supports LAZ (07:22:57) 2015-10-13 * Martin Isenburg Carlson 2016 also supports LAZ (10:01:51) 2015-10-06 * Martin Isenburg small typos (03:47:36) 2015-10-05 * Martin Isenburg little typos / name fixes (03:36:19) 2015-10-03 * Martin Isenburg 7 more software packages with LAZ support discovered at INTERGEO (08:22:03) 2015-09-06 * Martin Isenburg terrasolid and LiDAR analyst add LAZ support (14:12:01) 2015-08-31 * Martin Isenburg Merge branch 'master' of https://github.com/LASzip/LASzip (15:26:14) 2015-08-30 * Martin Isenburg RIEGL becomes Silver Sponsor (15:29:08) 2015-07-18 * Martin Isenburg Update blueprint.rst (10:59:29) * Martin Isenburg Update blueprint.rst (10:51:33) * Martin Isenburg Update blueprint.rst (10:48:42) * Martin Isenburg Update blueprint.rst (10:44:29) * Martin Isenburg Update blueprint.rst (10:44:06) * Martin Isenburg Update blueprint.rst (10:36:40) * Martin Isenburg Update blueprint.rst (10:35:43) * Martin Isenburg Update blueprint.rst (10:34:56) * Martin Isenburg Update blueprint.rst (10:32:28) * Martin Isenburg Update blueprint.rst (10:30:56) * Martin Isenburg Update blueprint.rst (10:17:43) 2015-07-13 * Martin Isenburg Update blueprint.rst (14:52:28) * Martin Isenburg Update blueprint.rst (12:27:58) * Martin Isenburg Update blueprint.rst (07:24:25) * Martin Isenburg Update blueprint.rst (07:03:39) * Martin Isenburg Update blueprint.rst (06:48:01) * Martin Isenburg Update blueprint.rst (06:42:14) * Martin Isenburg adding detail (06:40:47) * Martin Isenburg Update blueprint.rst (06:29:12) * Martin Isenburg objectives for "native LAS 1.4 extension" of LASzip (06:25:46) 2015-07-10 * Martin Isenburg Trimble becomes bronze sponsor and new open LAZ (05:39:27) 2015-06-11 * Martin Isenburg fixed LiMON link (09:43:13) 2015-06-10 * Martin Isenburg QINSy, Potree Converter, LiMON, FLAIM support LAZ (18:21:52) * Martin Isenburg Optech LMS and Leica Survey Studio support LAZ (15:32:23) * Martin Isenburg Quantum Spatial becomes bronze sponsor (15:18:24) 2015-03-28 * Martin Isenburg new file integrity checks that throw exceptions (21:38:52) * Martin Isenburg small fix for reading / writing uncompressed LAS 1.4 (21:31:16) * Martin Isenburg two new softwares support LAZ (21:06:30) 2014-12-02 * Martin Isenburg new LAZ data in Switzerland and New Zealand (01:16:10) 2014-11-14 * Martin Isenburg USGS bulk LAZ (09:36:44) 2014-11-09 * Howard Butler Merge pull request #14 from SiggyF/makefile (09:51:39) 2014-11-08 * Fedor Baart keep Makefile.am in sync with cmake file (15:34:17) 2014-10-16 * Martin Isenburg typo (22:10:21) 2014-10-11 * Martin Isenburg added Pointfuse (16:38:03) * Martin Isenburg added plas.io (04:17:41) * Martin Isenburg CloudPro, PointCAB, DTMaster support and Gold Sponsors (04:12:21) 2014-09-11 * Martin Isenburg Merge branch 'master' of https://github.com/LASzip/LASzip (06:40:37) * Martin Isenburg update in (internal) struct alignment for read / write of uncompressed LAS 1.4 (06:39:49) 2014-09-08 * Howard Butler Merge branch 'master' of github.com:LASzip/LASzip (09:17:18) * Howard Butler default to osgeo4w64 for OSGEO4W_DIR (09:17:15) * Howard Butler Merge pull request #12 from chambbj/cmake-update-entropy-encoder (08:43:55) * Bradley J Chambers update CMakeLists, fixes #11 (07:06:21) 2014-09-07 * Martin Isenburg removal of (unused) EntropyEncoder and EntropyDecoder purely virtual classes (10:37:28) * Martin Isenburg removal of (unused) EntropyEncoder and EntropyDecoder purely virtual classes (10:36:24) * Martin Isenburg purely cosmetic change in comments (09:33:30) * Martin Isenburg alignment of auxiliary struct to 8 bytes (09:31:43) * Martin Isenburg cosmetic changes and consistent pack/unpack naming (09:15:20) * Martin Isenburg Merge pull request #7 from verma/master (07:23:28) 2014-09-06 * Martin Isenburg delay read of chunk table until first read() or seek() is called (12:29:14) 2014-08-21 * Howard Butler Merge pull request #10 from tigerfoot/master (09:22:05) * Bruno Friedmann Update COPYING (09:08:52) 2014-07-31 * Martin Isenburg added Fugroviewer and Scop++ to list of softwares (03:54:14) 2014-07-27 * Howard Butler Merge branch 'master' of https://github.com/LASzip/LASzip (23:10:29) * Howard Butler point at osgeo4w64 instead of osgeo4w (23:10:26) 2014-07-20 * Martin Isenburg critical read bug for truncated LAZ files compressed with 'adaptive chunking' (now also aborts for streaming input) (07:47:28) * Martin Isenburg critical read bug for truncated LAZ files compressed with 'adaptive chunking' (07:28:50) * Martin Isenburg Merge branch 'master' of https://github.com/LASzip/LASzip (06:06:43) 2014-07-05 * Howard Butler Merge pull request #9 from mloskot/fix_copy_files_osgeo4w (20:12:12) 2014-07-04 * Mateusz Åoskot Tweak and correct the original fix (17:37:34) * Mateusz Åoskot Correct headers location in OSGeo4W deploying (17:11:31) 2014-06-15 * Howard Butler cast to U32 to silence warning (15:51:57) 2014-06-07 * Howard Butler clean up some warnings that msvc2013 found (22:57:21) 2014-06-06 * Howard Butler fix issue identified in libLAS/libLAS#9 where LASzip headers were not installing in correct location for autoconf builds (16:44:30) 2014-05-29 * Martin Isenburg added BLAZE as LAZ supporter (16:15:36) 2014-05-23 * Martin Isenburg Trimble Realworks 8.1 adds LAZ support (import/export) (10:07:55) 2014-05-22 * Martin Isenburg added ERDAS, La Rioja, and SonomaVeg (04:19:49) 2014-05-13 * Howard Butler #include laszipexport.hpp again (17:25:24) * Howard Butler add ../dll include directory (17:24:58) * Howard Butler Add MSVC 2012 and 2013 types (17:24:39) * Howard Butler add missing pnacl file (11:09:26) 2014-04-29 * Howard Butler Merge pull request #8 from gadomski/no-using-std-globally (09:16:46) 2014-04-28 * Pete Gadomski Remove using namespace std from global namespace (12:14:27) 2014-04-12 * Uday Verma Move wavepacket struct to a common header, rename make/lay functions to unpack/pack (08:55:51) 2014-04-10 * Uday Verma Refactor wavepacket struct and change wavepacket pointer cast to bytes packing (17:05:07) 2014-04-07 * Howard Butler don't use laszip_dll unless we're windows (16:37:18) 2014-03-27 * Martin Isenburg preparing LAZ for integration of LAX (07:54:54) 2014-03-24 * Howard Butler clean up NaCl module (11:12:21) * Howard Butler tweak laszip_dll stuff so it builds cleanly (11:09:07) * Martin Isenburg better DLL after meeting hobu in Vienna (10:51:45) * Howard Butler add bytestreamin_array.hpp from PulseWaves (10:34:04) * Martin Isenburg better DLL after meeting hobu in Vienna (05:38:00) * Howard Butler Merge pull request #4 from gcasey/master (02:27:22) 2014-03-22 * Martin Isenburg added netherlands and espa engine (03:23:14) * Martin Isenburg Merge branch 'master' of https://github.com/LASzip/LASzip (01:09:44) * Martin Isenburg Merge pull request #5 from scw/patch-1 (01:09:18) * Shaun Walbridge swap license to the correct one. (01:00:48) 2014-03-21 * Martin Isenburg Merge branch 'master' of https://github.com/LASzip/LASzip (23:49:36) 2014-03-19 * Howard Butler try a different theme (13:48:43) 2014-03-14 * Howard Butler rename module source file (09:44:59) * Howard Butler add some scaffolding to be able to build LASzip in emscripten (not working) (09:35:34) * Howard Butler add fclose() (09:35:18) 2014-03-02 * Martin Isenburg added laszip-cli.exe (06:53:11) 2014-03-01 * Howard Butler fix up skip and start parameters (16:03:45) * Martin Isenburg website updates (06:35:32) 2014-02-28 * Howard Butler rename to plasio_laszip, don't iterate off the end, return count back to reader (16:40:09) * Howard Butler implement start, skip, and count for read() method of nacl module (13:32:07) * Howard Butler count-based reader (09:18:47) 2014-02-27 * Howard Butler use minsize build, return ArrayBuffer (22:30:00) * Howard Butler fix up travis script now that we don't do Debug/Release binary directory (17:54:05) * Howard Butler open our own files instead of web ones (17:39:33) * Howard Butler it appears we're reading data (16:35:00) * Howard Butler getheader working (14:45:13) * Casey Goodlett Add option to disable buildosgeo4w on windows (10:00:00) * Howard Butler c++ example works now (09:40:51) 2014-02-26 * Howard Butler cleanups. basic read of a point works (13:59:02) * Howard Butler able to read a point from the zip file (11:35:52) 2014-02-25 * Howard Butler successfully read a laszip file -- doesn't do anything useful though (13:10:14) 2014-02-24 * Howard Butler fail at opening a laszip file (16:34:01) * Howard Butler initial hello world fopen pnacl example (14:24:40) 2014-01-31 * Martin Isenburg update AusCover Airborne LiDAR (08:27:02) 2014-01-25 * Martin Isenburg LAZ in Alaska (20:54:12) 2014-01-13 * Martin Isenburg removing restriction (R) (04:49:55) 2013-12-29 * Martin Isenburg added K2Vi by AAM Group (19:06:36) * Martin Isenburg added ENVI LiDAR and GRASS GIS (11:04:01) 2013-12-28 * Martin Isenburg added SURE (11:55:18) * Martin Isenburg added ZEB1 (07:22:35) * Martin Isenburg added OCAD (06:39:13) * Martin Isenburg added FUSION and PDF3D (06:13:52) 2013-11-02 * Martin Isenburg new softwares support LAZ (22:30:39) 2013-09-03 * Martin Isenburg fixed a tiny bug (02:30:45) 2013-08-07 * Howard Butler fix links to new release (07:21:21) 2013-08-05 * Howard Butler ignore test.tmp and laszipper.log (13:05:19) * Howard Butler add headers to SOURCES so they're included in tarball (13:04:08) * Howard Butler increment version to 2.2.0 in preparation for release (09:21:13) * Howard Butler add Travis configuration (09:08:46) * Howard Butler update AUTHORS (08:56:36) 2013-08-04 * Martin Isenburg bug fix and update email and company name (14:44:44) * Martin Isenburg update email and company name (14:43:03) * Martin Isenburg bug fix and update email and company name (14:42:46) * Martin Isenburg incremented version to 2.1 rev 1 (14:40:56) * Martin Isenburg update email and company name (14:35:32) * Martin Isenburg removed ancient laszip.cpp and lasdiff.cpp junk (14:33:32) * Martin Isenburg removed ancient laszip.cpp and lasdiff.cpp junk (14:32:23) * Martin Isenburg removed ancient laszip.cpp and lasdiff.cpp junk (14:29:16) * Martin Isenburg more software with LAZ support (10:01:57) 2013-05-08 * Martin Isenburg added TERN AusCover LAZ data (17:02:03) 2013-02-16 * Martin Isenburg Merge https://github.com/LASzip/LASzip (06:23:36) * Martin Isenburg Danish, GRAFCAN, more DNR MN (06:21:33) 2013-02-07 * Howard Butler Merge pull request #1 from torsti/mingw (12:03:53) 2013-02-06 * Martin Isenburg more LAS data (01:20:17) 2013-02-03 * Martin Isenburg another folder of LAZ (01:34:31) 2013-01-18 * Martin Isenburg cloud compare supports LAZ (10:17:37) 2012-12-22 * Martin Isenburg more MN LAZ (13:38:10) 2012-12-07 * Martin Isenburg more LAZ from DNR Minnesota and NOAA (09:23:42) * Martin Isenburg more LAZ from PSLC (06:08:52) 2012-12-06 * Martin Isenburg all LAS of puget sound LiDAR consortium converted to LAZ (11:54:30) 2012-11-15 * Martin Isenburg more LAZ in MN (07:26:12) 2012-11-12 * Torsti Schulz Support compilation with MinGW toolchain (07:17:23) 2012-10-05 * Martin Isenburg more MN LAZ (23:35:00) 2012-10-03 * Martin Isenburg added more minnesota LAZ links (17:13:56) 2012-08-20 * Martin Isenburg adding pointools news (13:32:27) * Martin Isenburg test of hobu's web updates (05:35:32) 2012-08-13 * Martin Isenburg more LAS (18:44:22) 2012-08-12 * Martin Isenburg new data (14:06:29) 2012-08-04 * Martin Isenburg more LAS/LAZ files (09:27:34) * Howard Butler tweak indenting (08:32:57) 2012-07-29 * Martin Isenburg updated links (17:37:54) 2012-07-09 * Martin Isenburg more LAZ sources (06:25:13) 2012-06-25 * Martin Isenburg link more uncompressed LAS archives (17:06:19) 2012-06-24 * Martin Isenburg link some uncompressed LAS archives (18:03:00) * Martin Isenburg link some uncompressed LAS archives (17:28:57) 2012-06-17 * Martin Isenburg more DNR MN LAZ (06:03:24) 2012-05-31 * Martin Isenburg fixed bug for reading chunked LAZ with chunktable from stdin pipe (07:49:25) 2012-05-10 * Martin Isenburg changed version to 2.1.0 (14:23:30) 2012-05-09 * Martin Isenburg national land survey of finland (06:17:40) 2012-04-28 * Martin Isenburg win (14:37:32) 2012-03-22 * Martin Isenburg more software supports LAZ (19:20:49) 2012-01-21 * Martin Isenburg added lidar-online (10:26:19) 2012-01-04 * Howard Butler point to new release (11:55:44) * Howard Butler increment version to 2.1.0 in preparation for release (11:45:25) * Howard Butler re-export LASitem because you are expected to use it to find out about the compression (11:31:04) 2012-01-03 * Martin Isenburg fix seeking without chunk table (13:37:29) * Martin Isenburg fix seeking without chunk table (13:32:08) * Martin Isenburg fix seeking without chunk table (13:30:15) * Martin Isenburg fix seeking without chunk table (13:29:11) * Martin Isenburg fix seeking without chunk table (13:28:59) * Martin Isenburg fix seeking without chunk table (13:26:44) * Martin Isenburg fix seeking without chunk table (13:26:17) * Martin Isenburg fix seeking without chunk table (13:26:12) * Martin Isenburg fix seeking without chunk table (13:25:12) * Martin Isenburg fix seeking without chunk table + LAS 1.4 stubs (13:23:46) * Martin Isenburg fix seeking without chunk table + LAS 1.4 stubs (13:23:40) * Martin Isenburg fix seeking without chunk table + LAS 1.4 stubs (13:17:18) * Martin Isenburg fix seeking without chunk table + LAS 1.4 stubs (13:17:10) * Martin Isenburg fix seeking without chunk table + LAS 1.4 stubs (13:15:20) * Martin Isenburg fix seeking without chunk table (13:11:32) * Martin Isenburg fix seeking without chunk table (13:11:26) 2011-12-07 * Martin Isenburg typo (05:57:59) 2011-12-06 * Martin Isenburg added paper, video, LAZ links (16:50:15) 2011-11-09 * Howard Butler Revert "win32 dll fix" (09:59:27) 2011-10-27 * Michael P. Gerlek win32 dll fix (12:52:17) 2011-10-07 * Howard Butler update typos (15:36:53) * Howard Butler point to new release (15:23:15) * Howard Butler remove hg tags file (14:52:11) * Howard Butler ignore git stuff when packaging (14:52:04) * Howard Butler move .hgignore to .gitignore (14:47:10) * Howard Butler increment versions in preparation for release (14:42:12) * Howard Butler clean up _strdup vs strdup warnings on MSVC>1500 (14:36:24) * Howard Butler cast to streamoff instead of streampos (14:07:03) * Martin Isenburg revision bump to 2.0.2. the changes: * large file support (>2GB LAZ) * ability to partly read LAZ files where the compressor was interrupted * ability to partly read LAZ files where the file transfer was interrupted (08:02:25) 2011-08-23 * hobu point to new repository (09:33:56) 2011-08-19 * Howard Butler merge (15:18:40) * Howard Butler first (15:17:24) 2011-06-30 * Howard Butler point to new release (11:38:33) * Howard Butler Added tag 2.0.1 for changeset 76d7e6da5196 (11:21:06) * Howard Butler increment versions in preparation for 2.0.1 release (11:21:01) 2011-06-29 * Michael P. Gerlek missing DLL export (20:08:39) 2011-06-28 * isenburg fixed for chunked compression of 0 points (10:12:29) 2011-06-27 * Howard Butler malloc demands free, not delete [] (14:39:15) 2011-06-24 * Howard Butler Added tag 2.0.0 for changeset d69574ffd060 (08:34:13) * Howard Butler update version number for website and date of release (08:33:53) 2011-06-23 * isenburg unused variable clean-up (18:29:05) * isenburg updates test (17:48:49) * isenburg switching on LASzip v2.0 with chunking (17:48:07) * isenburg merge (17:46:15) * isenburg formulation (17:45:21) * isenburg switching on LASzip v2.0 with chunking (17:43:36) * Howard Butler Added tag 2.0.0 for changeset 037abfa227a0 (13:24:25) * Howard Butler update website to point at LASzip 2.0.0 release (13:24:08) * Howard Butler increment version to 2.0.0 (08:49:06) * Howard Butler update notes about which version numbers to increment (08:48:00) 2011-06-22 * isenburg tiny bug. glad i ran another extensive test series (11:13:09) * isenburg fixed link (07:42:11) 2011-06-21 * isenburg more LAZ online (20:05:21) 2011-06-13 * isenburg proper EOF handling with throw EOF (15:34:28) * isenburg adding broken test data (12:50:05) * isenburg updated error info via const char* get_error() (12:19:15) * isenburg updated error info via const char* get_error() (12:18:18) * isenburg updated usage example again (12:17:37) * isenburg updated usage example (07:56:51) * isenburg improved GPS time compression (07:55:54) * isenburg updated error information via char* error_string (07:54:33) * isenburg updated error information via char* error_string (07:52:36) 2011-05-16 * isenburg compressed chunking information and better GPS time compression (10:01:23) * isenburg new test for variable chunking (10:00:05) 2011-05-11 * isenburg merge (18:38:59) * isenburg quitting random seek loop after 100 seeks (18:34:07) * Howard Butler remove extra qualification (13:48:20) 2011-05-10 * isenburg added a test for seeking (09:35:16) * isenburg fixed a memory little bug (09:34:02) * isenburg moved all version control into LASzip (07:01:55) * isenburg moved all version control into LASzip (07:00:51) * isenburg moved all version control into LASzip (07:00:26) * isenburg further clean-up and commenting (06:59:03) 2011-05-09 * isenburg fixed up laszippertest to be a better example (18:28:19) * isenburg allows variable-sized chunking with explicit zipper.chunk() call when chunk_size == 0 (15:04:25) * isenburg allows variable-sized chunking with explicit zipper.chunk() call when chunk_size == 0 (15:03:25) 2011-05-06 * isenburg added functions to query point type and size (07:53:12) * isenburg added functions to query point type and size (07:52:24) 2011-05-05 * isenburg example with packing/unpacking of VLR (19:05:48) * isenburg added pack and unpack of VLRs (19:05:14) * isenburg added pack and unpack of VLRs (19:04:55) 2011-04-25 * isenburg the updated laszippertest. does not yet test seeking. (18:31:25) * isenburg the file i usually forget to commit (18:28:13) * isenburg point reader and writer with chunking (18:27:48) * isenburg implementation of new laszip interface (18:26:15) * isenburg updated i/o model to support seeking (18:21:18) * isenburg fixed wrong number of end bytes bug (18:20:14) * isenburg new interface for chunking (18:18:10) * isenburg new interface for chunking (18:16:45) 2011-04-07 * isenburg more LAZ (05:58:40) 2011-04-05 * Howard Butler Added tag 1.2.0 for changeset 8144ee77b770 (11:33:47) * Howard Butler typo on link (10:40:25) * Howard Butler update to point at location of new release (10:31:57) * Howard Butler missing header file for autoconf build (10:26:52) * Howard Butler update CPACK_SOURCE_IGNORE_FILES (10:24:20) * Howard Butler typo for CPACK_PACKAGE_VERSION_PATCH (09:50:55) * Howard Butler increment version information to 1.2.0 in preparation for next release (08:38:35) 2011-04-03 * isenburg merge (07:54:21) * isenburg fix (07:53:03) 2011-03-24 * Howard Butler add v2 to cmake (18:41:07) * isenburg more data (11:16:27) 2011-03-23 * isenburg i always forget one (17:29:02) * isenburg more LAZ and formatting (04:40:29) 2011-03-22 * isenburg more LAZ and formatting (16:20:22) * isenburg moving detail from and data to main page (14:12:09) * isenburg adding laszip version 2.0 (13:22:22) * isenburg adding laszip version 2.0 (13:21:12) * isenburg adding laszip version 2.0 (13:19:47) * isenburg adding laszip version 2.0 (13:07:35) * isenburg adding laszip version 2.0 (13:06:35) * isenburg adding laszip version 2.0 (12:59:57) * isenburg another webpage (12:24:29) * isenburg another webpage (09:19:21) 2011-03-21 * isenburg adding laszip version 2.0 (06:20:11) 2011-03-18 * Howard Butler add page pointing to LASzip data available for download (08:09:25) 2011-02-27 * isenburg some lossless blurb (09:24:56) 2011-02-20 * isenburg eliminated another lurking error (11:18:17) 2011-02-08 * Michael P. Gerlek use %u, not %d (17:24:47) 2011-02-04 * Howard Butler tweak language and layout a little bit (22:19:23) * isenburg adding content to webpage (21:19:52) 2011-02-01 * Howard Butler update links to new release (11:18:40) * Howard Butler Added tag 1.0.1 for changeset a216ab3ddb11 (11:14:44) * Howard Butler increment versions in preparation for release (08:39:26) * Howard Butler add compile-time endianness check from libLAS and issue an #error when it's determined we're big-endian (08:26:54) 2011-01-31 * Howard Butler add Sphinx makefile (16:20:49) * Howard Butler add Sphinx dox for website (16:04:13) * isenburg small efficiency fix (15:35:44) * isenburg mean bug fix due to floating-point 'Inf' compiler differences (15:22:30) * isenburg forgot to uncomment a line. got rid of tabs. (13:28:38) * isenburg compress/decompress scan angle as U8 avoids danger (13:15:44) * Michael P. Gerlek added asserts (12:17:43) * Michael P. Gerlek VS2010 lint (11:47:13) * Michael P. Gerlek fix vs2010 warnings; fix crlfs (11:46:22) * Michael P. Gerlek added -x, to set random seed (and fix crlf) (11:42:25) * isenburg init functions return BOOL instead of I32 (10:50:56) 2011-01-30 * isenburg fixed messed up licensing comments (07:40:05) * isenburg fixed for windows (07:14:53) 2011-01-29 * Howard Butler import, not export the dll (20:18:26) * Howard Butler proper #ifdefs for range encoder test (20:10:43) 2011-01-28 * isenburg consistent (and nicer) looking licensing headers (08:53:17) * isenburg consistent (and nicer) looking licensing headers (08:52:29) 2011-01-21 * Howard Butler static build option (13:29:25) * Howard Butler rename copied symbol from liblas (12:56:49) * Howard Butler turn off LASZIP_DLL entirely if we haven't asked for it (12:14:33) 2011-01-17 * Howard Butler merge (12:08:54) * Howard Butler increment version in preparation for release (12:05:57) * Howard Butler move range encoder/decoder into unused directory and add to ignores list for package building (12:04:51) * Howard Butler remove liblas-specific stuff (12:04:16) * Howard Butler add release howto (11:58:39) * Michael P. Gerlek blind fix for Hobu (10:00:09) 2011-01-16 * Michael P. Gerlek made Settings be a singleton, added proper logging (18:38:27) 2011-01-14 * Michael P. Gerlek added help mssg (17:06:41) * Michael P. Gerlek added Settings object to hold cmd line params; added cmd line interface; added randomness (17:03:29) * Howard Butler update my little config (12:47:28) 2011-01-13 * Michael P. Gerlek consolidate still more, so can add infinite loop (13:20:44) * Michael P. Gerlek refactor to remove triplicated code paths (12:51:08) 2011-01-12 * Michael P. Gerlek pull-merge (15:55:19) * isenburg fixed mean bug for k == 32 (15:28:11) * Howard Butler destroy symbolmodel for m_gpstime_0diff (14:58:35) * Howard Butler use array delete for writers_raw and writers_compressed (14:49:33) * Howard Butler undo r138 (14:45:51) * Howard Butler don't leak writers_raw and writers_compressed pointers when cleaning up (14:38:41) * Michael P. Gerlek put rangecoder tests under #ifdef (11:23:39) * Howard Butler update to reflect export.hpp name change (10:37:22) * Howard Butler actually rename export.hpp to laszipexport.hpp (09:01:15) * isenburg export.hpp name change (08:22:34) * isenburg removing rangecoder (07:34:39) 2011-01-11 * Michael P. Gerlek "bool" is valid post-VC6 (14:45:20) * Michael P. Gerlek pull-merge (10:42:14) 2011-01-10 * Michael P. Gerlek vs2010 detritus (18:44:17) * Howard Butler add newline (12:56:58) * Howard Butler add newline (12:56:18) 2011-01-07 * Howard Butler tweak version (14:26:42) * Howard Butler packaging (13:58:53) * Howard Butler update ChangeLog (13:56:34) * isenburg more efficient big endian handling (11:45:52) * isenburg more efficient big endian handling (11:42:34) * Howard Butler turn off osgeo4w building by default (09:24:25) 2011-01-06 * Michael P. Gerlek do need to delete martin's stream (but not ours) (15:23:42) * isenburg for testing if extra freads/fwrites affect performance (12:01:53) * Howard Butler export LASunzipper too (11:40:14) 2011-01-05 * Howard Butler add install_name for OSX (21:35:08) * Howard Butler put LASZIP_DLL back. Martin, please let me know your error message(s) instead of removing this as I need it for the OSGeo4W windows deployment (21:08:32) * isenburg forgot to copy & commit (11:56:48) 2011-01-04 * isenburg improved endianness again, renamed compression to algorithm, improved wavepacket13 compressor (17:57:54) * isenburg mpg: the LAS_ZIP_DLL does not work with my code. can you ifdef it? (17:52:11) * Howard Butler add a few more ignores (12:02:44) * Howard Butler simplify to a single package install for osgeo4w (09:38:56) 2011-01-03 * Howard Butler fix osgeo4w dependency and add OSGEO4W_UPSTREAM_RELEASE usage (14:47:10) * Howard Butler osgeo4w packaging (12:31:23) * Howard Butler add osgeo4w packaging script (12:20:33) * Howard Butler add laszip-config and laszip.pc packageconfig (12:06:27) * Howard Butler bring in line with cmake setup (12:06:15) * Howard Butler bring in line with cmake setup (12:06:06) * Howard Butler ignore .lax test files and change location of laszip-config and laszip.pc package config files (12:05:51) * Howard Butler add packaging and soname for dll (11:49:44) * Howard Butler add a laszip-config target (11:49:29) * Howard Butler add a few more ignores (11:48:54) * Howard Butler these files are not used anymore according to Martin (11:30:22) 2010-12-30 * Howard Butler add my base config (11:32:59) * Howard Butler export the laszip dll items (11:32:45) * Howard Butler fix install target to LASZIP_LIB_DIR instead of _BIN, build shared library by default (10:53:47) * Howard Butler start adding LASZIP_DLL exports definition in preparation for shared library build/install/usage (09:10:52) * Howard Butler add logic or setting CMAKE_BUILD_TYPE to Debug by default if not set and not in the cache (09:03:28) * Howard Butler add some missing header files (09:02:59) 2010-12-27 * Michael P. Gerlek explicit default param no longer needed (13:44:10) * Michael P. Gerlek use an enum for the compression type, for type safety (13:35:32) * Michael P. Gerlek fix err checks on open() (13:17:59) * Michael P. Gerlek remove fprintf calls (13:15:58) * Michael P. Gerlek remove calls to fprintf, exit (13:14:06) 2010-12-23 * isenburg one last optimization to compress 1.5 percent better (19:24:25) * isenburg fix of pointreader and small optimization of POINT10 compressor (12:11:19) * isenburg added test for new WAVEPACKET13 compressor (08:11:29) * isenburg added test for new WAVEPACKET13 compressor (08:02:14) * isenburg updated RGB encoding to be endian neutral (07:45:46) 2010-12-22 * Michael P. Gerlek sync up w/ Martin's versioning (16:16:19) * Michael P. Gerlek memleak (16:12:44) * Michael P. Gerlek move header functions into .cpp file (15:09:56) * Michael P. Gerlek sync w/ Martin's changes (13:25:03) * Michael P. Gerlek pull-merge (13:18:36) * Michael P. Gerlek pass streams by ref, not as pointers; return status code on open, not bool; declare items parameter as an array (12:14:01) 2010-12-21 * isenburg renaming to GPSTIME11, RGB12, and WAVEPACKET13 (14:25:15) * isenburg added LASzip struct to be used as VLR data (14:20:28) 2010-12-20 * isenburg changing functions to const (21:33:42) * isenburg changing functions to const (21:30:57) * isenburg more minor changes under the hood (12:12:32) * isenburg minor changes to finalize interface (12:08:46) 2010-12-18 * Michael P. Gerlek pull-merge (14:29:58) * Michael P. Gerlek added LASitem::set helper (14:29:41) * Michael P. Gerlek comment fix (14:28:42) * isenburg merge (13:50:41) * isenburg consolidated all IO paths (13:49:15) * isenburg consolidated all IO paths (13:47:29) 2010-12-17 * Michael P. Gerlek added VERSION constants (23:23:16) * Michael P. Gerlek add cast for vs2010; consolidate byte writer path (22:12:22) * isenburg changed LASitem from struct to class (21:44:46) * isenburg updated the endian handling (21:43:02) * isenburg updated the endian handling and allow seeking (21:41:05) * Michael P. Gerlek c/p error in stream creation (09:49:21) 2010-12-16 * Michael P. Gerlek consolidated the MC6 macro usage (23:00:21) * Michael P. Gerlek dead code (22:36:31) 2010-12-15 * Howard Butler typo (16:36:05) * Howard Butler a whole slug of #ifdefs for the VC6 iostream vs stl iostream stuff -- segfaults currently on OS X (16:28:14) * isenburg the (slower) rangecoder that was replaced in laszip with the (faster) arithmetic coder in january 2010 (15:58:44) * isenburg added rangecoder and improved test output (13:10:35) * isenburg added rangecoder and fixed read past write issue (13:09:47) * isenburg reinsert lost changes (10:37:53) * isenburg reinsert lost changes (10:35:42) * isenburg merging with my code (10:27:40) * isenburg merging with my code (10:26:34) * isenburg added check for input & output bytes (10:25:56) * isenburg eof instead of bad (10:08:22) * isenburg getting annoyed at hg (10:02:55) * isenburg getting annoyed at hg (10:02:04) * Howard Butler remove all std:: explicit calls and instead put 'using namespace std;' in place to allow for usage by vc6 (08:51:42) * isenburg getting byte count (08:44:51) * isenburg getting byte count (08:43:46) * Howard Butler merge (08:39:58) * Howard Butler merge (08:39:18) * isenburg merge (08:38:48) * isenburg handling big endian writes and reads (07:11:54) 2010-12-14 * Michael P. Gerlek refine MSC_VER for vc6 usage (21:35:05) * isenburg handling of raw point writing on big endian platforms (20:21:57) * isenburg it was not using streams but FILE* ... try again. i get a bug. (20:15:49) * Howard Butler update autoconf build (10:35:09) * Howard Butler Use explicit std:: prefix for streams, move laszippertest into the tools directory, turn off lasdiff and laszip for now, as these depend on LAStools. (10:12:41) * Howard Butler merge (09:46:42) * isenburg missing header file (05:36:54) 2010-12-13 * Michael P. Gerlek sync w/ Martin's changes (22:09:36) * Michael P. Gerlek move win32 DEPRECATE stuff into CMake (22:08:00) * isenburg updated for new laszip sources (20:19:41) * isenburg adding refactored laszip compressor modules (20:14:08) * isenburg added optional FILE* input. iostream still broken. (20:10:44) * isenburg removing all classes that are no longer relevant (20:00:03) 2010-12-12 * isenburg more modular interface for liblas integration. only three headerfiles. example use given. still some missing files under the hood dur to remaining bugs (20:32:11) 2010-12-11 * Michael P. Gerlek (testing hg config) (15:43:31) * Michael P. Gerlek stub out a stake in the ground for "liblaszip" exported interface (15:24:30) * Michael P. Gerlek VS2010 lint (15:23:59) * Michael P. Gerlek remove gzip usage; elide some windows warnings (15:03:01) 2010-12-01 * Howard Butler rename all header files from .h to .hpp. Move include files from include/ to include/laszip. Provide CMake configuration. (09:50:10) 2010-01-19 * Martin Isenburg ran dos2unix & added lasdiff (12:44:51) * Martin Isenburg ran dos2unix (12:43:52) * Howard Butler enable laszip building (12:10:21) * Howard Butler merging (11:50:33) * Martin Isenburg adding an actual executable (11:53:06) * Howard Butler use tabs instead of spaces in makefiles (11:50:13) * Howard Butler remove extraneous ; (11:45:27) 2010-01-18 * Martin Isenburg those also needed to be changed (23:42:10) * Martin Isenburg added the licensing info again (23:34:52) * Martin Isenburg adding arithmetic coder to main branch (23:14:58) * Martin Isenburg adding arithmetic coder to the main branch (23:05:41) * Martin Isenburg alternate coder moves into main branch (22:56:45) 2010-01-14 * Martin Isenburg major overhaul of the compressor (19:19:32) 2010-01-12 * isenburg@swan5.cs.unc.edu no need for alternate coder right now (16:15:50) * isenburg@swan5.cs.unc.edu ull for constant (16:15:05) * isenburg@swan5.cs.unc.edu ull for constant (16:14:38) * Howard Butler fix up compilation issues (10:05:53) * Howard Butler add missing stuff so things can build (10:01:01) 2010-01-04 * Howard Butler clean up warning (10:57:30) * Howard Butler It compiles! (on os x) (08:48:28) LASzip-3.4.3/HOWTORELEASE.txt000066400000000000000000000035601356234217100153350ustar00rootroot00000000000000 Steps for Making a LASzip Release ============================================================================== :Author: Howard Butler :Contact: hobu.inc@gmail.com :Revision: $Revision$ :Date: $Date$ This document describes the process for releasing a new version of LASzip. General Notes ------------------------------------------------------------------------------ Release Process 1) Increment Version Numbers - CMakeLists.txt * SET(LASZIP_VERSION_MAJOR "2") * SET(LASZIP_VERSION_MINOR "0") * SET(LASZIP_VERSION_PATCH "0") * SET(LASZIP_LIB_SOVERSION "4.0.2") - include/laszip/laszip.hpp * #define LASZIP_VERSION_MAJOR 2 * #define LASZIP_VERSION_MINOR 0 * #define LASZIP_VERSION_REV 0 - configure.ac * m4_define([laszip_version_major], [2]) * m4_define([laszip_version_minor], [0]) * m4_define([laszip_version_micro], [0]) - Makefile.am -- see http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html * liblaszip_la_LDFLAGS = -version-info 6:0:0 2) Update README to include any relevant info about the release that might have changed. 3) Build Windows version - Issue nmake and nmake install commands :: nmake /f Makefile osgeo4w nmake /f Makefile osgeo4w 4) Make the source distribution :: make dist 5) Generate MD5 sums :: md5 laszip-1.0.0.tar.bz2 > laszip-1.0.0.tar.bz2.md5 6) Edit release page on http://liblas.org/zip/ 7) Upload to OSGeo download site 8) Tag the release. Use the ``-f`` switch if you are retagging because you missed something. :: git tag 1.0.0b1 git push --tags 9) Write the release notes. Place a copy of the release notes on the release page you created as well as send an email to liblas-devel announcing the new release. $Id$ LASzip-3.4.3/NEWS000066400000000000000000000044221356234217100133700ustar00rootroot00000000000000================================================================================ LASzip ================================================================================ 3.2.9 27-DEC-18 -------------------------------------------------------------------------------- * Decompression bug for PRDF 8 or 10 when the scanner channel and the NIR field are populated. 3.2.8 19-NOV-18 -------------------------------------------------------------------------------- ** NOTE: The version number is 3.2.8 to be brought in line with the patch version number present in LAStools, which had been incremented without being kept in sync with the laszip.org version. We regret the error. The following bug fixes have been made since 3.2.2: * 7 November 2018 -- upped to 3.2 r8 for identical legacy and extended flags check * 20 October 2018 -- upped to 3.2 r7 for rare bug in LASinterval::merge_intervals() * 5 October 2018 -- upped to 3.2 r6 for corrected 'is_empty' return value * 28 September 2018 -- upped to 3.2 r5 for fix in extended classification writing 3.2.2 27-MAR-18 -------------------------------------------------------------------------------- * A version number was not properly incremented to 3.2.1, necessitating a new release to eliminate confusion. 3.2.1 26-MAR-18 -------------------------------------------------------------------------------- * Library SOVERSIONing for libtool to 8.0.0 https://github.com/LASzip/LASzip/issues/36 * Update NEWS and ChangeLog * Library version inadvertently had major version in name (only relevant on windows) * Now building on AppVeyor and Travis https://ci.appveyor.com/project/hobu/laszip/history https://travis-ci.org/LASzip/LASzip 3.2.0 21-MAR-18 -------------------------------------------------------------------------------- * Fix install of laszip_api_version.h https://github.com/LASzip/LASzip/issues/30 * Add LAZ V4 reader methods in preparation for a future release 3.1.1 10-OCT-17 -------------------------------------------------------------------------------- * Fix packaging issue with laszip_api_version.h https://github.com/LASzip/LASzip/issues/30 * NEWS and ChangeLog updates 3.1.0 13-SEP-17 -------------------------------------------------------------------------------- * LAZ 1.4 support * New "DLL" API replaces previous API LASzip-3.4.3/README000066400000000000000000000000001356234217100135350ustar00rootroot00000000000000LASzip-3.4.3/README.rst000066400000000000000000000004121356234217100143530ustar00rootroot00000000000000LASzip -------------------------------------------------------- https://laszip.org/ Testing ........................................................ .. image:: https://travis-ci.org/LASzip/LASzip.svg?branch=master :target: https://travis-ci.org/LASzip/LASzip LASzip-3.4.3/appveyor.yml000066400000000000000000000020201356234217100152510ustar00rootroot00000000000000version: 1.0.{build} image: Visual Studio 2017 platform: x64 configuration: Release environment: OSGEO4W_ROOT: C:\\OSGeo4W64 matrix: - OSGEO4W_BUILD: ON matrix: fast_finish: true # Should speed up repository cloning shallow_clone: true clone_depth: 5 install: - ps: mkdir c:\\laszip-install | out-null - set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\7-Zip;C:\Program Files\Microsoft Windows Performance Toolkit\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Tools\GitVersion;C:\Program Files (x86)\CMake\bin;C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin;C:\Program Files\AppVeyor\BuildAgent - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - call .\\scripts\\appveyor\\config.cmd build_script: - call .\\scripts\\appveyor\\build.cmd after_build: - call .\\scripts\\appveyor\\install.cmd LASzip-3.4.3/cmake/000077500000000000000000000000001356234217100137475ustar00rootroot00000000000000LASzip-3.4.3/cmake/common.cmake000066400000000000000000000006771356234217100162530ustar00rootroot00000000000000# # To reduce typing. # set(CDIR "${CMAKE_CURRENT_LIST_DIR}") # # This must be first. # include(${CDIR}/directories.cmake) # # This must come before macros, but I don't understand why the policies # apply to the macros rather than the invocation of the macros. # include(${CDIR}/policies.cmake NO_POLICY_SCOPE) include(${CDIR}/macros.cmake) include(${CDIR}/libraries.cmake) include(${CDIR}/compiler_options.cmake) include(${CDIR}/modules.cmake) LASzip-3.4.3/cmake/compiler_options.cmake000066400000000000000000000003671356234217100203440ustar00rootroot00000000000000include_directories( ${LASZIP_INCLUDE_DIR} ${PROJECT_BINARY_DIR}/include ) if (WIN32) include (${CMAKE_CURRENT_LIST_DIR}/win32_compiler_options.cmake) else() include (${CMAKE_CURRENT_LIST_DIR}/unix_compiler_options.cmake) endif() LASzip-3.4.3/cmake/cpack.cmake000066400000000000000000000037401356234217100160360ustar00rootroot00000000000000#------------------------------------------------------------------------------ # CPACK controls #------------------------------------------------------------------------------ SET(CPACK_PACKAGE_VERSION_MAJOR ${LASZIP_API_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${LASZIP_API_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${LASZIP_API_VERSION_PATCH}) SET(CPACK_PACKAGE_NAME "LASzip") SET(CPACK_SOURCE_GENERATOR "TBZ2;TGZ") SET(CPACK_PACKAGE_VENDOR "LASzip Development Team") SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/COPYING") set(CPACK_SOURCE_PACKAGE_FILE_NAME "laszip-src-${LASZIP_API_VERSION_STRING}") set(CPACK_SOURCE_IGNORE_FILES "/\\\\.gitattributes;/\\\\.vagrant;/\\\\.DS_Store;/CVS/;/\\\\.git/;\\\\.swp$;~$;\\\\.\\\\#;/\\\\#") list(APPEND CPACK_SOURCE_IGNORE_FILES "CMakeScripts/") list(APPEND CPACK_SOURCE_IGNORE_FILES "CMakeCache.txt") list(APPEND CPACK_SOURCE_IGNORE_FILES ".xcodeproj") list(APPEND CPACK_SOURCE_IGNORE_FILES "build.make") list(APPEND CPACK_SOURCE_IGNORE_FILES "_CPack_Packages") list(APPEND CPACK_SOURCE_IGNORE_FILES "CPackSourceConfig.cmake") list(APPEND CPACK_SOURCE_IGNORE_FILES "CPackConfig.cmake") list(APPEND CPACK_SOURCE_IGNORE_FILES "cmake_install.cmake") list(APPEND CPACK_SOURCE_IGNORE_FILES "Testing") list(APPEND CPACK_SOURCE_IGNORE_FILES "bin/") list(APPEND CPACK_SOURCE_IGNORE_FILES "data/") list(APPEND CPACK_SOURCE_IGNORE_FILES "scripts/") list(APPEND CPACK_SOURCE_IGNORE_FILES "lib/") list(APPEND CPACK_SOURCE_IGNORE_FILES "/build/") list(APPEND CPACK_SOURCE_IGNORE_FILES "Makefile") list(APPEND CPACK_SOURCE_IGNORE_FILES ".gz") list(APPEND CPACK_SOURCE_IGNORE_FILES ".bz2") list(APPEND CPACK_SOURCE_IGNORE_FILES "unused/") list(APPEND CPACK_SOURCE_IGNORE_FILES "CMakeFiles") list(APPEND CPACK_SOURCE_IGNORE_FILES "CTestTestfile.cmake") list(APPEND CPACK_SOURCE_IGNORE_FILES "/test/data/local/") list(APPEND CPACK_SOURCE_IGNORE_FILES "/docs") list(APPEND CPACK_SOURCE_IGNORE_FILES "/include/laszip/laszip_api_version.h") include(CPack) LASzip-3.4.3/cmake/directories.cmake000066400000000000000000000003361356234217100172670ustar00rootroot00000000000000if(NOT ROOT_DIR) message(FATAL_ERROR "ROOT_DIR must be set in top-level CMakeLists.txt") endif() set(LASZIP_SRC_DIR ${ROOT_DIR}/src) set(LASZIP_CMAKE_DIR ${ROOT_DIR}/cmake) set(LASZIP_INCLUDE_DIR ${ROOT_DIR}/include) LASzip-3.4.3/cmake/examples/000077500000000000000000000000001356234217100155655ustar00rootroot00000000000000LASzip-3.4.3/cmake/examples/hobu-config.bat000066400000000000000000000004611356234217100204560ustar00rootroot00000000000000@echo off set G="NMake Makefiles" REM set G="Visual Studio 9 2008" REM set G="Visual Studio 10" REM set BUILD_TYPE=RelWithDebInfo REM set BUILD_TYPE=Debug set BUILD_TYPE=Release cmake -G %G% ^ -DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^ -DCMAKE_VERBOSE_MAKEFILE=OFF ^ -DBUILD_STATIC=FALSE ^ . LASzip-3.4.3/cmake/examples/hobu-config.sh000077500000000000000000000002421356234217100203220ustar00rootroot00000000000000#!/bin/bash GENERATOR="Unix Makefiles" BUILD_TYPE="Debug" rm -rf build mkdir build cd build cmake -G "$GENERATOR" \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ .. LASzip-3.4.3/cmake/libraries.cmake000066400000000000000000000006251356234217100167300ustar00rootroot00000000000000# Build shared libraries by default. option(LASZIP_BUILD_STATIC "Build LASzip as a static library" OFF) if (LASZIP_BUILD_STATIC) set(LASZIP_LIB_TYPE "STATIC") set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) else () set(LASZIP_LIB_TYPE "SHARED") if (WIN32) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_IMPORT_LIBRARY_SUFFIX}) endif() endif() mark_as_advanced(LASZIP_BUILD_STATIC) LASzip-3.4.3/cmake/macros.cmake000066400000000000000000000216731356234217100162460ustar00rootroot00000000000000########################################################################## # These macros were taken from the Point Cloud Library (pointclouds.org) # # and have been modified for LASZIP. License details follow. # ########################################################################## # Software License Agreement (BSD License) # # # # Point Cloud Library (PCL) - www.pointclouds.org # # Copyright (c) 2009-2012, Willow Garage, Inc. # # Copyright (c) 2012-, Open Perception, Inc. # # Copyright (c) XXX, respective authors. # # # # All rights reserved. # # # # Redistribution and use in source and binary forms, with or without # # modification, are permitted provided that the following conditions # # are met: # # # # * Redistributions of source code must retain the above copyright # # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # # copyright notice, this list of conditions and the following # # disclaimer in the documentation and/or other materials provided # # with the distribution. # # * Neither the name of the copyright holder(s) nor the names of its # # contributors may be used to endorse or promote products derived # # from this software without specific prior written permission. # # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # # POSSIBILITY OF SUCH DAMAGE. # ########################################################################## ############################################################################### # Add a set of include files to install. # _component The part of LASZIP that the install files belong to. # _subdir The sub-directory for these include files. # ARGN The include files. macro(LASZIP_ADD_INCLUDES _subdir) install(FILES ${ARGN} DESTINATION ${LASZIP_INCLUDE_INSTALL_DIR}/${_subdir}) endmacro(LASZIP_ADD_INCLUDES) ############################################################################### # Add a library target. # _name The library name. # _component The part of LASZIP that this library belongs to. # ARGN The source files for the library. macro(LASZIP_ADD_LIBRARY _name) add_library(${_name} ${LASZIP_LIB_TYPE} ${ARGN}) set_target_properties( ${_name} PROPERTIES VERSION ${LASZIP_SO_VERSION} SOVERSION ${LASZIP_COMPATIBILITY_VERSION} CLEAN_DIRECT_OUTPUT 1 FOLDER Libraries ) install(TARGETS ${_name} EXPORT LASZIPTargets RUNTIME DESTINATION ${LASZIP_BIN_INSTALL_DIR} LIBRARY DESTINATION ${LASZIP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LASZIP_LIB_INSTALL_DIR}) if (APPLE) set_target_properties(${_name} PROPERTIES INSTALL_NAME_DIR "@executable_path/../lib") endif() endmacro(LASZIP_ADD_LIBRARY) ############################################################################### # Add an executable target. # _name The executable name. # _component The part of LASZIP that this library belongs to. # ARGN the source files for the library. macro(LASZIP_ADD_EXECUTABLE _name) add_executable(${_name} ${ARGN}) set(LASZIP_EXECUTABLES ${LASZIP_EXECUTABLES} ${_name}) install(TARGETS ${_name} EXPORT LASZIPTargets RUNTIME DESTINATION ${LASZIP_BIN_INSTALL_DIR}) endmacro(LASZIP_ADD_EXECUTABLE) ############################################################################### # Add a test target. # _name The driver name. # ARGN : # FILES the source files for the test # LINK_WITH link test executable with libraries macro(LASZIP_ADD_TEST _name) set(options) set(oneValueArgs) set(multiValueArgs FILES LINK_WITH) cmake_parse_arguments(LASZIP_ADD_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) include_directories(${PROJECT_SOURCE_DIR}/test/unit) include_directories(${PROJECT_BINARY_DIR}/test/unit) set(common_srcs ${PROJECT_SOURCE_DIR}/test/unit/Support.cpp ${PROJECT_SOURCE_DIR}/test/unit/TestConfig.cpp ) if (WIN32) list(APPEND ${LASZIP_ADD_TEST_FILES} ${LASZIP_TARGET_OBJECTS}) add_definitions("-DLASZIP_DLL_EXPORT=1") endif() add_executable(${_name} ${LASZIP_ADD_TEST_FILES} ${common_srcs}) set_target_properties(${_name} PROPERTIES COMPILE_DEFINITIONS LASZIP_DLL_IMPORT) set_property(TARGET ${_name} PROPERTY FOLDER "Tests") target_link_libraries(${_name} ${LASZIP_BASE_LIB_NAME} gtest ${LASZIP_ADD_TEST_LINK_WITH}) add_test(NAME ${_name} COMMAND "${PROJECT_BINARY_DIR}/bin/${_name}" WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/..") set_property(TEST ${_name} PROPERTY ENVIRONMENT # Ensure plugins are loaded from build dir # https://github.com/LASZIP/LASZIP/issues/840 "LASZIP_DRIVER_PATH=${PROJECT_BINARY_DIR}/lib" ) endmacro(LASZIP_ADD_TEST) ############################################################################### # Get the operating system information. Generally, CMake does a good job of # this. Sometimes, though, it doesn't give enough information. This macro will # distinguish between the UNIX variants. Otherwise, use the CMake variables # such as WIN32 and APPLE and CYGWIN. # Sets OS_IS_64BIT if the operating system is 64-bit. # Sets LINUX if the operating system is Linux. macro(GET_OS_INFO) string(REGEX MATCH "Linux" OS_IS_LINUX ${CMAKE_SYSTEM_NAME}) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(OS_IS_64BIT TRUE) else(CMAKE_SIZEOF_VOID_P EQUAL 8) set(OS_IS_64BIT FALSE) endif(CMAKE_SIZEOF_VOID_P EQUAL 8) endmacro(GET_OS_INFO) ############################################################################### # Pull the component parts out of the version number. macro(DISSECT_VERSION) # Find version components string(REGEX REPLACE "^([0-9]+).*" "\\1" LASZIP_API_VERSION_MAJOR "${LASZIP_API_VERSION_STRING}") string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" LASZIP_API_VERSION_MINOR "${LASZIP_API_VERSION_STRING}") string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" LASZIP_API_VERSION_PATCH "${LASZIP_API_VERSION_STRING}") if (NOT LASZIP_API_VERSION_MINOR) set(LASZIP_API_VERSION_MINOR "0") endif() if (NOT LASZIP_API_VERSION_PATCH) set(LASZIP_API_VERSION_PATCH "0") endif() endmacro(DISSECT_VERSION) ############################################################################### # Set the destination directories for installing stuff. # Sets LASZIP_LIB_INSTALL_DIR. Install libraries here. # Sets LASZIP_BIN_INSTALL_DIR. Install binaries here. # Sets LASZIP_INCLUDE_INSTALL_DIR. Install include files here, preferably in a # subdirectory named after the library in question (e.g. # "registration/blorgle.h") macro(SET_INSTALL_DIRS) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) if (NOT DEFINED LASZIP_LIB_INSTALL_DIR) if (DEFINED CMAKE_INSTALL_LIBDIR) set(LASZIP_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") else() set(LASZIP_LIB_INSTALL_DIR "lib") endif() endif () set(LASZIP_INCLUDE_INSTALL_ROOT "include/") set(LASZIP_INCLUDE_INSTALL_DIR "${LASZIP_INCLUDE_INSTALL_ROOT}") set(LASZIP_DOC_INCLUDE_DIR "share/doc/${PROJECT_NAME_LOWER}-${LASZIP_VERSION_MAJOR}.${LASZIP_VERSION_MINOR}") set(LASZIP_BIN_INSTALL_DIR "bin") set(LASZIP_PLUGIN_INSTALL_DIR "share/pdal/plugins") if(WIN32) set(LASZIPCONFIG_INSTALL_DIR "cmake") else(WIN32) set(LASZIPCONFIG_INSTALL_DIR "share/${PROJECT_NAME_LOWER}-${LASZIP_VERSION_MAJOR}.${LASZIP_VERSION_MINOR}") endif(WIN32) endmacro(SET_INSTALL_DIRS) LASzip-3.4.3/cmake/modules.cmake000066400000000000000000000001631356234217100164210ustar00rootroot00000000000000# # Processing necessary to deal with modules. # set(CMAKE_MODULE_PATH ${LASZIP_MODULE_DIR} ${CMAKE_MODULE_PATH}) LASzip-3.4.3/cmake/policies.cmake000066400000000000000000000001561356234217100165620ustar00rootroot00000000000000# # cmake policies # if (CMAKE_MAJOR_VERSION GREATER 2) cmake_policy(SET CMP0042 NEW) # osx rpath endif() LASzip-3.4.3/cmake/unix_compiler_options.cmake000066400000000000000000000015701356234217100214040ustar00rootroot00000000000000set(LASZIP_COMMON_CXX_FLAGS "-Wextra -Wall -Wno-unused-parameter -Wno-unused-variable -Wpointer-arith -Wcast-qual -Wredundant-decls -Wno-long-long -Wno-unknown-pragmas -isystem /usr/local/include" ) if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") if (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.7) set(CXX_STANDARD "-std=c++0x") else() set(CXX_STANDARD "-std=c++11") endif() if (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 4.6) set(LASZIP_NO_AS_NEEDED_START "-Wl,--no-as-needed") set(LASZIP_NO_AS_NEEDED_END "-Wl,--as-needed") endif() set(LASZIP_COMPILER_GCC 1) elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set(CXX_STANDARD "-std=c++11") set(LASZIP_COMPILER_CLANG 1) else() message(FATAL_ERROR "Unsupported C++ compiler") endif() set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LASZIP_COMMON_CXX_FLAGS} ${CXX_STANDARD}") LASzip-3.4.3/cmake/win32_compiler_options.cmake000066400000000000000000000053731356234217100213700ustar00rootroot00000000000000if (MSVC) set(PDAL_COMPILER_MSVC 1) if (MSVC12) set(PDAL_COMPILER_VC12 1) elseif (MSVC11) set(PDAL_COMPILER_VC11 1) elseif (MSVC10) set(PDAL_COMPILER_VC10 1) elseif (MSVC9) set(PDAL_COMPILER_VC9 1) elseif (MSVC8) set(PDAL_COMPILER_VC8 1) endif() add_definitions(-DBOOST_ALL_NO_LIB) # check for MSVC 8+ if (NOT (MSVC_VERSION VERSION_LESS 1400)) add_definitions(-D_CRT_SECURE_NO_DEPRECATE) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_NONSTDC_NO_WARNING) add_definitions(-D_SCL_SECURE_NO_WARNINGS) add_definitions(-DNOMINMAX) # Nitro makes use of Exception Specifications, which results in # numerous warnings when compiling in MSVC. We will ignore them for # now. add_definitions("/wd4290") add_definitions("/wd4800") # Windows still warns about nameless struct/union, but we assume # that all of our compilers support this #add_definitions("/wd4201") endif() if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]") string(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3") endif() # check for MSVC 9+ if (NOT (MSVC_VERSION VERSION_LESS 1500)) include(ProcessorCount) ProcessorCount(N) if(NOT N EQUAL 0) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP${N}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${N}") endif() endif() option(PDAL_USE_STATIC_RUNTIME "Use the static runtime" FALSE) if (PDAL_USE_STATIC_RUNTIME) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MT") # Note that the CMake cache will still show /MD # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif(${flag_var} MATCHES "/MD") endforeach(flag_var) endif() endif(MSVC) add_definitions(-DWIN32_LEAN_AND_MEAN) # note we default to debug mode #if(NOT MSVC_IDE) # if(NOT CMAKE_BUILD_TYPE) # set(CMAKE_BUILD_TYPE Debug CACHE STRING # "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel" FORCE) # endif() # message(STATUS "Setting PDAL build type - ${CMAKE_BUILD_TYPE}") #endif() set(CMAKE_INCLUDE_PATH "c:/OSGeo4W64/include;$ENV{CMAKE_INCLUDE_PATH}") set(CMAKE_LIBRARY_PATH "c:/OSGeo4W64/lib;$ENV{CMAKE_LIBRARY_PATH}") set(CMAKE_PREFIX_PATH "c:/OSGeo4W64/cmake;$ENV{CMAKE_LIBRARY_PATH}") #ABELL - WHY? set(PDAL_PLATFORM_WIN32 1) LASzip-3.4.3/data/000077500000000000000000000000001356234217100136005ustar00rootroot00000000000000LASzip-3.4.3/data/broken_coder.laz000066400000000000000000000017501356234217100167470ustar00rootroot00000000000000LASFTerraScanãIe@möøI{®Gáz„?{®Gáz„?{®Gáz„?€€€È=#AÔ;#A€oqRA1qRAÍÌÌÌÌTe@ ×£p=jG@»ªlaszip encoded¼V.(c) LAStools by Martin IsenburgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÌ Âå=ÑG<cÙ=ª7A G_æHÓµÌAü’V_ù’è²×­×ûÚçÀònª¢3øîö°áž@@0ÿ¶ýMá ­4ðâ‘CGYW¤°5íìÍ%SžãºÏCFnóØmGˆ¹˜ÖÚ¨¶>äç®2`×eõùa@‰Ó)1f¯¦Ê«½é°ÜYÒÄìÁk`ä ¿-´‹ª,Qn ¿ŽæŽ¦ùÆoÈ‹Ø:áÜV:ÏFû‡àNñÉÌÒ~(t4mÆ™½Š«ˆuÏV§ÿ}vq"W6´XQvðǯð·Ðü÷%V‡5Û9ò)ÃyûiTpÑjª†ÌEu|’TÍëäå˜×ÔÍud­XÙíäܬò\ñ3íGüXê¼ËSü8äJårR@?ŽgPÈÒ¼jôŽCHÌÐt,qÀ¹K-Ï^[ m»G ™¡ÄThtA¬‰……ÀìJ_4v³ ãý.XÖ!öˆùû¥SöEP}Ô0V†2$ÉØ ëêËÛ[-b¸±P;…Ið"8ÐUaºúB¤ª<Œ ˜‘v'Póà߯™8qÊF•<Ñ»nì_ìòÚ¹Z‘H­*–VN!tç—ÈóÑ’ ø¬_§þLnÙS@W‹•¾Yãär§ë¬ÔV·°¦AÍÅE™*ÂÚØÏEð9ûa1æE;u…³©ÛŒTð¢Ÿw÷\þ¹ ý[RN _ëüœ6”&ù í:,=6¿óI8-ùF,‹qËÇ^Äæþâ¬Ý¹ñE›Šw† c|¹ØËúª3b9\zÄ)¿uê….W#%íù^Wç"ªÇ-eUê-ÞÖ/¨ÿØ£ø2K-þ18]ÿç2¾ ‘ãDñ f,ð¬[ÈI¤G —LASzip-3.4.3/data/broken_compressor.laz000066400000000000000000000017501356234217100200470ustar00rootroot00000000000000LASFTerraScanãIe@möøI{®Gáz„?{®Gáz„?{®Gáz„?€€€È=#AÔ;#A€oqRA1qRAÍÌÌÌÌTe@ ×£p=jG@»ªlaszip encoded¼V.(c) LAStools by Martin IsenburgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÌ Âå=ÑG<cÙ=ª7A G_æHÓµÌAü’V_ù’è²×­×ûÚçÀònª¢3øîö°áž@@0ÿ¶ýMá ­4ðâ‘CGYW¤°5íìÍ%SžãºÏCFnóØmGˆ¹˜ÖÚ¨¶>äç®2`×eõùa@‰Ó)1f¯¦Ê«½é°ÜYÒÄìÁk`ä ¿-´‹ª,Qn ¿ŽæŽ¦ùÆoÈ‹Ø:áÜV:ÏFû‡àNñÉÌÒ~(t4mÆ™½Š«ˆuÏV§ÿ}vq"W6´XQvðǯð·Ðü÷%V‡5Û9ò)ÃyûiTpÑjª†ÌEu|’TÍëäå˜×ÔÍud­XÙíäܬò\ñ3íGüXê¼ËSü8äJårR@?ŽgPÈÒ¼jôŽCHÌÐt,qÀ¹K-Ï^[ m»G ™¡ÄThtA¬‰……ÀìJ_4v³ ãý.XÖ!öˆùû¥SöEP}Ô0V†2$ÉØ ëêËÛ[-b¸±P;…Ið"8ÐUaºúB¤ª<Œ ˜‘v'Póà߯™8qÊF•<Ñ»nì_ìòÚ¹Z‘H­*–VN!tç—ÈóÑ’ ø¬_§þLnÙS@W‹•¾Yãär§ë¬ÔV·°¦AÍÅE™*ÂÚØÏEð9ûa1æE;u…³©ÛŒTð¢Ÿw÷\þ¹ ý[RN _ëüœ6”&ù í:,=6¿óI8-ùF,‹qËÇ^Äæþâ¬Ý¹ñE›Šw† c|¹ØËúª3b9\zÄ)¿uê….W#%íù^Wç"ªÇ-eUê-ÞÖ/¨ÿØ£ø2K-þ18]ÿç2¾ ‘ãDñ f,ð¬[ÈI¤G —LASzip-3.4.3/data/broken_size.laz000066400000000000000000000017501356234217100166250ustar00rootroot00000000000000LASFTerraScanãIe@möøI{®Gáz„?{®Gáz„?{®Gáz„?€€€È=#AÔ;#A€oqRA1qRAÍÌÌÌÌTe@ ×£p=jG@»ªlaszip encoded¼V.(c) LAStools by Martin IsenburgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÌ Âå=ÑG<cÙ=ª7A G_æHÓµÌAü’V_ù’è²×­×ûÚçÀònª¢3øîö°áž@@0ÿ¶ýMá ­4ðâ‘CGYW¤°5íìÍ%SžãºÏCFnóØmGˆ¹˜ÖÚ¨¶>äç®2`×eõùa@‰Ó)1f¯¦Ê«½é°ÜYÒÄìÁk`ä ¿-´‹ª,Qn ¿ŽæŽ¦ùÆoÈ‹Ø:áÜV:ÏFû‡àNñÉÌÒ~(t4mÆ™½Š«ˆuÏV§ÿ}vq"W6´XQvðǯð·Ðü÷%V‡5Û9ò)ÃyûiTpÑjª†ÌEu|’TÍëäå˜×ÔÍud­XÙíäܬò\ñ3íGüXê¼ËSü8äJårR@?ŽgPÈÒ¼jôŽCHÌÐt,qÀ¹K-Ï^[ m»G ™¡ÄThtA¬‰……ÀìJ_4v³ ãý.XÖ!öˆùû¥SöEP}Ô0V†2$ÉØ ëêËÛ[-b¸±P;…Ið"8ÐUaºúB¤ª<Œ ˜‘v'Póà߯™8qÊF•<Ñ»nì_ìòÚ¹Z‘H­*–VN!tç—ÈóÑ’ ø¬_§þLnÙS@W‹•¾Yãär§ë¬ÔV·°¦AÍÅE™*ÂÚØÏEð9ûa1æE;u…³©ÛŒTð¢Ÿw÷\þ¹ ý[RN _ëüœ6”&ù í:,=6¿óI8-ùF,‹qËÇ^Äæþâ¬Ý¹ñE›Šw† c|¹ØËúª3b9\zÄ)¿uê….W#%íù^Wç"ªÇ-eUê-ÞÖ/¨ÿØ£ø2K-þ18]ÿç2¾ ‘ãDñ f,ð¬[ÈI¤G —LASzip-3.4.3/data/broken_type.laz000066400000000000000000000017501356234217100166340ustar00rootroot00000000000000LASFTerraScanãIe@möøI{®Gáz„?{®Gáz„?{®Gáz„?€€€È=#AÔ;#A€oqRA1qRAÍÌÌÌÌTe@ ×£p=jG@»ªlaszip encoded¼V.(c) LAStools by Martin IsenburgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÌ Âå=ÑG<cÙ=ª7A G_æHÓµÌAü’V_ù’è²×­×ûÚçÀònª¢3øîö°áž@@0ÿ¶ýMá ­4ðâ‘CGYW¤°5íìÍ%SžãºÏCFnóØmGˆ¹˜ÖÚ¨¶>äç®2`×eõùa@‰Ó)1f¯¦Ê«½é°ÜYÒÄìÁk`ä ¿-´‹ª,Qn ¿ŽæŽ¦ùÆoÈ‹Ø:áÜV:ÏFû‡àNñÉÌÒ~(t4mÆ™½Š«ˆuÏV§ÿ}vq"W6´XQvðǯð·Ðü÷%V‡5Û9ò)ÃyûiTpÑjª†ÌEu|’TÍëäå˜×ÔÍud­XÙíäܬò\ñ3íGüXê¼ËSü8äJårR@?ŽgPÈÒ¼jôŽCHÌÐt,qÀ¹K-Ï^[ m»G ™¡ÄThtA¬‰……ÀìJ_4v³ ãý.XÖ!öˆùû¥SöEP}Ô0V†2$ÉØ ëêËÛ[-b¸±P;…Ið"8ÐUaºúB¤ª<Œ ˜‘v'Póà߯™8qÊF•<Ñ»nì_ìòÚ¹Z‘H­*–VN!tç—ÈóÑ’ ø¬_§þLnÙS@W‹•¾Yãär§ë¬ÔV·°¦AÍÅE™*ÂÚØÏEð9ûa1æE;u…³©ÛŒTð¢Ÿw÷\þ¹ ý[RN _ëüœ6”&ù í:,=6¿óI8-ùF,‹qËÇ^Äæþâ¬Ý¹ñE›Šw† c|¹ØËúª3b9\zÄ)¿uê….W#%íù^Wç"ªÇ-eUê-ÞÖ/¨ÿØ£ø2K-þ18]ÿç2¾ ‘ãDñ f,ð¬[ÈI¤G —LASzip-3.4.3/data/broken_version.laz000066400000000000000000000017501356234217100173400ustar00rootroot00000000000000LASFTerraScanãIe@möøI{®Gáz„?{®Gáz„?{®Gáz„?€€€È=#AÔ;#A€oqRA1qRAÍÌÌÌÌTe@ ×£p=jG@»ªlaszip encoded¼V.(c) LAStools by Martin IsenburgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÌ Âå=ÑG<cÙ=ª7A G_æHÓµÌAü’V_ù’è²×­×ûÚçÀònª¢3øîö°áž@@0ÿ¶ýMá ­4ðâ‘CGYW¤°5íìÍ%SžãºÏCFnóØmGˆ¹˜ÖÚ¨¶>äç®2`×eõùa@‰Ó)1f¯¦Ê«½é°ÜYÒÄìÁk`ä ¿-´‹ª,Qn ¿ŽæŽ¦ùÆoÈ‹Ø:áÜV:ÏFû‡àNñÉÌÒ~(t4mÆ™½Š«ˆuÏV§ÿ}vq"W6´XQvðǯð·Ðü÷%V‡5Û9ò)ÃyûiTpÑjª†ÌEu|’TÍëäå˜×ÔÍud­XÙíäܬò\ñ3íGüXê¼ËSü8äJårR@?ŽgPÈÒ¼jôŽCHÌÐt,qÀ¹K-Ï^[ m»G ™¡ÄThtA¬‰……ÀìJ_4v³ ãý.XÖ!öˆùû¥SöEP}Ô0V†2$ÉØ ëêËÛ[-b¸±P;…Ið"8ÐUaºúB¤ª<Œ ˜‘v'Póà߯™8qÊF•<Ñ»nì_ìòÚ¹Z‘H­*–VN!tç—ÈóÑ’ ø¬_§þLnÙS@W‹•¾Yãär§ë¬ÔV·°¦AÍÅE™*ÂÚØÏEð9ûa1æE;u…³©ÛŒTð¢Ÿw÷\þ¹ ý[RN _ëüœ6”&ù í:,=6¿óI8-ùF,‹qËÇ^Äæþâ¬Ý¹ñE›Šw† c|¹ØËúª3b9\zÄ)¿uê….W#%íù^Wç"ªÇ-eUê-ÞÖ/¨ÿØ£ø2K-þ18]ÿç2¾ ‘ãDñ f,ð¬[ÈI¤G —LASzip-3.4.3/design/000077500000000000000000000000001356234217100141405ustar00rootroot00000000000000LASzip-3.4.3/design/blueprint.rst000066400000000000000000000205231356234217100167000ustar00rootroot00000000000000LASzip for LAS 1.4 (native extension) ======== a working document -------- This document summarizes new features and implementation details that define the "native extension" of the LASzip compressor for the new point types 6 to 10 of the LAS 1.4 specification. This includes feedback from our `"Open Call for Input" `_ from early 2014 as well as ideas from out initial proposal for a joint `LAS 1.4 compressor with ESRI `_ that was presented in form of a widely circulated and loudly applauded `April Fools' Day prank `_ after months of direct communication with ESRI had failed to produce any useful progress. We should point out that the current `LASzip compressor `_ can already handle (most) LAS 1.4 files via the `"LAS 1.4 compatibility mode" `_ that was sponsored in part by NOAA, Quantum Spatial, and Trimble. However, LAS 1.4 files are likely to stay with us for a long long time. The "native extension" of LASzip seeks to exploit the "natural break" in the lineage of the LAS specification to add entirely new features to the compressor that allow better exploitation of LAS files in the cloud or on Web portals as originally planned and suggested in the `joint proposal `_. In the past ESRI has claimed to have identified very particular needs for processing LiDAR in the cloud that have warranted the development of their competing closed standard also know as the `"LAZ clone" `_. The resulting format fragmentation has `upset `_ the geospatial community and led to an `Open Letter `_ by OSGeo that has asked ESRI to change their course and work with the LiDAR users to avoid a format war. In parallel to the `on-going mediation `_ under way via the Open Geospatial Consortium (OGC) in form of a new `Point Cloud Domain Working Group `_ we are intending to progress towards a set of useful features for compressed LAS 1.4 content in the open and transparent manner, yet at the speed that the needs of our industry demands. Therefore we invite in particular ESRI to tell us what exactly they want us to include in the "native extension" of `LASzip `_ to the new point types: .. Dear ESRI, please tell us what features would you like in the native LAS 1.4 extension of LASzip? What exactly are the key differences of your own "optimized LAS" that are currently missing in LASzip? .. Some of the things that ESRI has added to "optimized LAS" are already part of LASzip and others may already be on our TODO list. So as we wait for ESRI's answer, let's already start fleshing out the feature set that the rest of the community wants to see in the new LASzip: Core Features -------- **1. Selective Decompression:** Often only a subset of all the attributes of a LiDAR return stored in the LAS format are actually needed by an application. Currently all points attributes have to be read and decompressed by an application opening a LAS or a LAZ file. This is the most far reaching new feature of the native LAS 1.4 extension of LASzip: for the new point types, it will allow reading and decompressing only those points attributes that are relevant to the application. A Web-based LiDAR viewer, for example, may only have to download, parse, and decompress the xyz coordinates and the intensities of the point cloud and a cloud-based service for DTM generation will only have to download, parse, and decompress the xyz coordinates and the classification values. **2. Variable Chunking:** Instead of having each atomic unit of points that are compressed together - a chunk - have the same size of a default 50,000 points the compressor offer the option to let each chunk have a different size. This is in particularly useful when creating point orders that support spatially indexing by rearranging them, for example, into the cells of a quad tree that are laid out along a space-filling curve. Variable chunking allows granular access to only those points of a cell that was selected for loading. Optional Features -------- **3. Tighter Integration of Spatial Indexing (likely)** Already supported in the existing LASzip compressor as an optional item this will become a mandatory part of every new LAZ file that is written. Area-of-interest queries are also a form or "selective decompression" and require two things: Knowledge where in the file the points that fall into the interesting area are located (e.g. in the seventeen point intervals [5236312,5236312], [6523634,6634523], ....) and the ability to seek in the compressed file and decompress only those point intervals. The letter has been an integral part of the LASzip compressor since day one as this was one of the core features sponsored by USACE. The first has been added after little by little to LASzip in order not to disrupt anything since the concept (i.e. LASindex and tiny LAX files) was first introduced at ELMF in 2012. The concept needs to be reworked slightly to accommodate files with over 4 billion points. **4. Re-writeable Flags and Classification (maybe, definitely via LASlayers of LASlib) ** Most of the point attribute of an LAS file will never change --- *at laest* once the LiDAR was published. The xyz coordinates are final once the LiDAR flightlines were aligned, the return counts are fix, the intensities are direct measured, and the original GPS time stamps and the point source IDs should be preserved for posterity. What often does change, however, are the point classifications into "ground", "building", "noise", or "water" points, as well as the flags describing which points are to be "withheld" or which ones are part of the not always desired "overlap". This is the second far reaching new feature of the native LAS 1.4 extension of LASzip: based on mechanisms that have already been field-tested as part of the "LASlayers" effort the new LASzip will support overriding the existing classifications or flags with a new layer of values. **4. Attach-able Attributes (maybe, more likely via LASlayers of LASlib) ** Some LiDAR processing steps create additional per-point attributes such as RGB colors or NDVI values from a different source, error estimates, or point normals. During the design process of the the native LAS 1.4 extension of LASzip we want to consider to allow adding such attributes later without requiring a complete re-write of all existing points attributes that have not changed. **5. Explode-able Files (maybe, more likely via LASlayers of LASlib) ** Selective decompression - or more importantly selective download - of large files may in some cases be more feasible to implement for a 3D Web viewer or a LiDAR service portal when the data for selectable attributes is stored for download in separate files. During the design process of the the native LAS 1.4 extension of LASzip we want to accomodate to later add the option to store one compressed LAZ file as a number of compressed files each of which encodes a different set of point attributes. **6. Specification Document (`in progress `_) ** The LASzip compressor is currently only documented via an open source reference implementation in C++. In order to create LASzip compressors and decompressors in other programming languages it is currently necessary to step through the (reasonably well documented) C++ source code. We hope that funds can be made available that allow us to hire technical writers who can create a proper `specification document `_ that describes the open LASzip compressed LiDAR format. Open Forum -------- Please join us to continue the already on-going discussion in the `"LAS room" `_ where we will finalize the feature set in an open censensus process. LASzip-3.4.3/design/specification.rst000066400000000000000000000541711356234217100175220ustar00rootroot00000000000000LASzip for LAS 1.4 (native extension) ======== Specification Document -------- As before the LASheader and the VLRs are stored uncompressed but the highest bit of the point type field is set (i.e. the compressed point types 128 to 138 correspond to the uncompressed point types 0 to 10). LiDAR points are compressed in completely independent chunks that default to 50,000 points per chunk. Each chunk can be decompressed "on its own" once the start byte is know. For point types 0 to 5 nothing changes and the same compression scheme as before is used. For the new point types 6 to 10 of LAS 1.4 there are two main changes: the chunks are encoded in layers and the chunks can have variable size. As before the first point of each chunk is stored raw. The attributes of all following points are broken into several layers. Only the first layer containing the x and y coordinates (and a few pieces of information) is mandatory to read and decompress. The remaining layers containing independently useful attributes such as elevation, intensity, classifications, flags, GPS times, colors, point source ID, user data, scan angles, wavepackets, and extra bytes do not necessarily need be decompressed (or be read from disk). Another new (or rather "revived") feature in LASzip compression for the new point types of LAS 1.4 is that it will be possible to continously vary the chunk size. This was in the design of the original LASzip coder but broke whenever the file was streamed due to missing access to the per chunk point counts during a streaming read as those were only stored in the chunk table at the very end of the LAZ file. This is fixed now (but only for the new point types) by also storing the number of points at the beginning of each chunk. LAZ File Layout: ---------------- 1. LASheader 2. VLRs + LASzip VLR 3. Sequence of n Chunks 1. Chunk 1 2. Chunk 2 3. Chunk 3 .... n. Chunk n 4. Chunk Table (chunk starts and point numbers) 5. EVLRs 6. LASindex EVLR (future feature: optional index for faster spatial queries) 7. LASlayers EVLR (future feature: for in-place edits of classifications / flags) Chunk Layout: ------------- 1) Raw point [30 - 68 (or more) bytes] 2) Numbers and Bytes + Number of *remaining* points [4 bytes] + Number of bytes (maybe compressed) - scanner channel, point source ID change, GPS time change, scan angle change, return counts, and XY layer [4 bytes] - Z layer [4 bytes] - classification layer [4 byte] - flags layer [4 bytes] - intensity layer [4 bytes] - scan angle layer [4 bytes] - user data layer [4 bytes] - point source ID layer [4bytes] - GPS time layer [4 bytes] optional - RGB layer [4 bytes] - NIR layer [4 bytes] - WavePacket layer [4 bytes] - "Extra Bytes" layer [4 bytes per byte] 3) Layers - scanner channel, point source ID change, GPS time change, scan angle change, return counts, and XY layer - Z layer - classification layer - flags layer - intensity layer - scan angle layer - user data layer - point source ID layer - GPS time layer optional - RGB layer - NIR layer - WavePacket layer - "Extra Bytes" layer(s) Compression of scanner channel, point source ID change, GPS time change, scan angle change, return counts, and XY layer ----------------------------------------------------------------------------- Due to the new scanner channel it is *crucial* to first encode whether a point is from the same and if not from which other scanner channel so that the correct context can be used for all subsequent predictions. We also encode whether a point has a a different point source ID, a different GPS time, and a different scan angle as the previous point from the same scanner channel as these changes correlate strongly with another. The return counts that are also recorded in this layer. * scanner channel compared to the scanner channel of the previous point (same = 0 / different = 1) * point source ID compared to the point source ID of the previous point from the *same* scanner channel (same = 0 / different = 1) * GPS time stamp compared to the GPS time stamp of the previous point from the *same* scanner channel (same = 0 / different = 1) * scan angle compared to the scan angle of the previous point from the *same* scanner channel (same = 0 / different = 1) * number of returns compared to the number of returns of the previous point from the *same* scanner channel (same = 0 / different = 1) * return number compared to the return number of the previous point from the *same* scanner channel (same = 0 / plus one = 1 / minus one = 2 / other difference = 3) These 7 bits of information are combined into one symbol whose value ranges from 0 to 127 that we then compress with one of four (4) different contexts based on whether the *directly* previous point (no matter from which scanner channel) was a single return (0), or the first (1), the last (2) or the intermediate (3) return in case of multi-return. Only if the **scanner channel is different** (as indicated by these 7 bits) we use one symbol whose value ranges from 0 to 2 to encode whether we need to add 1, 2, or 3 to the previous scanner channel to get (modulo 4) to the current scanner channel that we then compress using the previous scanner channel as one of four different contexts. All following predictions in all different layers are relative to the previous point from the *same* scanner channel. They first check whether the current point is from the same scanner channel and switch context if not. If no previous point exists for the new scanner channel (because this scanner channel appears the first time in this chunk) then the previous point (from whichever other scanner channel) is used. For the very first point per chunk *that gets compressed* this is that one point that is stored raw at the beginning of every chunk. Only if the **number of returns has an other difference** (as indicated by the 7 bits earlier) we use one symbol whose value ranges from 0 to 15 that we then compress with the previous number of returns (from the same scanner channel) as one of sixteen contexts. Only if the **return number is different** (as indicated by the 7 bits earlier) we encode in in two possible ways depending on whether the GPS time stamp has changed: - if the GPS time stamp *has not* changed we use one symbol whose value ranges from 0 to 12 to encode whether we need to add 2, 3, 4 ... 12, 13 or 14 to the previous return number (from the same scanner channel) to get (modulo 16) to the current return number that we then compress using the previous return number (from the same scanner channel) as one of sixteen contexts. - if the GPS time stamp *has* changed we use one symbol whose value ranges from 0 to 15 to encode the current return number that we then compress with the (already encoded) number of returns as one of sixteen contexts. Next we use the number of returns n and the return number r to to derive two numbers between 0 and 15 that are used for switching contexts later: a *return map m* and *a return level l*. The *return map m* simply serializes the valid combinations of r and n: for r = 1 and n = 1 it is 0, for r = 1 and n = 2 it is 1, for r = 2 and n = 2 it is 2, for r = 1 and n = 3 it is 3, for r = 2 and n = 3 it is 4, for r = 3 and n = 3 it is 5, for r = 1 and n = 4 it is 6, etc. Unfortunately, some LAS files start numbering r and n at 0, only have return numbers r, or only have number of return of given pulse counts n. We therefore complete the table to also map invalid combinations to be used as a context. Furthermore with up to 15 returns there would be too many different combinations (namely 120). Therefore we map combinations of many returns pulses to the same number m and also complete the table for all combinations of r and n as shown below: const U8 number_return_map_4bit[16][16] = { { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, { 14, 0, 1, 3, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, { 13, 1, 2, 4, 7, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10 }, { 12, 3, 4, 5, 8, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11 }, { 11, 6, 7, 8, 9, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 11 }, { 10, 10, 11, 12, 13, 14, 14, 13, 13, 12, 12, 12, 12, 12, 12, 12 }, { 9, 10, 11, 12, 13, 14, 15, 14, 13, 13, 13, 12, 12, 12, 12, 12 }, { 8, 10, 11, 12, 12, 13, 14, 15, 14, 13, 13, 13, 13, 12, 12, 12 }, { 7, 10, 11, 12, 12, 13, 13, 14, 15, 14, 14, 13, 13, 13, 13, 13 }, { 6, 10, 11, 11, 12, 12, 13, 13, 14, 15, 14, 14, 14, 13, 13, 13 }, { 5, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 14, 14, 14, 13, 13 }, { 4, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 14, 14, 14 }, { 3, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 14, 14 }, { 2, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 14 }, { 1, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15 }, { 0, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15 } }; However. This turned out to give too many contexts resulting in many tables and hardly used prediction models. Therefore the above table was finally simplified to only map to 6 different contexts. const U8 number_return_map_6ctx[16][16] = { { 0, 1, 2, 3, 4, 5, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5 }, { 1, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, { 2, 1, 2, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3 }, { 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 3, 3, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5 } }; The *return level l* specifies how many returns there have already been for a given pulse prior to this return. Given only valid combinations for the return number r and the number of returns of given pulse n we could compute it as l = n − r. But we again use a completed look-up table as shown below to map invalid combinations for r and l to different contexts. const U8 number_return_level_4bit[16][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 14, 15 }, { 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 14 }, { 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12 }, { 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, { 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, { 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8 }, { 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7 }, { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6 }, { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5 }, { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4 }, { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3 }, { 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2 }, { 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1 }, { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } }; However. This turned out to give too many contexts resulting in many tables and hardly used prediction models. Therefore the above table was simplified to only map to 8 different contexts. const U8 number_return_level_8ctx[16][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, { 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7 }, { 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7 }, { 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7 }, { 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7 }, { 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7 }, { 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7 }, { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7 }, { 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7 }, { 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6 }, { 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5 }, { 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4 }, { 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3 }, { 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2 }, { 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1 }, { 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0 } }; We also create a simple return context 'cpr' with four values for the *current point* that is used after its return number and its number of returns were compressed. Its values are single = 3, first = 1, last = 2, and intermediate = 0 and it is computed: I32 cpr = (r == 1 ? 2 : 0); // is first ? cpr += (r >= n ? 1 : 0); // is last ? We encode the X and Y coordinates with a second order predictor. We predict the differences dX and dY to the X and Y coordinates of the previous point from the same scanner channel with recently occuring differences. We predicts dX and dY between as the median of the five immediately preceding differences of points from the scanner channel and with the same return map m. The intuition behind this is, for example, that single returns are always from a different laser pulse than the previous point and therefore have a wider spacing in X and/or Y than the middle of three returns. Compression of classification layer ----------------------------------- We compress the classification as a symbol between 0 and 255 using 64 different context. This context is computed as the five lowest bits of the classification of the previous point (from the same scanner channel) multiplied by two plus one when the previous point (from the same scanner channel) was a single return. Compression of flags layer -------------------------- We compress the classification as a 6 bit number or a symbol between 0 and 63 using 64 different context. The highest bit is the 'edge_of_flight_line' flag. The second higest bit is the 'scan_direction' flag. The lowest four bits are the four classification flags in the order listed in the LAS 1.4 specification. The context is simply the 6 bit number that represented the flags of the previous point (from the same scanner channel). Compression of intensity layer ------------------------------ We compress the intensity with the difference integer compressor using four contexts that is simply the 'cpr' defined earlier. We use one of 8 possible previous intensities as the prediction. Which one is used is decided by the 'cpr' multiplied by two plus one if the GPS time in respect to the previous point (from the same scanner channel) has changed. All eight possible previous intensities are initialized to the intensity of the first point (from the same scanner channel) and updated after the intensity was compressed. Compression of scan angle layer ------------------------------ Only if the **scan angle is different** (as indicated by the 7 bits earlier) we compress it with the difference integer compressor using two contexts that is whether the GPS time stamp of the previous point (from the same scanner channel) has changed (1) or not (0). We use the scan angle of the previous point (from the same scanner channel) as the prediction. Compression of user data layer ------------------------------ We compress the user data layer which is an 8 bit number as a symbol between 0 and 255 using 64 different contexts. The context is simply the user data of the previous point (from the same scanner channel) divided by 4. Compression of point source ID layer ------------------------------ Only if the **point source ID is different** (as indicated by the 7 bits earlier) we compress Compression of GPS time layer ----------------------------- Only if the **GPS time is different** (as indicated by the 7 bits earlier) we compress it the same way it was done in the old LASzip coder. The GPS times of a single flight line stored in aquisition order are a monotonically increasing sequence of double-precision floating-point numbers where returns of the same pulse have the same GPS time and where subsequent pulses have a more or less constant spacing in time. LASzip treats the double-precision floating-point GPS times as signed 64 bit integers and predicts the deltas between them. We store up to four previously compressed GPS times with corresponding deltas to account for repeated jumps in GPS times that can arise when multiple flight paths are merged with fine spatial granularity. Nothing needs to be encoded when the GPS times are identical. Otherwise we distinguishes several cases that are entropy coded with 515 symbols depending on if the current GPS time is + 0–500 : predicted using the current delta times 0 to 500. + 501–510 : predicted using the current delta times -1 to -10. + 511 : starting a new context. + 512–514 : predicted with one of the other three contexts. For the first two cases we subsequently difference code the delta prediction and the actual delta. We starts a new context when the delta overflows a 32 bit integer. For that it difference codes the 32 higher bits of the current GPS time and the current context and stores the lower 32 bits raw. Otherwise it switches to the specified context (where the delta will not overflows a 32 bit integer) and recurses. The current deltas stored with each context are updated to the actual delta when they were outside the predictable range more than 3 consecutive times (i.e. bigger than 500 times the current delta, smaller than -10 times the current delta, or zero). Compression of RGB layer ------------------------------ We compress the RGB values the same way it was done in the old LASzip coder. LAS uses unsigned 16 bit integers for the R, G, and B channel. Some files—incorrectly—populate only the lower 8 bits so that the upper 8 bits are zero. Other files correctly multiply 8-bit colors with 256 so that the lower 8 bits are zero. The LASzip compressor therefore compresses the upper and lower byte of each channel separately. First it entropy codes (a) 6 bits that specify which of the six bytes have changed in comparison to the previous point (from the same scanner channel) and (b) one bit that specifies whether those changes are the same in all three channels (i.e. grey colors) as one symbol between 0 and 127. For all bytes that have changed it then entropy codes the difference to the respective previous byte (of the point from the same scanner channel) modulo 256. If the 7 bit symbol indicates that the changes are identical in all three channels only the R channel is compressed. Otherwise the channels are encoded in the order R, G, and B. Differences encoded in earlier channels are used to predict differences in later channels as there tends to be a correlation in the intensity across channels. For example, if there was a byte difference in the low byte of the R channel that difference is added to low byte of the G channel which - clamped to a 0 to 255 range - becomes the value to which the difference of the current low byte is computed. Compression of NIR layer ------------------------------ We compress the NIR value using the same technique as done for the RGB values. First it entropy codes 2 bits that specify which bytes have changed as one symbol. For all bytes that have changed it then entropy codes the difference to the respective previous byte (of the point from the same scanner channel) modulo 256. Compression of WavePacket layer ------------------------------ We compress the WavePackets the same way it was done in the old LASzip coder. They only occur in point types 9 and 10. So far there has been very little real-world demand for compressing LAS files containing waveform data simply due to a lack of data stored in this format (i.e. there is no a dedicated format for full waveform LiDAR called 'PulseWaves'). LASzip simply entropy codes the wave packet descriptor index, an unsigned byte that is zero if a point has no waveform and indexes the variable length record describing the format of the waveform otherwise. To compress the bytes offset to waveform data it entropy encodes one of 4 possible cases: 1) same as last offset 2) use last offset plus last packet size 3) difference to last offset is less than 32 bits 4) difference to last offset is more than 32 bits In the first two cases no other information is needed. For the other two cases LASzip difference codes the 32 or the 64 bit numbers. The LASzip compressor difference coded all remaining fields. Only waveform packet size in bytes is an integer number. The return point waveform location, x(t), y(t), and z(t) are single-precision floating-point numbers whose 32 bits are treated as if they were a 32-bit integer. Compression of "Extra Bytes" layer(s) ------------------------------ We compress the "Extra Bytes" the same way it was done in the old LASzip coder but each byte is compressed into its own layer. A LAS point has “Extra Bytes†when the LAS header specifies a point size larger than required by the respective point type. Each “Extra Byte†is entropy encoded with its own context as the difference to the “Extra Byte†from the previous point (from the same scanner channel) modulo 256. Treating them as individual bytes is the best that the LASzip compressor can do as there is not always a description what these “Extra Bytes†may mean. Six “extra bytesâ€, for example, could be a single-precision float storing the echo width followed by an unsigned short storing the normalized reflectivity. Or it could be an unsigned short storing a tile index followed by an unsigned integer storing the original index of the point. LASzip-3.4.3/dll/000077500000000000000000000000001356234217100134425ustar00rootroot00000000000000LASzip-3.4.3/dll/CMakeLists.txt000066400000000000000000000003111356234217100161750ustar00rootroot00000000000000 set(LASZIP_API_SOURCES laszip_api.c ) LASZIP_ADD_LIBRARY(${LASZIP_API_LIB_NAME} ${LASZIP_API_SOURCES}) LASZIP_ADD_INCLUDES("laszip" "${LASZIP_HEADERS_DIR}/laszip_api.h" ${LASZIP_API_VERSION_H}) LASzip-3.4.3/dll/laszip_api.c000066400000000000000000001062421356234217100157460ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_api.c CONTENTS: A simple set of linkable function signatures for the DLL of LASzip PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ #include // DLL function definitions #ifdef __cplusplus extern "C" { #endif /*---------------------------------------------------------------------------*/ /*---------------- DLL functions to manage the LASzip DLL -------------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_version_def) ( laszip_U8* version_major , laszip_U8* version_minor , laszip_U16* version_revision , laszip_U32* version_build ); laszip_get_version_def laszip_get_version_ptr = 0; LASZIP_API laszip_I32 laszip_get_version ( laszip_U8* version_major , laszip_U8* version_minor , laszip_U16* version_revision , laszip_U32* version_build ) { if (laszip_get_version_ptr) { return (*laszip_get_version_ptr)(version_major, version_minor, version_revision, version_build); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_create_def) ( laszip_POINTER* pointer ); laszip_create_def laszip_create_ptr = 0; LASZIP_API laszip_I32 laszip_create ( laszip_POINTER* pointer ) { if (laszip_create_ptr) { return (*laszip_create_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_clean_def) ( laszip_POINTER pointer ); laszip_clean_def laszip_clean_ptr = 0; LASZIP_API laszip_I32 laszip_clean ( laszip_POINTER pointer ) { if (laszip_clean_ptr) { return (*laszip_clean_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_error_def) ( laszip_POINTER pointer , laszip_CHAR** error ); laszip_get_error_def laszip_get_error_ptr = 0; LASZIP_API laszip_I32 laszip_get_error ( laszip_POINTER pointer , laszip_CHAR** error ) { if (laszip_get_error_ptr) { return (*laszip_get_error_ptr)(pointer, error); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_warning_def) ( laszip_POINTER pointer , laszip_CHAR** warning ); laszip_get_warning_def laszip_get_warning_ptr = 0; LASZIP_API laszip_I32 laszip_get_warning ( laszip_POINTER pointer , laszip_CHAR** warning ) { if (laszip_get_warning_ptr) { return (*laszip_get_warning_ptr)(pointer, warning); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_destroy_def) ( laszip_POINTER pointer ); laszip_destroy_def laszip_destroy_ptr = 0; LASZIP_API laszip_I32 laszip_destroy ( laszip_POINTER pointer ) { if (laszip_destroy_ptr) { return (*laszip_destroy_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ /*---------- DLL functions to write and read LAS and LAZ files --------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_header_pointer_def) ( laszip_POINTER pointer , laszip_header_struct** header_pointer ); laszip_get_header_pointer_def laszip_get_header_pointer_ptr = 0; LASZIP_API laszip_I32 laszip_get_header_pointer ( laszip_POINTER pointer , laszip_header_struct** header_pointer ) { if (laszip_get_header_pointer_ptr) { return (*laszip_get_header_pointer_ptr)(pointer, header_pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_point_pointer_def) ( laszip_POINTER pointer , laszip_point_struct** point_pointer ); laszip_get_point_pointer_def laszip_get_point_pointer_ptr = 0; LASZIP_API laszip_I32 laszip_get_point_pointer ( laszip_POINTER pointer , laszip_point_struct** point_pointer ) { if (laszip_get_point_pointer_ptr) { return (*laszip_get_point_pointer_ptr)(pointer, point_pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_point_count_def) ( laszip_POINTER pointer , laszip_I64* point_count ); laszip_get_point_count_def laszip_get_point_count_ptr = 0; LASZIP_API laszip_I32 laszip_get_point_count ( laszip_POINTER pointer , laszip_I64* point_count ) { if (laszip_get_point_count_ptr) { return (*laszip_get_point_count_ptr)(pointer, point_count); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_header_def) ( laszip_POINTER pointer , const laszip_header_struct* header ); laszip_set_header_def laszip_set_header_ptr = 0; LASZIP_API laszip_I32 laszip_set_header ( laszip_POINTER pointer , const laszip_header_struct* header ) { if (laszip_set_header_ptr) { return (*laszip_set_header_ptr)(pointer, header); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_point_type_and_size_def) ( laszip_POINTER pointer , laszip_U8 point_type , laszip_U16 point_size ); laszip_set_point_type_and_size_def laszip_set_point_type_and_size_ptr = 0; LASZIP_API laszip_I32 laszip_set_point_type_and_size ( laszip_POINTER pointer , laszip_U8 point_type , laszip_U16 point_size ) { if (laszip_set_point_type_and_size_ptr) { return (*laszip_set_point_type_and_size_ptr)(pointer, point_type, point_size); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_check_for_integer_overflow_def) ( laszip_POINTER pointer ); laszip_check_for_integer_overflow_def laszip_check_for_integer_overflow_ptr = 0; LASZIP_API laszip_I32 laszip_check_for_integer_overflow ( laszip_POINTER pointer ) { if (laszip_check_for_integer_overflow_ptr) { return (*laszip_check_for_integer_overflow_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_auto_offset_def) ( laszip_POINTER pointer ); laszip_auto_offset_def laszip_auto_offset_ptr = 0; LASZIP_API laszip_I32 laszip_auto_offset ( laszip_POINTER pointer ) { if (laszip_auto_offset_ptr) { return (*laszip_auto_offset_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_point_def) ( laszip_POINTER pointer , const laszip_point_struct* point ); laszip_set_point_def laszip_set_point_ptr = 0; LASZIP_API laszip_I32 laszip_set_point ( laszip_POINTER pointer , const laszip_point_struct* point ) { if (laszip_set_point_ptr) { return (*laszip_set_point_ptr)(pointer, point); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_coordinates_def) ( laszip_POINTER pointer , const laszip_F64* coordinates ); laszip_set_coordinates_def laszip_set_coordinates_ptr = 0; LASZIP_API laszip_I32 laszip_set_coordinates ( laszip_POINTER pointer , const laszip_F64* coordinates ) { if (laszip_set_coordinates_ptr) { return (*laszip_set_coordinates_ptr)(pointer, coordinates); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_get_coordinates_def) ( laszip_POINTER pointer , laszip_F64* coordinates ); laszip_get_coordinates_def laszip_get_coordinates_ptr = 0; LASZIP_API laszip_I32 laszip_get_coordinates ( laszip_POINTER pointer , laszip_F64* coordinates ) { if (laszip_get_coordinates_ptr) { return (*laszip_get_coordinates_ptr)(pointer, coordinates); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_geokeys_def) ( laszip_POINTER pointer , laszip_U32 number , const laszip_geokey_struct* key_entries ); laszip_set_geokeys_def laszip_set_geokeys_ptr = 0; LASZIP_API laszip_I32 laszip_set_geokeys ( laszip_POINTER pointer , laszip_U32 number , const laszip_geokey_struct* key_entries ) { if (laszip_set_geokeys_ptr) { return (*laszip_set_geokeys_ptr)(pointer, number, key_entries); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_geodouble_params_def) ( laszip_POINTER pointer , laszip_U32 number , const laszip_F64* geodouble_params ); laszip_set_geodouble_params_def laszip_set_geodouble_params_ptr = 0; LASZIP_API laszip_I32 laszip_set_geodouble_params ( laszip_POINTER pointer , laszip_U32 number , const laszip_F64* geodouble_params ) { if (laszip_set_geodouble_params_ptr) { return (*laszip_set_geodouble_params_ptr)(pointer, number, geodouble_params); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_geoascii_params_def) ( laszip_POINTER pointer , laszip_U32 number , const laszip_CHAR* geoascii_params ); laszip_set_geoascii_params_def laszip_set_geoascii_params_ptr = 0; LASZIP_API laszip_I32 laszip_set_geoascii_params ( laszip_POINTER pointer , laszip_U32 number , const laszip_CHAR* geoascii_params ) { if (laszip_set_geoascii_params_ptr) { return (*laszip_set_geoascii_params_ptr)(pointer, number, geoascii_params); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_add_attribute_def) ( laszip_POINTER pointer , laszip_U32 type , const laszip_CHAR* name , const laszip_CHAR* description , laszip_F64 scale , laszip_F64 offset ); laszip_add_attribute_def laszip_add_attribute_ptr = 0; LASZIP_API laszip_I32 laszip_add_attribute ( laszip_POINTER pointer , laszip_U32 type , const laszip_CHAR* name , const laszip_CHAR* description , laszip_F64 scale , laszip_F64 offset ) { if (laszip_add_attribute_ptr) { return (*laszip_add_attribute_ptr)(pointer, type, name, description, scale, offset); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_add_vlr_def) ( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id , laszip_U16 record_length_after_header , const laszip_CHAR* description , const laszip_U8* data ); laszip_add_vlr_def laszip_add_vlr_ptr = 0; LASZIP_API laszip_I32 laszip_add_vlr ( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id , laszip_U16 record_length_after_header , const laszip_CHAR* description , const laszip_U8* data ) { if (laszip_add_vlr_ptr) { return (*laszip_add_vlr_ptr)(pointer, user_id, record_id, record_length_after_header, description, data); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_remove_vlr_def) ( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id ); laszip_remove_vlr_def laszip_remove_vlr_ptr = 0; LASZIP_API laszip_I32 laszip_remove_vlr ( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id ) { if (laszip_remove_vlr_ptr) { return (*laszip_remove_vlr_ptr)(pointer, user_id, record_id); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_create_spatial_index_def) ( laszip_POINTER pointer , const laszip_BOOL create , const laszip_BOOL append ); laszip_create_spatial_index_def laszip_create_spatial_index_ptr = 0; LASZIP_API laszip_I32 laszip_create_spatial_index ( laszip_POINTER pointer , const laszip_BOOL create , const laszip_BOOL append ) { if (laszip_create_spatial_index_ptr) { return (*laszip_create_spatial_index_ptr)(pointer, create, append); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_preserve_generating_software_def) ( laszip_POINTER pointer , const laszip_BOOL preserve ); laszip_preserve_generating_software_def laszip_preserve_generating_software_ptr = 0; LASZIP_API laszip_I32 laszip_preserve_generating_software ( laszip_POINTER pointer , const laszip_BOOL preserve ) { if (laszip_preserve_generating_software_ptr) { return (*laszip_preserve_generating_software_ptr)(pointer, preserve); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_request_native_extension_def) ( laszip_POINTER pointer , const laszip_BOOL request ); laszip_request_native_extension_def laszip_request_native_extension_ptr = 0; LASZIP_API laszip_I32 laszip_request_native_extension ( laszip_POINTER pointer , const laszip_BOOL request ) { if (laszip_request_native_extension_ptr) { return (*laszip_request_native_extension_ptr)(pointer, request); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_request_compatibility_mode_def) ( laszip_POINTER pointer , const laszip_BOOL request ); laszip_request_compatibility_mode_def laszip_request_compatibility_mode_ptr = 0; LASZIP_API laszip_I32 laszip_request_compatibility_mode ( laszip_POINTER pointer , const laszip_BOOL request ) { if (laszip_request_compatibility_mode_ptr) { return (*laszip_request_compatibility_mode_ptr)(pointer, request); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_set_chunk_size_def) ( laszip_POINTER pointer , const laszip_U32 chunk_size ); laszip_set_chunk_size_def laszip_set_chunk_size_ptr = 0; LASZIP_API laszip_I32 laszip_set_chunk_size ( laszip_POINTER pointer , const laszip_U32 chunk_size ) { if (laszip_set_chunk_size_ptr) { return (*laszip_set_chunk_size_ptr)(pointer, chunk_size); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_open_writer_def) ( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL compress ); laszip_open_writer_def laszip_open_writer_ptr = 0; LASZIP_API laszip_I32 laszip_open_writer ( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL compress ) { if (laszip_open_writer_ptr) { return (*laszip_open_writer_ptr)(pointer, file_name, compress); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_write_point_def) ( laszip_POINTER pointer ); laszip_write_point_def laszip_write_point_ptr = 0; LASZIP_API laszip_I32 laszip_write_point ( laszip_POINTER pointer ) { if (laszip_write_point_ptr) { return (*laszip_write_point_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_write_indexed_point_def) ( laszip_POINTER pointer ); laszip_write_indexed_point_def laszip_write_indexed_point_ptr = 0; LASZIP_API laszip_I32 laszip_write_indexed_point ( laszip_POINTER pointer ) { if (laszip_write_indexed_point_ptr) { return (*laszip_write_indexed_point_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_update_inventory_def) ( laszip_POINTER pointer ); laszip_update_inventory_def laszip_update_inventory_ptr = 0; LASZIP_API laszip_I32 laszip_update_inventory ( laszip_POINTER pointer ) { if (laszip_update_inventory_ptr) { return (*laszip_update_inventory_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_close_writer_def) ( laszip_POINTER pointer ); laszip_close_writer_def laszip_close_writer_ptr = 0; LASZIP_API laszip_I32 laszip_close_writer ( laszip_POINTER pointer ) { if (laszip_close_writer_ptr) { return (*laszip_close_writer_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_exploit_spatial_index_def) ( laszip_POINTER pointer , const laszip_BOOL exploit ); laszip_exploit_spatial_index_def laszip_exploit_spatial_index_ptr = 0; LASZIP_API laszip_I32 laszip_exploit_spatial_index ( laszip_POINTER pointer , const laszip_BOOL exploit ) { if (laszip_exploit_spatial_index_ptr) { return (*laszip_exploit_spatial_index_ptr)(pointer, exploit); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_decompress_selective_def) ( laszip_POINTER pointer , const laszip_U32 decompress_selective ); laszip_decompress_selective_def laszip_decompress_selective_ptr = 0; LASZIP_API laszip_I32 laszip_decompress_selective ( laszip_POINTER pointer , const laszip_U32 decompress_selective ) { if (laszip_decompress_selective_ptr) { return (*laszip_decompress_selective_ptr)(pointer, decompress_selective); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_open_reader_def) ( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL* is_compressed ); laszip_open_reader_def laszip_open_reader_ptr = 0; LASZIP_API laszip_I32 laszip_open_reader ( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL* is_compressed ) { if (laszip_open_reader_ptr) { return (*laszip_open_reader_ptr)(pointer, file_name, is_compressed); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_has_spatial_index_def) ( laszip_POINTER pointer , laszip_BOOL* is_compressed , laszip_BOOL* is_appended ); laszip_has_spatial_index_def laszip_has_spatial_index_ptr = 0; LASZIP_API laszip_I32 laszip_has_spatial_index ( laszip_POINTER pointer , laszip_BOOL* is_compressed , laszip_BOOL* is_appended ) { if (laszip_has_spatial_index_ptr) { return (*laszip_has_spatial_index_ptr)(pointer, is_compressed, is_appended); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_inside_rectangle_def) ( laszip_POINTER pointer , laszip_F64 r_min_x , laszip_F64 r_min_y , laszip_F64 r_max_x , laszip_F64 r_max_y , laszip_BOOL* is_empty ); laszip_inside_rectangle_def laszip_inside_rectangle_ptr = 0; LASZIP_API laszip_I32 laszip_inside_rectangle ( laszip_POINTER pointer , laszip_F64 r_min_x , laszip_F64 r_min_y , laszip_F64 r_max_x , laszip_F64 r_max_y , laszip_BOOL* is_empty ) { if (laszip_inside_rectangle_ptr) { return (*laszip_inside_rectangle_ptr)(pointer, r_min_x, r_min_y, r_max_x, r_max_y, is_empty); } return 1; }; /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_seek_point_def) ( laszip_POINTER pointer , laszip_I64 index ); laszip_seek_point_def laszip_seek_point_ptr = 0; LASZIP_API laszip_I32 laszip_seek_point( laszip_POINTER pointer , laszip_I64 index ) { if (laszip_seek_point_ptr) { return (*laszip_seek_point_ptr)(pointer, index); } return 1; } /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_read_point_def) ( laszip_POINTER pointer ); laszip_read_point_def laszip_read_point_ptr = 0; LASZIP_API laszip_I32 laszip_read_point( laszip_POINTER pointer ) { if (laszip_read_point_ptr) { return (*laszip_read_point_ptr)(pointer); } return 1; } /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_read_inside_point_def) ( laszip_POINTER pointer , laszip_BOOL* is_done ); laszip_read_inside_point_def laszip_read_inside_point_ptr = 0; LASZIP_API laszip_I32 laszip_read_inside_point( laszip_POINTER pointer , laszip_BOOL* is_done ) { if (laszip_read_inside_point_ptr) { return (*laszip_read_inside_point_ptr)(pointer, is_done); } return 1; } /*---------------------------------------------------------------------------*/ typedef laszip_I32 (*laszip_close_reader_def) ( laszip_POINTER pointer ); laszip_close_reader_def laszip_close_reader_ptr = 0; LASZIP_API laszip_I32 laszip_close_reader ( laszip_POINTER pointer ) { if (laszip_close_reader_ptr) { return (*laszip_close_reader_ptr)(pointer); } return 1; }; /*---------------------------------------------------------------------------*/ /*---------------- DLL functions to load and unload LASzip ------------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ #ifdef _WIN32 #include #define FreeLibraryZeroMeansFail 1 #else #include typedef void* HINSTANCE; #ifndef NULL #define NULL 0 #endif #define LoadLibrary dlopen #define GetProcAddress dlsym #define FreeLibrary dlclose #define FreeLibraryZeroMeansFail 0 #define TEXT #endif static HINSTANCE laszip_HINSTANCE = NULL; laszip_I32 laszip_load_dll() { // Assure DLL not yet loaded if (laszip_HINSTANCE != NULL) { return 1; } // Load DLL file #ifdef _WIN32 #ifdef _WIN64 laszip_HINSTANCE = LoadLibrary(TEXT("LASzip64.dll")); #else laszip_HINSTANCE = LoadLibrary(TEXT("LASzip.dll")); #endif // _WIN64 #elif __APPLE__ laszip_HINSTANCE = LoadLibrary("liblaszip.dylib", RTLD_NOW); #else laszip_HINSTANCE = LoadLibrary("liblaszip.so", RTLD_NOW); #endif if (laszip_HINSTANCE == NULL) { return 1; } // Get function pointers laszip_get_version_ptr = (laszip_get_version_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_version"); if (laszip_get_version_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_create_ptr = (laszip_create_def)GetProcAddress(laszip_HINSTANCE, "laszip_create"); if (laszip_create_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_clean_ptr = (laszip_clean_def)GetProcAddress(laszip_HINSTANCE, "laszip_clean"); if (laszip_clean_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_error_ptr = (laszip_get_error_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_error"); if (laszip_get_error_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_warning_ptr = (laszip_get_warning_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_warning"); if (laszip_get_warning_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_destroy_ptr = (laszip_destroy_def)GetProcAddress(laszip_HINSTANCE, "laszip_destroy"); if (laszip_destroy_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_header_pointer_ptr = (laszip_get_header_pointer_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_header_pointer"); if (laszip_get_header_pointer_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_point_pointer_ptr = (laszip_get_point_pointer_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_point_pointer"); if (laszip_get_point_pointer_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_point_count_ptr = (laszip_get_point_count_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_point_count"); if (laszip_get_point_count_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_header_ptr = (laszip_set_header_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_header"); if (laszip_set_header_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_point_type_and_size_ptr = (laszip_set_point_type_and_size_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_point_type_and_size"); if (laszip_set_point_type_and_size_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_check_for_integer_overflow_ptr = (laszip_check_for_integer_overflow_def)GetProcAddress(laszip_HINSTANCE, "laszip_check_for_integer_overflow"); if (laszip_check_for_integer_overflow_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_auto_offset_ptr = (laszip_auto_offset_def)GetProcAddress(laszip_HINSTANCE, "laszip_auto_offset"); if (laszip_auto_offset_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_point_ptr = (laszip_set_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_point"); if (laszip_set_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_coordinates_ptr = (laszip_set_coordinates_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_coordinates"); if (laszip_set_coordinates_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_get_coordinates_ptr = (laszip_get_coordinates_def)GetProcAddress(laszip_HINSTANCE, "laszip_get_coordinates"); if (laszip_get_coordinates_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_geokeys_ptr = (laszip_set_geokeys_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_geokeys"); if (laszip_set_geokeys_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_geodouble_params_ptr = (laszip_set_geodouble_params_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_geodouble_params"); if (laszip_set_geodouble_params_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_geoascii_params_ptr = (laszip_set_geoascii_params_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_geoascii_params"); if (laszip_set_geoascii_params_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_add_attribute_ptr = (laszip_add_attribute_def)GetProcAddress(laszip_HINSTANCE, "laszip_add_attribute"); if (laszip_add_attribute_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_add_vlr_ptr = (laszip_add_vlr_def)GetProcAddress(laszip_HINSTANCE, "laszip_add_vlr"); if (laszip_add_vlr_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_remove_vlr_ptr = (laszip_remove_vlr_def)GetProcAddress(laszip_HINSTANCE, "laszip_remove_vlr"); if (laszip_remove_vlr_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_create_spatial_index_ptr = (laszip_create_spatial_index_def)GetProcAddress(laszip_HINSTANCE, "laszip_create_spatial_index"); if (laszip_create_spatial_index_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_preserve_generating_software_ptr = (laszip_preserve_generating_software_def)GetProcAddress(laszip_HINSTANCE, "laszip_preserve_generating_software"); if (laszip_preserve_generating_software_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_request_native_extension_ptr = (laszip_request_native_extension_def)GetProcAddress(laszip_HINSTANCE, "laszip_request_native_extension"); if (laszip_request_native_extension_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_request_compatibility_mode_ptr = (laszip_request_compatibility_mode_def)GetProcAddress(laszip_HINSTANCE, "laszip_request_compatibility_mode"); if (laszip_request_compatibility_mode_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_set_chunk_size_ptr = (laszip_set_chunk_size_def)GetProcAddress(laszip_HINSTANCE, "laszip_set_chunk_size"); if (laszip_set_chunk_size_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_open_writer_ptr = (laszip_open_writer_def)GetProcAddress(laszip_HINSTANCE, "laszip_open_writer"); if (laszip_open_writer_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_write_point_ptr = (laszip_write_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_write_point"); if (laszip_write_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_write_indexed_point_ptr = (laszip_write_indexed_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_write_indexed_point"); if (laszip_write_indexed_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_update_inventory_ptr = (laszip_update_inventory_def)GetProcAddress(laszip_HINSTANCE, "laszip_update_inventory"); if (laszip_update_inventory_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_close_writer_ptr = (laszip_close_writer_def)GetProcAddress(laszip_HINSTANCE, "laszip_close_writer"); if (laszip_close_writer_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_exploit_spatial_index_ptr = (laszip_exploit_spatial_index_def)GetProcAddress(laszip_HINSTANCE, "laszip_exploit_spatial_index"); if (laszip_exploit_spatial_index_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_decompress_selective_ptr = (laszip_decompress_selective_def)GetProcAddress(laszip_HINSTANCE, "laszip_decompress_selective"); if (laszip_decompress_selective_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_open_reader_ptr = (laszip_open_reader_def)GetProcAddress(laszip_HINSTANCE, "laszip_open_reader"); if (laszip_open_reader_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_has_spatial_index_ptr = (laszip_has_spatial_index_def)GetProcAddress(laszip_HINSTANCE, "laszip_has_spatial_index"); if (laszip_has_spatial_index_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_inside_rectangle_ptr = (laszip_inside_rectangle_def)GetProcAddress(laszip_HINSTANCE, "laszip_inside_rectangle"); if (laszip_inside_rectangle_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_seek_point_ptr = (laszip_seek_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_seek_point"); if (laszip_seek_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_read_point_ptr = (laszip_read_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_read_point"); if (laszip_read_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_read_inside_point_ptr = (laszip_read_inside_point_def)GetProcAddress(laszip_HINSTANCE, "laszip_read_inside_point"); if (laszip_read_inside_point_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } laszip_close_reader_ptr = (laszip_close_reader_def)GetProcAddress(laszip_HINSTANCE, "laszip_close_reader"); if (laszip_close_reader_ptr == NULL) { FreeLibrary(laszip_HINSTANCE); return 1; } return 0; }; /*---------------------------------------------------------------------------*/ laszip_I32 laszip_unload_dll() { if (laszip_HINSTANCE == NULL) { return 1; } if (FreeLibraryZeroMeansFail) { if (!FreeLibrary(laszip_HINSTANCE)) { return 1; } } else { if (FreeLibrary(laszip_HINSTANCE)) { return 1; } } laszip_HINSTANCE = NULL; return 0; } #ifdef __cplusplus } #endif LASzip-3.4.3/docs/000077500000000000000000000000001356234217100136175ustar00rootroot00000000000000LASzip-3.4.3/docs/Makefile000066400000000000000000000127021356234217100152610ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LASzip.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LASzip.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/LASzip" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LASzip" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." LASzip-3.4.3/docs/make.bat000066400000000000000000000117611356234217100152320ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LASzip.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LASzip.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end LASzip-3.4.3/docs/source/000077500000000000000000000000001356234217100151175ustar00rootroot00000000000000LASzip-3.4.3/docs/source/_static/000077500000000000000000000000001356234217100165455ustar00rootroot00000000000000LASzip-3.4.3/docs/source/_static/dummy000066400000000000000000000000001356234217100176110ustar00rootroot00000000000000LASzip-3.4.3/docs/source/conf.py000066400000000000000000000211011356234217100164110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # LASzip documentation build configuration file, created by # sphinx-quickstart on Mon Jan 31 15:24:10 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'LASzip' copyright = u'2019, Martin Isenburg' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '3.4.3' # The full version, including alpha/beta/rc tags. release = '3.4.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'agogo' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'LASzipdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'LASzip.tex', u'LASzip Documentation', u'Martin Isenburg', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'laszip', u'LASzip Documentation', [u'Martin Isenburg'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'LASzip', u'LASzip Documentation', u'Martin Isenburg', 'LASzip', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. texinfo_appendices = [] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'LASzip' epub_author = u'Martin Isenburg' epub_publisher = u'Martin Isenburg' epub_copyright = u'2011, Martin Isenburg' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # A tuple containing the cover image and cover page html template filenames. #epub_cover = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True LASzip-3.4.3/docs/source/data.rst000066400000000000000000000044241356234217100165660ustar00rootroot00000000000000.. _data: ****************************************************************************** Download LAZ data (compressed LAS) ****************************************************************************** * http://gisfiles.wm.edu/files/lidar/ * http://gisfiles.wm.edu/files/lidar/ESLiDAR/LiDAR_ClassifiedPointCloud/ * http://gisfiles.wm.edu/files/lidar/a11county/LAZ/ * ftp://lidar.dnr.state.mn.us/data/raw/county/dodge/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/douglas/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/faribault/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/fillmore/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/freeborn/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/houston/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/jackson/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/lesueur/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/martin/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/mower/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/murray/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/nobles/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/olmsted/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/pine/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/pope/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/rice/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/rock/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/steele/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/wabasha/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/waseca/laz/ * ftp://lidar.dnr.state.mn.us/data/raw/county/winona/laz/ * http://liblas.org/samples/ .. _`OSGeo4W`: http://trac.osgeo.org/osgeo4w .. _`Martin Isenburg`: http://www.cs.unc.edu/~isenburg .. _`ASPRS LAS format`: http://www.asprs.org/society/committees/standards/lidar_exchange_format.html .. _`LGPL`: http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License .. _`bz2`: http://en.wikipedia.org/wiki/Bzip2 .. _`gzip`: http://en.wikipedia.org/wiki/Gzip .. _`rar`: http://en.wikipedia.org/wiki/Rar .. _`LAStools`: http://lastools.org .. _`libLAS`: http://liblas.org .. _`lasLIB`: http://www.cs.unc.edu/~isenburg/lastools/download/laslib_README.txt .. _`lasLIB source`: http://www.cs.unc.edu/~isenburg/lastools/download/laslib.zip .. _`laszip.exe`: http://www.cs.unc.edu/~isenburg/lastools/ LASzip-3.4.3/docs/source/detail.rst000066400000000000000000000017571356234217100171250ustar00rootroot00000000000000 For example, the ``x`` and ``y`` coordinate of a point are predicted by adding their delta in the preceding two points to the ``x`` and ``y`` of the last point, whereas the difference between subsequent points' time values is expressed as a multiple of the most common increment, while RGB valued are compressed with simple difference coding. In each case the prediction residuals are compressed with adaptive arithmetic coding. The compressor treats the LAS points of types 0, 1, 2, 3, 4, 5, and 6 as consisting of a number of items: POINT10, GPSTIME11, RGB12, and WAVEPACKET13 and uses separate modules with separate version numbers to compress each item. This makes it easy to improve, for example, the compressor for the ``gps_time`` without affecting the other compression schemes while guaranteeing full backwards compatibility. More importantly it allows the engine to add new LAS point types as the LAS specification evolves into the future without affecting existing point types. LASzip-3.4.3/docs/source/index.rst000066400000000000000000000763031356234217100167710ustar00rootroot00000000000000.. _home: ****************************************************************************** LASzip - free and lossless LiDAR compression ****************************************************************************** LASzip - a free open source product of `rapidlasso GmbH `_ - quickly turns bulky LAS files into compact LAZ files without information loss. Terabytes of LAZ data are now available for free download from various agencies making LASzip, winner of the 2012 Geospatial World Forum `Technology Innovation Award `_ in LiDAR Processing and runner-up for `innovative product at INTERGEO 2012 `_, the de-facto standard for LiDAR compression. Source .............................................................................. * **2019-11-11** - `laszip-3.4.3.tar.gz `_ `(md5) `__ Past Release(s) ~~~~~~~~~~~~~~~~~~~~~~~~~ * **2019-04-12** - `laszip-3.4.1.tar.gz `_ `(md5) `__ * **2018-12-27** - `laszip-3.2.9.tar.gz `_ `(md5) `__ * **2018-11-19** - `laszip-3.2.8.tar.gz `_ `(md5) `__ * **2018-03-27** - `laszip-3.2.2.tar.gz `_ `(md5) `__ * **2017-10-10** - `laszip-3.1.1.tar.gz `_ `(md5) `__ * **2017-09-13** - `laszip-3.1.0.tar.gz `_ * **2013-08-05** - `laszip-2.2.0.tar.gz `_ `(md5) `__ - `laszip-win32-msvc2009.zip `_ `(md5) `__ Platinum Sponsors (USD 25,000 or more) ------------------------------------------------------------------------------ * `Digital Coast - NOAA Office for Coastal Management `_ Gold Sponsors (USD 10,000 or more) ------------------------------------------------------------------------------ * `CRREL - U.S. Army Corps of Engineers `_ Silver Sponsors (USD 5,000 or more) ------------------------------------------------------------------------------ * `RIEGL Laser Measurement Systems `_ Bronze Sponsors (USD 2,000 or more) ------------------------------------------------------------------------------ * `Quantum Spatial Inc. `_ * `Trimble Geospatial `_ Download ------------------------------------------------------------------------------ The LGPL-licensed LASzip library is easiest integrated via the DLL that is in the LASzip subdirectory of the `LAStools`_ distribtion. Other options are to link LASzip via the BSD-licensed `libLAS`_ library or to work with the `LASlib`_ library which fully integrates and enhances the LASzip codebase with spatial indexing, filters, transforms, geo-referencing, ... of LAS and LAZ files. Binaries .............................................................................. - See `OSGeo4W`_ for Windows .lib and include files to compile LASzip into your own application. `libLAS`_ binaries through `OSGeo4W`_ also link LASzip. - For explicit compression (decompression) of LAS (LAZ) files a Windows binary `laszip.exe`_ is available (command-line only `laszip-cli.exe`_), as well as source code, examples, and makefiles to build your own `LASzip`_ on Windows, Linux, or MacOS. Documentation .............................................................................. - The LASzip `paper`_ and `video`_ from the ELMF 2011 presentation in Salzburg, Austria. An `interview `_ with editor Christine Grahl of POB magazine. Development Source ------------------------------------------------------------------------------ * Current Trunk: https://github.com/LASzip/LASzip Background ------------------------------------------------------------------------------ LASzip is a compression library that was developed by `Martin Isenburg`_ for compressing `ASPRS LAS format`_ data in his `LAStools`_. It has been provided as an `LGPL`_-licensed stand-alone software library to allow other softwares that handle LAS data to read and write LASzip-compressed data. The BSD-licensed `libLAS`_ and the LGPL-licensed `LASlib`_ can take advantage of LASzip to read and write compressed data. LASzip is completely lossless. It compresses bulky LAS files into compact LAZ files that are only 7-20 percent of the original size, accurately preserving every single bit. For example, compressing and decompressing the LAS file lidar.las with `laszip.exe`_ (command-line only `laszip-cli.exe`_) as shown below results in lidar_copy.las that is bit-identical to lidar.las. However, the small size of lidar.laz makes it much easier to store, copy, transmit, or archive large amounts of LIDAR. * laszip -i lidar.las -o lidar.laz * laszip -i lidar.laz -o lidar_copy.las LASzip compression can be many times smaller and many times faster than generic compressors like `bz2`_, `gzip`_, and `rar`_ because it knows what the different bytes in a LAS file represent. Another advantage of LASzip is that it allows you to treat compressed LAZ files just like standard LAS files. You can load them directly from compressed form into your application without needing to decompress them onto disk first. The availability of the `LASzip`_ DLL and two APIs, `libLAS`_ and `LASlib`_, with LASzip capability makes it easy to add native LAZ support to your own software package. Software with native LAZ support ------------------------------------------------------------------------------ * Fugroviewer (2.0 and up) by `Fugro `_ * QT Modeler (7.1.6 and up) by `Applied Imagery `_ * ERDAS IMAGINE (14.1 and up) by `Hexagon Geospatial `_ * Global Mapper (13.1 and up) by `Blue Marble Geo `_ * Trimble RealWorks (8.1 and up) by `Trimble Navigation Limited `_ * ENVI LiDAR (5.1 and up) by `Exelis VIS `_ * FME (2012 and up) by `Safe Software `_ * TopoDOT by `Certainty3D `_ * Pointools by `Bentley Systems `_ * Pix4uav by `Pix4D `_ * CloudCompare by `Daniel Girardeau-Montaut `_ * SURE by `nframes `_ * Pointfuse by `Arithmetica `_ * LAStools by `rapidlasso - fast tools to catch reality `_ * plas.io 3D Web Viewer by `Hobu Inc. `_ * RiProcess by `RIEGL LMS GmbH `_ * CloudPro by `Leica Geosystems AG `_ * Optech LMS (3.0 and up) by `Teledyne Optech `_ * Leica LIDAR Survey Studio LSS (2.2 and up) by `Leica Geosystems AG `_ * FUSION (3.40 and up) by `Bob McGaughey of the USDA `_ * ZEB1 by `3D Laser Mapping `_ * OCAD (11.4.0 and up) by `OCAD Inc. `_ * Gexcel R3 by `Gexcel `_ * Voyager (1.3 and up) by `Voyager GIS `_ * LIDAR Analyst (5.2 or 6.0 and up) by `TEXTRON Systems `_ * TerraScan, TerraMatch, TerraPhoto, and TerraSlave (015.xxx and up) by `Terrasolid `_ * Carlson (2016 and up) by `Carlson Software `_ * Remote Sensing Software by `Joanneum Research Forschungsgesellschaft mbH `_ * LiMON Viewer by `Dephos Software `_ * Scanopy by `imagination `_ * WinGeoTransform by `KLT Assoc `_ * BayesStripAlign by `BayesMap Solutions, LLC `_ * Point Cloud Technology by `Point Cloud Technology, GmbH `_ * Scalypso by `Ingenieurbuero Dr.-Ing. R. Koenig `_ * Photogrammetry Software by `Menci Software `_ * TcpMDT by `Aplitop `_ * PhotoMesh by `SmartEarth `_ * QINSy - Quality Integrated Navigation System by `Quality Positioning Services (QPS) B.V. `_ * Potree Converter (1.0 and up) by `Markus Schuetz `_ * FLAIM by `Fugro GeoServices B.V. `_ * ScanLook by `LiDAR USA `_ * GRASS GIS (7.0 and up) by `Open Source Geospatial Foundation (OSGeo) `_ * OPALS by `TU Vienna `_ * Scop++ (5.5.3 and up) by `Trimble and TU Vienna `_ * DTMaster (6.0 and up) by `Trimble INPHO `_ * Pythagoras by `Pythagoras BVBA `_ * EspaEngine by `ESPA Systems `_ * Blaze Point Cloud and Blaze Terra by `Eternix Ltd `_ * ReportGen (2.9.0 and up), by `PDF3D `_ * OrbitGIS by `Orbit `_ * PFMABE Software by `PFMABE Software `_ * K2Vi by `AAM Group `_ * Card/1 (8.4 and up) by `IB&T GmbH `_ * SceneMark by `XtSense GmbH `_ * MapWorks (6.0 and up) by `DotSoft `_ * LiS by `LASERDATA `_ * PointCloudViz by `mirage `_ * Geoverse by `euclideon `_ * PointCab by `PointCab GmbH `_ * Z+F SynCaT Mobile Mapping Software by `Z+F Zoller+Frohlich `_ * LidarViewer by `routescene `_ * 3Dsurvey by `Modri Planet d. o. o. `_ * Vision Lidar by `geo-plus `_ * PPIMMS by `viametris `_ * SuperGIS by `Supergeo Technologies Inc. `_ * Smart Processing Lidar by `3D TARGET srl `_ * Geomapping+ by `GEOMAPPING `_ * GEOgraph 3D by `HHK Datentechnik GmbH `_ * Dot3DEdit (version 2.0 and up) by `DotProduct LLC `_ * HydroVish and KomVish by `AirborneHydroMapping GmbH `_ Download LAZ data ------------------------------------------------------------------------------ * USGS `LiDAR bulk download `_ such as * `AK_BrooksCamp_2012 `_, `AK_Coastal_2009 `_, `AK_Fairbanks-NSBorough_2010 `_, `AK_Juneau_2012 `_, ... * `CA_AlamedaCo_2006 `_, `CA-OR_KlamathRiver_2010 `_, `CA-NV_LakeTahoe_2010 `_, `CA_CanyonFire_2007 `_, ... * `... many more here ... `_ * Sonoma County LiDAR from `SonomaVegMap Project `_ * WMS served LiDAR by `Government of La Rioja in Spain `_ * `Puget Sound LiDAR Consortium `_ * 2007: `sumpter `_ * 2009: `douglasco `_, `snohoriver `_, `umpqua `_, `wenas `_, `wenatchee `_ * 2011: `kittitas `_, `quinault `_, `rattlesnake `_ * 2012: `chehalis `_, `hoh `_, `jefferson_clallam `_, `quinault `_, `upper_naches `_ * open LiDAR data strategy of the `National Land Survey of Finland `_ * nationwide open LiDAR data of `the Netherlands `_ * `Digital Coast LiDAR `_ by NOAA (+ `how to download `_) and `folders for batch download `_ * LiDAR of `Kanton Zurich, Switzerland `_ * LiDAR of `Kanton Solothurn, Switzerland `_ * GRAFCAN `LiDAR of the Canary Islands `_ * Alaska LiDAR in the `Matanuska-Susitna Borough `_ * NSF-funded LiDAR hosting facility `OpenTopography `_ * Clark County Kentucky LiDAR data `Clark County GIS `_ * Bay of Plenty, New Zealand `BOPLASS LiDAR `_ * Nevada Barringer Meteorite Crater of the `Lunar and Planetary Institute `_ * Alaska LiDAR hosted by `Division of Geological and Geophysical Surveys (DGGS) `_ * Statewide LiDAR of `Elevation Mapping Project by Minnesota DNR `_ * Counties: `aitkin `_, `anoka `_, `becker `_, `beltrami `_, `benton `_, `bigstone `_, `blueearth `_, `brown `_, `carlton `_, `carver `_, `cass `_, `chippewa `_, `chisago `_, `clay `_, `clearwater `_, `cook `_, `cottonwood `_, `crowwing `_, `dakota `_, `dodge `_, `douglas `_, `faribault `_, `fillmore `_, `freeborn `_, `goodhue `_, `grant `_, `hennepin `_, `houston `_, `hubbard `_, `isanti `_, `itasca `_, `jackson `_, `kanabec `_, `kandiyohi `_, `kittson `_, `koochiching `_, `lacquiparle `_, `lake `_, `lakeofthewoods `_, `lesueur `_, `lincoln `_, `lyon `_, `mahnomen `_, `marshall `_, `martin `_, `meeker `_, `millelacs `_, `morrison `_, `mower `_, `murray `_, `nicollet `_, `nobles `_, `norman `_, `olmsted `_, `ottertail `_, `pennington `_, `pine `_, `pipestone `_, `polk `_, `pope `_, `ramsey `_, `redlake `_, `redwood `_, `renville `_, `rice `_, `rock `_, `roseau `_, `scott `_, `sherburne `_, `sibley `_, `stearns `_, `steele `_, `stevens `_, `swift `_, `todd `_, `traverse `_, `wabasha `_, `wadena `_, `waseca `_, `washington `_, `watonwan `_, `wilkin `_, `winona `_, `wright `_, `yellowmedicine `_ * Arrowhead: `block 1 `_, `block 2 `_, `block 3 `_, `block 4 `_, `block 5 `_ * Twin Cities Metro: `block a c `_, `block b `_, `block d `_, `block e `_, `block f `_, `block g `_, `block h `_, `block dakota `_, `block maple grove `_, `block metro `_ * Central Lakes: `block 1 `_, `block 2 `_, `block 3 `_, `block 4 `_, `block 5 `_ * TERN AusCover Airborne LiDAR: `tumbarumba `_, `tsliig `_, `robsons creek `_, `credo `_, `chowilla `_ * http://liblas.org/samples/ * `Virginia LiDAR `_ of College of William and Mary: `Eleven Coastal Counties `_, `Eastern Shore `_, `Shenandoah Valley `_ * `MassGIS LiDAR Terrain Data `_ * https://www.lidar-online.com/product-list.php * `Nationwide LiDAR Data of Denmark `_ Users of LASzip ------------------------------------------------------------------------------ * `Fugro `_ * `Blom `_ * `COWI `_ * `Watershed Sciences, Inc. `_ * `Riegl `_ * `NOAA `_ * `USGS `_ * `Euclideon `_ * `Dielmo 3D `_ * `Oregon Lidar Consortium `_ * `Minnesota Department of Natural Resources `_ * `US Army Corps of Engineers `_ * and many many more ... Download LAS data (yet to be laszipped) ------------------------------------------------------------------------------ * `Spring 2011 Rhode Island Statewide LiDAR Data `_ * `PAMAP - LiDAR data of Pennsylvania `_ * `Iowa LiDAR Mapping Project `_ * `Sacramento-San Joaquin Delta LiDAR `_ * `Illinois Height Modernization Project LiDAR `_ * `Northwest Florida Water Management District LiDAR `_ * Washington University in St. Louis: `Franklin `_, `Jasper `_, `Washington Iron `_, `St. Francois `_, `Jefferson City (1) `_, `Jefferson City (2) `_, `Jefferson City (3) `_, `Jefferson Ste Genevieve `_, `USGS Drive `_, `Stone County MO `_ * Alaska LiDAR: `Caswell Lakes `_, `Core Area `_, `Matanuska `_, `North Susitna `_, `Point MacKenzie `_, `Willow `_, `Talkeetna `_ * Spain: `Pais Vasco LiDAR `_ .. toctree:: :hidden: .. _`OSGeo4W`: http://trac.osgeo.org/osgeo4w .. _`Martin Isenburg`: http://www.cs.unc.edu/~isenburg .. _`ASPRS LAS format`: http://www.asprs.org/society/committees/standards/lidar_exchange_format.html .. _`LAS`: http://www.asprs.org/society/committees/standards/lidar_exchange_format.html .. _`LGPL`: http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License .. _`bz2`: http://en.wikipedia.org/wiki/Bzip2 .. _`gzip`: http://en.wikipedia.org/wiki/Gzip .. _`rar`: http://en.wikipedia.org/wiki/Rar .. _`LAStools`: http://lastools.org/download/lastools.zip .. _`libLAS`: http://liblas.org .. _`LASlib`: http://lastools.org/download/laslib.zip .. _`LASzip`: http://lastools.org/download/laszip.zip .. _`laszip.exe`: http://lastools.org/download/laszip.exe .. _`laszip-cli.exe`: http://lastools.org/download/laszip-cli.exe .. _`paper`: http://lastools.org/download/laszip.pdf .. _`video`: http://www.youtube.com/watch?v=A0s0fVktj6U LASzip-3.4.3/example/000077500000000000000000000000001356234217100143225ustar00rootroot00000000000000LASzip-3.4.3/example/CMakeLists.txt000066400000000000000000000057541356234217100170750ustar00rootroot00000000000000############################################################################### # # tools/CMakeLists.txt controls building of laszip utilities # # Copyright (c) 2009 Mateusz Loskot # ############################################################################### include_directories( . ../include ../include/laszip) set(APPS_CPP_DEPENDENCIES ${LASZIP_LIB_NAME}) set(LASZIPPERTEST laszippertest) set(LASZIP_UTILITIES ${LASZIPPERTEST} ) if(WIN32) if(NOT BUILD_STATIC) add_definitions("-DLASZIP_DLL_IMPORT=1") endif() endif() # TODO: Experimental and requires testing --mloskot # Generate user-specific settings for Visual Studio project set(VCPROJ_USER_REMOTE_MACHINE_DEBUG ${MACHINE_NAME}) set(VCPROJ_USER_ENVIRONMENT_DEBUG "${ENVIRONMENT_PATH}") if(MSVC) foreach(utility ${LASZIP_UTILITIES}) set(USER_FILE ${utility}.vcproj.$ENV{USERDOMAIN}.$ENV{USERNAME}.user) set(OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${USER_FILE}) message(STATUS "Generating ${CMAKE_GENERATOR} user-specific settings in ${USER_FILE}") configure_file(${CMAKE_SOURCE_DIR}/cmake/laszip.vcproj.user.template ${OUTPUT_PATH} @ONLY) endforeach() endif() if(LASZIPPERTEST) add_executable(${LASZIPPERTEST} laszippertest.cpp) target_link_libraries(${LASZIPPERTEST} ${APPS_CPP_DEPENDENCIES} ) if (EMSCRIPTEN) SET_TARGET_PROPERTIES(${LASZIPPERTEST} PROPERTIES SUFFIX .js) endif() endif() if(UNIX) # Autoconf compatibility variables to use the same script source. set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${CMAKE_INSTALL_PREFIX}/bin) set(libdir ${CMAKE_INSTALL_PREFIX}/lib) GET_DIRECTORY_PROPERTY(LASZIP_DEFINITIONS DIRECTORY ${laszip_SOURCE_DIR}/ COMPILE_DEFINITIONS) set(LASZIP_CONFIG_DEFINITIONS "") foreach(definition ${LASZIP_DEFINITIONS}) set(LASZIP_CONFIG_DEFINITIONS "${LASZIP_CONFIG_DEFINITIONS} -D${definition}") endforeach() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/laszip-config.in ${CMAKE_CURRENT_BINARY_DIR}/laszip-config @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/laszip-config DESTINATION bin/ PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) #pkgconfig set(PKGCFG_PREFIX "${CMAKE_INSTALL_PREFIX}") set(PKGCFG_INC_DIR "${CMAKE_INSTALL_PREFIX}/${LIBLAS_INCLUDE_SUBDIR}") set(PKGCFG_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${LIBLAS_LIB_SUBDIR}") set(PKGCFG_REQUIRES "") set(PKGCFG_VERSION ${VERSION}) set(PKGCFG_LINK_FLAGS "-llaszip") set(PKGCFG_COMPILE_FLAGS "$CMAKE_CXX_FLAGS") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/laszip.pc.in ${CMAKE_CURRENT_BINARY_DIR}/laszip.pc @ONLY) endif(UNIX) ############################################################################### # Targets installation install(TARGETS ${LASZIP_UTILITIES} RUNTIME DESTINATION ${LASZIP_BIN_DIR} LIBRARY DESTINATION ${LASZIP_LIB_DIR} ARCHIVE DESTINATION ${LASZIP_LIB_DIR}) LASzip-3.4.3/example/laszip-config.in000066400000000000000000000013611356234217100174200ustar00rootroot00000000000000#!/bin/sh prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ INCLUDES="-I${prefix}/include " LIBS="-L$libdir -llaszip" usage() { cat <&2 fi case $1 in --libs) echo $LIBS ;; --prefix) echo ${prefix} ;; --ldflags) echo -L${libdir} ;; --defines) echo @LASZIP_CONFIG_DEFINITIONS@ @DEFS@ ;; --includes) echo ${INCLUDES} ;; --cflags) echo @CMAKE_C_FLAGS@ @CFLAGS@ ;; --cxxflags) echo @CMAKE_CXX_FLAGS@ @CXXFLAGS@ ;; --version) echo @VERSION@ ;; *) usage 1 1>&2 ;; esac LASzip-3.4.3/example/laszip.pc.in000066400000000000000000000005151356234217100165560ustar00rootroot00000000000000prefix=@PKGCFG_PREFIX@ exec_prefix=@PKGCFG_PREFIX@ libdir=@PKGCFG_LIB_DIR@ includedir=@PKGCFG_INC_DIR@ Name: LASzip Description: Library (C/C++) and tools for the LAS LiDAR compression Requires: @PKGCFG_REQUIRES@ Version: @PKGCFG_VERSION@ Libs: -L${libdir} @PKGCFG_LINK_FLAGS@ Cflags: -I${includedir}/laszip @PKGCFG_COMPILE_FLAGS@ LASzip-3.4.3/example/laszipdllexample.cpp000066400000000000000000004057621356234217100204160ustar00rootroot00000000000000/* =============================================================================== FILE: laszipdllexample.cpp CONTENTS: This source code implements several different easy-to-follow examples on how to use the LASzip DLL. The first and the second examples implement a small compression and decompression utilitity. The third example shows how to use the DLL to export points to a proper geo-referenced LAZ file. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 7 September 2018 -- introduced the LASCopyString macro to replace _strdup 28 May 2017 -- 14th example reads compressed LAS 1.4 with "selective decompression" 25 April 2017 -- 13th example writes LAS 1.4 using new "native LAS 1.4 extension" 11 January 2017 -- 12th example changes the default chunk size from 50000 to 5000 8 January 2017 -- changed from "laszip_dll.h" to "laszip_api.h" because of hobu 23 September 2015 -- 11th example writes without a-priori bounding box or counters 22 September 2015 -- 10th upconverts to LAS 1.4 with pre-existing "extra bytes" 5 September 2015 -- eighth and nineth example show pre-existing "extra bytes" 19 July 2015 -- sixth and seventh example show LAS 1.4 compatibility mode 2 April 2015 -- fourth and fifth example with integrated spatially indexing 11 August 2013 -- added third example for exporting geo-referenced points 29 July 2013 -- created for the LASzip DLL after returning to Sommerhausen =============================================================================== */ #include #include #include #include #include #if defined(_MSC_VER) && \ (_MSC_FULL_VER >= 150000000) #define LASCopyString _strdup #else #define LASCopyString strdup #endif void usage(bool wait=false) { fprintf(stderr,"usage:\n"); fprintf(stderr,"laszipdllexample\n"); fprintf(stderr,"laszipdllexample in.las out.laz\n"); fprintf(stderr,"laszipdllexample in.laz out.las\n"); fprintf(stderr,"laszipdllexample in.las out.las\n"); fprintf(stderr,"laszipdllexample in.laz out.laz\n"); fprintf(stderr,"laszipdllexample -h\n"); if (wait) { fprintf(stderr,"\n"); getc(stdin); } exit(1); } static void dll_error(laszip_POINTER laszip) { if (laszip) { laszip_CHAR* error; if (laszip_get_error(laszip, &error)) { fprintf(stderr,"DLL ERROR: getting error messages\n"); } fprintf(stderr,"DLL ERROR MESSAGE: %s\n", error); } } static void byebye(bool error=false, bool wait=false, laszip_POINTER laszip=0) { if (error) { dll_error(laszip); } if (wait) { fprintf(stderr,"\n"); getc(stdin); } exit(error); } static double taketime() { return (double)(clock())/CLOCKS_PER_SEC; } #define EXAMPLE_ONE 1 #define EXAMPLE_TWO 2 #define EXAMPLE_THREE 3 #define EXAMPLE_FOUR 4 #define EXAMPLE_FIVE 5 #define EXAMPLE_SIX 6 #define EXAMPLE_SEVEN 7 #define EXAMPLE_EIGHT 8 #define EXAMPLE_NINE 9 #define EXAMPLE_TEN 10 #define EXAMPLE_ELEVEN 11 #define EXAMPLE_TWELVE 12 #define EXAMPLE_THIRTEEN 13 #define EXAMPLE_FOURTEEN 14 #define EXAMPLE_FIFTEEN 15 #define EXAMPLE_SIXTEEN 16 #define EXAMPLE EXAMPLE_SIXTEEN int main(int argc, char *argv[]) { laszip_U32 i; double start_time = 0.0; char* file_name_in = 0; char* file_name_out = 0; // load LASzip DLL if (laszip_load_dll()) { fprintf(stderr,"DLL ERROR: loading LASzip DLL\n"); byebye(true, argc==1); } // get version of LASzip DLL laszip_U8 version_major; laszip_U8 version_minor; laszip_U16 version_revision; laszip_U32 version_build; if (laszip_get_version(&version_major, &version_minor, &version_revision, &version_build)) { fprintf(stderr,"DLL ERROR: getting LASzip DLL version number\n"); byebye(true, argc==1); } fprintf(stderr,"LASzip DLL v%d.%d r%d (build %d)\n", (int)version_major, (int)version_minor, (int)version_revision, (int)version_build); if (argc == 1) { char file_name[256]; fprintf(stderr,"%s is better run in the command line\n", argv[0]); fprintf(stderr,"enter input file%s: ", ((EXAMPLE == EXAMPLE_THREE) ? " (not used)" : "")); fgets(file_name, 256, stdin); file_name[strlen(file_name)-1] = '\0'; file_name_in = LASCopyString(file_name); fprintf(stderr,"enter output file: "); fgets(file_name, 256, stdin); file_name[strlen(file_name)-1] = '\0'; file_name_out = LASCopyString(file_name); } else if (argc == 3) { file_name_in = LASCopyString(argv[1]); file_name_out = LASCopyString(argv[2]); } else { if ((argc != 2) || (strcmp(argv[1], "-h") != 0)) { fprintf(stderr, "ERROR: cannot understand arguments\n"); } usage(); } start_time = taketime(); if (EXAMPLE == EXAMPLE_ONE) { fprintf(stderr,"running EXAMPLE_ONE (reading *without* and writing *without* compatibility mode)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64d\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_ONE if (EXAMPLE == EXAMPLE_TWO) { fprintf(stderr,"running EXAMPLE_TWO (another way of reading *without* and writing *without* compatibility mode)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header_read; if (laszip_get_header_pointer(laszip_reader, &header_read)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header_read->number_of_point_records ? header_read->number_of_point_records : header_read->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header_write; if (laszip_get_header_pointer(laszip_writer, &header_write)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // copy entries from the reader header to the writer header header_write->file_source_ID = header_read->file_source_ID; header_write->global_encoding = header_read->global_encoding; header_write->project_ID_GUID_data_1 = header_read->project_ID_GUID_data_1; header_write->project_ID_GUID_data_2 = header_read->project_ID_GUID_data_2; header_write->project_ID_GUID_data_3 = header_read->project_ID_GUID_data_3; memcpy(header_write->project_ID_GUID_data_4, header_read->project_ID_GUID_data_4, 8); header_write->version_major = header_read->version_major; header_write->version_minor = header_read->version_minor; memcpy(header_write->system_identifier, header_read->system_identifier, 32); memcpy(header_write->generating_software, header_read->generating_software, 32); header_write->file_creation_day = header_read->file_creation_day; header_write->file_creation_year = header_read->file_creation_year; header_write->header_size = header_read->header_size; header_write->offset_to_point_data = header_read->header_size; /* note !!! */ header_write->number_of_variable_length_records = header_read->number_of_variable_length_records; header_write->point_data_format = header_read->point_data_format; header_write->point_data_record_length = header_read->point_data_record_length; header_write->number_of_point_records = header_read->number_of_point_records; for (i = 0; i < 5; i++) { header_write->number_of_points_by_return[i] = header_read->number_of_points_by_return[i]; } header_write->x_scale_factor = header_read->x_scale_factor; header_write->y_scale_factor = header_read->y_scale_factor; header_write->z_scale_factor = header_read->z_scale_factor; header_write->x_offset = header_read->x_offset; header_write->y_offset = header_read->y_offset; header_write->z_offset = header_read->z_offset; header_write->max_x = header_read->max_x; header_write->min_x = header_read->min_x; header_write->max_y = header_read->max_y; header_write->min_y = header_read->min_y; header_write->max_z = header_read->max_z; header_write->min_z = header_read->min_z; // LAS 1.3 and higher only header_write->start_of_waveform_data_packet_record = header_read->start_of_waveform_data_packet_record; // LAS 1.4 and higher only header_write->start_of_first_extended_variable_length_record = header_read->start_of_first_extended_variable_length_record; header_write->number_of_extended_variable_length_records = header_read->number_of_extended_variable_length_records; header_write->extended_number_of_point_records = header_read->extended_number_of_point_records; for (i = 0; i < 15; i++) { header_write->extended_number_of_points_by_return[i] = header_read->extended_number_of_points_by_return[i]; } // we may modify output because we omit any user defined data that may be ** the header if (header_read->user_data_in_header_size) { header_write->header_size -= header_read->user_data_in_header_size; header_write->offset_to_point_data -= header_read->user_data_in_header_size; fprintf(stderr,"omitting %d bytes of user_data_in_header\n", header_read->user_data_after_header_size); } // add all the VLRs if (header_read->number_of_variable_length_records) { fprintf(stderr,"offset_to_point_data before adding %u VLRs is : %d\n", header_read->number_of_variable_length_records, (laszip_I32)header_write->offset_to_point_data); for (i = 0; i < header_read->number_of_variable_length_records; i++) { if (laszip_add_vlr(laszip_writer, header_read->vlrs[i].user_id, header_read->vlrs[i].record_id, header_read->vlrs[i].record_length_after_header, header_read->vlrs[i].description, header_read->vlrs[i].data)) { fprintf(stderr,"DLL ERROR: adding VLR %u of %u to the header of the laszip writer\n", i+i, header_read->number_of_variable_length_records); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLR number %u is : %d\n", i+1, (laszip_I32)header_write->offset_to_point_data); } } // we may modify output because we omit any user defined data that may be *after* the header if (header_read->user_data_after_header_size) { fprintf(stderr,"omitting %d bytes of user_data_after_header\n", header_read->user_data_after_header_size); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the reader will be read laszip_point* point_read; if (laszip_get_point_pointer(laszip_reader, &point_read)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // get a pointer to the point of the writer that we will populate and write laszip_point* point_write; if (laszip_get_point_pointer(laszip_writer, &point_write)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64d\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point point_write->X = point_read->X; point_write->Y = point_read->Y; point_write->Z = point_read->Z; point_write->intensity = point_read->intensity; point_write->return_number = point_read->return_number; point_write->number_of_returns = point_read->number_of_returns; point_write->scan_direction_flag = point_read->scan_direction_flag; point_write->edge_of_flight_line = point_read->edge_of_flight_line; point_write->classification = point_read->classification; point_write->withheld_flag = point_read->withheld_flag; point_write->keypoint_flag = point_read->keypoint_flag; point_write->synthetic_flag = point_read->synthetic_flag; point_write->scan_angle_rank = point_read->scan_angle_rank; point_write->user_data = point_read->user_data; point_write->point_source_ID = point_read->point_source_ID; point_write->gps_time = point_read->gps_time; memcpy(point_write->rgb, point_read->rgb, 8); memcpy(point_write->wave_packet, point_read->wave_packet, 29); // LAS 1.4 only point_write->extended_scanner_channel = point_read->extended_scanner_channel; point_write->extended_classification_flags = point_read->extended_classification_flags; point_write->extended_classification = point_read->extended_classification; point_write->extended_return_number = point_read->extended_return_number; point_write->extended_number_of_returns = point_read->extended_number_of_returns; point_write->extended_scan_angle = point_read->extended_scan_angle; if (point_read->num_extra_bytes) { memcpy(point_write->extra_bytes, point_read->extra_bytes, point_read->num_extra_bytes); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_TWO if (EXAMPLE == EXAMPLE_THREE) { fprintf(stderr,"running EXAMPLE_THREE (writing five points of type 1 to LAS 1.2 file)\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = (1<<0); // see LAS specification for details header->version_major = 1; header->version_minor = 2; strncpy(header->system_identifier, "LASzip DLL example 3", 32); header->file_creation_day = 120; header->file_creation_year = 2013; header->point_data_format = 1; header->point_data_record_length = 28; header->number_of_point_records = 5; header->number_of_points_by_return[0] = 3; header->number_of_points_by_return[1] = 2; header->max_x = 630499.95; header->min_x = 630498.56; header->max_y = 4834749.66; header->min_y = 4834748.73; header->max_z = 63.68; header->min_z = 61.33; // optional: use the bounding box and the scale factor to create a "good" offset if (laszip_auto_offset(laszip_writer)) { fprintf(stderr,"DLL ERROR: during automatic offset creation\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } // create the geokeys with the projection information laszip_geokey_struct key_entries[5]; // projected coordinates key_entries[0].key_id = 1024; // GTModelTypeGeoKey key_entries[0].tiff_tag_location = 0; key_entries[0].count = 1; key_entries[0].value_offset = 1; // ModelTypeProjected // projection key_entries[1].key_id = 3072; // ProjectedCSTypeGeoKey key_entries[1].tiff_tag_location = 0; key_entries[1].count = 1; key_entries[1].value_offset = 32613; // PCS_WGS84_UTM_zone_13N // horizontal units key_entries[2].key_id = 3076; // ProjLinearUnitsGeoKey key_entries[2].tiff_tag_location = 0; key_entries[2].count = 1; key_entries[2].value_offset = 9001; // meters // vertical units key_entries[3].key_id = 4099; // VerticalUnitsGeoKey key_entries[3].tiff_tag_location = 0; key_entries[3].count = 1; key_entries[3].value_offset = 9001; // meters // vertical datum key_entries[4].key_id = 4096; // VerticalCSTypeGeoKey key_entries[4].tiff_tag_location = 0; key_entries[4].count = 1; key_entries[4].value_offset = 5030; // WGS84 // add the geokeys (create or replace the appropriate VLR) fprintf(stderr,"offset_to_point_data before adding projection VLR : %d\n", (laszip_I32)header->offset_to_point_data); if (laszip_set_geokeys(laszip_writer, 5, key_entries)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding two VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write five points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 62.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->return_number = 2; point->number_of_returns = 2; point->classification = 2; point->scan_angle_rank = 21; point->gps_time = 413162.560400; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->return_number = 1; point->number_of_returns = 1; point->classification = 1; point->scan_angle_rank = 21; point->gps_time = 413162.563600; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->return_number = 1; point->number_of_returns = 1; point->classification = 1; point->scan_angle_rank = 22; point->gps_time = 413162.566800; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fourth point coordinates[0] = 630498.56; coordinates[1] = 4834749.41; coordinates[2] = 63.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 20; point->return_number = 1; point->number_of_returns = 2; point->classification = 3; point->scan_angle_rank = 22; point->gps_time = 413162.580200; // write the fourth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fifth point coordinates[0] = 630498.80; coordinates[1] = 4834748.73; coordinates[2] = 62.16; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 110; point->return_number = 2; point->number_of_returns = 2; point->classification = 2; point->scan_angle_rank = 22; point->gps_time = 413162.580200; // write the fifth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_THREE if (EXAMPLE == EXAMPLE_FOUR) { fprintf(stderr,"running EXAMPLE_FOUR (reading area-of-interest from a file exploiting possibly existing spatial indexing information)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // signal that spatial queries are coming laszip_BOOL exploit = 1; if (laszip_exploit_spatial_index(laszip_reader, exploit)) { fprintf(stderr,"DLL ERROR: signaling laszip reader that spatial queries are coming for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // check whether spatial indexing information is available laszip_BOOL is_indexed = 0; laszip_BOOL is_appended = 0; if (laszip_has_spatial_index(laszip_reader, &is_indexed, &is_appended)) { fprintf(stderr,"DLL ERROR: checking laszip reader whether spatial indexing information is present for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' does %shave spatial indexing information\n", file_name_in, (is_indexed ? "" : "not ")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // create a rectangular box enclosing a subset of points at the center of the full bounding box const laszip_F64 sub = 0.05; laszip_F64 mid_x = (header->min_x + header->max_x) / 2; laszip_F64 mid_y = (header->min_y + header->max_y) / 2; laszip_F64 range_x = header->max_x - header->min_x; laszip_F64 range_y = header->max_y - header->min_y; laszip_F64 sub_min_x = mid_x - sub * range_x; laszip_F64 sub_min_y = mid_y - sub * range_y; laszip_F64 sub_max_x = mid_x + sub * range_x; laszip_F64 sub_max_y = mid_y + sub * range_y; // request the reader to only read this specified rectangular subset of points laszip_BOOL is_empty = 0; if (laszip_inside_rectangle(laszip_reader, sub_min_x, sub_min_y, sub_max_x, sub_max_y, &is_empty)) { fprintf(stderr,"DLL ERROR: requesting points inside of rectangle [%g,%g] (%g,%g) from laszip reader\n", sub_min_x, sub_min_y, sub_max_x, sub_max_y); byebye(true, argc==1, laszip_reader); } // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_BOOL is_done = 0; laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_inside_point(laszip_reader, &is_done)) { fprintf(stderr,"DLL ERROR: reading point %I64d\n", p_count); byebye(true, argc==1, laszip_reader); } // are we done reading if (is_done) { break; } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update the inventory if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_FOUR if (EXAMPLE == EXAMPLE_FIVE) { fprintf(stderr,"running EXAMPLE_FIVE (reading from one file and writing to another file while simultaneously generating a spatial index)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // enable the creation of spatial indices laszip_BOOL create = 1; laszip_BOOL append = 0; /* not supported yet */ if (laszip_create_spatial_index(laszip_writer, create, append)) { fprintf(stderr,"DLL ERROR: signaling laszip writer to create spatial indexing information\n"); byebye(true, argc==1, laszip_writer); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' spatially indexed and %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64d\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_indexed_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing indexed point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d indexed points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing indexed & %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_FIVE if (EXAMPLE == EXAMPLE_SIX) { fprintf(stderr,"running EXAMPLE_SIX (writing five points of type 6 to LAS 1.4 without compatibility)\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = (1<<0) | (1<<4); // see LAS specification for details header->version_major = 1; header->version_minor = 4; strncpy(header->system_identifier, "LASzip DLL example 6", 32); header->file_creation_day = 30; header->file_creation_year = 2015; header->header_size = 375; header->offset_to_point_data = 375; header->point_data_format = 6; header->point_data_record_length = 30; header->number_of_point_records = 0; // legacy 32-bit counters should be zero for new point types > 5 for (i = 0; i < 5; i++) { header->number_of_points_by_return[i] = 0; } header->extended_number_of_point_records = 5; header->extended_number_of_points_by_return[0] = 1; header->extended_number_of_points_by_return[1] = 2; header->extended_number_of_points_by_return[7] = 1; header->extended_number_of_points_by_return[8] = 1; header->max_x = 630499.95; header->min_x = 630498.56; header->max_y = 4834749.66; header->min_y = 4834748.73; header->max_z = 63.68; header->min_z = 61.33; // optional: use the bounding box and the scale factor to create a "good" offset if (laszip_auto_offset(laszip_writer)) { fprintf(stderr,"DLL ERROR: during automatic offset creation\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding empty OGC WKT VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add intentionally empty OGC WKT if (laszip_add_vlr(laszip_writer, "LASF_Projection", 2112, 0, "intentionally empty OGC WKT", 0)) { fprintf(stderr,"DLL ERROR: adding intentionally empty OGC WKT VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // this should fail if compress is true if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write five points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 62.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3500; point->extended_scanner_channel = 1; point->extended_classification_flags = 8; // overflag flag is set point->gps_time = 53413162.560400; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->extended_return_number = 8; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 41; point->extended_scan_angle = 3567; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.563600; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->extended_return_number = 9; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 42; point->extended_scan_angle = 3633; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.566800; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fourth point coordinates[0] = 630498.56; coordinates[1] = 4834749.41; coordinates[2] = 63.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 20; point->extended_return_number = 1; point->extended_number_of_returns = 2; point->classification = 5; // it must be set because it "fits" in 5 bits point->extended_classification = 5; point->extended_scan_angle = 3700; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fourth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fifth point coordinates[0] = 630498.80; coordinates[1] = 4834748.73; coordinates[2] = 62.16; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 110; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3767; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fifth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_SIX if (EXAMPLE == EXAMPLE_SEVEN) // CHECK { fprintf(stderr,"running EXAMPLE_SEVEN (writing five points of type 6 to LAS 1.4 *with* compatibility to compressed LAZ *and* also uncompressed LAS)\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = (1<<0) | (1<<4); // see LAS specification for details header->version_major = 1; header->version_minor = 4; strncpy(header->system_identifier, "LASzip DLL example 7", 32); header->file_creation_day = 30; header->file_creation_year = 2015; header->header_size = 375; header->offset_to_point_data = 375; header->point_data_format = 6; header->point_data_record_length = 30; header->number_of_point_records = 0; // legacy 32-bit counters should be zero for new point types > 5 for (i = 0; i < 5; i++) { header->number_of_points_by_return[i] = 0; } header->extended_number_of_point_records = 5; header->extended_number_of_points_by_return[0] = 1; header->extended_number_of_points_by_return[1] = 2; header->extended_number_of_points_by_return[7] = 1; header->extended_number_of_points_by_return[8] = 1; header->max_x = 630499.95; header->min_x = 630498.56; header->max_y = 4834749.66; header->min_y = 4834748.73; header->max_z = 63.68; header->min_z = 61.33; // optional: use the bounding box and the scale factor to create a "good" offset if (laszip_auto_offset(laszip_writer)) { fprintf(stderr,"DLL ERROR: during automatic offset creation\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding empty OGC WKT VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add intentionally empty OGC WKT if (laszip_add_vlr(laszip_writer, "LASF_Projection", 2112, 0, "intentionally empty OGC WKT", 0)) { fprintf(stderr,"DLL ERROR: adding intentionally empty OGC WKT VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // enable the compatibility mode laszip_BOOL request = 1; if (laszip_request_compatibility_mode(laszip_writer, request)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode\n"); byebye(true, argc==1, laszip_writer); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write five points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 62.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3500; point->extended_scanner_channel = 1; point->extended_classification_flags = 8; // overflag flag is set point->gps_time = 53413162.560400; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->extended_return_number = 8; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 41; point->extended_scan_angle = 3567; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.563600; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->extended_return_number = 9; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 42; point->extended_scan_angle = 3633; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.566800; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fourth point coordinates[0] = 630498.56; coordinates[1] = 4834749.41; coordinates[2] = 63.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 20; point->extended_return_number = 1; point->extended_number_of_returns = 2; point->classification = 5; // it must be set because it "fits" in 5 bits point->extended_classification = 5; point->extended_scan_angle = 3700; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fourth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fifth point coordinates[0] = 630498.80; coordinates[1] = 4834748.73; coordinates[2] = 62.16; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 110; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3767; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fifth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_SEVEN if (EXAMPLE == EXAMPLE_EIGHT) { fprintf(stderr,"running EXAMPLE_EIGHT (always *with* compatibility mode when reading but when writing *only* for compressed output)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // request compatibility mode for the reader laszip_BOOL request_reader = 1; if (laszip_request_compatibility_mode(laszip_reader, request_reader)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // check if the output is compressed laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // *only* enable the compatibility mode for the writer for compressed output if (compress) { laszip_BOOL request_writer = 1; if (laszip_request_compatibility_mode(laszip_writer, request_writer)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the writer\n"); byebye(true, argc==1, laszip_writer); } } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_EIGHT if (EXAMPLE == EXAMPLE_NINE) { fprintf(stderr,"running EXAMPLE_NINE (writing LAS 1.4 points with \"extra bytes\" *with* compatibility to compressed LAZ *and* also uncompressed LAS)\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = (1<<0) | (1<<4); // see LAS specification for details header->version_major = 1; header->version_minor = 4; strncpy(header->system_identifier, "LASzip DLL example 9", 32); header->file_creation_day = 30; header->file_creation_year = 2015; header->header_size = 375; header->offset_to_point_data = 375; header->point_data_format = 6; header->point_data_record_length = 30 + 2 + 1; // three "extra bytes" per point store two additional attributes header->number_of_point_records = 0; // legacy 32-bit counters should be zero for new point types > 5 for (i = 0; i < 5; i++) { header->number_of_points_by_return[i] = 0; } header->extended_number_of_point_records = 5; header->extended_number_of_points_by_return[0] = 1; header->extended_number_of_points_by_return[1] = 2; header->extended_number_of_points_by_return[7] = 1; header->extended_number_of_points_by_return[8] = 1; header->max_x = 630499.95; header->min_x = 630498.56; header->max_y = 4834749.66; header->min_y = 4834748.73; header->max_z = 63.68; header->min_z = 61.33; // optional: use the bounding box and the scale factor to create a "good" offset if (laszip_auto_offset(laszip_writer)) { fprintf(stderr,"DLL ERROR: during automatic offset creation\n"); byebye(true, argc==1, laszip_writer); } // add description for the two attributes in the three "extra bytes" fprintf(stderr,"offset_to_point_data before adding 'height above ground' is : %d\n", (laszip_I32)header->offset_to_point_data); if (laszip_add_attribute(laszip_writer, 3, "height above ground", "quantized to 5 cm above 1s SRTM", 0.05, 0.0)) { fprintf(stderr,"DLL ERROR: adding 'height above ground' attribute\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding 'coverage count' is : %d\n", (laszip_I32)header->offset_to_point_data); if (laszip_add_attribute(laszip_writer, 0, "coverage count", "by 0.5 m radius of high returns", 1.0, 0.0)) { fprintf(stderr,"DLL ERROR: adding 'coverage count' attribute\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding empty OGC WKT VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add intentionally empty OGC WKT if (laszip_add_vlr(laszip_writer, "LASF_Projection", 2112, 0, "intentionally empty OGC WKT", 0)) { fprintf(stderr,"DLL ERROR: adding intentionally empty OGC WKT VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // enable the compatibility mode laszip_BOOL request = 1; if (laszip_request_compatibility_mode(laszip_writer, request)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode\n"); byebye(true, argc==1, laszip_writer); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write five points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 62.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3500; point->extended_scanner_channel = 1; point->extended_classification_flags = 8; // overflag flag is set point->gps_time = 53413162.560400; // set attribute 'height above ground' quantized to 0.05 m *((laszip_I16*)(point->extra_bytes + 0)) = (laszip_I16)(12.50 / 0.05); // set attribute 'coverage count' *((laszip_U8*)(point->extra_bytes + 2)) = 3; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->extended_return_number = 8; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 41; point->extended_scan_angle = 3567; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.563600; // set attribute 'height above ground' quantized to 0.05 m *((laszip_I16*)(point->extra_bytes + 0)) = (laszip_I16)(9.32 / 0.05); // set attribute 'coverage count' *((laszip_U8*)(point->extra_bytes + 2)) = 5; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->extended_return_number = 9; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 42; point->extended_scan_angle = 3633; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.566800; // set attribute 'height above ground' quantized to 0.05 m *((laszip_I16*)(point->extra_bytes + 0)) = (laszip_I16)(23.50 / 0.05); // set attribute 'coverage count' *((laszip_U8*)(point->extra_bytes + 2)) = 0; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fourth point coordinates[0] = 630498.56; coordinates[1] = 4834749.41; coordinates[2] = 63.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 20; point->extended_return_number = 1; point->extended_number_of_returns = 2; point->classification = 5; // it must be set because it "fits" in 5 bits point->extended_classification = 5; point->extended_scan_angle = 3700; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // set attribute 'height above ground' quantized to 0.05 m *((laszip_I16*)(point->extra_bytes + 0)) = (laszip_I16)(8.65 / 0.05); // set attribute 'coverage count' *((laszip_U8*)(point->extra_bytes + 2)) = 6; // write the fourth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fifth point coordinates[0] = 630498.80; coordinates[1] = 4834748.73; coordinates[2] = 62.16; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 110; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3767; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // set attribute 'height above ground' quantized to 0.05 m *((laszip_I16*)(point->extra_bytes + 0)) = (laszip_I16)(16.13 / 0.05); // set attribute 'coverage count' *((laszip_U8*)(point->extra_bytes + 2)) = 2; // write the fifth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_NINE if (EXAMPLE == EXAMPLE_TEN) { fprintf(stderr,"running EXAMPLE_TEN (read LAS 1.0-1.3 file, upconvert old to new point types, write LAS 1.4 compatibility mode *only* for compressed output)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // enable the compatibility mode for the reader laszip_BOOL request_reader = 1; if (laszip_request_compatibility_mode(laszip_reader, request_reader)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header_read; if (laszip_get_header_pointer(laszip_reader, &header_read)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // make sure it is LAS 1.0, LAS 1.1, LAS 1.2, or LAS 1.3 if (header_read->version_minor > 3) { fprintf(stderr,"USER ERROR: input should be LAS 1.0 to LAS 1.3\n"); byebye(true, argc==1); } // how many points does the LAS 1.x (x < 4) file have laszip_I64 npoints = header_read->number_of_point_records; // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point_read; if (laszip_get_point_pointer(laszip_reader, &point_read)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // check if the output is compressed laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // *only* enable the compatibility mode for the writer for compressed output if (compress) { laszip_BOOL request_writer = 1; if (laszip_request_compatibility_mode(laszip_writer, request_writer)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the writer\n"); byebye(true, argc==1, laszip_writer); } } // get a pointer to the header of the writer so we can populate it laszip_header* header_write; if (laszip_get_header_pointer(laszip_writer, &header_write)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // copy entries from the reader header to the writer header header_write->file_source_ID = header_read->file_source_ID; header_write->global_encoding = header_read->global_encoding; header_write->project_ID_GUID_data_1 = header_read->project_ID_GUID_data_1; header_write->project_ID_GUID_data_2 = header_read->project_ID_GUID_data_2; header_write->project_ID_GUID_data_3 = header_read->project_ID_GUID_data_3; memcpy(header_write->project_ID_GUID_data_4, header_read->project_ID_GUID_data_4, 8); header_write->version_major = header_read->version_major; header_write->version_minor = header_read->version_minor; memcpy(header_write->system_identifier, header_read->system_identifier, 32); memcpy(header_write->generating_software, header_read->generating_software, 32); header_write->file_creation_day = header_read->file_creation_day; header_write->file_creation_year = header_read->file_creation_year; header_write->header_size = header_read->header_size; header_write->offset_to_point_data = header_read->header_size; /* note !!! */ header_write->number_of_variable_length_records = header_read->number_of_variable_length_records; header_write->point_data_format = header_read->point_data_format; header_write->point_data_record_length = header_read->point_data_record_length; header_write->number_of_point_records = header_read->number_of_point_records; for (i = 0; i < 5; i++) { header_write->number_of_points_by_return[i] = header_read->number_of_points_by_return[i]; } header_write->x_scale_factor = header_read->x_scale_factor; header_write->y_scale_factor = header_read->y_scale_factor; header_write->z_scale_factor = header_read->z_scale_factor; header_write->x_offset = header_read->x_offset; header_write->y_offset = header_read->y_offset; header_write->z_offset = header_read->z_offset; header_write->max_x = header_read->max_x; header_write->min_x = header_read->min_x; header_write->max_y = header_read->max_y; header_write->min_y = header_read->min_y; header_write->max_z = header_read->max_z; header_write->min_z = header_read->min_z; // LAS 1.3 and higher only header_write->start_of_waveform_data_packet_record = header_read->start_of_waveform_data_packet_record; // we may modify output because we omit any user defined data that may be *before* the header header_write->user_data_in_header_size = 0; if (header_read->user_data_in_header_size) { header_write->header_size -= header_read->user_data_in_header_size; header_write->offset_to_point_data -= header_read->user_data_in_header_size; fprintf(stderr,"omitting %d bytes of user_data_in_header\n", header_read->user_data_after_header_size); } // add all the VLRs if (header_read->number_of_variable_length_records) { fprintf(stderr,"offset_to_point_data before adding %u VLRs is : %d\n", header_read->number_of_variable_length_records, (laszip_I32)header_write->offset_to_point_data); for (i = 0; i < header_read->number_of_variable_length_records; i++) { if (laszip_add_vlr(laszip_writer, header_read->vlrs[i].user_id, header_read->vlrs[i].record_id, header_read->vlrs[i].record_length_after_header, header_read->vlrs[i].description, header_read->vlrs[i].data)) { fprintf(stderr,"DLL ERROR: adding VLR %u of %u to the header of the laszip writer\n", i+i, header_read->number_of_variable_length_records); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLR number %u is : %d\n", i+1, (laszip_I32)header_write->offset_to_point_data); } } // we may modify output because we omit any user defined data that may be *after* the header header_write->user_data_after_header_size = 0; if (header_read->user_data_after_header_size) { fprintf(stderr,"omitting %d bytes of user_data_after_header\n", header_read->user_data_after_header_size); } // upgrade the header and the points to LAS 1.4 header_write->version_minor = 4; if (header_read->version_minor == 3) { header_write->header_size += 140; header_write->offset_to_point_data += 140; } else { header_write->header_size += 148; header_write->offset_to_point_data += 148; } if (header_read->point_data_format == 0) { header_write->point_data_format = 6; header_write->point_data_record_length += 10; } else if (header_read->point_data_format == 1) { header_write->point_data_format = 6; header_write->point_data_record_length += 2; } else if (header_read->point_data_format == 2) { header_write->point_data_format = 7; header_write->point_data_record_length += 10; } else if (header_read->point_data_format == 3) { header_write->point_data_format = 7; header_write->point_data_record_length += 2; } else { fprintf(stderr,"USER ERROR: input point type should be 0 to 3 and not %d\n", header_read->point_data_format); byebye(true, argc==1); } // we do not add EVLRs header_write->start_of_first_extended_variable_length_record = 0; header_write->number_of_extended_variable_length_records = 0; // zero the legacy counters header_write->number_of_point_records = 0; for (i = 0; i < 5; i++) { header_write->number_of_points_by_return[i] = 0; } // populate the extended counters header_write->extended_number_of_point_records = header_read->number_of_point_records; for (i = 0; i < 5; i++) { header_write->extended_number_of_points_by_return[i] = header_read->number_of_points_by_return[i]; } for (i = 5; i < 15; i++) { header_write->extended_number_of_points_by_return[i] = 0; } // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point_write; if (laszip_get_point_pointer(laszip_writer, &point_write)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point point_write->X = point_read->X; point_write->Y = point_read->Y; point_write->Z = point_read->Z; point_write->intensity = point_read->intensity; point_write->scan_direction_flag = point_read->scan_direction_flag; point_write->edge_of_flight_line = point_read->edge_of_flight_line; point_write->user_data = point_read->user_data; point_write->point_source_ID = point_read->point_source_ID; point_write->gps_time = point_read->gps_time; memcpy(point_write->rgb, point_read->rgb, 8); point_write->extended_scanner_channel = 0; point_write->extended_classification_flags = (point_read->withheld_flag << 2) | (point_read->keypoint_flag << 1) | (point_read->synthetic_flag << 0);; point_write->extended_classification = point_read->classification; point_write->extended_return_number = point_read->return_number; point_write->extended_number_of_returns = point_read->number_of_returns; point_write->extended_scan_angle = (laszip_I16)( (point_read->scan_angle_rank > 0) ? ((1.0 / 0.006 * point_read->scan_angle_rank) + 0.5) : ((1.0 / 0.006 * point_read->scan_angle_rank) - 0.5) ); if (point_read->num_extra_bytes) { memcpy(point_write->extra_bytes, point_read->extra_bytes, point_read->num_extra_bytes); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_TEN if (EXAMPLE == EXAMPLE_ELEVEN) { fprintf(stderr,"running EXAMPLE_ELEVEN (writing points to LAS 1.4 without a-priori knowlegde of bounding box or point count (compatibility only for LAZ))\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = (1<<0) | (1<<4); // see LAS specification for details header->version_major = 1; header->version_minor = 4; strncpy(header->system_identifier, "LASzip DLL example 7", 32); header->file_creation_day = 30; header->file_creation_year = 2015; header->header_size = 375; header->offset_to_point_data = 375; header->point_data_format = 6; header->point_data_record_length = 30; header->number_of_point_records = 0; // legacy 32-bit counters should be zero for new point types > 5 for (i = 0; i < 5; i++) { header->number_of_points_by_return[i] = 0; // legacy 32-bit counters should be zero for new point types > 5 } header->extended_number_of_point_records = 0; // a-priori unknown number of points for (i = 0; i < 15; i++) { header->extended_number_of_points_by_return[i] = 0; } header->max_x = 0.0; // a-priori unknown bounding box header->min_x = 0.0; header->max_y = 0.0; header->min_y = 0.0; header->max_z = 0.0; header->min_z = 0.0; fprintf(stderr,"offset_to_point_data before adding empty OGC WKT VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add intentionally empty OGC WKT if (laszip_add_vlr(laszip_writer, "LASF_Projection", 2112, 0, "intentionally empty OGC WKT", 0)) { fprintf(stderr,"DLL ERROR: adding intentionally empty OGC WKT VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // compressed output or not? laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // if compressed output was requested enable the compatibility mode if (compress) { laszip_BOOL request = 1; if (laszip_request_compatibility_mode(laszip_writer, request)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode\n"); byebye(true, argc==1, laszip_writer); } } // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write five points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 62.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3500; point->extended_scanner_channel = 1; point->extended_classification_flags = 8; // overflag flag is set point->gps_time = 53413162.560400; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update inventory with first point if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->extended_return_number = 8; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 41; point->extended_scan_angle = 3567; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.563600; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update inventory with second point if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->extended_return_number = 9; point->extended_number_of_returns = 9; point->classification = 0; // it must be set to zero as the real value is stored in the extended field point->extended_classification = 42; point->extended_scan_angle = 3633; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.566800; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update inventory with third point if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fourth point coordinates[0] = 630498.56; coordinates[1] = 4834749.41; coordinates[2] = 63.68; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 20; point->extended_return_number = 1; point->extended_number_of_returns = 2; point->classification = 5; // it must be set because it "fits" in 5 bits point->extended_classification = 5; point->extended_scan_angle = 3700; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fourth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update inventory with fourth point if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the fifth point coordinates[0] = 630498.80; coordinates[1] = 4834748.73; coordinates[2] = 62.16; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 110; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->classification = 2; // it must be set because it "fits" in 5 bits point->extended_classification = 2; point->extended_scan_angle = 3767; point->extended_scanner_channel = 1; point->extended_classification_flags = 0; // no flag is not set point->gps_time = 53413162.580200; // write the fifth point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } // update inventory with fifth point if (laszip_update_inventory(laszip_writer)) { fprintf(stderr,"DLL ERROR: updating inventory for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_ELEVEN if (EXAMPLE == EXAMPLE_TWELVE) { fprintf(stderr,"running EXAMPLE_TWELVE (changing chunk size to 5000 *with* compatibility when writing *only* for compressed output)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // enable the compatibility mode for the reader laszip_BOOL request_reader = 1; if (laszip_request_compatibility_mode(laszip_reader, request_reader)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // check if the output is compressed laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // *only* enable the compatibility mode for the writer for compressed output if (compress) { laszip_BOOL request_writer = 1; if (laszip_request_compatibility_mode(laszip_writer, request_writer)) { fprintf(stderr,"DLL ERROR: enabling laszip LAS 1.4 compatibility mode for the writer\n"); byebye(true, argc==1, laszip_writer); } } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // change the chunk size from the default value to 50000 if (laszip_set_chunk_size(laszip_writer, 5000)) { fprintf(stderr,"DLL ERROR: setting chunk size 5000 for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_TWELVE if (EXAMPLE == EXAMPLE_THIRTEEN) { fprintf(stderr,"running EXAMPLE_THIRTEEN (*with* compatibility mode when reading compressed LAS 1.4 and *with* native extension when writing compressed LAS 1.4)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // request compatibility mode for the reader laszip_BOOL request_compatibility = 1; if (laszip_request_compatibility_mode(laszip_reader, request_compatibility)) { fprintf(stderr,"DLL ERROR: requesting LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // request native extension for the writer laszip_BOOL request_native = 1; if (laszip_request_native_extension(laszip_writer, request_native)) { fprintf(stderr,"DLL ERROR: requesting native LAS 1.4 extension for the writer\n"); byebye(true, argc==1, laszip_writer); } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // check if the output is compressed laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_THIRTEEN if (EXAMPLE == EXAMPLE_FOURTEEN) { fprintf(stderr,"running EXAMPLE_FOURTEEN (selective decompression of XYZ when reading native compressed LAS 1.4\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // request compatibility mode for the reader laszip_BOOL request_compatibility = 1; if (laszip_request_compatibility_mode(laszip_reader, request_compatibility)) { fprintf(stderr,"DLL ERROR: requesting LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // request compatibility mode for the reader laszip_U32 decompress_selective = laszip_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY | laszip_DECOMPRESS_SELECTIVE_Z; if (laszip_decompress_selective(laszip_reader, decompress_selective)) { fprintf(stderr,"DLL ERROR: decompressing XYZ selectively for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header; if (laszip_get_header_pointer(laszip_reader, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point; if (laszip_get_point_pointer(laszip_reader, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // request native extension for the writer laszip_BOOL request_native = 1; if (laszip_request_native_extension(laszip_writer, request_native)) { fprintf(stderr,"DLL ERROR: requesting native LAS 1.4 extension for the writer\n"); byebye(true, argc==1, laszip_writer); } // initialize the header for the writer using the header of the reader if (laszip_set_header(laszip_writer, header)) { fprintf(stderr,"DLL ERROR: setting header for laszip writer\n"); byebye(true, argc==1, laszip_writer); } // check if the output is compressed laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); // open the writer if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // read the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point if (laszip_set_point(laszip_writer, point)) { fprintf(stderr,"DLL ERROR: setting point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_FOURTEEN if (EXAMPLE == EXAMPLE_FIFTEEN) { fprintf(stderr,"running EXAMPLE_FIFETEEN (reading and writing native compressed LAS 1.4 by copying the points)\n"); // create the reader laszip_POINTER laszip_reader; if (laszip_create(&laszip_reader)) { fprintf(stderr,"DLL ERROR: creating laszip reader\n"); byebye(true, argc==1); } // request compatibility mode for the reader laszip_BOOL request_compatibility = 1; if (laszip_request_compatibility_mode(laszip_reader, request_compatibility)) { fprintf(stderr,"DLL ERROR: requesting LAS 1.4 compatibility mode for the reader\n"); byebye(true, argc==1, laszip_reader); } // open the reader laszip_BOOL is_compressed = 0; if (laszip_open_reader(laszip_reader, file_name_in, &is_compressed)) { fprintf(stderr,"DLL ERROR: opening laszip reader for '%s'\n", file_name_in); byebye(true, argc==1, laszip_reader); } fprintf(stderr,"file '%s' is %scompressed\n", file_name_in, (is_compressed ? "" : "un")); // get a pointer to the header of the reader that was just populated laszip_header* header_read; if (laszip_get_header_pointer(laszip_reader, &header_read)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // how many points does the file have laszip_I64 npoints = (header_read->number_of_point_records ? header_read->number_of_point_records : header_read->extended_number_of_point_records); // report how many points the file has fprintf(stderr,"file '%s' contains %I64d points\n", file_name_in, npoints); // get a pointer to the points that will be read laszip_point* point_read; if (laszip_get_point_pointer(laszip_reader, &point_read)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip reader\n"); byebye(true, argc==1, laszip_reader); } // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header_write; if (laszip_get_header_pointer(laszip_writer, &header_write)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header_write->file_source_ID = header_read->file_source_ID; header_write->global_encoding = header_read->global_encoding; header_write->version_major = header_read->version_major; header_write->version_minor = header_read->version_minor; strncpy(header_write->system_identifier, "LASzip DLL example 15", 32); header_write->file_creation_day = header_read->file_creation_day; header_write->file_creation_year = header_read->file_creation_year; header_write->header_size = header_read->header_size; header_write->offset_to_point_data = header_read->header_size; // real offset_to_point_data is calculated when adding VLRs header_write->point_data_format = header_read->point_data_format; header_write->point_data_record_length = header_read->point_data_record_length; if ((header_read->point_data_format > 5) || (header_read->extended_number_of_point_records > (2<<32-1))) { // legacy 32-bit counters should be zero for new point types > 5 or if there are more than 2<<32-1 points header_write->number_of_point_records = 0; for (i = 0; i < 5; i++) { header_write->number_of_points_by_return[i] = 0; } } else { // legacy 32-bit counters should be populated header_write->number_of_point_records = (header_read->number_of_point_records ? header_read->number_of_point_records : (laszip_U32)(header_read->extended_number_of_point_records)); for (i = 0; i < 5; i++) { header_write->number_of_points_by_return[i] = (header_read->number_of_points_by_return[i] ? header_read->number_of_points_by_return[i] : (laszip_U32)(header_read->extended_number_of_points_by_return[i])); } } header_write->extended_number_of_point_records = header_read->extended_number_of_point_records; for (i = 0; i < 15; i++) { header_write->extended_number_of_points_by_return[i] = header_read->extended_number_of_points_by_return[i]; } header_write->x_scale_factor = header_read->x_scale_factor; header_write->y_scale_factor = header_read->y_scale_factor; header_write->z_scale_factor = header_read->z_scale_factor; header_write->x_offset = header_read->x_offset; header_write->y_offset = header_read->y_offset; header_write->z_offset = header_read->z_offset; header_write->max_x = header_read->max_x; header_write->min_x = header_read->min_x; header_write->max_y = header_read->max_y; header_write->min_y = header_read->min_y; header_write->max_z = header_read->max_z; header_write->min_z = header_read->min_z; // extended VLRs or Waveforms are not supported yet header_write->start_of_waveform_data_packet_record = 0; header_write->number_of_extended_variable_length_records = 0; header_write->start_of_first_extended_variable_length_record = 0; // add VLRs for (i = 0; i < header_read->number_of_variable_length_records; i++) { if (laszip_add_vlr(laszip_writer, header_read->vlrs[i].user_id, header_read->vlrs[i].record_id, header_read->vlrs[i].record_length_after_header, header_read->vlrs[i].description, header_read->vlrs[i].data)) { fprintf(stderr,"DLL ERROR: adding VLR[%d] to the header\n", i); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding VLR[%d] : %d\n", i, (laszip_I32)header_write->offset_to_point_data); } // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point_write; if (laszip_get_point_pointer(laszip_writer, &point_write)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // read and write all the points laszip_I64 p_count = 0; while (p_count < npoints) { // read a point if (laszip_read_point(laszip_reader)) { fprintf(stderr,"DLL ERROR: reading point %I64\n", p_count); byebye(true, argc==1, laszip_reader); } // copy the point point_write->X = point_read->X; point_write->Y = point_read->Y; point_write->Z = point_read->Z; point_write->intensity = point_read->intensity; point_write->scan_direction_flag = point_read->scan_direction_flag; point_write->edge_of_flight_line = point_read->edge_of_flight_line; point_write->withheld_flag = point_read->withheld_flag; point_write->keypoint_flag = point_read->keypoint_flag; point_write->synthetic_flag = point_read->synthetic_flag; point_write->classification = point_read->classification; point_write->user_data = point_read->user_data; point_write->point_source_ID = point_read->point_source_ID; point_write->gps_time = point_read->gps_time; memcpy(point_write->rgb, point_read->rgb, 8); if (point_write->extended_point_type) { point_write->extended_scanner_channel = point_read->extended_scanner_channel; point_write->extended_classification_flags = point_read->extended_classification_flags; point_write->extended_classification = point_read->extended_classification; point_write->extended_return_number = point_read->extended_return_number; point_write->extended_number_of_returns = point_read->extended_number_of_returns; point_write->extended_scan_angle = point_read->extended_scan_angle; } else { point_write->return_number = point_read->return_number; point_write->number_of_returns = point_read->number_of_returns; point_write->scan_angle_rank = point_read->scan_angle_rank; } if (point_read->num_extra_bytes) { memcpy(point_write->extra_bytes, point_read->extra_bytes, point_read->num_extra_bytes); } // write the point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; } fprintf(stderr,"successfully read and written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } // close the reader if (laszip_close_reader(laszip_reader)) { fprintf(stderr,"DLL ERROR: closing laszip reader\n"); byebye(true, argc==1, laszip_reader); } // destroy the reader if (laszip_destroy(laszip_reader)) { fprintf(stderr,"DLL ERROR: destroying laszip reader\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for reading %scompressed and writing %scompressed\n", taketime()-start_time, (is_compressed ? "" : "un"), (compress ? "" : "un")); } // end of EXAMPLE_FIFTEEN if (EXAMPLE == EXAMPLE_SIXTEEN) { fprintf(stderr,"running EXAMPLE_SIXTEEN (writing three points of type 6 to LAS 1.4 file)\n"); // create the writer laszip_POINTER laszip_writer; if (laszip_create(&laszip_writer)) { fprintf(stderr,"DLL ERROR: creating laszip writer\n"); byebye(true, argc==1); } // get a pointer to the header of the writer so we can populate it laszip_header* header; if (laszip_get_header_pointer(laszip_writer, &header)) { fprintf(stderr,"DLL ERROR: getting header pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // populate the header header->file_source_ID = 4711; header->global_encoding = 0x0001; // time stamps are in adjusted standard GPS time header->version_major = 1; header->version_minor = 4; strncpy(header->system_identifier, "LASzip DLL example 16", 32); header->file_creation_day = 120; header->file_creation_year = 2018; header->header_size = 375; // must be 375 for LAS 1.4 header->offset_to_point_data = 375; // must be at least 375 for LAS 1.4 header->number_of_variable_length_records = 0; header->point_data_format = 6; header->point_data_record_length = 30; header->number_of_point_records = 0; // must be zero for point type 6 or higher header->number_of_points_by_return[0] = 0; // must be zero for point type 6 or higher header->number_of_points_by_return[1] = 0; // must be zero for point type 6 or higher header->number_of_points_by_return[2] = 0; // must be zero for point type 6 or higher header->number_of_points_by_return[3] = 0; // must be zero for point type 6 or higher header->number_of_points_by_return[4] = 0; // must be zero for point type 6 or higher header->max_x = 630499.95; header->min_x = 630498.56; header->max_y = 4834749.66; header->min_y = 4834748.73; header->max_z = 63.68; header->min_z = 61.33; header->extended_number_of_point_records = 3; header->extended_number_of_points_by_return[0] = 2; header->extended_number_of_points_by_return[1] = 1; header->extended_number_of_points_by_return[2] = 0; header->extended_number_of_points_by_return[3] = 0; header->extended_number_of_points_by_return[4] = 0; header->extended_number_of_points_by_return[5] = 0; header->extended_number_of_points_by_return[6] = 0; header->extended_number_of_points_by_return[7] = 0; header->extended_number_of_points_by_return[8] = 0; header->extended_number_of_points_by_return[9] = 0; header->extended_number_of_points_by_return[10] = 0; header->extended_number_of_points_by_return[11] = 0; header->extended_number_of_points_by_return[12] = 0; header->extended_number_of_points_by_return[13] = 0; header->extended_number_of_points_by_return[14] = 0; // optional: use the bounding box and the scale factor to create a "good" offset if (laszip_auto_offset(laszip_writer)) { fprintf(stderr,"DLL ERROR: during automatic offset creation\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data before adding funny VLR is : %d\n", (laszip_I32)header->offset_to_point_data); // add some funny VLR if (laszip_add_vlr(laszip_writer, "funny", 12345, 0, "just a funny VLR", 0)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } // create the geokeys with the projection information laszip_geokey_struct key_entries[5]; // projected coordinates key_entries[0].key_id = 1024; // GTModelTypeGeoKey key_entries[0].tiff_tag_location = 0; key_entries[0].count = 1; key_entries[0].value_offset = 1; // ModelTypeProjected // projection key_entries[1].key_id = 3072; // ProjectedCSTypeGeoKey key_entries[1].tiff_tag_location = 0; key_entries[1].count = 1; key_entries[1].value_offset = 32613; // PCS_WGS84_UTM_zone_13N // horizontal units key_entries[2].key_id = 3076; // ProjLinearUnitsGeoKey key_entries[2].tiff_tag_location = 0; key_entries[2].count = 1; key_entries[2].value_offset = 9001; // meters // vertical units key_entries[3].key_id = 4099; // VerticalUnitsGeoKey key_entries[3].tiff_tag_location = 0; key_entries[3].count = 1; key_entries[3].value_offset = 9001; // meters // vertical datum key_entries[4].key_id = 4096; // VerticalCSTypeGeoKey key_entries[4].tiff_tag_location = 0; key_entries[4].count = 1; key_entries[4].value_offset = 5030; // WGS84 // add the geokeys (create or replace the appropriate VLR) fprintf(stderr,"offset_to_point_data before adding projection VLR : %d\n", (laszip_I32)header->offset_to_point_data); if (laszip_set_geokeys(laszip_writer, 5, key_entries)) { fprintf(stderr,"DLL ERROR: adding funny VLR to the header\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"offset_to_point_data after adding two VLRs : %d\n", (laszip_I32)header->offset_to_point_data); // open the writer laszip_BOOL compress = (strstr(file_name_out, ".laz") != 0); if (laszip_open_writer(laszip_writer, file_name_out, compress)) { fprintf(stderr,"DLL ERROR: opening laszip writer for '%s'\n", file_name_out); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"writing file '%s' %scompressed\n", file_name_out, (compress ? "" : "un")); // get a pointer to the point of the writer that we will populate and write laszip_point* point; if (laszip_get_point_pointer(laszip_writer, &point)) { fprintf(stderr,"DLL ERROR: getting point pointer from laszip writer\n"); byebye(true, argc==1, laszip_writer); } // write three points laszip_I64 p_count = 0; laszip_F64 coordinates[3]; // populate the first point coordinates[0] = 630499.95; coordinates[1] = 4834749.17; coordinates[2] = 63.15; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 60; point->extended_return_number = 1; point->extended_number_of_returns = 2; point->extended_classification = 1; point->extended_classification_flags = 0; // none point->extended_scan_angle = (laszip_I16)((21.0/0.006) + 0.5); point->gps_time = 1132762996.478024; // write the first point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the second point coordinates[0] = 630499.83; coordinates[1] = 4834748.88; coordinates[2] = 62.18; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 90; point->extended_return_number = 2; point->extended_number_of_returns = 2; point->extended_classification = 1; point->extended_classification_flags = 0x4 | 0x2 | 0x1; // withheld, keypoint, synthetic flag point->extended_scan_angle = (laszip_I16)((21.0/0.006) + 0.5); point->gps_time = 1132762996.478024; // write the second point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // populate the third point coordinates[0] = 630499.54; coordinates[1] = 4834749.66; coordinates[2] = 62.66; if (laszip_set_coordinates(laszip_writer, coordinates)) { fprintf(stderr,"DLL ERROR: setting coordinates for point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } point->intensity = 70; point->extended_return_number = 1; point->extended_number_of_returns = 1; point->extended_classification = 2; point->extended_classification_flags = 0x8 | 0x4 | 0x2 | 0x1; // overlap, withheld, keypoint, synthetic flag point->extended_scan_angle = (laszip_I16)((21.25/0.006) + 0.5); point->gps_time = 1132762996.476224; // write the third point if (laszip_write_point(laszip_writer)) { fprintf(stderr,"DLL ERROR: writing point %I64d\n", p_count); byebye(true, argc==1, laszip_writer); } p_count++; // get the number of points written so far if (laszip_get_point_count(laszip_writer, &p_count)) { fprintf(stderr,"DLL ERROR: getting point count\n"); byebye(true, argc==1, laszip_writer); } fprintf(stderr,"successfully written %I64d points\n", p_count); // close the writer if (laszip_close_writer(laszip_writer)) { fprintf(stderr,"DLL ERROR: closing laszip writer\n"); byebye(true, argc==1, laszip_writer); } // destroy the writer if (laszip_destroy(laszip_writer)) { fprintf(stderr,"DLL ERROR: destroying laszip writer\n"); byebye(true, argc==1); } fprintf(stderr,"total time: %g sec for writing %scompressed\n", taketime()-start_time, (compress ? "" : "un")); } // end of EXAMPLE_SIXTEEN // unload LASzip DLL if (laszip_unload_dll()) { fprintf(stderr,"DLL ERROR: unloading LASzip DLL\n"); byebye(true, argc==1); } return 0; } LASzip-3.4.3/example/laszippertest.cpp000066400000000000000000000531131356234217100177420ustar00rootroot00000000000000/* =============================================================================== FILE laszippertest.cpp CONTENTS This tool reads and writes point data in the LAS 1.X format compressed or uncompressed via the laszipper and lasunzipper interfaces that are not (!) used by LASzip or LASlib but are the binding to libLAS. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 14 January 2011 -- mpg@flaxen.com adds randomness and commandline controls 10 January 2011 -- licensing change for LGPL release and liblas integration 13 December 2010 -- created to test the remodularized laszip compressor =============================================================================== */ #include "laszipper.hpp" #include "lasunzipper.hpp" #ifdef LZ_WIN32_VC6 #include #else #include #include using namespace std; #endif #include #include #include #include #include //--------------------------------------------------------------------------- static double taketime() { return (double)(clock())/CLOCKS_PER_SEC; } //--------------------------------------------------------------------------- // abstractions for doing I/O, which support VC6 streams, modern streams, and FILE* class OStream { public: OStream(bool use_iostream, const char* filename) : m_use_iostream(use_iostream), m_filename(filename), ofile(NULL), streamo(NULL) { if (m_use_iostream) { #ifdef LZ_WIN32_VC6 ofb.open(filename, ios::out); ofb.setmode(filebuf::binary); streamo = new ostream(&ofb); #else streamo = new ofstream(); streamo->open(filename, std::ios::out | std::ios::binary ); #endif } else { ofile = fopen(filename, "wb"); } }; ~OStream() { if (m_use_iostream) { delete streamo; #ifdef LZ_WIN32_VC6 ofb.close(); #endif } else { if (ofile) fclose(ofile); } }; bool m_use_iostream; const char* m_filename; FILE* ofile; filebuf ofb; #ifdef LZ_WIN32_VC6 ostream* streamo; #else ofstream* streamo; #endif }; //--------------------------------------------------------------------------- struct IStream { public: IStream(bool use_iostream, const char* filename) : m_use_iostream(use_iostream), m_filename(filename), ifile(NULL), streami(NULL) { if (m_use_iostream) { #ifdef LZ_WIN32_VC6 ifb.open(filename, ios::in); ifb.setmode(filebuf::binary); streami = new istream(&ifb); #else streami = new ifstream(); streami->open(filename, std::ios::in | std::ios::binary); #endif } else { ifile = fopen(filename, "rb"); } }; ~IStream() { if (m_use_iostream) { delete streami; #ifdef LZ_WIN32_VC6 ifb.close(); #endif } else { if (ifile) fclose(ifile); } }; bool m_use_iostream; const char* m_filename; FILE* ifile; filebuf ifb; #ifdef LZ_WIN32_VC6 istream* streami; #else ifstream* streami; #endif }; //--------------------------------------------------------------------------- class PointData { public: PointData(unsigned char type=5, unsigned short size=70) { point_type = type; point_size = size; point = 0; point_data = 0; } bool setup(unsigned int num_items, const LASitem* items) { unsigned int offset = 0; if (point) delete [] point; point = new unsigned char*[num_items]; if (point_data) delete [] point_data; point_data = new unsigned char[point_size]; for (unsigned int i = 0; i < num_items; i++) { point[i] = &(point_data[offset]); offset += items[i].size; } return (offset == point_size); } ~PointData() { if (point) delete [] point; if (point_data) delete [] point_data; } unsigned char point_type; unsigned short point_size; unsigned char** point; unsigned char* point_data; }; //--------------------------------------------------------------------------- class Settings { public: Settings(unsigned int num_pts, bool random, bool use_stream) : num_points(num_pts), use_random(random), use_iostream(use_stream) { logfile = fopen("zippertest.log","w"); return; } ~Settings() { fclose(logfile); return; } unsigned num_points; bool use_random; unsigned int seed; bool use_iostream; FILE* logfile; }; static Settings* settings = NULL; // singleton //--------------------------------------------------------------------------- static void log(const char* format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); fflush(stderr); va_start(args, format); vfprintf(settings->logfile, format, args); va_end(args); fflush(settings->logfile); return; } //--------------------------------------------------------------------------- static LASzipper* make_zipper(OStream* ost, const LASzip* laszip) { LASzipper* zipper = new LASzipper(); if (zipper == 0) { log("ERROR: could not alloc laszipper\n"); exit(1); } bool success; if (ost->m_use_iostream) success = zipper->open(*ost->streamo, laszip); else success = zipper->open(ost->ofile, laszip); if (!success) { log("ERROR: could not open laszipper with %s because %s\n", ost->m_filename, zipper->get_error()); exit(1); } return zipper; } //--------------------------------------------------------------------------- static LASunzipper* make_unzipper(IStream* ist, const LASzip* laszip) { LASunzipper* unzipper = new LASunzipper(); if (unzipper == 0) { log("ERROR: could not alloc lasunzipper\n"); exit(1); } bool success; if (ist->m_use_iostream) success = unzipper->open(*ist->streami, laszip); else success = unzipper->open(ist->ifile, laszip); if (!success) { log("ERROR: could not open laszipper with %s because %s\n", ist->m_filename, unzipper->get_error()); exit(1); } return unzipper; } //--------------------------------------------------------------------------- static void write_points(LASzipper* zipper, PointData& data) { if (zipper==NULL) return; double start_time, end_time; unsigned char c; unsigned int i,j; // the two branches of this IF are the same, except for the use of a random number; // we keep the random case separate, so that we can get fastest timing tests w/o random data if (settings->use_random) { srand(settings->seed); start_time = taketime(); c = rand() % 256; for (i = 0; i < settings->num_points; i++) { for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c = rand() % 256; } zipper->write(data.point); } } else { start_time = taketime(); c = 0; for (i = 0; i < settings->num_points; i++) { for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c++; } zipper->write(data.point); } } if (!zipper->close()) { log("ERROR on zipper->close(): %s\n", zipper->get_error()); } end_time = taketime(); log("laszipper wrote %u points in %g seconds\n", settings->num_points, end_time-start_time); return; } //--------------------------------------------------------------------------- static void read_points(LASunzipper* unzipper, PointData& data) { if (unzipper==NULL) return; unsigned char c; unsigned int i,j; unsigned int num_errors; double start_time, end_time; start_time = taketime(); num_errors = 0; if (settings->use_random) { srand(settings->seed); c = rand() % 256; for (i = 0; i < settings->num_points; i++) { unzipper->read(data.point); for (j = 0; j < data.point_size; j++) { if (data.point_data[j] != c) { log("%d %d %d != %d\n", i, j, data.point_data[j], c); num_errors++; if (num_errors > 20) break; } c = rand() % 256; } if (num_errors > 20) break; } } else { c = 0; for (i = 0; i < settings->num_points; i++) { unzipper->read(data.point); for (j = 0; j < data.point_size; j++) { if (data.point_data[j] != c) { log("%d %d %d != %d\n", i, j, data.point_data[j], c); num_errors++; if (num_errors > 20) break; } c++; } if (num_errors > 20) break; } } if (!unzipper->close()) { log("ERROR on unzipper->close(): %s\n", unzipper->get_error()); } end_time = taketime(); if (num_errors) { log("ERROR: with lasunzipper %d\n", num_errors); getc(stdin); } else { log("SUCCESS: lasunzipper read %u points in %g seconds\n", settings->num_points, end_time-start_time); } return; } //--------------------------------------------------------------------------- static void write_points_seek(LASzipper* zipper, PointData& data) { if (zipper==NULL) return; double start_time, end_time; unsigned char c; unsigned int i,j; start_time = taketime(); // the two branches of this IF are the same, except for the use of a random number; // we keep the random case separate, so that we can get fastest timing tests w/o random data if (settings->use_random) { for (i = 0; i < settings->num_points; i++) { srand(i); c = rand() % 256; for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c = rand() % 256; } zipper->write(data.point); } } else { for (i = 0; i < settings->num_points; i++) { c = (unsigned char)i; for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c++; } zipper->write(data.point); } } if (!zipper->close()) { log("ERROR on zipper->close(): %s\n", zipper->get_error()); } end_time = taketime(); log("laszipper wrote %u points in %g seconds\n", settings->num_points, end_time-start_time); return; } //--------------------------------------------------------------------------- static void read_points_seek(LASunzipper* unzipper, PointData& data) { if (unzipper==NULL) return; unsigned char c; unsigned int i,j; unsigned int num_errors, num_seeks; double start_time, end_time; start_time = taketime(); num_errors = 0; num_seeks = 0; if (settings->use_random) { for (i = 0; i < settings->num_points; i++) { if (i%1000 == 0) { if (num_seeks > 100) break; int s = (rand()*rand())%settings->num_points; fprintf(stderr, "at position %d seeking to %d\n", i, s); unzipper->seek(s); num_seeks++; i = s; } unzipper->read(data.point); srand(i); c = rand() % 256; for (j = 0; j < data.point_size; j++) { if (data.point_data[j] != c) { log("%d %d %d != %d\n", i, j, data.point_data[j], c); num_errors++; if (num_errors > 20) break; } c = rand() % 256; } if (num_errors > 20) break; } } else { for (i = 0; i < settings->num_points; i++) { if (i%1000 == 0) { if (num_seeks > 100) break; int s = (rand()*rand())%settings->num_points; fprintf(stderr, "at position %d seeking to %d\n", i, s); unzipper->seek(s); num_seeks++; i = s; } unzipper->read(data.point); c = (unsigned char)i; for (j = 0; j < data.point_size; j++) { if (data.point_data[j] != c) { log("%d %d %d != %d\n", i, j, data.point_data[j], c); num_errors++; if (num_errors > 20) break; } c++; } if (num_errors > 20) break; } } if (!unzipper->close()) { log("ERROR on unzipper->close(): %s\n", unzipper->get_error()); } end_time = taketime(); if (num_errors) { log("ERROR: with lasunzipper %d\n", num_errors); getc(stdin); } else { log("SUCCESS: lasunzipper read %u bytes in %g seconds\n", settings->num_points, end_time-start_time); } return; } //--------------------------------------------------------------------------- static void write_points_explicit_chunk(LASzipper* zipper, PointData& data) { if (zipper==NULL) return; double start_time, end_time; unsigned char c; unsigned int i,j; unsigned int next_chunk = settings->num_points/10; // the two branches of this IF are the same, except for the use of a random number; // we keep the random case separate, so that we can get fastest timing tests w/o random data if (settings->use_random) { srand(settings->seed); start_time = taketime(); c = rand() % 256; for (i = 0; i < settings->num_points; i++) { for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c = rand() % 256; } zipper->write(data.point); if (i == next_chunk) { zipper->chunk(); next_chunk += settings->num_points/10; next_chunk -= c; } } } else { start_time = taketime(); c = 0; for (i = 0; i < settings->num_points; i++) { for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c++; } zipper->write(data.point); if (i == next_chunk) { zipper->chunk(); next_chunk += settings->num_points/10; next_chunk -= (rand() % 256); } } } if (!zipper->close()) { log("ERROR on zipper->close(): %s\n", zipper->get_error()); } end_time = taketime(); log("laszipper wrote %u points in %g seconds\n", settings->num_points, end_time-start_time); return; } //--------------------------------------------------------------------------- static void write_points_explicit_chunk_seek(LASzipper* zipper, PointData& data) { if (zipper==NULL) return; double start_time, end_time; unsigned char c; unsigned int i,j; unsigned int next_chunk = settings->num_points/10; start_time = taketime(); // the two branches of this IF are the same, except for the use of a random number; // we keep the random case separate, so that we can get fastest timing tests w/o random data if (settings->use_random) { for (i = 0; i < settings->num_points; i++) { srand(i); c = rand() % 256; for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c = rand() % 256; } zipper->write(data.point); if (i == next_chunk) { zipper->chunk(); next_chunk += settings->num_points/10; next_chunk -= c; } } } else { for (i = 0; i < settings->num_points; i++) { c = (unsigned char)i; for (j = 0; j < data.point_size; j++) { data.point_data[j] = c; c++; } zipper->write(data.point); if (i == next_chunk) { zipper->chunk(); next_chunk += settings->num_points/10; next_chunk -= (rand() % 256); } } } if (!zipper->close()) { log("ERROR on zipper->close(): %s\n", zipper->get_error()); } end_time = taketime(); log("laszipper wrote %u points in %g seconds\n", settings->num_points, end_time-start_time); return; } //--------------------------------------------------------------------------- static void run_test(const char* filename, PointData& data, unsigned short compressor, int requested_version=-1, int chunk_size=-1, bool random_seeks=false) { // // COMPRESSION // // setting up LASzip parameters LASzip laszip; if (!laszip.setup(data.point_type, data.point_size, compressor)) { log("ERROR on laszip.setup(): %s\n", laszip.get_error()); } if (requested_version > -1) laszip.request_version((unsigned short)requested_version); if (chunk_size > -1) laszip.set_chunk_size((unsigned int)chunk_size); // packing up LASzip unsigned char* bytes; int num; if (!laszip.pack(bytes, num)) { log("ERROR on laszip.pack(): %s\n", laszip.get_error()); } // creating the output stream OStream* ost = new OStream(settings->use_iostream, filename); // creating the zipper LASzipper* laszipper = make_zipper(ost, &laszip); // allocating the data to read from data.setup(laszip.num_items, laszip.items); // writing the points if (chunk_size == 0) { if (random_seeks) write_points_explicit_chunk_seek(laszipper, data); else write_points_explicit_chunk(laszipper, data); } else { if (random_seeks) write_points_seek(laszipper, data); else write_points(laszipper, data); } // cleaning up delete laszipper; delete ost; // // DECOMPRESSION // // setting up LASzip parameters LASzip laszip_dec; if (!laszip_dec.unpack(bytes, num)) { log("ERROR on laszip_dec.unpack(): %s\n", laszip_dec.get_error()); } // creating the input stream IStream* ist = new IStream(settings->use_iostream, filename); // creating the unzipper LASunzipper* lasunzipper = make_unzipper(ist, &laszip_dec); // allocating the data to write into data.setup(laszip_dec.num_items, laszip_dec.items); // reading the points if (random_seeks) read_points_seek(lasunzipper, data); else read_points(lasunzipper, data); // cleaning up delete lasunzipper; delete ist; return; } //--------------------------------------------------------------------------- int main(int argc, char *argv[]) { unsigned int num_points = 100000; bool use_iostream = false; bool run_forever = false; bool use_random = false; unsigned int user_seed = (unsigned int)time(NULL); for (int i=1; iseed = user_seed; unsigned int run = 1; do { PointData data; // use a seed based on the current time if (run_forever && settings->use_random) { settings->seed = (unsigned int)time(NULL); log("Seed: %u\n", settings->seed); } run_test("test.tmp", data, LASZIP_COMPRESSOR_NONE); // not chunked version 1.0 and sequential version 2.0 log("run_test(test.tmp, data, LASZIP_COMPRESSOR_NOT_CHUNKED, 1);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_NOT_CHUNKED, 1); log("run_test(test.tmp, data, LASZIP_COMPRESSOR_NOT_CHUNKED, 2);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_NOT_CHUNKED, 2); // chunk every 10000 points log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 1, 10000);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 1, 10000); log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 2, 10000);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 2, 10000); // explicit chunk() calls log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 1, 0);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 1, 0); log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 2, 0);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 2, 0); // chunk every 10000 points and random seeks during read log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 1, 10000, true);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 1, 10000, true); log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 2, 10000, true);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 2, 10000, true); // explicit chunk() calls and random seeks during read log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 1, 0, true);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 1, 0, true); log("run_test(test.tmp, data, LASZIP_COMPRESSOR_CHUNKED, 2, 0, true);\n"); run_test("test.tmp", data, LASZIP_COMPRESSOR_CHUNKED, 2, 0, true); log("Finished %u runs\n\n", run); ++run; } while (run_forever); return 0; } LASzip-3.4.3/include/000077500000000000000000000000001356234217100143125ustar00rootroot00000000000000LASzip-3.4.3/include/laszip/000077500000000000000000000000001356234217100156145ustar00rootroot00000000000000LASzip-3.4.3/include/laszip/laszip_api.h000066400000000000000000000506431356234217100201300ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_api.h CONTENTS: A simple DLL interface to LASzip PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 22 August 2017 -- Add version info. 4 August 2017 -- 'laszip_set_point_type_and_size()' as minimal setup for ostream writer 3 August 2017 -- new 'laszip_create_laszip_vlr()' gets VLR as C++ std::vector 29 July 2017 -- integrating minimal stream-based reading/writing into branch 20 July 2017 -- Andrew Bell adds support for stream-based reading/writing. 28 May 2017 -- support for "LAS 1.4 selective decompression" added into DLL API 25 April 2017 -- adding initial support for new "native LAS 1.4 extension" 8 January 2017 -- name change from 'laszip_dll.h' and integration Hobu's changes for Unix 7 January 2017 -- set reserved field in LASzip VLR from 0xAABB to 0x0 7 January 2017 -- make scan angle quantization in compatibility mode consistent with LIB 7 January 2017 -- compatibility mode *decompression* fix for points with waveforms 23 September 2015 -- correct update of bounding box and counters from inventory on closing 22 September 2015 -- bug fix for not overwriting description of pre-existing "extra bytes" 5 September 2015 -- "LAS 1.4 compatibility mode" now allows pre-existing "extra bytes" 3 August 2015 -- incompatible DLL change for QSI-sponsored "LAS 1.4 compatibility mode" 8 July 2015 -- adding support for NOAA-sponsored "LAS 1.4 compatibility mode" 1 April 2015 -- adding exploitation and creation of spatial indexing information 8 August 2013 -- added laszip_get_coordinates() and laszip_set_coordinates() 6 August 2013 -- added laszip_auto_offset() and laszip_check_for_integer_overflow() 31 July 2013 -- added laszip_get_point_count() for FUSION integration 29 July 2013 -- reorganized to create an easy to use LASzip DLL =============================================================================== */ #ifndef LASZIP_API_H #define LASZIP_API_H #ifdef LASZIP_API_VERSION #include #endif #ifdef _WIN32 # ifdef LASZIP_DYN_LINK # ifdef LASZIP_SOURCE # define LASZIP_API __declspec(dllexport) # else # define LASZIP_API __declspec(dllimport) # endif # else # define LASZIP_API # endif #else # define LASZIP_API #endif #ifdef __cplusplus extern "C" { #endif #include /*---------------------------------------------------------------------------*/ /*--------------- DLL variables to pass data to/from LASzip -----------------*/ /*---------------------------------------------------------------------------*/ #ifdef _WIN32 typedef int laszip_BOOL; typedef unsigned char laszip_U8; typedef unsigned short laszip_U16; typedef unsigned int laszip_U32; typedef unsigned __int64 laszip_U64; typedef char laszip_I8; typedef short laszip_I16; typedef int laszip_I32; typedef __int64 laszip_I64; typedef char laszip_CHAR; typedef float laszip_F32; typedef double laszip_F64; typedef void* laszip_POINTER; #else #include typedef int laszip_BOOL; typedef uint8_t laszip_U8; typedef uint16_t laszip_U16; typedef uint32_t laszip_U32; typedef uint64_t laszip_U64; typedef int8_t laszip_I8; typedef int16_t laszip_I16; typedef int32_t laszip_I32; typedef int64_t laszip_I64; typedef char laszip_CHAR; typedef float laszip_F32; typedef double laszip_F64; typedef void* laszip_POINTER; #endif typedef struct laszip_geokey { laszip_U16 key_id; laszip_U16 tiff_tag_location; laszip_U16 count; laszip_U16 value_offset; } laszip_geokey_struct; typedef struct laszip_vlr { laszip_U16 reserved; laszip_CHAR user_id[16]; laszip_U16 record_id; laszip_U16 record_length_after_header; laszip_CHAR description[32]; laszip_U8* data; } laszip_vlr_struct; typedef struct laszip_header { laszip_U16 file_source_ID; laszip_U16 global_encoding; laszip_U32 project_ID_GUID_data_1; laszip_U16 project_ID_GUID_data_2; laszip_U16 project_ID_GUID_data_3; laszip_CHAR project_ID_GUID_data_4[8]; laszip_U8 version_major; laszip_U8 version_minor; laszip_CHAR system_identifier[32]; laszip_CHAR generating_software[32]; laszip_U16 file_creation_day; laszip_U16 file_creation_year; laszip_U16 header_size; laszip_U32 offset_to_point_data; laszip_U32 number_of_variable_length_records; laszip_U8 point_data_format; laszip_U16 point_data_record_length; laszip_U32 number_of_point_records; laszip_U32 number_of_points_by_return[5]; laszip_F64 x_scale_factor; laszip_F64 y_scale_factor; laszip_F64 z_scale_factor; laszip_F64 x_offset; laszip_F64 y_offset; laszip_F64 z_offset; laszip_F64 max_x; laszip_F64 min_x; laszip_F64 max_y; laszip_F64 min_y; laszip_F64 max_z; laszip_F64 min_z; // LAS 1.3 and higher only laszip_U64 start_of_waveform_data_packet_record; // LAS 1.4 and higher only laszip_U64 start_of_first_extended_variable_length_record; laszip_U32 number_of_extended_variable_length_records; laszip_U64 extended_number_of_point_records; laszip_U64 extended_number_of_points_by_return[15]; // optional laszip_U32 user_data_in_header_size; laszip_U8* user_data_in_header; // optional VLRs laszip_vlr_struct* vlrs; // optional laszip_U32 user_data_after_header_size; laszip_U8* user_data_after_header; } laszip_header_struct; typedef struct laszip_point { laszip_I32 X; laszip_I32 Y; laszip_I32 Z; laszip_U16 intensity; laszip_U8 return_number : 3; laszip_U8 number_of_returns : 3; laszip_U8 scan_direction_flag : 1; laszip_U8 edge_of_flight_line : 1; laszip_U8 classification : 5; laszip_U8 synthetic_flag : 1; laszip_U8 keypoint_flag : 1; laszip_U8 withheld_flag : 1; laszip_I8 scan_angle_rank; laszip_U8 user_data; laszip_U16 point_source_ID; // LAS 1.4 only laszip_I16 extended_scan_angle; laszip_U8 extended_point_type : 2; laszip_U8 extended_scanner_channel : 2; laszip_U8 extended_classification_flags : 4; laszip_U8 extended_classification; laszip_U8 extended_return_number : 4; laszip_U8 extended_number_of_returns : 4; // for 8 byte alignment of the GPS time laszip_U8 dummy[7]; laszip_F64 gps_time; laszip_U16 rgb[4]; laszip_U8 wave_packet[29]; laszip_I32 num_extra_bytes; laszip_U8* extra_bytes; } laszip_point_struct; /*---------------------------------------------------------------------------*/ /*------ DLL constants for selective decompression via LASzip DLL -----------*/ /*---------------------------------------------------------------------------*/ #define laszip_DECOMPRESS_SELECTIVE_ALL 0xFFFFFFFF #define laszip_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY 0x00000000 #define laszip_DECOMPRESS_SELECTIVE_Z 0x00000001 #define laszip_DECOMPRESS_SELECTIVE_CLASSIFICATION 0x00000002 #define laszip_DECOMPRESS_SELECTIVE_FLAGS 0x00000004 #define laszip_DECOMPRESS_SELECTIVE_INTENSITY 0x00000008 #define laszip_DECOMPRESS_SELECTIVE_SCAN_ANGLE 0x00000010 #define laszip_DECOMPRESS_SELECTIVE_USER_DATA 0x00000020 #define laszip_DECOMPRESS_SELECTIVE_POINT_SOURCE 0x00000040 #define laszip_DECOMPRESS_SELECTIVE_GPS_TIME 0x00000080 #define laszip_DECOMPRESS_SELECTIVE_RGB 0x00000100 #define laszip_DECOMPRESS_SELECTIVE_NIR 0x00000200 #define laszip_DECOMPRESS_SELECTIVE_WAVEPACKET 0x00000400 #define laszip_DECOMPRESS_SELECTIVE_BYTE0 0x00010000 #define laszip_DECOMPRESS_SELECTIVE_BYTE1 0x00020000 #define laszip_DECOMPRESS_SELECTIVE_BYTE2 0x00040000 #define laszip_DECOMPRESS_SELECTIVE_BYTE3 0x00080000 #define laszip_DECOMPRESS_SELECTIVE_BYTE4 0x00100000 #define laszip_DECOMPRESS_SELECTIVE_BYTE5 0x00200000 #define laszip_DECOMPRESS_SELECTIVE_BYTE6 0x00400000 #define laszip_DECOMPRESS_SELECTIVE_BYTE7 0x00800000 #define laszip_DECOMPRESS_SELECTIVE_EXTRA_BYTES 0xFFFF0000 /*---------------------------------------------------------------------------*/ /*---------------- DLL functions to manage the LASzip DLL -------------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_version ( laszip_U8* version_major , laszip_U8* version_minor , laszip_U16* version_revision , laszip_U32* version_build ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_create( laszip_POINTER* pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_error ( laszip_POINTER pointer , laszip_CHAR** error ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_warning ( laszip_POINTER pointer , laszip_CHAR** warning ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_clean( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_destroy( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ /*---------- DLL functions to write and read LAS and LAZ files --------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_header_pointer( laszip_POINTER pointer , laszip_header_struct** header_pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_point_pointer( laszip_POINTER pointer , laszip_point_struct** point_pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_point_count( laszip_POINTER pointer , laszip_I64* count ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_header( laszip_POINTER pointer , const laszip_header_struct* header ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_point_type_and_size( laszip_POINTER pointer , laszip_U8 point_type , laszip_U16 point_size ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_check_for_integer_overflow( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_auto_offset( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_point( laszip_POINTER pointer , const laszip_point_struct* point ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_coordinates( laszip_POINTER pointer , const laszip_F64* coordinates ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_coordinates( laszip_POINTER pointer , laszip_F64* coordinates ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geokeys( laszip_POINTER pointer , laszip_U32 number , const laszip_geokey_struct* key_entries ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geodouble_params( laszip_POINTER pointer , laszip_U32 number , const laszip_F64* geodouble_params ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geoascii_params( laszip_POINTER pointer , laszip_U32 number , const laszip_CHAR* geoascii_params ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_add_attribute( laszip_POINTER pointer , laszip_U32 type , const laszip_CHAR* name , const laszip_CHAR* description , laszip_F64 scale , laszip_F64 offset ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_add_vlr( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id , laszip_U16 record_length_after_header , const laszip_CHAR* description , const laszip_U8* data ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_remove_vlr( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_create_spatial_index( laszip_POINTER pointer , const laszip_BOOL create , const laszip_BOOL append ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_preserve_generating_software( laszip_POINTER pointer , const laszip_BOOL preserve ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_request_native_extension( laszip_POINTER pointer , const laszip_BOOL request ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_request_compatibility_mode( laszip_POINTER pointer , const laszip_BOOL request ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_chunk_size( laszip_POINTER pointer , const laszip_U32 chunk_size ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_writer( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL compress ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_write_point( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_write_indexed_point( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_update_inventory( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_close_writer( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_exploit_spatial_index( laszip_POINTER pointer , const laszip_BOOL exploit ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_decompress_selective( laszip_POINTER pointer , const laszip_U32 decompress_selective ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_reader( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL* is_compressed ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_has_spatial_index( laszip_POINTER pointer , laszip_BOOL* is_indexed , laszip_BOOL* is_appended ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_inside_rectangle( laszip_POINTER pointer , laszip_F64 min_x , laszip_F64 min_y , laszip_F64 max_x , laszip_F64 max_y , laszip_BOOL* is_empty ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_seek_point( laszip_POINTER pointer , laszip_I64 index ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_read_point( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_read_inside_point( laszip_POINTER pointer , laszip_BOOL* is_done ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_close_reader( laszip_POINTER pointer ); /*---------------------------------------------------------------------------*/ /*---------------- DLL functions to load and unload LASzip ------------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_load_dll ( ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_unload_dll ( ); #ifdef __cplusplus } // extern "C" #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include using namespace std; #endif /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_reader_stream( laszip_POINTER pointer , istream& stream , laszip_BOOL* is_compressed ); /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_writer_stream( laszip_POINTER pointer , ostream& stream , laszip_BOOL compress , laszip_BOOL do_not_write_header ); /*---------------------------------------------------------------------------*/ // make LASzip VLR for point type and point size already specified earlier LASZIP_API laszip_I32 laszip_create_laszip_vlr( laszip_POINTER pointer , laszip_U8** vlr , laszip_U32* vlr_size ); #endif // __cplusplus #endif /* LASZIP_API_H */ LASzip-3.4.3/laszip_api_version.h.in000066400000000000000000000022561356234217100173520ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_api_version.h CONTENTS: Version information for LASzip API interface PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 22 August 2017 -- Created =============================================================================== */ #ifndef LASZIP_API_VERSION_H #define LASZIP_API_VERSION_H /* * version settings */ #define LASZIP_API_VERSION_MAJOR @LASZIP_API_VERSION_MAJOR@ #define LASZIP_API_VERSION_MINOR @LASZIP_API_VERSION_MINOR@ #define LASZIP_API_VERSION_PATCH @LASZIP_API_VERSION_PATCH@ #define HAVE_UNORDERED_MAP @HAVE_UNORDERED_MAP@ #endif /* LASZIP_API_VERSION_H */ LASzip-3.4.3/scripts/000077500000000000000000000000001356234217100143565ustar00rootroot00000000000000LASzip-3.4.3/scripts/appveyor/000077500000000000000000000000001356234217100162235ustar00rootroot00000000000000LASzip-3.4.3/scripts/appveyor/build.cmd000066400000000000000000000000221356234217100200010ustar00rootroot00000000000000nmake /f Makefile LASzip-3.4.3/scripts/appveyor/config.cmd000066400000000000000000000003431356234217100201550ustar00rootroot00000000000000@echo off SET LASZIP_INSTALL_PREFIX="C:/OSGeo4W64/" cmake -G "NMake Makefiles" ^ -DCMAKE_BUILD_TYPE=RelWithDebInfo ^ -DCMAKE_INSTALL_PREFIX=%LASZIP_INSTALL_PREFIX% ^ -DCMAKE_VERBOSE_MAKEFILE=OFF ^ . LASzip-3.4.3/scripts/appveyor/install.cmd000066400000000000000000000006321356234217100203570ustar00rootroot00000000000000@echo off REM cmake --build . --target install --config Release nmake /f Makefile install DESTDIR=C:\laszip-install\install REM cd c:\projects\pdal\install\osgeo4w64 REM tar jcvf ..\pdal-%APPVEYOR_REPO_COMMIT%.tar.bz2 . REM copy c:\pdal-%APPVEYOR_REPO_COMMIT%.tar.bz2 c:\projects\pdal REM echo "OSGeo4W64 build will be uploaded to https://s3.amazonaws.com/pdal/osgeo4w/pdal-%APPVEYOR_REPO_COMMIT%.tar.bz2" LASzip-3.4.3/scripts/ci/000077500000000000000000000000001356234217100147515ustar00rootroot00000000000000LASzip-3.4.3/scripts/ci/add_deploy_key.sh000077500000000000000000000011561356234217100202670ustar00rootroot00000000000000#!/bin/bash if [ -n "$encrypted_de53628fc98a_key" ]; then echo "decrypting SSH for github login" openssl aes-256-cbc -K $encrypted_de53628fc98a_key -iv $encrypted_de53628fc98a_iv -in scripts/ci/pdaldocs-private.key.enc -out scripts/ci/pdaldocs-private.key -d # openssl aes-256-cbc -K $encrypted_de53628fc98a_key -iv $encrypted_de53628fc98a_iv -in scripts/ci/pdaldocs-private.key.enc -out ~\/.ssh/pdal-docs/id_rsa -d cp scripts/ci/pdaldocs-private.key ~/.ssh/id_rsa rm scripts/ci/pdaldocs-private.key chmod 600 ~/.ssh/id_rsa echo -e "Host *\n\tStrictHostKeyChecking no\n" > ~/.ssh/config fi; LASzip-3.4.3/scripts/ci/build_docs.sh000077500000000000000000000003451356234217100174210ustar00rootroot00000000000000#!/bin/bash #!/bin/bash echo "building docs for $TRAVIS_BUILD_DIR/docs" buildpath=`pwd` if [[ ! -z $TRAVIS_BUILD_DIR ]]; then buildpath="$TRAVIS_BUILD_DIR" fi docker run -v $buildpath:/data -w /data/docs pdal/docs make html LASzip-3.4.3/scripts/ci/common.sh000066400000000000000000000006701356234217100166000ustar00rootroot00000000000000#!/bin/bash if [[ "$TRAVIS" != "true" ]] ; then echo "Running this script makes no sense outside of travis-ci.org" exit 1 fi # Functions tmstamp() { echo -n "[$(date '+%H:%M:%S')]" ; } # Environment NUMTHREADS=4 if [[ -f /sys/devices/system/cpu/online ]]; then # Calculates 1.5 times physical threads NUMTHREADS=$(( ( $(cut -f 2 -d '-' /sys/devices/system/cpu/online) + 1 ) * 15 / 10 )) fi #NUMTHREADS=1 # disable MP export NUMTHREADS LASzip-3.4.3/scripts/ci/deploy_website.sh000077500000000000000000000012261356234217100203270ustar00rootroot00000000000000#!/bin/bash echo "deploying docs for $TRAVIS_BUILD_DIR/docs" builddir=$1 destdir=$2 echo "builddir: " $builddir echo "destdir: " $destdir DATE=$(date +'%y.%m.%d %H:%M:%S') git clone git@github.com:LASzip/laszip.github.io.git $destdir/laszipdocs cd $destdir/laszipdocs git checkout master cd $builddir/html cp -rf * $destdir/laszipdocs #cd $builddir/latex/ #cp PDAL.pdf $destdir/laszipdocs cd $destdir/laszipdocs git config user.email "howard+pdal-docs@hobu.co" git config user.name "PDAL Travis docsbot" git add -A git commit -m "update with results of commit https://github.com/LASzip/LASzip/commit/$TRAVIS_COMMIT for ${DATE}" git push origin master LASzip-3.4.3/scripts/ci/docker.sh000077500000000000000000000001651356234217100165610ustar00rootroot00000000000000#!/bin/bash # proj.4 image has all of the Sphinx # dependencies need to build proj.4's docs docker pull pdal/docs LASzip-3.4.3/scripts/ci/pdaldocs-private.key.enc000066400000000000000000000032201356234217100214650ustar00rootroot00000000000000á-Yšd¤;Ç%ú mX«CwD÷™ÒXi¬jZ ò࠮ݵ`»€éFÝLÓ‚¶!Ax†H“4[uJg×Üßp<]½“ƒŸ(ñˆObKlâÃG-8¯¶•oò!Ñ‹ï˜­Ô ”Â.¹B+š=[}™ŽXWs«W„2Ú{ö¹IºúA1ÿÎ ëf{¤‘eã%/4EÛ„äJ?™W°3Ò®‡Óc ¯«ÀÐecÎÒRÉ Þ¿Qp¢Ë² 5Eaà ãÕè îѧ í|g{œHãáËWé©ûïäŸÁ<¨–oZ2œLo%r߉&ûÕq+ÏvFù*Ô}Þ^r¸Üý¥h,*'¬åíÉ´Í0 z²÷EŸÓlÁÇ"ûôœ¾0\­=Ë>L½­¹ÍÛEO8ïgÂÕ¬`­•F?…ï}G²+ÿ´Âçxt:ðVÅ ɼô(¾JýÁ¯hæÊÞa.qËvÜrId 基KâÛ^”Á„ºÀ$—Á~¥8mŒlT»‘V8*EÆ{$“·¾j‡ÿ;'ðÅ«;¹¸âØ0ÑÒ—Ñ ”`v^&fIÛÛÔ‘P#7 }ÔoB/S9§r§þ¡ò‘°CwöYÙ&Ì¡$b{YÖÛq)øº¶²¹w3l|§X>K숵€›ö‹‡^ºÑôÕ‘l é¯Ñö €¢ÐÜì,$4gû¥Fq œÒÏþj*3Ô¤½Ô’þŸ þ ìCÝRDw;ëEá1@ c ˆþŒ1™¦PãѲ–3»äÞW“]ç'ÏTêÄ&j§·vå®ÓÝ˦#®±÷Àš <9…Ó4":´Šk¡YËöª…‡aù3]àNˆŸª ¡ðFe(¢ÏºÎut„ Ù­¡¶Ööh›W|è|–邵a[]›îÅ2²MòÛ¬s™†˜¨JñuYM„¯‹)!ÈNÞ©1‰>q½Åòш¶¾Ê©]` ?ÙF BúÌïh£Mа9sèB0À;°‚€½|Ë00±Õ¸Üu¨uÀU`¼Îú%»™1kËŒ¹–fø¶·3@{†µ\„z])ç¸;j4r ½*+´\GÞèNp†ðÏLÚòç¼ì®3×?Qtî²’MIª"!Ò|ï4 yÔ5QNâË IV_mTMð]®ú¹=2ÖoV¿õÝ*Ó¤tjÕ¡ÈÅÄcÕß½Ð.ÑS s>õœµA<çÙ‰ÄØÏ޽QÒØö¥uÞ ðvr1Ÿ07VòcN¸Œƒ XGŽ`  ŸHǃ°B.”¬Æ)$‰Æ4/Ô×ÛpT‡eúˆåøB/Xc6±mÙ²íEœm$Þx{;ÞCL¨ŠRº+ƾ1EÊEqXµíò‚™žØ¥{& æaôœ®s®Ô1¦™z ´iÛý@Ýw¬‰\¼ù³7±oød uoñò&·¤ú”íg©Û çƒ\öNuUS`Ev .—×'ƒêѶcx9¢¨ŸàÔîU"°á›„ó=+ï ·N8FG+·Î tU4 ƒ¨°~×[â}#Du•¼óÀ9!`R=4N \%ÑÉê]CßÉ⺯TÁ?WÉ É@ÿJkj3–N”ßÖ$I² u™˜PŽ%¾%-*~OТd™¼Lû›èEŸäÌQ%¦ŠââÿA‡Ku‡.æ}Àì Yfê7F¤K)c$:€ëPóÄHÆÝ¤ 'Ï–žéð}žµö]Z…bËRiçÜTC#(Q¼ųÂu& ð'1dѰòD:ðvóØ—^Â=™ X&Ä”'ÌÀÖḆã¬`m³ø^ôzawª‰JUxNPRFHû…ÓCÑåÙ¶ê³…ãË.ñR±´¿ˆö×C_Ñ@X×d:ÒŒ;óÉ mÀ’+÷T2Ï“ÓjÎ tJŽrz¬Éà¾'˜b|EÍÝÑq½Ó¥“¤Ãi2O’gX˜Ù2ÁÿgLZÒ7I_ÂH†ñŽò ¢ÿ‰nO ŸØŒ>‘"nÖdº÷¬Ï{Nz0S 94h’ƒÃ…ßÚ?áf\•Ï'u2R¶(äºd¹é¶9ÞuYŠß£D‹Ñ) ’ÚͤeŽ|¾"_V¯Jóm 8ˆfãO§XmtLASzip-3.4.3/scripts/ci/script.sh000077500000000000000000000002341356234217100166130ustar00rootroot00000000000000#!/bin/bash -e # Builds and tests LASzip source ./scripts/ci/common.sh mkdir -p _build || exit 1 cd _build || exit 1 cmake .. make #./bin/laszippertest LASzip-3.4.3/src/000077500000000000000000000000001356234217100134565ustar00rootroot00000000000000LASzip-3.4.3/src/CMakeLists.txt000066400000000000000000000020231356234217100162130ustar00rootroot00000000000000############################################################################### # # src/CMakeLists.txt controls building of laszip library # # Copyright (c) 2009 Mateusz Loskot # ############################################################################### set(LASZIP_SOURCES arithmeticdecoder.cpp arithmeticencoder.cpp arithmeticmodel.cpp integercompressor.cpp lasindex.cpp lasinterval.cpp lasquadtree.cpp lasreaditemcompressed_v1.cpp lasreaditemcompressed_v2.cpp lasreaditemcompressed_v3.cpp lasreaditemcompressed_v4.cpp lasreadpoint.cpp laswriteitemcompressed_v1.cpp laswriteitemcompressed_v2.cpp laswriteitemcompressed_v3.cpp laswriteitemcompressed_v4.cpp laswritepoint.cpp laszip.cpp laszip_dll.cpp mydefs.cpp ) add_definitions(-DLASZIPDLL_EXPORTS) add_definitions(-DUNORDERED) if(HAVE_UNORDERED_MAP) add_definitions(-DHAVE_UNORDERED_MAP=1) endif(HAVE_UNORDERED_MAP) LASZIP_ADD_LIBRARY(${LASZIP_BASE_LIB_NAME} ${LASZIP_SOURCES}) LASzip-3.4.3/src/arithmeticdecoder.cpp000066400000000000000000000271461356234217100176530ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticdecoder.cpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // **************************** - // ARITHMETIC CODING EXAMPLES - // **************************** - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. The original version of this code can be found in - // Digital Signal Compression: Principles and Practice - // (Cambridge University Press, 2011, ISBN: 9780511984655) - // - // Copyright (c) 2019 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // 1. Redistributions of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // 2. Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include "arithmeticdecoder.hpp" #include #include #include "arithmeticmodel.hpp" ArithmeticDecoder::ArithmeticDecoder() { instream = 0; } BOOL ArithmeticDecoder::init(ByteStreamIn* instream, BOOL really_init) { if (instream == 0) return FALSE; this->instream = instream; length = AC__MaxLength; if (really_init) { value = (instream->getByte() << 24); value |= (instream->getByte() << 16); value |= (instream->getByte() << 8); value |= (instream->getByte()); } return TRUE; } void ArithmeticDecoder::done() { instream = 0; } ArithmeticBitModel* ArithmeticDecoder::createBitModel() { ArithmeticBitModel* m = new ArithmeticBitModel(); return m; } void ArithmeticDecoder::initBitModel(ArithmeticBitModel* m) { m->init(); } void ArithmeticDecoder::destroyBitModel(ArithmeticBitModel* m) { delete m; } ArithmeticModel* ArithmeticDecoder::createSymbolModel(U32 n) { ArithmeticModel* m = new ArithmeticModel(n, FALSE); return m; } void ArithmeticDecoder::initSymbolModel(ArithmeticModel* m, U32 *table) { m->init(table); } void ArithmeticDecoder::destroySymbolModel(ArithmeticModel* m) { delete m; } U32 ArithmeticDecoder::decodeBit(ArithmeticBitModel* m) { assert(m); U32 x = m->bit_0_prob * (length >> BM__LengthShift); // product l x p0 U32 sym = (value >= x); // decision // update & shift interval if (sym == 0) { length = x; ++m->bit_0_count; } else { value -= x; // shifted interval base = 0 length -= x; } if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (--m->bits_until_update == 0) m->update(); // periodic model update return sym; // return data bit value } U32 ArithmeticDecoder::decodeSymbol(ArithmeticModel* m) { U32 n, sym, x, y = length; if (m->decoder_table) { // use table look-up for faster decoding unsigned dv = value / (length >>= DM__LengthShift); unsigned t = dv >> m->table_shift; sym = m->decoder_table[t]; // initial decision based on table look-up n = m->decoder_table[t+1] + 1; while (n > sym + 1) { // finish with bisection search U32 k = (sym + n) >> 1; if (m->distribution[k] > dv) n = k; else sym = k; } // compute products x = m->distribution[sym] * length; if (sym != m->last_symbol) y = m->distribution[sym+1] * length; } else { // decode using only multiplications x = sym = 0; length >>= DM__LengthShift; U32 k = (n = m->symbols) >> 1; // decode via bisection search do { U32 z = length * m->distribution[k]; if (z > value) { n = k; y = z; // value is smaller } else { sym = k; x = z; // value is larger or equal } } while ((k = (sym + n) >> 1) != sym); } value -= x; // update interval length = y - x; if (length < AC__MinLength) renorm_dec_interval(); // renormalization ++m->symbol_count[sym]; if (--m->symbols_until_update == 0) m->update(); // periodic model update assert(sym < m->symbols); return sym; } U32 ArithmeticDecoder::readBit() { U32 sym = value / (length >>= 1); // decode symbol, change length value -= length * sym; // update interval if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (sym >= 2) { throw 4711; } return sym; } U32 ArithmeticDecoder::readBits(U32 bits) { assert(bits && (bits <= 32)); if (bits > 19) { U32 tmp = readShort(); bits = bits - 16; U32 tmp1 = readBits(bits) << 16; return (tmp1|tmp); } U32 sym = value / (length >>= bits);// decode symbol, change length value -= length * sym; // update interval if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (sym >= (1u<>= 8); // decode symbol, change length value -= length * sym; // update interval if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (sym >= (1u<<8)) { throw 4711; } return (U8)sym; } U16 ArithmeticDecoder::readShort() { U32 sym = value / (length >>= 16); // decode symbol, change length value -= length * sym; // update interval if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (sym >= (1u<<16)) { throw 4711; } return (U16)sym; } U32 ArithmeticDecoder::readInt() { U32 lowerInt = readShort(); U32 upperInt = readShort(); return (upperInt<<16)|lowerInt; } F32 ArithmeticDecoder::readFloat() /* danger in float reinterpretation */ { U32I32F32 u32i32f32; u32i32f32.u32 = readInt(); return u32i32f32.f32; } U64 ArithmeticDecoder::readInt64() { U64 lowerInt = readInt(); U64 upperInt = readInt(); return (upperInt<<32)|lowerInt; } F64 ArithmeticDecoder::readDouble() /* danger in float reinterpretation */ { U64I64F64 u64i64f64; u64i64f64.u64 = readInt64(); return u64i64f64.f64; } ArithmeticDecoder::~ArithmeticDecoder() { } inline void ArithmeticDecoder::renorm_dec_interval() { do { // read least-significant byte value = (value << 8) | instream->getByte(); } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 } LASzip-3.4.3/src/arithmeticdecoder.hpp000066400000000000000000000064711356234217100176560ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticdecoder.hpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 22 August 2016 -- can be used as init dummy by "native LAS 1.4 compressor" 13 November 2014 -- integrity check in readBits(), readByte(), readShort() 6 September 2014 -- removed the (unused) inheritance from EntropyDecoder 10 January 2011 -- licensing change for LGPL release and liblas integration 8 December 2010 -- unified framework for all entropy coders 30 October 2009 -- refactoring Amir Said's FastAC code =============================================================================== */ #ifndef ARITHMETIC_DECODER_HPP #define ARITHMETIC_DECODER_HPP #include "mydefs.hpp" #include "bytestreamin.hpp" class ArithmeticModel; class ArithmeticBitModel; class ArithmeticDecoder { public: /* Constructor & Destructor */ ArithmeticDecoder(); ~ArithmeticDecoder(); /* Manage decoding */ BOOL init(ByteStreamIn* instream, BOOL really_init = TRUE); void done(); /* Manage an entropy model for a single bit */ ArithmeticBitModel* createBitModel(); void initBitModel(ArithmeticBitModel* model); void destroyBitModel(ArithmeticBitModel* model); /* Manage an entropy model for n symbols (table optional) */ ArithmeticModel* createSymbolModel(U32 n); void initSymbolModel(ArithmeticModel* model, U32* table=0); void destroySymbolModel(ArithmeticModel* model); /* Decode a bit with modelling */ U32 decodeBit(ArithmeticBitModel* model); /* Decode a symbol with modelling */ U32 decodeSymbol(ArithmeticModel* model); /* Decode a bit without modelling */ U32 readBit(); /* Decode bits without modelling */ U32 readBits(U32 bits); /* Decode an unsigned char without modelling */ U8 readByte(); /* Decode an unsigned short without modelling */ U16 readShort(); /* Decode an unsigned int without modelling */ U32 readInt(); /* Decode a float without modelling */ F32 readFloat(); /* Decode an unsigned 64 bit int without modelling */ U64 readInt64(); /* Decode a double without modelling */ F64 readDouble(); /* Only read from instream if ArithmeticDecoder is dummy */ ByteStreamIn* getByteStreamIn() const { return instream; }; private: ByteStreamIn* instream; void renorm_dec_interval(); U32 value, length; }; #endif LASzip-3.4.3/src/arithmeticencoder.cpp000066400000000000000000000312151356234217100176550ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticencoder.cpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // **************************** - // ARITHMETIC CODING EXAMPLES - // **************************** - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. The original version of this code can be found in - // Digital Signal Compression: Principles and Practice - // (Cambridge University Press, 2011, ISBN: 9780511984655) - // - // Copyright (c) 2019 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // 1. Redistributions of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // 2. Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include "arithmeticencoder.hpp" #include #include #include FILE* file = 0; #include "arithmeticmodel.hpp" ArithmeticEncoder::ArithmeticEncoder() { outstream = 0; outbuffer = (U8*)malloc(sizeof(U8)*2*AC_BUFFER_SIZE); endbuffer = outbuffer + 2 * AC_BUFFER_SIZE; } ArithmeticEncoder::~ArithmeticEncoder() { free(outbuffer); } BOOL ArithmeticEncoder::init(ByteStreamOut* outstream) { if (outstream == 0) return FALSE; this->outstream = outstream; base = 0; length = AC__MaxLength; outbyte = outbuffer; endbyte = endbuffer; return TRUE; } void ArithmeticEncoder::done() { U32 init_base = base; // done encoding: set final data bytes BOOL another_byte = TRUE; if (length > 2 * AC__MinLength) { base += AC__MinLength; // base offset length = AC__MinLength >> 1; // set new length for 1 more byte } else { base += AC__MinLength >> 1; // base offset length = AC__MinLength >> 9; // set new length for 2 more bytes another_byte = FALSE; } if (init_base > base) propagate_carry(); // overflow = carry renorm_enc_interval(); // renormalization = output last bytes if (endbyte != endbuffer) { assert(outbyte < outbuffer + AC_BUFFER_SIZE); outstream->putBytes(outbuffer + AC_BUFFER_SIZE, AC_BUFFER_SIZE); } U32 buffer_size = (U32)(outbyte - outbuffer); if (buffer_size) outstream->putBytes(outbuffer, buffer_size); // write two or three zero bytes to be in sync with the decoder's byte reads outstream->putByte(0); outstream->putByte(0); if (another_byte) outstream->putByte(0); outstream = 0; } ArithmeticBitModel* ArithmeticEncoder::createBitModel() { ArithmeticBitModel* m = new ArithmeticBitModel(); return m; } void ArithmeticEncoder::initBitModel(ArithmeticBitModel* m) { m->init(); } void ArithmeticEncoder::destroyBitModel(ArithmeticBitModel* m) { delete m; } ArithmeticModel* ArithmeticEncoder::createSymbolModel(U32 n) { ArithmeticModel* m = new ArithmeticModel(n, true); return m; } void ArithmeticEncoder::initSymbolModel(ArithmeticModel* m, U32* table) { m->init(table); } void ArithmeticEncoder::destroySymbolModel(ArithmeticModel* m) { delete m; } void ArithmeticEncoder::encodeBit(ArithmeticBitModel* m, U32 sym) { assert(m && (sym <= 1)); U32 x = m->bit_0_prob * (length >> BM__LengthShift); // product l x p0 // update interval if (sym == 0) { length = x; ++m->bit_0_count; } else { U32 init_base = base; base += x; length -= x; if (init_base > base) propagate_carry(); // overflow = carry } if (length < AC__MinLength) renorm_enc_interval(); // renormalization if (--m->bits_until_update == 0) m->update(); // periodic model update } void ArithmeticEncoder::encodeSymbol(ArithmeticModel* m, U32 sym) { assert(m && (sym <= m->last_symbol)); U32 x, init_base = base; // compute products if (sym == m->last_symbol) { x = m->distribution[sym] * (length >> DM__LengthShift); base += x; // update interval length -= x; // no product needed } else { x = m->distribution[sym] * (length >>= DM__LengthShift); base += x; // update interval length = m->distribution[sym+1] * length - x; } if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization ++m->symbol_count[sym]; if (--m->symbols_until_update == 0) m->update(); // periodic model update } void ArithmeticEncoder::writeBit(U32 sym) { assert(sym < 2); U32 init_base = base; base += sym * (length >>= 1); // new interval base and length if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } void ArithmeticEncoder::writeBits(U32 bits, U32 sym) { assert(bits && (bits <= 32) && (sym < (1u< 19) { writeShort(sym&U16_MAX); sym = sym >> 16; bits = bits - 16; } U32 init_base = base; base += sym * (length >>= bits); // new interval base and length if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } void ArithmeticEncoder::writeByte(U8 sym) { U32 init_base = base; base += (U32)(sym) * (length >>= 8); // new interval base and length if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } void ArithmeticEncoder::writeShort(U16 sym) { U32 init_base = base; base += (U32)(sym) * (length >>= 16); // new interval base and length if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } void ArithmeticEncoder::writeInt(U32 sym) { writeShort((U16)(sym & 0xFFFF)); // lower 16 bits writeShort((U16)(sym >> 16)); // UPPER 16 bits } void ArithmeticEncoder::writeFloat(F32 sym) /* danger in float reinterpretation */ { U32I32F32 u32i32f32; u32i32f32.f32 = sym; writeInt(u32i32f32.u32); } void ArithmeticEncoder::writeInt64(U64 sym) { writeInt((U32)(sym & 0xFFFFFFFF)); // lower 32 bits writeInt((U32)(sym >> 32)); // UPPER 32 bits } void ArithmeticEncoder::writeDouble(F64 sym) /* danger in float reinterpretation */ { U64I64F64 u64i64f64; u64i64f64.f64 = sym; writeInt64(u64i64f64.u64); } inline void ArithmeticEncoder::propagate_carry() { U8 * p; if (outbyte == outbuffer) p = endbuffer - 1; else p = outbyte - 1; while (*p == 0xFFU) { *p = 0; if (p == outbuffer) p = endbuffer - 1; else p--; assert(outbuffer <= p); assert(p < endbuffer); assert(outbyte < endbuffer); } ++*p; } inline void ArithmeticEncoder::renorm_enc_interval() { do { // output and discard top byte assert(outbuffer <= outbyte); assert(outbyte < endbuffer); assert(outbyte < endbyte); *outbyte++ = (U8)(base >> 24); if (outbyte == endbyte) manage_outbuffer(); base <<= 8; } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 } inline void ArithmeticEncoder::manage_outbuffer() { if (outbyte == endbuffer) outbyte = outbuffer; outstream->putBytes(outbyte, AC_BUFFER_SIZE); endbyte = outbyte + AC_BUFFER_SIZE; assert(endbyte > outbyte); assert(outbyte < endbuffer); } LASzip-3.4.3/src/arithmeticencoder.hpp000066400000000000000000000066661356234217100176760ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticencoder.hpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 1 July 2016 -- can be used as init dummy by "native LAS 1.4 compressor" 6 September 2014 -- removed the (unused) inheritance from EntropyEncoder 10 January 2011 -- licensing change for LGPL release and liblas integration 8 December 2010 -- unified framework for all entropy coders 30 October 2009 -- refactoring Amir Said's FastAC code =============================================================================== */ #ifndef ARITHMETIC_ENCODER_HPP #define ARITHMETIC_ENCODER_HPP #include "mydefs.hpp" #include "bytestreamout.hpp" class ArithmeticModel; class ArithmeticBitModel; class ArithmeticEncoder { public: /* Constructor & Destructor */ ArithmeticEncoder(); ~ArithmeticEncoder(); /* Manage encoding */ BOOL init(ByteStreamOut* outstream); void done(); /* Manage an entropy model for a single bit */ ArithmeticBitModel* createBitModel(); void initBitModel(ArithmeticBitModel* model); void destroyBitModel(ArithmeticBitModel* model); /* Manage an entropy model for n symbols (table optional) */ ArithmeticModel* createSymbolModel(U32 n); void initSymbolModel(ArithmeticModel* model, U32 *table=0); void destroySymbolModel(ArithmeticModel* model); /* Encode a bit with modelling */ void encodeBit(ArithmeticBitModel* model, U32 sym); /* Encode a symbol with modelling */ void encodeSymbol(ArithmeticModel* model, U32 sym); /* Encode a bit without modelling */ void writeBit(U32 sym); /* Encode bits without modelling */ void writeBits(U32 bits, U32 sym); /* Encode an unsigned char without modelling */ void writeByte(U8 sym); /* Encode an unsigned short without modelling */ void writeShort(U16 sym); /* Encode an unsigned int without modelling */ void writeInt(U32 sym); /* Encode a float without modelling */ void writeFloat(F32 sym); /* Encode an unsigned 64 bit int without modelling */ void writeInt64(U64 sym); /* Encode a double without modelling */ void writeDouble(F64 sym); /* Only write to outstream if ArithmeticEncoder is dummy */ ByteStreamOut* getByteStreamOut() const { return outstream; }; private: ByteStreamOut* outstream; void propagate_carry(); void renorm_enc_interval(); void manage_outbuffer(); U8* outbuffer; U8* endbuffer; U8* outbyte; U8* endbyte; U32 base, length; }; #endif LASzip-3.4.3/src/arithmeticmodel.cpp000066400000000000000000000163001356234217100173340ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticmodel.cpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. It is provided as is, without any express or - // implied warranty, without even the warranty of fitness for any particular - // purpose, or that the implementations are correct. - // - // Permission to copy and redistribute this code is hereby granted, provided - // that this warning and copyright notices are not removed or altered. - // - // Copyright (c) 2004 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include "arithmeticmodel.hpp" #include #include ArithmeticModel::ArithmeticModel(U32 symbols, BOOL compress) { this->symbols = symbols; this->compress = compress; distribution = 0; } ArithmeticModel::~ArithmeticModel() { if (distribution) delete [] distribution; } I32 ArithmeticModel::init(U32* table) { if (distribution == 0) { if ( (symbols < 2) || (symbols > (1 << 11)) ) { return -1; // invalid number of symbols } last_symbol = symbols - 1; if ((!compress) && (symbols > 16)) { U32 table_bits = 3; while (symbols > (1U << (table_bits + 2))) ++table_bits; table_size = 1 << table_bits; table_shift = DM__LengthShift - table_bits; distribution = new U32[2*symbols+table_size+2]; decoder_table = distribution + 2 * symbols; } else // small alphabet: no table needed { decoder_table = 0; table_size = table_shift = 0; distribution = new U32[2*symbols]; } if (distribution == 0) { return -1; // "cannot allocate model memory"); } symbol_count = distribution + symbols; } total_count = 0; update_cycle = symbols; if (table) for (U32 k = 0; k < symbols; k++) symbol_count[k] = table[k]; else for (U32 k = 0; k < symbols; k++) symbol_count[k] = 1; update(); symbols_until_update = update_cycle = (symbols + 6) >> 1; return 0; } void ArithmeticModel::update() { // halve counts when a threshold is reached if ((total_count += update_cycle) > DM__MaxCount) { total_count = 0; for (U32 n = 0; n < symbols; n++) { total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1); } } // compute cumulative distribution, decoder table U32 k, sum = 0, s = 0; U32 scale = 0x80000000U / total_count; if (compress || (table_size == 0)) { for (k = 0; k < symbols; k++) { distribution[k] = (scale * sum) >> (31 - DM__LengthShift); sum += symbol_count[k]; } } else { for (k = 0; k < symbols; k++) { distribution[k] = (scale * sum) >> (31 - DM__LengthShift); sum += symbol_count[k]; U32 w = distribution[k] >> table_shift; while (s < w) decoder_table[++s] = k - 1; } decoder_table[0] = 0; while (s <= table_size) decoder_table[++s] = symbols - 1; } // set frequency of model updates update_cycle = (5 * update_cycle) >> 2; U32 max_cycle = (symbols + 6) << 3; if (update_cycle > max_cycle) update_cycle = max_cycle; symbols_until_update = update_cycle; } ArithmeticBitModel::ArithmeticBitModel() { init(); } ArithmeticBitModel::~ArithmeticBitModel() { } void ArithmeticBitModel::init() { // initialization to equiprobable model bit_0_count = 1; bit_count = 2; bit_0_prob = 1U << (BM__LengthShift - 1); // start with frequent updates update_cycle = bits_until_update = 4; } void ArithmeticBitModel::update() { // halve counts when a threshold is reached if ((bit_count += update_cycle) > BM__MaxCount) { bit_count = (bit_count + 1) >> 1; bit_0_count = (bit_0_count + 1) >> 1; if (bit_0_count == bit_count) ++bit_count; } // compute scaled bit 0 probability U32 scale = 0x80000000U / bit_count; bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift); // set frequency of model updates update_cycle = (5 * update_cycle) >> 2; if (update_cycle > 64) update_cycle = 64; bits_until_update = update_cycle; } LASzip-3.4.3/src/arithmeticmodel.hpp000066400000000000000000000053251356234217100173460ustar00rootroot00000000000000/* =============================================================================== FILE: arithmeticmodel.hpp CONTENTS: A modular C++ wrapper for an adapted version of Amir Said's FastAC Code. see: http://www.cipr.rpi.edu/~said/FastAC.html PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 11 April 2019 -- 1024 AC_BUFFER_SIZE to 4096 for propagate_carry() overflow 10 January 2011 -- licensing change for LGPL release and liblas integration 8 December 2010 -- unified framework for all entropy coders 30 October 2009 -- refactoring Amir Said's FastAC code =============================================================================== */ #ifndef ARITHMETIC_MODEL_HPP #define ARITHMETIC_MODEL_HPP #include #include #include "mydefs.hpp" /* this header byte needs to change in case incompatible change happen */ #define AC_HEADER_BYTE 2 #define AC_BUFFER_SIZE 4096 const U32 AC__MinLength = 0x01000000U; // threshold for renormalization const U32 AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length // Maximum values for binary models const U32 BM__LengthShift = 13; // length bits discarded before mult. const U32 BM__MaxCount = 1 << BM__LengthShift; // for adaptive models // Maximum values for general models const U32 DM__LengthShift = 15; // length bits discarded before mult. const U32 DM__MaxCount = 1 << DM__LengthShift; // for adaptive models class ArithmeticModel { public: ArithmeticModel(U32 symbols, BOOL compress); ~ArithmeticModel(); I32 init(U32* table=0); private: void update(); U32 * distribution, * symbol_count, * decoder_table; U32 total_count, update_cycle, symbols_until_update; U32 symbols, last_symbol, table_size, table_shift; BOOL compress; friend class ArithmeticEncoder; friend class ArithmeticDecoder; }; class ArithmeticBitModel { public: ArithmeticBitModel(); ~ArithmeticBitModel(); void init(); private: void update(); U32 update_cycle, bits_until_update; U32 bit_0_prob, bit_0_count, bit_count; friend class ArithmeticEncoder; friend class ArithmeticDecoder; }; #endif LASzip-3.4.3/src/bytestreamin.hpp000066400000000000000000000067301356234217100167030ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamin.hpp CONTENTS: Abstract base class for input streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 2 January 2013 -- new functions for reading a stream of groups of bits 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_IN_HPP #define BYTE_STREAM_IN_HPP #include "mydefs.hpp" class ByteStreamIn { public: /* write single bits */ inline U32 getBits(U32 num_bits) { if (num_buffer < num_bits) { U32 input_bits; get32bitsLE((U8*)&input_bits); bit_buffer = bit_buffer | (((U64)input_bits) << num_buffer); num_buffer = num_buffer + 32; } U32 new_bits = (U32)(bit_buffer & ((1 << num_bits) - 1)); bit_buffer = bit_buffer >> num_bits; num_buffer = num_buffer - num_bits; return new_bits; }; /* read a single byte */ virtual U32 getByte() = 0; /* read an array of bytes */ virtual void getBytes(U8* bytes, const U32 num_bytes) = 0; /* read 16 bit low-endian field */ virtual void get16bitsLE(U8* bytes) = 0; /* read 32 bit low-endian field */ virtual void get32bitsLE(U8* bytes) = 0; /* read 64 bit low-endian field */ virtual void get64bitsLE(U8* bytes) = 0; /* read 16 bit big-endian field */ virtual void get16bitsBE(U8* bytes) = 0; /* read 32 bit big-endian field */ virtual void get32bitsBE(U8* bytes) = 0; /* read 64 bit big-endian field */ virtual void get64bitsBE(U8* bytes) = 0; /* is the stream seekable (e.g. stdin is not) */ virtual BOOL isSeekable() const = 0; /* get current position of stream */ virtual I64 tell() const = 0; /* seek to this position in the stream */ virtual BOOL seek(const I64 position) = 0; /* seek to the end of the file */ virtual BOOL seekEnd(const I64 distance=0) = 0; /* seek to the end of the file */ virtual BOOL skipBytes(const U32 num_bytes) { I64 curr = tell(); return seek(curr + num_bytes); }; /* constructor */ inline ByteStreamIn() { bit_buffer = 0; num_buffer = 0; }; /* destructor */ virtual ~ByteStreamIn() {}; private: U64 bit_buffer; U32 num_buffer; }; #endif LASzip-3.4.3/src/bytestreamin_array.hpp000066400000000000000000000154361356234217100201040ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamin_array.hpp CONTENTS: PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 23 June 2016 -- alternative init option for "native LAS 1.4 compressor" 19 July 2015 -- moved from LASlib to LASzip for "compatibility mode" in DLL 9 April 2012 -- created after cooking Zuccini/Onion/Potatoe dinner for Mara =============================================================================== */ #ifndef BYTE_STREAM_IN_ARRAY_H #define BYTE_STREAM_IN_ARRAY_H #include "bytestreamin.hpp" #include #include class ByteStreamInArray : public ByteStreamIn { public: ByteStreamInArray(); ByteStreamInArray(const U8* data, I64 size); /* init the array */ BOOL init(const U8* data, I64 size); /* read a single byte */ U32 getByte(); /* read an array of bytes */ void getBytes(U8* bytes, const U32 num_bytes); /* is the stream seekable (e.g. stdin is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the stream */ BOOL seekEnd(const I64 distance=0); /* destructor */ ~ByteStreamInArray(){}; protected: const U8* data; I64 size; I64 curr; }; class ByteStreamInArrayLE : public ByteStreamInArray { public: ByteStreamInArrayLE(); ByteStreamInArrayLE(const U8* data, I64 size); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; class ByteStreamInArrayBE : public ByteStreamInArray { public: ByteStreamInArrayBE(); ByteStreamInArrayBE(const U8* data, I64 size); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; inline ByteStreamInArray::ByteStreamInArray() { this->data = 0; this->size = 0; this->curr = 0; } inline ByteStreamInArray::ByteStreamInArray(const U8* data, I64 size) { init(data, size); } inline BOOL ByteStreamInArray::init(const U8* data, I64 size) { this->curr = 0; if (data) { this->data = data; this->size = size; } else { this->data = 0; this->size = 0; if (size) return FALSE; } return TRUE; } inline U32 ByteStreamInArray::getByte() { if (curr == size) { throw EOF; } U32 byte = data[curr]; curr++; return byte; } inline void ByteStreamInArray::getBytes(U8* bytes, const U32 num_bytes) { if ((curr + num_bytes) > size) { throw EOF; } memcpy((void*)bytes, (void*)(data+curr), num_bytes); curr += num_bytes; } inline BOOL ByteStreamInArray::isSeekable() const { return TRUE; } inline I64 ByteStreamInArray::tell() const { return curr; } inline BOOL ByteStreamInArray::seek(const I64 position) { if ((0 <= position) && (position <= size)) { curr = position; return TRUE; } return FALSE; } inline BOOL ByteStreamInArray::seekEnd(const I64 distance) { if ((0 <= distance) && (distance <= size)) { curr = size - distance; return TRUE; } return FALSE; } inline ByteStreamInArrayLE::ByteStreamInArrayLE() : ByteStreamInArray() { } inline ByteStreamInArrayLE::ByteStreamInArrayLE(const U8* data, I64 size) : ByteStreamInArray(data, size) { } inline void ByteStreamInArrayLE::get16bitsLE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInArrayLE::get32bitsLE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInArrayLE::get64bitsLE(U8* bytes) { getBytes(bytes, 8); } inline void ByteStreamInArrayLE::get16bitsBE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInArrayLE::get32bitsBE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInArrayLE::get64bitsBE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline ByteStreamInArrayBE::ByteStreamInArrayBE() : ByteStreamInArray() { } inline ByteStreamInArrayBE::ByteStreamInArrayBE(const U8* data, I64 size) : ByteStreamInArray(data, size) { } inline void ByteStreamInArrayBE::get16bitsLE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInArrayBE::get32bitsLE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInArrayBE::get64bitsLE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline void ByteStreamInArrayBE::get16bitsBE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInArrayBE::get32bitsBE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInArrayBE::get64bitsBE(U8* bytes) { getBytes(bytes, 8); } #endif LASzip-3.4.3/src/bytestreamin_file.hpp000066400000000000000000000154721356234217100177050ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamin_file.hpp CONTENTS: Class for FILE*-based input streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_IN_FILE_H #define BYTE_STREAM_IN_FILE_H #include "bytestreamin.hpp" #include #if defined(_MSC_VER) && (_MSC_VER < 1300) extern "C" __int64 _cdecl _ftelli64(FILE*); extern "C" int _cdecl _fseeki64(FILE*, __int64, int); #endif class ByteStreamInFile : public ByteStreamIn { public: ByteStreamInFile(FILE* file); /* read a single byte */ U32 getByte(); /* read an array of bytes */ void getBytes(U8* bytes, const U32 num_bytes); /* is the stream seekable (e.g. stdin is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(const I64 distance=0); /* destructor */ ~ByteStreamInFile(){}; protected: FILE* file; }; class ByteStreamInFileLE : public ByteStreamInFile { public: ByteStreamInFileLE(FILE* file); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; class ByteStreamInFileBE : public ByteStreamInFile { public: ByteStreamInFileBE(FILE* file); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; inline ByteStreamInFile::ByteStreamInFile(FILE* file) { this->file = file; } inline U32 ByteStreamInFile::getByte() { int byte = getc(file); if (byte == EOF) { throw EOF; } return (U32)byte; } inline void ByteStreamInFile::getBytes(U8* bytes, const U32 num_bytes) { if (fread(bytes, 1, num_bytes, file) != num_bytes) { throw EOF; } } inline BOOL ByteStreamInFile::isSeekable() const { return (file != stdin); } inline I64 ByteStreamInFile::tell() const { #if defined _WIN32 && ! defined (__MINGW32__) return _ftelli64(file); #elif defined (__MINGW32__) return (I64)ftello64(file); #else return (I64)ftello(file); #endif } inline BOOL ByteStreamInFile::seek(const I64 position) { if (tell() != position) { #if defined _WIN32 && ! defined (__MINGW32__) return !(_fseeki64(file, position, SEEK_SET)); #elif defined (__MINGW32__) return !(fseeko64(file, (off_t)position, SEEK_SET)); #else return !(fseeko(file, (off_t)position, SEEK_SET)); #endif } return TRUE; } inline BOOL ByteStreamInFile::seekEnd(const I64 distance) { #if defined _WIN32 && ! defined (__MINGW32__) return !(_fseeki64(file, -distance, SEEK_END)); #elif defined (__MINGW32__) return !(fseeko64(file, (off_t)-distance, SEEK_END)); #else return !(fseeko(file, (off_t)-distance, SEEK_END)); #endif } inline ByteStreamInFileLE::ByteStreamInFileLE(FILE* file) : ByteStreamInFile(file) { } inline void ByteStreamInFileLE::get16bitsLE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInFileLE::get32bitsLE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInFileLE::get64bitsLE(U8* bytes) { getBytes(bytes, 8); } inline void ByteStreamInFileLE::get16bitsBE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInFileLE::get32bitsBE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInFileLE::get64bitsBE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline ByteStreamInFileBE::ByteStreamInFileBE(FILE* file) : ByteStreamInFile(file) { } inline void ByteStreamInFileBE::get16bitsLE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInFileBE::get32bitsLE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInFileBE::get64bitsLE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline void ByteStreamInFileBE::get16bitsBE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInFileBE::get32bitsBE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInFileBE::get64bitsBE(U8* bytes) { getBytes(bytes, 8); } #endif LASzip-3.4.3/src/bytestreamin_istream.hpp000066400000000000000000000152321356234217100204240ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamin_istream.hpp CONTENTS: Class for istream-based input streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2018, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 10 July 2018 -- because it's hard to determine seek-ability, user must set it 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_IN_ISTREAM_H #define BYTE_STREAM_IN_ISTREAM_H #include "bytestreamin.hpp" #ifdef LZ_WIN32_VC6 #include #else #include #include using namespace std; #endif class ByteStreamInIstream : public ByteStreamIn { public: ByteStreamInIstream(istream& stream, BOOL seekable=TRUE); /* read a single byte */ U32 getByte(); /* read an array of bytes */ void getBytes(U8* bytes, const U32 num_bytes); /* is the stream seekable (e.g. stdin is not) */ BOOL isSeekable() const { return seekable; }; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(const I64 distance=0); /* destructor */ ~ByteStreamInIstream(){}; protected: istream& stream; BOOL seekable; }; class ByteStreamInIstreamLE : public ByteStreamInIstream { public: ByteStreamInIstreamLE(istream& stream, BOOL seekable=TRUE); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; class ByteStreamInIstreamBE : public ByteStreamInIstream { public: ByteStreamInIstreamBE(istream& stream, BOOL seekable=TRUE); /* read 16 bit low-endian field */ void get16bitsLE(U8* bytes); /* read 32 bit low-endian field */ void get32bitsLE(U8* bytes); /* read 64 bit low-endian field */ void get64bitsLE(U8* bytes); /* read 16 bit big-endian field */ void get16bitsBE(U8* bytes); /* read 32 bit big-endian field */ void get32bitsBE(U8* bytes); /* read 64 bit big-endian field */ void get64bitsBE(U8* bytes); private: U8 swapped[8]; }; inline ByteStreamInIstream::ByteStreamInIstream(istream& stream_param, BOOL seekable_param) : stream(stream_param), seekable(seekable_param) { } inline U32 ByteStreamInIstream::getByte() { int byte = stream.get(); if (stream.eof()) { throw EOF; } return (U32)byte; } inline void ByteStreamInIstream::getBytes(U8* bytes, const U32 num_bytes) { stream.read((char*)bytes, num_bytes); if (!stream.good()) { throw EOF; } } inline I64 ByteStreamInIstream::tell() const { return (I64)stream.tellg(); } inline BOOL ByteStreamInIstream::seek(const I64 position) { if (tell() != position) { stream.seekg(static_cast(position)); return stream.good(); } return TRUE; } inline BOOL ByteStreamInIstream::seekEnd(const I64 distance) { stream.seekg(static_cast(-distance), ios::end); return stream.good(); } inline ByteStreamInIstreamLE::ByteStreamInIstreamLE(istream& stream, BOOL seekable) : ByteStreamInIstream(stream, seekable) { } inline void ByteStreamInIstreamLE::get16bitsLE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInIstreamLE::get32bitsLE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInIstreamLE::get64bitsLE(U8* bytes) { getBytes(bytes, 8); } inline void ByteStreamInIstreamLE::get16bitsBE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInIstreamLE::get32bitsBE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInIstreamLE::get64bitsBE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline ByteStreamInIstreamBE::ByteStreamInIstreamBE(istream& stream, BOOL seekable) : ByteStreamInIstream(stream, seekable) { } inline void ByteStreamInIstreamBE::get16bitsLE(U8* bytes) { getBytes(swapped, 2); bytes[0] = swapped[1]; bytes[1] = swapped[0]; } inline void ByteStreamInIstreamBE::get32bitsLE(U8* bytes) { getBytes(swapped, 4); bytes[0] = swapped[3]; bytes[1] = swapped[2]; bytes[2] = swapped[1]; bytes[3] = swapped[0]; } inline void ByteStreamInIstreamBE::get64bitsLE(U8* bytes) { getBytes(swapped, 8); bytes[0] = swapped[7]; bytes[1] = swapped[6]; bytes[2] = swapped[5]; bytes[3] = swapped[4]; bytes[4] = swapped[3]; bytes[5] = swapped[2]; bytes[6] = swapped[1]; bytes[7] = swapped[0]; } inline void ByteStreamInIstreamBE::get16bitsBE(U8* bytes) { getBytes(bytes, 2); } inline void ByteStreamInIstreamBE::get32bitsBE(U8* bytes) { getBytes(bytes, 4); } inline void ByteStreamInIstreamBE::get64bitsBE(U8* bytes) { getBytes(bytes, 8); } #endif LASzip-3.4.3/src/bytestreaminout.hpp000066400000000000000000000023601356234217100174260ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreaminout.hpp CONTENTS: Abstract base class for streams that both input and output with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 29 December 2013 -- created after helping a client to QA their Optech LiDAR =============================================================================== */ #ifndef BYTE_STREAM_INOUT_HPP #define BYTE_STREAM_INOUT_HPP #include "mydefs.hpp" #include "bytestreamin.hpp" #include "bytestreamout.hpp" class ByteStreamInOut : public ByteStreamIn, ByteStreamOut { public: /* destructor */ virtual ~ByteStreamInOut() {}; }; #endif LASzip-3.4.3/src/bytestreaminout_file.hpp000066400000000000000000000031141356234217100204230ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreaminout_file.hpp CONTENTS: Class for FILE*-based streams that both input and output with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 29 December 2013 -- created after helping a client to QA their Optech LiDAR =============================================================================== */ #ifndef BYTE_STREAM_INOUT_FILE_HPP #define BYTE_STREAM_INOUT_FILE_HPP #include "bytestreamin_file.hpp" #include "bytestreamout_file.hpp" class ByteStreamInOutFileLE : public ByteStreamInFileLE, public ByteStreamOutFileLE { public: ByteStreamInOutFileLE(FILE* file); }; class ByteStreamInOutFileBE : public ByteStreamInFileBE, public ByteStreamOutFileBE { public: ByteStreamInOutFileBE(FILE* file); }; inline ByteStreamInOutFileLE::ByteStreamInOutFileLE(FILE* file) : ByteStreamInFileLE(file), ByteStreamOutFileLE(file) { } inline ByteStreamInOutFileBE::ByteStreamInOutFileBE(FILE* file) : ByteStreamInFileBE(file), ByteStreamOutFileBE(file) { } #endif LASzip-3.4.3/src/bytestreamout.hpp000066400000000000000000000072161356234217100171040ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamout.hpp CONTENTS: Abstract base class for output streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 2 January 2013 -- new functions for writing a stream of groups of bits 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_OUT_HPP #define BYTE_STREAM_OUT_HPP #include "mydefs.hpp" class ByteStreamOut { public: /* write single bits */ inline BOOL putBits(U32 bits, U32 num_bits) { U64 new_bits = bits; bit_buffer |= (new_bits << num_buffer); num_buffer += num_bits; if (num_buffer >= 32) { U32 output_bits = (U32)(bit_buffer & U32_MAX); bit_buffer = bit_buffer >> 32; num_buffer = num_buffer - 32; return put32bitsLE((U8*)&output_bits); } return TRUE; }; /* called after writing bits before closing or writing bytes */ inline BOOL flushBits() { if (num_buffer) { U32 num_zero_bits = 32 - num_buffer; U32 output_bits = (U32)(bit_buffer >> num_zero_bits); bit_buffer = 0; num_buffer = 0; return put32bitsLE((U8*)&output_bits); } return TRUE; }; /* write a single byte */ virtual BOOL putByte(U8 byte) = 0; /* write an array of bytes */ virtual BOOL putBytes(const U8* bytes, U32 num_bytes) = 0; /* write 16 bit low-endian field */ virtual BOOL put16bitsLE(const U8* bytes) = 0; /* write 32 bit low-endian field */ virtual BOOL put32bitsLE(const U8* bytes) = 0; /* write 64 bit low-endian field */ virtual BOOL put64bitsLE(const U8* bytes) = 0; /* write 16 bit big-endian field */ virtual BOOL put16bitsBE(const U8* bytes) = 0; /* write 32 bit big-endian field */ virtual BOOL put32bitsBE(const U8* bytes) = 0; /* write 64 bit big-endian field */ virtual BOOL put64bitsBE(const U8* bytes) = 0; /* is the stream seekable (e.g. standard out is not) */ virtual BOOL isSeekable() const = 0; /* get current position of stream */ virtual I64 tell() const = 0; /* seek to this position in the stream */ virtual BOOL seek(const I64 position) = 0; /* seek to the end of the file */ virtual BOOL seekEnd() = 0; /* constructor */ inline ByteStreamOut() { bit_buffer = 0; num_buffer = 0; }; /* destructor */ virtual ~ByteStreamOut() {}; private: U64 bit_buffer; U32 num_buffer; }; #endif LASzip-3.4.3/src/bytestreamout_array.hpp000066400000000000000000000162011356234217100202740ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamout_array.hpp CONTENTS: PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 11 April 2019 -- increase default alloc from 1024 bytes to 4096 bytes 10 April 2019 -- fix potential memory leak found by Connor Manning's valgrind 22 June 2016 -- access to current size for "native LAS 1.4 compressor" 19 July 2015 -- moved from LASlib to LASzip for "compatibility mode" in DLL 9 April 2012 -- created after cooking Zuccini/Onion/Potatoe dinner for Mara =============================================================================== */ #ifndef BYTE_STREAM_OUT_ARRAY_HPP #define BYTE_STREAM_OUT_ARRAY_HPP #include "bytestreamout.hpp" #include #include class ByteStreamOutArray : public ByteStreamOut { public: ByteStreamOutArray(I64 alloc=4096); /* write a single byte */ BOOL putByte(U8 byte); /* write an array of bytes */ BOOL putBytes(const U8* bytes, U32 num_bytes); /* is the stream seekable (e.g. standard out is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(); /* destructor */ ~ByteStreamOutArray() { if (data) free(data); }; /* get access to data */ inline I64 getSize() const { return size; }; inline I64 getCurr() const { return curr; }; inline const U8* getData() const { return data; }; inline U8* takeData() { U8* d = data; data = 0; alloc = 0; size = 0; curr = 0; return d; }; protected: U8* data; I64 alloc; I64 size; I64 curr; }; class ByteStreamOutArrayLE : public ByteStreamOutArray { public: ByteStreamOutArrayLE(I64 alloc=4096); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; class ByteStreamOutArrayBE : public ByteStreamOutArray { public: ByteStreamOutArrayBE(I64 alloc=4096); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; inline ByteStreamOutArray::ByteStreamOutArray(I64 alloc) { this->data = (U8*)malloc((U32)alloc); this->alloc = alloc; this->size = 0; this->curr = 0; } inline BOOL ByteStreamOutArray::putByte(U8 byte) { if (curr == alloc) { alloc += 4096; data = (U8*)realloc(data, (U32)alloc); if (data == 0) { return FALSE; } } data[curr] = byte; if (curr == size) size++; curr++; return TRUE; } inline BOOL ByteStreamOutArray::putBytes(const U8* bytes, U32 num_bytes) { if ((curr+num_bytes) > alloc) { alloc += (4096+num_bytes); data = (U8*)realloc(data, (U32)alloc); if (data == 0) { return FALSE; } } memcpy((void*)(data+curr), bytes, num_bytes); curr += num_bytes; if (curr > size) size = curr; return TRUE; } inline BOOL ByteStreamOutArray::isSeekable() const { return TRUE; } inline I64 ByteStreamOutArray::tell() const { return curr; } inline BOOL ByteStreamOutArray::seek(I64 position) { if ((0 <= position) && (position <= size)) { curr = position; return TRUE; } return FALSE; } inline BOOL ByteStreamOutArray::seekEnd() { curr = size; return TRUE; /* if ((0 <= distance) && (distance <= size)) { curr = size - distance; return TRUE; } return FALSE; */ } inline ByteStreamOutArrayLE::ByteStreamOutArrayLE(I64 alloc) : ByteStreamOutArray(alloc) { } inline BOOL ByteStreamOutArrayLE::put16bitsLE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutArrayLE::put32bitsLE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutArrayLE::put64bitsLE(const U8* bytes) { return putBytes(bytes, 8); } inline BOOL ByteStreamOutArrayLE::put16bitsBE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutArrayLE::put32bitsBE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutArrayLE::put64bitsBE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline ByteStreamOutArrayBE::ByteStreamOutArrayBE(I64 alloc) : ByteStreamOutArray(alloc) { } inline BOOL ByteStreamOutArrayBE::put16bitsLE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutArrayBE::put32bitsLE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutArrayBE::put64bitsLE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline BOOL ByteStreamOutArrayBE::put16bitsBE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutArrayBE::put32bitsBE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutArrayBE::put64bitsBE(const U8* bytes) { return putBytes(bytes, 8); } #endif LASzip-3.4.3/src/bytestreamout_file.hpp000066400000000000000000000161561356234217100201060ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamout_file.hpp CONTENTS: Class for FILE*-based output streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_OUT_FILE_H #define BYTE_STREAM_OUT_FILE_H #include "bytestreamout.hpp" #include #if defined(_MSC_VER) && (_MSC_VER < 1300) extern "C" int _cdecl _fseeki64(FILE*, __int64, int); extern "C" __int64 _cdecl _ftelli64(FILE*); #endif class ByteStreamOutFile : public ByteStreamOut { public: ByteStreamOutFile(FILE* file); /* replace a closed FILE* with a reopened FILE* in "ab" mode */ BOOL refile(FILE* file); /* write a single byte */ BOOL putByte(U8 byte); /* write an array of bytes */ BOOL putBytes(const U8* bytes, U32 num_bytes); /* is the stream seekable (e.g. standard out is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(); /* destructor */ ~ByteStreamOutFile(){}; protected: FILE* file; }; class ByteStreamOutFileLE : public ByteStreamOutFile { public: ByteStreamOutFileLE(FILE* file); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; class ByteStreamOutFileBE : public ByteStreamOutFile { public: ByteStreamOutFileBE(FILE* file); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; inline ByteStreamOutFile::ByteStreamOutFile(FILE* file) { this->file = file; } inline BOOL ByteStreamOutFile::refile(FILE* file) { if (file == 0) return FALSE; this->file = file; return TRUE; } inline BOOL ByteStreamOutFile::putByte(U8 byte) { return (fputc(byte, file) == byte); } inline BOOL ByteStreamOutFile::putBytes(const U8* bytes, U32 num_bytes) { return (fwrite(bytes, 1, num_bytes, file) == num_bytes); } inline BOOL ByteStreamOutFile::isSeekable() const { return (file != stdout); } inline I64 ByteStreamOutFile::tell() const { #if defined _WIN32 && ! defined (__MINGW32__) return _ftelli64(file); #elif defined (__MINGW32__) return (I64)ftello64(file); #else return (I64)ftello(file); #endif } inline BOOL ByteStreamOutFile::seek(I64 position) { #if defined _WIN32 && ! defined (__MINGW32__) return !(_fseeki64(file, position, SEEK_SET)); #elif defined (__MINGW32__) return !(fseeko64(file, (off_t)position, SEEK_SET)); #else return !(fseeko(file, (off_t)position, SEEK_SET)); #endif } inline BOOL ByteStreamOutFile::seekEnd() { #if defined _WIN32 && ! defined (__MINGW32__) return !(_fseeki64(file, 0, SEEK_END)); #elif defined (__MINGW32__) return !(fseeko64(file, (off_t)0, SEEK_END)); #else return !(fseeko(file, (off_t)0, SEEK_END)); #endif } inline ByteStreamOutFileLE::ByteStreamOutFileLE(FILE* file) : ByteStreamOutFile(file) { } inline BOOL ByteStreamOutFileLE::put16bitsLE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutFileLE::put32bitsLE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutFileLE::put64bitsLE(const U8* bytes) { return putBytes(bytes, 8); } inline BOOL ByteStreamOutFileLE::put16bitsBE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutFileLE::put32bitsBE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutFileLE::put64bitsBE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline ByteStreamOutFileBE::ByteStreamOutFileBE(FILE* file) : ByteStreamOutFile(file) { } inline BOOL ByteStreamOutFileBE::put16bitsLE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutFileBE::put32bitsLE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutFileBE::put64bitsLE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline BOOL ByteStreamOutFileBE::put16bitsBE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutFileBE::put32bitsBE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutFileBE::put64bitsBE(const U8* bytes) { return putBytes(bytes, 8); } #endif LASzip-3.4.3/src/bytestreamout_nil.hpp000066400000000000000000000071051356234217100177430ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamout_.hpilp CONTENTS: Class for a black hole that only counts the bytes. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_OUT_NIL_H #define BYTE_STREAM_OUT_NIL_H #include "bytestreamout.hpp" #include class ByteStreamOutNil : public ByteStreamOut { public: ByteStreamOutNil(); /* write a single byte */ BOOL putByte(U8 byte); /* write an array of bytes */ BOOL putBytes(const U8* bytes, U32 num_bytes); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); /* is the stream seekable (e.g. standard out is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(); /* destructor */ ~ByteStreamOutNil(){}; private: I64 num_bytes; }; inline ByteStreamOutNil::ByteStreamOutNil() { num_bytes = 0; } inline BOOL ByteStreamOutNil::putByte(U8 byte) { num_bytes++; return TRUE; } inline BOOL ByteStreamOutNil::putBytes(const U8* bytes, U32 num_bytes) { this->num_bytes += num_bytes; return TRUE; } inline BOOL ByteStreamOutNil::put16bitsLE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutNil::put32bitsLE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutNil::put64bitsLE(const U8* bytes) { return putBytes(bytes, 8); } inline BOOL ByteStreamOutNil::put16bitsBE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutNil::put32bitsBE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutNil::put64bitsBE(const U8* bytes) { return putBytes(bytes, 8); } inline BOOL ByteStreamOutNil::isSeekable() const { return TRUE; } inline I64 ByteStreamOutNil::tell() const { return num_bytes; } inline BOOL ByteStreamOutNil::seek(I64 position) { return TRUE; } inline BOOL ByteStreamOutNil::seekEnd() { return TRUE; } #endif LASzip-3.4.3/src/bytestreamout_ostream.hpp000066400000000000000000000150421356234217100206320ustar00rootroot00000000000000/* =============================================================================== FILE: bytestreamout_ostream.hpp Class for ostream-based output streams with endian handling. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 1 October 2011 -- added 64 bit file support in MSVC 6.0 at McCafe at Hbf Linz 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-; =============================================================================== */ #ifndef BYTE_STREAM_OUT_OSTREAM_H #define BYTE_STREAM_OUT_OSTREAM_H #include "bytestreamout.hpp" #ifdef LZ_WIN32_VC6 #include #else #include #include using namespace std; #endif class ByteStreamOutOstream : public ByteStreamOut { public: ByteStreamOutOstream(ostream& stream); /* write a single byte */ BOOL putByte(U8 byte); /* write an array of bytes */ BOOL putBytes(const U8* bytes, U32 num_bytes); /* is the stream seekable (e.g. standard out is not) */ BOOL isSeekable() const; /* get current position of stream */ I64 tell() const; /* seek to this position in the stream */ BOOL seek(const I64 position); /* seek to the end of the file */ BOOL seekEnd(); /* destructor */ ~ByteStreamOutOstream(){}; protected: ostream& stream; }; class ByteStreamOutOstreamLE : public ByteStreamOutOstream { public: ByteStreamOutOstreamLE(ostream& stream); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; class ByteStreamOutOstreamBE : public ByteStreamOutOstream { public: ByteStreamOutOstreamBE(ostream& stream); /* write 16 bit low-endian field */ BOOL put16bitsLE(const U8* bytes); /* write 32 bit low-endian field */ BOOL put32bitsLE(const U8* bytes); /* write 64 bit low-endian field */ BOOL put64bitsLE(const U8* bytes); /* write 16 bit big-endian field */ BOOL put16bitsBE(const U8* bytes); /* write 32 bit big-endian field */ BOOL put32bitsBE(const U8* bytes); /* write 64 bit big-endian field */ BOOL put64bitsBE(const U8* bytes); private: U8 swapped[8]; }; inline ByteStreamOutOstream::ByteStreamOutOstream(ostream& stream_param) : stream(stream_param) { } inline BOOL ByteStreamOutOstream::putByte(U8 byte) { stream.put(byte); return stream.good(); } inline BOOL ByteStreamOutOstream::putBytes(const U8* bytes, U32 num_bytes) { stream.write((const char*)bytes, num_bytes); return stream.good(); } inline BOOL ByteStreamOutOstream::isSeekable() const { return !!(static_cast(stream)); } inline I64 ByteStreamOutOstream::tell() const { return (I64)stream.tellp(); } inline BOOL ByteStreamOutOstream::seek(I64 position) { stream.seekp(static_cast(position)); return stream.good(); } inline BOOL ByteStreamOutOstream::seekEnd() { stream.seekp(0, ios::end); return stream.good(); } inline ByteStreamOutOstreamLE::ByteStreamOutOstreamLE(ostream& stream) : ByteStreamOutOstream(stream) { } inline BOOL ByteStreamOutOstreamLE::put16bitsLE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutOstreamLE::put32bitsLE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutOstreamLE::put64bitsLE(const U8* bytes) { return putBytes(bytes, 8); } inline BOOL ByteStreamOutOstreamLE::put16bitsBE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutOstreamLE::put32bitsBE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutOstreamLE::put64bitsBE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline ByteStreamOutOstreamBE::ByteStreamOutOstreamBE(ostream& stream) : ByteStreamOutOstream(stream) { } inline BOOL ByteStreamOutOstreamBE::put16bitsLE(const U8* bytes) { swapped[0] = bytes[1]; swapped[1] = bytes[0]; return putBytes(swapped, 2); } inline BOOL ByteStreamOutOstreamBE::put32bitsLE(const U8* bytes) { swapped[0] = bytes[3]; swapped[1] = bytes[2]; swapped[2] = bytes[1]; swapped[3] = bytes[0]; return putBytes(swapped, 4); } inline BOOL ByteStreamOutOstreamBE::put64bitsLE(const U8* bytes) { swapped[0] = bytes[7]; swapped[1] = bytes[6]; swapped[2] = bytes[5]; swapped[3] = bytes[4]; swapped[4] = bytes[3]; swapped[5] = bytes[2]; swapped[6] = bytes[1]; swapped[7] = bytes[0]; return putBytes(swapped, 8); } inline BOOL ByteStreamOutOstreamBE::put16bitsBE(const U8* bytes) { return putBytes(bytes, 2); } inline BOOL ByteStreamOutOstreamBE::put32bitsBE(const U8* bytes) { return putBytes(bytes, 4); } inline BOOL ByteStreamOutOstreamBE::put64bitsBE(const U8* bytes) { return putBytes(bytes, 8); } #endif LASzip-3.4.3/src/endian.hpp000066400000000000000000000071551356234217100154350ustar00rootroot00000000000000/****************************************************************************** * $Id$ * * Project: liblas - http://liblas.org - A BSD library for LAS format data. * Purpose: Endian macros * Author: Mateusz Loskot, mateusz@loskot.net * * This file has been stolen from and * modified for libLAS purposes. * * (C) Copyright Mateusz Loskot 2007, mateusz@loskot.net * (C) Copyright Caleb Epstein 2005 * (C) Copyright John Maddock 2006 * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Revision History * 06 Feb 2006 - Initial Revision * 09 Nov 2006 - fixed variant and version bits for v4 guids * 13 Nov 2006 - added serialization * 17 Nov 2006 - added name-based guid creation * 20 Nov 2006 - add fixes for gcc (from Tim Blechmann) * 07 Mar 2007 - converted to header only * 20 Jan 2008 - removed dependency of Boost and modified for LASZIP (by Mateusz Loskot) ****************************************************************************** * * Copyright (c) 1997 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * * Copyright notice reproduced from , from * which this code was originally taken. * * Modified by Caleb Epstein to use with GNU libc and to * defined the BOOST_ENDIAN macro. ****************************************************************************/ #ifndef LASZIP_DETAIL_ENDIAN_HPP_INCLUDED #define LASZIP_DETAIL_ENDIAN_HPP_INCLUDED // GNU libc offers the helpful header which defines // __BYTE_ORDER #if defined (__GLIBC__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define LASZIP_LITTLE_ENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) # define LASZIP_BIG_ENDIAN # elif (__BYTE_ORDER == __PDP_ENDIAN) # define LASZIP_PDP_ENDIAN # else # error Unknown machine endianness detected. # endif # define LASZIP_BYTE_ORDER __BYTE_ORDER #elif defined(_BIG_ENDIAN) # define LASZIP_BIG_ENDIAN # define LASZIP_BYTE_ORDER 4321 #elif defined(_LITTLE_ENDIAN) # define LASZIP_LITTLE_ENDIAN # define LASZIP_BYTE_ORDER 1234 #elif defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) # define LASZIP_LITTLE_ENDIAN # define LASZIP_BYTE_ORDER 1234 #elif defined(__sparc) || defined(__sparc__) \ || defined(_POWER) || defined(__powerpc__) \ || defined(__ppc__) || defined(__hpux) \ || defined(_MIPSEB) || defined(_POWER) \ || defined(__s390__) # define LASZIP_BIG_ENDIAN # define LASZIP_BYTE_ORDER 4321 #elif defined(__i386__) || defined(__alpha__) \ || defined(__ia64) || defined(__ia64__) \ || defined(_M_IX86) || defined(_M_IA64) \ || defined(_M_ALPHA) || defined(__amd64) \ || defined(__amd64__) || defined(_M_AMD64) \ || defined(__x86_64) || defined(__x86_64__) \ || defined(_M_X64) # define LASZIP_LITTLE_ENDIAN # define LASZIP_BYTE_ORDER 1234 #else # error The file src/endian.hpp needs to be set up for your CPU type. #endif #if defined(LASZIP_BIG_ENDIAN) # error LASzip is not currently big endian safe. Please contact the authors on the liblas-devel mailing list for more information #endif #endif // LASZIP_DETAIL_ENDIAN_HPP_INCLUDED LASzip-3.4.3/src/integercompressor.cpp000066400000000000000000000340351356234217100177410ustar00rootroot00000000000000/* =============================================================================== FILE: integercompressor.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "integercompressor.hpp" #define COMPRESS_ONLY_K #undef COMPRESS_ONLY_K #define CREATE_HISTOGRAMS #undef CREATE_HISTOGRAMS #include #include #ifdef CREATE_HISTOGRAMS #include #endif IntegerCompressor::IntegerCompressor(ArithmeticEncoder* enc, U32 bits, U32 contexts, U32 bits_high, U32 range) { assert(enc); this->enc = enc; this->dec = 0; this->bits = bits; this->contexts = contexts; this->bits_high = bits_high; this->range = range; if (range) // the corrector's significant bits and range { corr_bits = 0; corr_range = range; while (range) { range = range >> 1; corr_bits++; } if (corr_range == (1u << (corr_bits-1))) { corr_bits--; } // the corrector must fall into this interval corr_min = -((I32)(corr_range/2)); corr_max = corr_min + corr_range - 1; } else if (bits && bits < 32) { corr_bits = bits; corr_range = 1u << bits; // the corrector must fall into this interval corr_min = -((I32)(corr_range/2)); corr_max = corr_min + corr_range - 1; } else { corr_bits = 32; corr_range = 0; // the corrector must fall into this interval corr_min = I32_MIN; corr_max = I32_MAX; } k = 0; mBits = 0; mCorrector = 0; #ifdef CREATE_HISTOGRAMS corr_histogram = (int**)malloc(sizeof(int*) * (corr_bits+1)); for (int k = 0; k <= corr_bits; k++) { corr_histogram[k] = (int*)malloc(sizeof(int) * ((1<enc = 0; this->dec = dec; this->bits = bits; this->contexts = contexts; this->bits_high = bits_high; this->range = range; if (range) // the corrector's significant bits and range { corr_bits = 0; corr_range = range; while (range) { range = range >> 1; corr_bits++; } if (corr_range == (1u << (corr_bits-1))) { corr_bits--; } // the corrector must fall into this interval corr_min = -((I32)(corr_range/2)); corr_max = corr_min + corr_range - 1; } else if (bits && bits < 32) { corr_bits = bits; corr_range = 1u << bits; // the corrector must fall into this interval corr_min = -((I32)(corr_range/2)); corr_max = corr_min + corr_range - 1; } else { corr_bits = 32; corr_range = 0; // the corrector must fall into this interval corr_min = I32_MIN; corr_max = I32_MAX; } k = 0; mBits = 0; mCorrector = 0; } IntegerCompressor::~IntegerCompressor() { U32 i; if (mBits) { for (i = 0; i < contexts; i++) { if (enc) enc->destroySymbolModel(mBits[i]); else dec->destroySymbolModel(mBits[i]); } delete [] mBits; } #ifndef COMPRESS_ONLY_K if (mCorrector) { if (enc) enc->destroyBitModel((ArithmeticBitModel*)mCorrector[0]); else dec->destroyBitModel((ArithmeticBitModel*)mCorrector[0]); for (i = 1; i <= corr_bits; i++) { if (enc) enc->destroySymbolModel(mCorrector[i]); else dec->destroySymbolModel(mCorrector[i]); } delete [] mCorrector; } #endif #ifdef CREATE_HISTOGRAMS if (end) { int total_number = 0; double total_entropy = 0.0f; double total_raw = 0.0f; for (int k = 0; k <= corr_bits; k++) { int number = 0; int different = 0; for (int c = 0; c <= (1<createSymbolModel(corr_bits+1); } #ifndef COMPRESS_ONLY_K mCorrector = new ArithmeticModel*[corr_bits+1]; mCorrector[0] = (ArithmeticModel*)enc->createBitModel(); for (i = 1; i <= corr_bits; i++) { if (i <= bits_high) { mCorrector[i] = enc->createSymbolModel(1<createSymbolModel(1<initSymbolModel(mBits[i]); } #ifndef COMPRESS_ONLY_K enc->initBitModel((ArithmeticBitModel*)mCorrector[0]); for (i = 1; i <= corr_bits; i++) { enc->initSymbolModel(mCorrector[i]); } #endif } void IntegerCompressor::compress(I32 pred, I32 real, U32 context) { assert(enc); // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] I32 corr = real - pred; // we fold the corrector into the interval [ corr_min ... corr_max ] if (corr < corr_min) corr += corr_range; else if (corr > corr_max) corr -= corr_range; writeCorrector(corr, mBits[context]); } void IntegerCompressor::initDecompressor() { U32 i; assert(dec); // maybe create the models if (mBits == 0) { mBits = new ArithmeticModel*[contexts]; for (i = 0; i < contexts; i++) { mBits[i] = dec->createSymbolModel(corr_bits+1); } #ifndef COMPRESS_ONLY_K mCorrector = new ArithmeticModel*[corr_bits+1]; mCorrector[0] = (ArithmeticModel*)dec->createBitModel(); for (i = 1; i <= corr_bits; i++) { if (i <= bits_high) { mCorrector[i] = dec->createSymbolModel(1<createSymbolModel(1<initSymbolModel(mBits[i]); } #ifndef COMPRESS_ONLY_K dec->initBitModel((ArithmeticBitModel*)mCorrector[0]); for (i = 1; i <= corr_bits; i++) { dec->initSymbolModel(mCorrector[i]); } #endif } I32 IntegerCompressor::decompress(I32 pred, U32 context) { assert(dec); I32 real = pred + readCorrector(mBits[context]); if (real < 0) real += corr_range; else if ((U32)(real) >= corr_range) real -= corr_range; return real; } /* static const char log_table256[256] = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; unsigned int v; // 32-bit word to find the log of unsigned r; // r will be lg(v) register unsigned int t, tt; // temporaries if (tt = v >> 16) { r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; } else { r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v]; } */ void IntegerCompressor::writeCorrector(I32 c, ArithmeticModel* mBits) { U32 c1; // find the tighest interval [ - (2^k - 1) ... + (2^k) ] that contains c k = 0; // do this by checking the absolute value of c (adjusted for the case that c is 2^k) c1 = (c <= 0 ? -c : c-1); // this loop could be replaced with more efficient code while (c1) { c1 = c1 >> 1; k = k + 1; } // the number k is between 0 and corr_bits and describes the interval the corrector falls into // we can compress the exact location of c within this interval using k bits enc->encodeSymbol(mBits, k); #ifdef COMPRESS_ONLY_K if (k) // then c is either smaller than 0 or bigger than 1 { assert((c != 0) && (c != 1)); if (k < 32) { // translate the corrector c into the k-bit interval [ 0 ... 2^k - 1 ] if (c < 0) // then c is in the interval [ - (2^k - 1) ... - (2^(k-1)) ] { // so we translate c into the interval [ 0 ... + 2^(k-1) - 1 ] by adding (2^k - 1) enc->writeBits(k, c + ((1<writeBits(k, c - 1); #ifdef CREATE_HISTOGRAMS corr_histogram[k][c - 1]++; #endif } } } else // then c is 0 or 1 { assert((c == 0) || (c == 1)); enc->writeBit(c); #ifdef CREATE_HISTOGRAMS corr_histogram[0][c]++; #endif } #else // COMPRESS_ONLY_K if (k) // then c is either smaller than 0 or bigger than 1 { assert((c != 0) && (c != 1)); if (k < 32) { // translate the corrector c into the k-bit interval [ 0 ... 2^k - 1 ] if (c < 0) // then c is in the interval [ - (2^k - 1) ... - (2^(k-1)) ] { // so we translate c into the interval [ 0 ... + 2^(k-1) - 1 ] by adding (2^k - 1) c += ((1<encodeSymbol(mCorrector[k], c); } else // for larger k we need to code the interval in two steps { // figure out how many lower bits there are int k1 = k-bits_high; // c1 represents the lowest k-bits_high+1 bits c1 = c & ((1<> k1; // compress the higher bits using a context table enc->encodeSymbol(mCorrector[k], c); // store the lower k1 bits raw enc->writeBits(k1, c1); } } } else // then c is 0 or 1 { assert((c == 0) || (c == 1)); enc->encodeBit((ArithmeticBitModel*)mCorrector[0],c); } #endif // COMPRESS_ONLY_K } I32 IntegerCompressor::readCorrector(ArithmeticModel* mBits) { I32 c; // decode within which interval the corrector is falling k = dec->decodeSymbol(mBits); // decode the exact location of the corrector within the interval #ifdef COMPRESS_ONLY_K if (k) // then c is either smaller than 0 or bigger than 1 { if (k < 32) { c = dec->readBits(k); if (c >= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ] { // so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1 c += 1; } else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ] { // so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1) c -= ((1<readBit(); } #else // COMPRESS_ONLY_K if (k) // then c is either smaller than 0 or bigger than 1 { if (k < 32) { if (k <= bits_high) // for small k we can do this in one step { // decompress c with the range coder c = dec->decodeSymbol(mCorrector[k]); } else { // for larger k we need to do this in two steps int k1 = k-bits_high; // decompress higher bits with table c = dec->decodeSymbol(mCorrector[k]); // read lower bits raw int c1 = dec->readBits(k1); // put the corrector back together c = (c << k1) | c1; } // translate c back into its correct interval if (c >= (1<<(k-1))) // if c is in the interval [ 2^(k-1) ... + 2^k - 1 ] { // so we translate c back into the interval [ 2^(k-1) + 1 ... 2^k ] by adding 1 c += 1; } else // otherwise c is in the interval [ 0 ... + 2^(k-1) - 1 ] { // so we translate c back into the interval [ - (2^k - 1) ... - (2^(k-1)) ] by subtracting (2^k - 1) c -= ((1<decodeBit((ArithmeticBitModel*)mCorrector[0]); } #endif // COMPRESS_ONLY_K return c; } LASzip-3.4.3/src/integercompressor.hpp000066400000000000000000000060041356234217100177410ustar00rootroot00000000000000/* =============================================================================== FILE: integercompressor.hpp CONTENTS: This compressor provides three different contexts for encoding integer numbers whose range may lie anywhere between 1 and 31 bits, which is specified with the SetPrecision function. The compressor encodes two things: (1) the number k of miss-predicted low-order bits and (2) the k-bit number that corrects the missprediction The k-bit number is usually coded broken in two chunks. The highest bits are compressed using an arithmetic range table. The lower bits are stored raw without predicive coding. How many of the higher bits are compressed can be specified with bits_high. The default is 8. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 10 January 2011 -- licensing change for LGPL release and liblas integration 10 December 2010 -- unified for all entropy coders at Baeckerei Schaefer 31 October 2009 -- switched from the Rangecoder to the Entropycoder 30 September 2005 -- now splitting the corrector into raw and compressed bits 13 July 2005 -- created after returning with many mosquito bites from OBX =============================================================================== */ #ifndef INTEGER_COMPRESSOR_HPP #define INTEGER_COMPRESSOR_HPP #include "arithmeticencoder.hpp" #include "arithmeticdecoder.hpp" class IntegerCompressor { public: // Constructor & Deconstructor IntegerCompressor(ArithmeticEncoder* enc, U32 bits=16, U32 contexts=1, U32 bits_high=8, U32 range=0); IntegerCompressor(ArithmeticDecoder* dec, U32 bits=16, U32 contexts=1, U32 bits_high=8, U32 range=0); ~IntegerCompressor(); // Manage Compressor void initCompressor(); void compress(I32 iPred, I32 iReal, U32 context=0); // Manage Decompressor void initDecompressor(); I32 decompress(I32 iPred, U32 context=0); // Get the k corrector bits from the last compress/decompress call U32 getK() const {return k;}; private: void writeCorrector(I32 c, ArithmeticModel* model); I32 readCorrector(ArithmeticModel* model); U32 k; U32 contexts; U32 bits_high; U32 bits; U32 range; U32 corr_bits; U32 corr_range; I32 corr_min; I32 corr_max; ArithmeticEncoder* enc; ArithmeticDecoder* dec; ArithmeticModel** mBits; ArithmeticModel** mCorrector; #ifdef CREATE_HISTOGRAMS int** corr_histogram; #endif }; #endif LASzip-3.4.3/src/lasattributer.hpp000066400000000000000000000427471356234217100170720ustar00rootroot00000000000000/* =============================================================================== FILE: lasattributer.hpp CONTENTS: This class assists with handling the "extra bytes" that allow storing additional per point attributes. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2015, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 13 September 2018 -- removed tuples and triple support from attributes 19 July 2015 -- created after FOSS4GE in the train back from Lake Como =============================================================================== */ #ifndef LAS_ATTRIBUTER_HPP #define LAS_ATTRIBUTER_HPP #include "mydefs.hpp" #define LAS_ATTRIBUTE_U8 0 #define LAS_ATTRIBUTE_I8 1 #define LAS_ATTRIBUTE_U16 2 #define LAS_ATTRIBUTE_I16 3 #define LAS_ATTRIBUTE_U32 4 #define LAS_ATTRIBUTE_I32 5 #define LAS_ATTRIBUTE_U64 6 #define LAS_ATTRIBUTE_I64 7 #define LAS_ATTRIBUTE_F32 8 #define LAS_ATTRIBUTE_F64 9 class LASattribute { public: U8 reserved[2]; // 2 bytes U8 data_type; // 1 byte U8 options; // 1 byte CHAR name[32]; // 32 bytes U8 unused[4]; // 4 bytes U64I64F64 no_data[3]; // 24 = 3*8 bytes U64I64F64 min[3]; // 24 = 3*8 bytes U64I64F64 max[3]; // 24 = 3*8 bytes F64 scale[3]; // 24 = 3*8 bytes F64 offset[3]; // 24 = 3*8 bytes CHAR description[32]; // 32 bytes LASattribute(U8 size) { if (size == 0) throw; memset(this, 0, sizeof(LASattribute)); scale[0] = scale[1] = scale[2] = 1.0; this->options = size; }; LASattribute(U32 type, const CHAR* name, const CHAR* description=0) { if (type > LAS_ATTRIBUTE_F64) throw; if (name == 0) throw; memset(this, 0, sizeof(LASattribute)); scale[0] = scale[1] = scale[2] = 1.0; this->data_type = type+1; strncpy(this->name, name, 32); if (description) strncpy(this->description, description, 32); }; inline BOOL set_no_data(U8 no_data) { if (0 == get_type()) { this->no_data[0].u64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(I8 no_data) { if (1 == get_type()) { this->no_data[0].i64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(U16 no_data) { if (2 == get_type()) { this->no_data[0].u64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(I16 no_data) { if (3 == get_type()) { this->no_data[0].i64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(U32 no_data) { if (4 == get_type()) { this->no_data[0].u64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(I32 no_data) { if (5 == get_type()) { this->no_data[0].i64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(U64 no_data) { if (6 == get_type()) { this->no_data[0].u64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(I64 no_data) { if (7 == get_type()) { this->no_data[0].i64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(F32 no_data) { if (8 == get_type()) { this->no_data[0].f64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline BOOL set_no_data(F64 no_data) { switch (get_type()) { case 0: case 2: case 4: case 6: this->no_data[0].u64 = (U64)no_data; options |= 0x01; return TRUE; case 1: case 3: case 5: case 7: this->no_data[0].i64 = (I64)no_data; options |= 0x01; return TRUE; case 8: case 9: this->no_data[0].f64 = no_data; options |= 0x01; return TRUE; } return FALSE; }; inline void set_min(U8* min) { this->min[0] = cast(min); options |= 0x02; }; inline void update_min(U8* min) { this->min[0] = smallest(cast(min), this->min[0]); }; inline BOOL set_min(U8 min) { if (0 == get_type()) { this->min[0].u64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(I8 min) { if (1 == get_type()) { this->min[0].i64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(U16 min) { if (2 == get_type()) { this->min[0].u64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(I16 min) { if (3 == get_type()) { this->min[0].i64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(U32 min) { if (4 == get_type()) { this->min[0].u64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(I32 min) { if (5 == get_type()) { this->min[0].i64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(U64 min) { if (6 == get_type()) { this->min[0].u64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(I64 min) { if (7 == get_type()) { this->min[0].i64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(F32 min) { if (8 == get_type()) { this->min[0].f64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline BOOL set_min(F64 min) { if (9 == get_type()) { this->min[0].f64 = min; options |= 0x02; return TRUE; } return FALSE; }; inline void set_max(U8* max) { this->max[0] = cast(max); options |= 0x04; }; inline void update_max(U8* max) { this->max[0] = biggest(cast(max), this->max[0]); }; inline BOOL set_max(U8 max) { if (0 == get_type()) { this->max[0].u64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(I8 max) { if (1 == get_type()) { this->max[0].i64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(U16 max) { if (2 == get_type()) { this->max[0].u64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(I16 max) { if (3 == get_type()) { this->max[0].i64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(U32 max) { if (4 == get_type()) { this->max[0].u64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(I32 max) { if (5 == get_type()) { this->max[0].i64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(U64 max) { if (6 == get_type()) { this->max[0].u64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(I64 max) { if (7 == get_type()) { this->max[0].i64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(F32 max) { if (8 == get_type()) { this->max[0].f64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_max(F64 max) { if (9 == get_type()) { this->max[0].f64 = max; options |= 0x04; return TRUE; } return FALSE; }; inline BOOL set_scale(F64 scale) { if (data_type) { this->scale[0] = scale; options |= 0x08; return TRUE; } return FALSE; }; inline BOOL set_offset(F64 offset) { if (data_type) { this->offset[0] = offset; options |= 0x10; return TRUE; } return FALSE; }; inline BOOL unset_scale() { if (data_type) { options &= (~0x08); return TRUE; } return FALSE; }; inline BOOL unset_offset() { if (data_type) { options &= (~0x10); return TRUE; } return FALSE; }; inline BOOL has_no_data() const { return options & 0x01; }; inline BOOL has_min() const { return options & 0x02; }; inline BOOL has_max() const { return options & 0x04; }; inline BOOL has_scale() const { return options & 0x08; }; inline BOOL has_offset() const { return options & 0x10; }; inline U32 get_size() const { if (data_type) { const U32 size_table[10] = { 1, 1, 2, 2, 4, 4, 8, 8, 4, 8 }; I32 type = get_type(); I32 dim = get_dim(); return size_table[type] * dim; } else { return options; } }; inline F64 get_value_as_float(U8* pointer) const { F64 cast_value; I32 type = get_type(); if (type == 0) cast_value = (F64)*((U8*)pointer); else if (type == 1) cast_value = (F64)*((I8*)pointer); else if (type == 2) cast_value = (F64)*((U16*)pointer); else if (type == 3) cast_value = (F64)*((I16*)pointer); else if (type == 4) cast_value = (F64)*((U32*)pointer); else if (type == 5) cast_value = (F64)*((I32*)pointer); else if (type == 6) cast_value = (F64)(I64)*((U64*)pointer); else if (type == 7) cast_value = (F64)*((I64*)pointer); else if (type == 8) cast_value = (F64)*((F32*)pointer); else cast_value = *((F64*)pointer); if (options & 0x08) { if (options & 0x10) { return offset[0]+scale[0]*cast_value; } else { return scale[0]*cast_value; } } else { if (options & 0x10) { return offset[0]+cast_value; } else { return cast_value; } } }; inline void set_value_as_float(U8* pointer, F64 value) const { F64 unoffset_and_unscaled_value; if (options & 0x08) { if (options & 0x10) { unoffset_and_unscaled_value = (value - offset[0])/scale[0]; } else { unoffset_and_unscaled_value = value/scale[0]; } } else { if (options & 0x10) { unoffset_and_unscaled_value = value - offset[0]; } else { unoffset_and_unscaled_value = value; } } I32 type = get_type(); if (type == 0) *((U8*)pointer) = U8_QUANTIZE(unoffset_and_unscaled_value); else if (type == 1) *((I8*)pointer) = I8_QUANTIZE(unoffset_and_unscaled_value); else if (type == 2) *((U16*)pointer) = U16_QUANTIZE(unoffset_and_unscaled_value); else if (type == 3) *((I16*)pointer) = I16_QUANTIZE(unoffset_and_unscaled_value); else if (type == 4) *((U32*)pointer) = U32_QUANTIZE(unoffset_and_unscaled_value); else if (type == 5) *((I32*)pointer) = U32_QUANTIZE(unoffset_and_unscaled_value); else if (type == 6) *((U64*)pointer) = U64_QUANTIZE(unoffset_and_unscaled_value); else if (type == 7) *((I64*)pointer) = I64_QUANTIZE(unoffset_and_unscaled_value); else if (type == 8) *((F32*)pointer) = (F32)unoffset_and_unscaled_value; else *((F64*)pointer) = unoffset_and_unscaled_value; }; private: inline I32 get_type() const { return ((I32)data_type - 1)%10; }; inline I32 get_dim() const // compute dimension of deprecated tuple and triple attributes { return ((I32)data_type - 1)/10 + 1; }; inline U64I64F64 cast(U8* pointer) const { I32 type = get_type(); U64I64F64 cast_value; if (type == 0) cast_value.u64 = *((U8*)pointer); else if (type == 1) cast_value.i64 = *((I8*)pointer); else if (type == 2) cast_value.u64 = *((U16*)pointer); else if (type == 3) cast_value.i64 = *((I16*)pointer); else if (type == 4) cast_value.u64 = *((U32*)pointer); else if (type == 5) cast_value.i64 = *((I32*)pointer); else if (type == 6) cast_value.u64 = *((U64*)pointer); else if (type == 7) cast_value.i64 = *((I64*)pointer); else if (type == 8) cast_value.f64 = *((F32*)pointer); else cast_value.f64 = *((F64*)pointer); return cast_value; }; inline U64I64F64 smallest(U64I64F64 a, U64I64F64 b) const { I32 type = get_type(); if (type >= 8) // float compare { if (a.f64 < b.f64) return a; else return b; } if (type & 1) // int compare { if (a.i64 < b.i64) return a; else return b; } if (a.u64 < b.u64) return a; else return b; }; inline U64I64F64 biggest(U64I64F64 a, U64I64F64 b) const { I32 type = get_type(); if (type >= 8) // float compare { if (a.f64 > b.f64) return a; else return b; } if (type & 1) // int compare { if (a.i64 > b.i64) return a; else return b; } if (a.u64 > b.u64) return a; else return b; }; }; class LASattributer { public: BOOL attributes_linked; I32 number_attributes; LASattribute* attributes; I32* attribute_starts; I32* attribute_sizes; LASattributer() { attributes_linked = TRUE; number_attributes = 0; attributes = 0; attribute_starts = 0; attribute_sizes = 0; }; ~LASattributer() { clean_attributes(); }; void clean_attributes() { if (attributes_linked) { if (attributes) { number_attributes = 0; free(attributes); attributes = 0; free(attribute_starts); attribute_starts = 0; free(attribute_sizes); attribute_sizes = 0; } } }; BOOL init_attributes(U32 number_attributes, LASattribute* attributes) { U32 i; clean_attributes(); this->number_attributes = number_attributes; this->attributes = (LASattribute*)malloc(sizeof(LASattribute)*number_attributes); if (this->attributes == 0) { return FALSE; } memcpy(this->attributes, attributes, sizeof(LASattribute)*number_attributes); attribute_starts = (I32*)malloc(sizeof(I32)*number_attributes); if (attribute_starts == 0) { return FALSE; } attribute_sizes = (I32*)malloc(sizeof(I32)*number_attributes); if (attribute_sizes == 0) { return FALSE; } attribute_starts[0] = 0; attribute_sizes[0] = attributes[0].get_size(); for (i = 1; i < number_attributes; i++) { attribute_starts[i] = attribute_starts[i-1] + attribute_sizes[i-1]; attribute_sizes[i] = attributes[i].get_size(); } return TRUE; }; I32 add_attribute(const LASattribute attribute) { if (attribute.get_size()) { if (attributes) { number_attributes++; attributes = (LASattribute*)realloc(attributes, sizeof(LASattribute)*number_attributes); if (attributes == 0) { return -1; } attribute_starts = (I32*)realloc(attribute_starts, sizeof(I32)*number_attributes); if (attribute_starts == 0) { return -1; } attribute_sizes = (I32*)realloc(attribute_sizes, sizeof(I32)*number_attributes); if (attribute_sizes == 0) { return -1; } attributes[number_attributes-1] = attribute; attribute_starts[number_attributes-1] = attribute_starts[number_attributes-2] + attribute_sizes[number_attributes-2]; attribute_sizes[number_attributes-1] = attributes[number_attributes-1].get_size(); } else { number_attributes = 1; attributes = (LASattribute*)malloc(sizeof(LASattribute)); if (attributes == 0) { return -1; } attribute_starts = (I32*)malloc(sizeof(I32)); if (attribute_starts == 0) { return -1; } attribute_sizes = (I32*)malloc(sizeof(I32)); if (attribute_sizes == 0) { return -1; } attributes[0] = attribute; attribute_starts[0] = 0; attribute_sizes[0] = attributes[0].get_size(); } return number_attributes-1; } return -1; }; inline I16 get_attributes_size() const { return (attributes ? attribute_starts[number_attributes-1] + attribute_sizes[number_attributes-1] : 0); } I32 get_attribute_index(const CHAR* name) const { I32 i; for (i = 0; i < number_attributes; i++) { if (strcmp(attributes[i].name, name) == 0) { return i; } } return -1; } I32 get_attribute_start(const CHAR* name) const { I32 i; for (i = 0; i < number_attributes; i++) { if (strcmp(attributes[i].name, name) == 0) { return attribute_starts[i]; } } return -1; } I32 get_attribute_start(I32 index) const { if (index < number_attributes) { return attribute_starts[index]; } return -1; } I32 get_attribute_size(I32 index) const { if (index < number_attributes) { return attribute_sizes[index]; } return -1; } const CHAR* get_attribute_name(I32 index) const { if (index < number_attributes) { return attributes[index].name; } return 0; } BOOL remove_attribute(I32 index) { if (index < 0 || index >= number_attributes) { return FALSE; } for (index = index + 1; index < number_attributes; index++) { attributes[index-1] = attributes[index]; if (index > 1) { attribute_starts[index-1] = attribute_starts[index-2] + attribute_sizes[index-2]; } else { attribute_starts[index-1] = 0; } attribute_sizes[index-1] = attribute_sizes[index]; } number_attributes--; if (number_attributes) { attributes = (LASattribute*)realloc(attributes, sizeof(LASattribute)*number_attributes); attribute_starts = (I32*)realloc(attribute_starts, sizeof(I32)*number_attributes); attribute_sizes = (I32*)realloc(attribute_sizes, sizeof(I32)*number_attributes); } else { free(attributes); attributes = 0; free(attribute_starts); attribute_starts = 0; free(attribute_sizes); attribute_sizes = 0; } return TRUE; } BOOL remove_attribute(const CHAR* name) { I32 index = get_attribute_index(name); if (index != -1) { return remove_attribute(index); } return FALSE; } }; #endif LASzip-3.4.3/src/lasindex.cpp000066400000000000000000000427531356234217100160040ustar00rootroot00000000000000/* =============================================================================== FILE: lasindex.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2011-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasindex.hpp" #include #include #include #include "lasquadtree.hpp" #include "lasinterval.hpp" #ifdef LASZIPDLL_EXPORTS #include "lasreadpoint.hpp" #else #include "lasreader.hpp" #endif #include "bytestreamin_file.hpp" #include "bytestreamout_file.hpp" #ifdef UNORDERED // Figure out whether is in tr1 # ifdef __has_include # if __has_include() # include using namespace std; # define UNORDERED_FOUND # endif # endif # ifdef HAVE_UNORDERED_MAP # include using namespace std; # elif defined(UNORDERED_FOUND) # include using namespace std; using namespace tr1; # endif typedef unordered_map my_cell_hash; #elif defined(LZ_WIN32_VC6) #include using namespace std; typedef hash_map my_cell_hash; #else #include using namespace std; typedef unordered_map my_cell_hash; #endif LASindex::LASindex() { spatial = 0; interval = 0; have_interval = FALSE; start = 0; end = 0; full = 0; total = 0; cells = 0; } LASindex::~LASindex() { if (spatial) delete spatial; if (interval) delete interval; } void LASindex::prepare(LASquadtree* spatial, I32 threshold) { if (this->spatial) delete this->spatial; this->spatial = spatial; if (this->interval) delete this->interval; this->interval = new LASinterval(threshold); } BOOL LASindex::add(const F64 x, const F64 y, const U32 p_index) { I32 cell = spatial->get_cell_index(x, y); return interval->add(p_index, cell); } void LASindex::complete(U32 minimum_points, I32 maximum_intervals, const BOOL verbose) { if (verbose) { fprintf(stderr,"before complete %d %d\n", minimum_points, maximum_intervals); print(FALSE); } if (minimum_points) { I32 hash1 = 0; my_cell_hash cell_hash[2]; // insert all cells into hash1 interval->get_cells(); while (interval->has_cells()) { cell_hash[hash1][interval->index] = interval->full; } while (cell_hash[hash1].size()) { I32 hash2 = (hash1+1)%2; cell_hash[hash2].clear(); // coarsen if a coarser cell will still have fewer than minimum_points (and points in all subcells) BOOL coarsened = FALSE; U32 i, full; I32 coarser_index; U32 num_indices; U32 num_filled; I32* indices; my_cell_hash::iterator hash_element_inner; my_cell_hash::iterator hash_element_outer = cell_hash[hash1].begin(); while (hash_element_outer != cell_hash[hash1].end()) { if ((*hash_element_outer).second) { if (spatial->coarsen((*hash_element_outer).first, &coarser_index, &num_indices, &indices)) { full = 0; num_filled = 0; for (i = 0; i < num_indices; i++) { if ((*hash_element_outer).first == indices[i]) { hash_element_inner = hash_element_outer; } else { hash_element_inner = cell_hash[hash1].find(indices[i]); } if (hash_element_inner != cell_hash[hash1].end()) { full += (*hash_element_inner).second; (*hash_element_inner).second = 0; num_filled++; } } if ((full < minimum_points) && (num_filled == num_indices)) { interval->merge_cells(num_indices, indices, coarser_index); coarsened = TRUE; cell_hash[hash2][coarser_index] = full; } } } hash_element_outer++; } if (!coarsened) break; hash1 = (hash1+1)%2; } // tell spatial about the existing cells interval->get_cells(); while (interval->has_cells()) { spatial->manage_cell(interval->index); } if (verbose) { fprintf(stderr,"after minimum_points %d\n", minimum_points); print(FALSE); } } if (maximum_intervals < 0) { maximum_intervals = -maximum_intervals*interval->get_number_cells(); } if (maximum_intervals) { interval->merge_intervals(maximum_intervals, verbose); if (verbose) { fprintf(stderr,"after maximum_intervals %d\n", maximum_intervals); print(FALSE); } } } void LASindex::print(BOOL verbose) { U32 total_cells = 0; U32 total_full = 0; U32 total_total = 0; U32 total_intervals = 0; U32 total_check; U32 intervals; interval->get_cells(); while (interval->has_cells()) { total_check = 0; intervals = 0; while (interval->has_intervals()) { total_check += interval->end-interval->start+1; intervals++; } if (total_check != interval->total) { fprintf(stderr,"ERROR: total_check %d != interval->total %d\n", total_check, interval->total); } if (verbose) fprintf(stderr,"cell %d intervals %d full %d total %d (%.2f)\n", interval->index, intervals, interval->full, interval->total, 100.0f*interval->full/interval->total); total_cells++; total_full += interval->full; total_total += interval->total; total_intervals += intervals; } if (verbose) fprintf(stderr,"total cells/intervals %d/%d full %d (%.2f)\n", total_cells, total_intervals, total_full, 100.0f*total_full/total_total); } LASquadtree* LASindex::get_spatial() const { return spatial; } LASinterval* LASindex::get_interval() const { return interval; } BOOL LASindex::intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y) { have_interval = FALSE; cells = spatial->intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y); // fprintf(stderr,"%d cells of %g/%g %g/%g intersect rect %g/%g %g/%g\n", num_cells, spatial->get_min_x(), spatial->get_min_y(), spatial->get_max_x(), spatial->get_max_y(), r_min_x, r_min_y, r_max_x, r_max_y); if (cells) return merge_intervals(); return FALSE; } BOOL LASindex::intersect_tile(const F32 ll_x, const F32 ll_y, const F32 size) { have_interval = FALSE; cells = spatial->intersect_tile(ll_x, ll_y, size); // fprintf(stderr,"%d cells of %g/%g %g/%g intersect tile %g/%g/%g\n", num_cells, spatial->get_min_x(), spatial->get_min_y(), spatial->get_max_x(), spatial->get_max_y(), ll_x, ll_y, size); if (cells) return merge_intervals(); return FALSE; } BOOL LASindex::intersect_circle(const F64 center_x, const F64 center_y, const F64 radius) { have_interval = FALSE; cells = spatial->intersect_circle(center_x, center_y, radius); // fprintf(stderr,"%d cells of %g/%g %g/%g intersect circle %g/%g/%g\n", num_cells, spatial->get_min_x(), spatial->get_min_y(), spatial->get_max_x(), spatial->get_max_y(), center_x, center_y, radius); if (cells) return merge_intervals(); return FALSE; } BOOL LASindex::get_intervals() { have_interval = FALSE; return interval->get_merged_cell(); } BOOL LASindex::has_intervals() { if (interval->has_intervals()) { start = interval->start; end = interval->end; full = interval->full; have_interval = TRUE; return TRUE; } have_interval = FALSE; return FALSE; } BOOL LASindex::read(FILE* file) { if (file == 0) return FALSE; ByteStreamIn* stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamInFileLE(file); else stream = new ByteStreamInFileBE(file); if (!read(stream)) { delete stream; return FALSE; } delete stream; return TRUE; } BOOL LASindex::write(FILE* file) const { if (file == 0) return FALSE; ByteStreamOut* stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamOutFileLE(file); else stream = new ByteStreamOutFileBE(file); if (!write(stream)) { delete stream; return FALSE; } delete stream; return TRUE; } BOOL LASindex::read(const char* file_name) { if (file_name == 0) return FALSE; char* name = LASCopyString(file_name); if (strstr(file_name, ".las") || strstr(file_name, ".laz")) { name[strlen(name)-1] = 'x'; } else if (strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) { name[strlen(name)-1] = 'X'; } else { name[strlen(name)-3] = 'l'; name[strlen(name)-2] = 'a'; name[strlen(name)-1] = 'x'; } #ifdef _MSC_VER wchar_t* utf16_name = UTF8toUTF16(name); FILE* file = _wfopen(utf16_name, L"rb"); delete [] utf16_name; #else FILE* file = fopen(name, "rb"); #endif if (file == 0) { free(name); return FALSE; } if (!read(file)) { fprintf(stderr,"ERROR (LASindex): cannot read '%s'\n", name); fclose(file); free(name); return FALSE; } fclose(file); free(name); return TRUE; } BOOL LASindex::append(const char* file_name) const { #ifdef LASZIPDLL_EXPORTS return FALSE; #else LASreadOpener lasreadopener; if (file_name == 0) return FALSE; // open reader LASreader* lasreader = lasreadopener.open(file_name); if (lasreader == 0) return FALSE; if (lasreader->header.laszip == 0) return FALSE; // close reader lasreader->close(); #ifdef _MSC_VER wchar_t* utf16_file_name = UTF8toUTF16(file_name); FILE* file = _wfopen(utf16_file_name, L"rb"); delete [] utf16_file_name; #else FILE* file = fopen(file_name, "rb"); #endif ByteStreamIn* bytestreamin = 0; if (IS_LITTLE_ENDIAN()) bytestreamin = new ByteStreamInFileLE(file); else bytestreamin = new ByteStreamInFileBE(file); // maybe write LASindex EVLR start position into LASzip VLR I64 offset_laz_vlr = -1; // where to write LASindex EVLR that will contain the LAX file I64 number_of_special_evlrs = lasreader->header.laszip->number_of_special_evlrs; I64 offset_to_special_evlrs = lasreader->header.laszip->offset_to_special_evlrs; if ((number_of_special_evlrs == -1) && (offset_to_special_evlrs == -1)) { bytestreamin->seekEnd(); number_of_special_evlrs = 1; offset_to_special_evlrs = bytestreamin->tell(); // find LASzip VLR I64 total = lasreader->header.header_size + 2; U32 number_of_variable_length_records = lasreader->header.number_of_variable_length_records + 1 + (lasreader->header.vlr_lastiling != 0) + (lasreader->header.vlr_lasoriginal != 0); for (U32 u = 0; u < number_of_variable_length_records; u++) { bytestreamin->seek(total); CHAR user_id[16]; try { bytestreamin->getBytes((U8*)user_id, 16); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].user_id\n", u); return FALSE; } if (strcmp(user_id, "laszip encoded") == 0) { offset_laz_vlr = bytestreamin->tell() - 18; break; } U16 record_id; try { bytestreamin->get16bitsLE((U8*)&record_id); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].record_id\n", u); return FALSE; } U16 record_length_after_header; try { bytestreamin->get16bitsLE((U8*)&record_length_after_header); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].record_length_after_header\n", u); return FALSE; } total += (54 + record_length_after_header); } if (number_of_special_evlrs == -1) return FALSE; } delete bytestreamin; fclose(file); ByteStreamOut* bytestreamout; #ifdef _MSC_VER utf16_file_name = UTF8toUTF16(file_name); file = _wfopen(utf16_file_name, L"rb+"); delete [] utf16_file_name; #else file = fopen(file_name, "rb+"); #endif if (IS_LITTLE_ENDIAN()) bytestreamout = new ByteStreamOutFileLE(file); else bytestreamout = new ByteStreamOutFileBE(file); bytestreamout->seek(offset_to_special_evlrs); LASevlr lax_evlr; sprintf(lax_evlr.user_id, "LAStools"); lax_evlr.record_id = 30; sprintf(lax_evlr.description, "LAX spatial indexing (LASindex)"); bytestreamout->put16bitsLE((const U8*)&(lax_evlr.reserved)); bytestreamout->putBytes((const U8*)lax_evlr.user_id, 16); bytestreamout->put16bitsLE((const U8*)&(lax_evlr.record_id)); bytestreamout->put64bitsLE((const U8*)&(lax_evlr.record_length_after_header)); bytestreamout->putBytes((const U8*)lax_evlr.description, 32); if (!write(bytestreamout)) { fprintf(stderr,"ERROR (LASindex): cannot append LAX to '%s'\n", file_name); delete bytestreamout; fclose(file); delete lasreader; return FALSE; } // update LASindex EVLR lax_evlr.record_length_after_header = bytestreamout->tell() - offset_to_special_evlrs - 60; bytestreamout->seek(offset_to_special_evlrs + 20); bytestreamout->put64bitsLE((const U8*)&(lax_evlr.record_length_after_header)); // maybe update LASzip VLR if (number_of_special_evlrs != -1) { bytestreamout->seek(offset_laz_vlr + 54 + 16); bytestreamout->put64bitsLE((const U8*)&number_of_special_evlrs); bytestreamout->put64bitsLE((const U8*)&offset_to_special_evlrs); } // close writer bytestreamout->seekEnd(); delete bytestreamout; fclose(file); // delete reader delete lasreader; return TRUE; #endif } BOOL LASindex::write(const char* file_name) const { if (file_name == 0) return FALSE; char* name = LASCopyString(file_name); if (strstr(file_name, ".las") || strstr(file_name, ".laz")) { name[strlen(name)-1] = 'x'; } else if (strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) { name[strlen(name)-1] = 'X'; } else { name[strlen(name)-3] = 'l'; name[strlen(name)-2] = 'a'; name[strlen(name)-1] = 'x'; } #ifdef _MSC_VER wchar_t* utf16_name = UTF8toUTF16(name); FILE* file = _wfopen(utf16_name, L"wb"); delete [] utf16_name; #else FILE* file = fopen(name, "wb"); #endif if (file == 0) { fprintf(stderr,"ERROR (LASindex): cannot open '%s' for write\n", name); free(name); return FALSE; } if (!write(file)) { fprintf(stderr,"ERROR (LASindex): cannot write '%s'\n", name); fclose(file); free(name); return FALSE; } fclose(file); free(name); return TRUE; } BOOL LASindex::read(ByteStreamIn* stream) { if (spatial) { delete spatial; spatial = 0; } if (interval) { delete interval; interval = 0; } char signature[4]; try { stream->getBytes((U8*)signature, 4); } catch (...) { fprintf(stderr,"ERROR (LASindex): reading signature\n"); return FALSE; } if (strncmp(signature, "LASX", 4) != 0) { fprintf(stderr,"ERROR (LASindex): wrong signature %4s instead of 'LASX'\n", signature); return FALSE; } U32 version; try { stream->get32bitsLE((U8*)&version); } catch (...) { fprintf(stderr,"ERROR (LASindex): reading version\n"); return FALSE; } // read spatial quadtree spatial = new LASquadtree(); if (!spatial->read(stream)) { fprintf(stderr,"ERROR (LASindex): cannot read LASspatial (LASquadtree)\n"); return FALSE; } // read interval interval = new LASinterval(); if (!interval->read(stream)) { fprintf(stderr,"ERROR (LASindex): reading LASinterval\n"); return FALSE; } // tell spatial about the existing cells interval->get_cells(); while (interval->has_cells()) { spatial->manage_cell(interval->index); } return TRUE; } BOOL LASindex::write(ByteStreamOut* stream) const { if (!stream->putBytes((const U8*)"LASX", 4)) { fprintf(stderr,"ERROR (LASindex): writing signature\n"); return FALSE; } U32 version = 0; if (!stream->put32bitsLE((const U8*)&version)) { fprintf(stderr,"ERROR (LASindex): writing version\n"); return FALSE; } // write spatial quadtree if (!spatial->write(stream)) { fprintf(stderr,"ERROR (LASindex): cannot write LASspatial (LASquadtree)\n"); return FALSE; } // write interval if (!interval->write(stream)) { fprintf(stderr,"ERROR (LASindex): writing LASinterval\n"); return FALSE; } return TRUE; } // seek to next interval point #ifdef LASZIPDLL_EXPORTS BOOL LASindex::seek_next(LASreadPoint* reader, I64 &p_count) { if (!have_interval) { if (!has_intervals()) return FALSE; reader->seek((U32)p_count, start); p_count = start; } if (p_count == end) { have_interval = FALSE; } return TRUE; } #else BOOL LASindex::seek_next(LASreader* lasreader) { if (!have_interval) { if (!has_intervals()) return FALSE; lasreader->seek(start); } if (lasreader->p_count == end) { have_interval = FALSE; } return TRUE; } #endif // merge the intervals of non-empty cells BOOL LASindex::merge_intervals() { if (spatial->get_intersected_cells()) { U32 used_cells = 0; while (spatial->has_more_cells()) { if (interval->get_cell(spatial->current_cell)) { interval->add_current_cell_to_merge_cell_set(); used_cells++; } } // fprintf(stderr,"LASindex: used %d cells of total %d\n", used_cells, interval->get_number_cells()); if (used_cells) { BOOL r = interval->merge(); full = interval->full; total = interval->total; interval->clear_merge_cell_set(); return r; } } return FALSE; } LASzip-3.4.3/src/lasindex.hpp000066400000000000000000000062431356234217100160030ustar00rootroot00000000000000/* =============================================================================== FILE: lasindex.hpp CONTENTS: This class can create a spatial indexing, store a spatial indexing, write a spatial indexing to file, read a spatial indexing from file, and - most importantly - it can be used together with a lasreader for efficient access to a particular spatial region of a LAS file or a LAZ file. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro 7 January 2017 -- add read(FILE* file) for Trimble LASzip DLL improvement 2 April 2015 -- add seek_next(LASreadPoint* reader, I64 &p_count) for DLL 2 April 2015 -- delete read_next(LASreader* lasreader) that was not used 31 March 2015 -- remove unused LASquadtree inheritance of abstract LASspatial 29 April 2011 -- created after cable outage during the royal wedding (-: =============================================================================== */ #ifndef LAS_INDEX_HPP #define LAS_INDEX_HPP #include #include "mydefs.hpp" class LASquadtree; class LASinterval; #ifdef LASZIPDLL_EXPORTS class LASreadPoint; #else class LASreader; #endif class ByteStreamIn; class ByteStreamOut; class LASLIB_DLL LASindex { public: LASindex(); ~LASindex(); // create spatial index void prepare(LASquadtree* spatial, I32 threshold=1000); BOOL add(const F64 x, const F64 y, const U32 index); void complete(U32 minimum_points=100000, I32 maximum_intervals=-1, const BOOL verbose=TRUE); // read from file or write to file BOOL read(FILE* file); BOOL write(FILE* file) const; BOOL read(const char* file_name); BOOL append(const char* file_name) const; BOOL write(const char* file_name) const; BOOL read(ByteStreamIn* stream); BOOL write(ByteStreamOut* stream) const; // intersect BOOL intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y); BOOL intersect_tile(const F32 ll_x, const F32 ll_y, const F32 size); BOOL intersect_circle(const F64 center_x, const F64 center_y, const F64 radius); // access the intersected intervals BOOL get_intervals(); BOOL has_intervals(); U32 start; U32 end; U32 full; U32 total; U32 cells; // seek to next interval #ifdef LASZIPDLL_EXPORTS BOOL seek_next(LASreadPoint* reader, I64 &p_count); #else BOOL seek_next(LASreader* lasreader); #endif // for debugging void print(BOOL verbose); // for visualization LASquadtree* get_spatial() const; LASinterval* get_interval() const; private: BOOL merge_intervals(); LASquadtree* spatial; LASinterval* interval; BOOL have_interval; }; #endif LASzip-3.4.3/src/lasinterval.cpp000066400000000000000000000445651356234217100165240ustar00rootroot00000000000000/* =============================================================================== FILE: lasinterval.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2011-2015, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasinterval.hpp" #include "laszip.hpp" #include "bytestreamin.hpp" #include "bytestreamout.hpp" #include #include #include #include #include #include using namespace std; #ifdef UNORDERED // Figure out whether is in tr1 # ifdef __has_include # if __has_include() # include using namespace std; # define UNORDERED_FOUND # endif # endif # ifdef HAVE_UNORDERED_MAP # include using namespace std; # elif defined(UNORDERED_FOUND) # include using namespace std; using namespace tr1; # endif typedef unordered_map my_cell_hash; #elif defined(LZ_WIN32_VC6) #include using namespace std; typedef hash_map my_cell_hash; #else #include using namespace std; typedef unordered_map my_cell_hash; #endif typedef multimap my_cell_map; typedef set my_cell_set; LASintervalCell::LASintervalCell() { start = 0; end = 0; next = 0; } LASintervalCell::LASintervalCell(const U32 p_index) { start = p_index; end = p_index; next = 0; } LASintervalCell::LASintervalCell(const LASintervalCell* cell) { start = cell->start; end = cell->end; next = 0; } LASintervalStartCell::LASintervalStartCell() : LASintervalCell() { full = 0; total = 0; last = 0; } LASintervalStartCell::LASintervalStartCell(const U32 p_index) : LASintervalCell(p_index) { full = 1; total = 1; last = 0; } BOOL LASintervalStartCell::add(const U32 p_index, const U32 threshold) { U32 current_end = (last ? last->end : end); assert(p_index > current_end); U32 diff = p_index - current_end; full++; if (diff > threshold) { if (last) { last->next = new LASintervalCell(p_index); last = last->next; } else { next = new LASintervalCell(p_index); last = next; } total++; return TRUE; // created new interval } if (last) { last->end = p_index; } else { end = p_index; } total += diff; return FALSE; // added to interval } BOOL LASinterval::add(const U32 p_index, const I32 c_index) { if (last_cell == 0 || last_index != c_index) { last_index = c_index; my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->find(c_index); if (hash_element == ((my_cell_hash*)cells)->end()) { last_cell = new LASintervalStartCell(p_index); ((my_cell_hash*)cells)->insert(my_cell_hash::value_type(c_index, last_cell)); number_intervals++; return TRUE; } last_cell = (*hash_element).second; } if (last_cell->add(p_index, threshold)) { number_intervals++; return TRUE; } return FALSE; } // get total number of cells U32 LASinterval::get_number_cells() const { return (U32)((my_cell_hash*)cells)->size(); } // get total number of intervals U32 LASinterval::get_number_intervals() const { return number_intervals; } // merge cells (and their intervals) into one cell BOOL LASinterval::merge_cells(const U32 num_indices, const I32* indices, const I32 new_index) { U32 i; if (num_indices == 1) { my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->find(indices[0]); if (hash_element == ((my_cell_hash*)cells)->end()) { return FALSE; } ((my_cell_hash*)cells)->insert(my_cell_hash::value_type(new_index, (*hash_element).second)); ((my_cell_hash*)cells)->erase(hash_element); } else { if (cells_to_merge) ((my_cell_set*)cells_to_merge)->clear(); for (i = 0; i < num_indices; i++) { add_cell_to_merge_cell_set(indices[i], TRUE); } if (!merge(TRUE)) return FALSE; ((my_cell_hash*)cells)->insert(my_cell_hash::value_type(new_index, merged_cells)); merged_cells = 0; } return TRUE; } // merge adjacent intervals with small gaps in cells to reduce total interval number to maximum void LASinterval::merge_intervals(U32 maximum_intervals, const BOOL verbose) { U32 diff; LASintervalCell* cell; LASintervalCell* delete_cell; // each cell has minimum one interval if (maximum_intervals < get_number_cells()) { maximum_intervals = 0; } else { maximum_intervals -= get_number_cells(); } // order intervals by smallest gap my_cell_map map; my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->begin(); while (hash_element != ((my_cell_hash*)cells)->end()) { cell = (*hash_element).second; while (cell->next) { diff = cell->next->start - cell->end - 1; map.insert(my_cell_map::value_type(diff, cell)); cell = cell->next; } hash_element++; } // maybe nothing to do if (map.size() <= maximum_intervals) { if (verbose) { if (map.size() == 0) { fprintf(stderr,"maximum_intervals: %u number of interval gaps: 0 \n", maximum_intervals); } else { diff = (*(map.begin())).first; fprintf(stderr,"maximum_intervals: %u number of interval gaps: %u next largest interval gap %u\n", maximum_intervals, (U32)map.size(), diff); } } return; } my_cell_map::iterator map_element; U32 size = (U32)map.size(); while (size > maximum_intervals) { map_element = map.begin(); diff = (*map_element).first; cell = (*map_element).second; map.erase(map_element); if ((cell->start == 1) && (cell->end == 0)) // the (start == 1 && end == 0) signals that the cell is to be deleted { number_intervals--; delete cell; } else { delete_cell = cell->next; cell->end = delete_cell->end; cell->next = delete_cell->next; if (cell->next) { map.insert(my_cell_map::value_type(cell->next->start - cell->end - 1, cell)); delete_cell->start = 1; delete_cell->end = 0; // the (start == 1 && end == 0) signals that the cell is to be deleted } else { number_intervals--; delete delete_cell; } size--; } } map_element = map.begin(); while (true) { if (map_element == map.end()) break; cell = (*map_element).second; if ((cell->start == 1) && (cell->end == 0)) // the (start == 1 && end == 0) signals that the cell is to be deleted { number_intervals--; delete cell; } map_element++; } if (verbose) fprintf(stderr,"largest interval gap increased to %u\n", diff); // update totals LASintervalStartCell* start_cell; hash_element = ((my_cell_hash*)cells)->begin(); while (hash_element != ((my_cell_hash*)cells)->end()) { start_cell = (*hash_element).second; start_cell->total = 0; cell = start_cell; while (cell) { start_cell->total += (cell->end - cell->start + 1); cell = cell->next; } hash_element++; } } void LASinterval::get_cells() { last_index = I32_MIN; current_cell = 0; } BOOL LASinterval::has_cells() { my_cell_hash::iterator hash_element; if (last_index == I32_MIN) { hash_element = ((my_cell_hash*)cells)->begin(); } else { hash_element = ((my_cell_hash*)cells)->find(last_index); hash_element++; } if (hash_element == ((my_cell_hash*)cells)->end()) { last_index = I32_MIN; current_cell = 0; return FALSE; } last_index = (*hash_element).first; index = (*hash_element).first; full = (*hash_element).second->full; total = (*hash_element).second->total; current_cell = (*hash_element).second; return TRUE; } BOOL LASinterval::get_cell(const I32 c_index) { my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->find(c_index); if (hash_element == ((my_cell_hash*)cells)->end()) { current_cell = 0; return FALSE; } index = (*hash_element).first; full = (*hash_element).second->full; total = (*hash_element).second->total; current_cell = (*hash_element).second; return TRUE; } BOOL LASinterval::add_current_cell_to_merge_cell_set() { if (current_cell == 0) { return FALSE; } if (cells_to_merge == 0) { cells_to_merge = (void*) new my_cell_set; } ((my_cell_set*)cells_to_merge)->insert((LASintervalStartCell*)current_cell); return TRUE; } BOOL LASinterval::add_cell_to_merge_cell_set(const I32 c_index, const BOOL erase) { my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->find(c_index); if (hash_element == ((my_cell_hash*)cells)->end()) { return FALSE; } if (cells_to_merge == 0) { cells_to_merge = (void*) new my_cell_set; } ((my_cell_set*)cells_to_merge)->insert((*hash_element).second); if (erase) ((my_cell_hash*)cells)->erase(hash_element); return TRUE; } BOOL LASinterval::merge(const BOOL erase) { // maybe delete temporary merge cells from the previous merge if (merged_cells) { if (merged_cells_temporary) { LASintervalCell* next_next; LASintervalCell* next = merged_cells->next; while (next) { next_next = next->next; delete next; next = next_next; } delete merged_cells; } merged_cells = 0; } // are there cells to merge if (cells_to_merge == 0) return FALSE; if (((my_cell_set*)cells_to_merge)->size() == 0) return FALSE; // is there just one cell if (((my_cell_set*)cells_to_merge)->size() == 1) { merged_cells_temporary = FALSE; // simply use this cell as the merge cell my_cell_set::iterator set_element = ((my_cell_set*)cells_to_merge)->begin(); merged_cells = (*set_element); } else { merged_cells_temporary = TRUE; merged_cells = new LASintervalStartCell(); // iterate over all cells and add their intervals to map LASintervalCell* cell; my_cell_map map; my_cell_set::iterator set_element = ((my_cell_set*)cells_to_merge)->begin(); while (true) { if (set_element == ((my_cell_set*)cells_to_merge)->end()) break; cell = (*set_element); merged_cells->full += ((LASintervalStartCell*)cell)->full; while (cell) { map.insert(my_cell_map::value_type(cell->start, cell)); cell = cell->next; } set_element++; } // initialize merged_cells with first interval my_cell_map::iterator map_element = map.begin(); cell = (*map_element).second; map.erase(map_element); merged_cells->start = cell->start; merged_cells->end = cell->end; merged_cells->total = cell->end - cell->start + 1; if (erase) delete cell; // merge intervals LASintervalCell* last_cell = merged_cells; I32 diff; while (map.size()) { map_element = map.begin(); cell = (*map_element).second; map.erase(map_element); diff = cell->start - last_cell->end; if (diff > (I32)threshold) { last_cell->next = new LASintervalCell(cell); last_cell = last_cell->next; merged_cells->total += (cell->end - cell->start + 1); } else { diff = cell->end - last_cell->end; if (diff > 0) { last_cell->end = cell->end; merged_cells->total += diff; } number_intervals--; } if (erase) delete cell; } } current_cell = merged_cells; full = merged_cells->full; total = merged_cells->total; return TRUE; } void LASinterval::clear_merge_cell_set() { if (cells_to_merge) { ((my_cell_set*)cells_to_merge)->clear(); } } BOOL LASinterval::get_merged_cell() { if (merged_cells) { full = merged_cells->full; total = merged_cells->total; current_cell = merged_cells; return TRUE; } return FALSE; } BOOL LASinterval::has_intervals() { if (current_cell) { start = current_cell->start; end = current_cell->end; current_cell = current_cell->next; return TRUE; } return FALSE; } LASinterval::LASinterval(const U32 threshold) { cells = new my_cell_hash; cells_to_merge = 0; this->threshold = threshold; number_intervals = 0; last_index = I32_MIN; last_cell = 0; current_cell = 0; merged_cells = 0; merged_cells_temporary = FALSE; } LASinterval::~LASinterval() { // loop over all cells my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->begin(); while (hash_element != ((my_cell_hash*)cells)->end()) { LASintervalCell* previous_cell = (*hash_element).second; LASintervalCell* cell = previous_cell->next; while (cell) { delete previous_cell; previous_cell = cell; cell = cell->next; } delete previous_cell; hash_element++; } delete ((my_cell_hash*)cells); // maybe delete temporary merge cells from the previous merge if (merged_cells) { if (merged_cells_temporary) { LASintervalCell* next_next; LASintervalCell* next = merged_cells->next; while (next) { next_next = next->next; delete next; next = next_next; } delete merged_cells; } merged_cells = 0; } if (cells_to_merge) delete ((my_cell_set*)cells_to_merge); } BOOL LASinterval::read(ByteStreamIn* stream) { char signature[4]; try { stream->getBytes((U8*)signature, 4); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading signature\n"); return FALSE; } if (strncmp(signature, "LASV", 4) != 0) { fprintf(stderr,"ERROR (LASinterval): wrong signature %4s instead of 'LASV'\n", signature); return FALSE; } U32 version; try { stream->get32bitsLE((U8*)&version); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading version\n"); return FALSE; } // read number of cells U32 number_cells; try { stream->get32bitsLE((U8*)&number_cells); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading number of cells\n"); return FALSE; } // loop over all cells while (number_cells) { // read index of cell I32 cell_index; try { stream->get32bitsLE((U8*)&cell_index); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading cell index\n"); return FALSE; } // create cell and insert into hash LASintervalStartCell* start_cell = new LASintervalStartCell(); ((my_cell_hash*)cells)->insert(my_cell_hash::value_type(cell_index, start_cell)); LASintervalCell* cell = start_cell; // read number of intervals in cell U32 number_intervals; try { stream->get32bitsLE((U8*)&number_intervals); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading number of intervals in cell\n"); return FALSE; } // read number of points in cell U32 number_points; try { stream->get32bitsLE((U8*)&number_points); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading number of points in cell\n"); return FALSE; } start_cell->full = number_points; start_cell->total = 0; while (number_intervals) { // read start of interval try { stream->get32bitsLE((U8*)&(cell->start)); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading start %d of interval\n", cell->start); return FALSE; } // read end of interval try { stream->get32bitsLE((U8*)&(cell->end)); } catch (...) { fprintf(stderr,"ERROR (LASinterval): reading end %d of interval\n", cell->end); return FALSE; } start_cell->total += (cell->end - cell->start + 1); number_intervals--; if (number_intervals) { cell->next = new LASintervalCell(); cell = cell->next; } } number_cells--; } return TRUE; } BOOL LASinterval::write(ByteStreamOut* stream) const { if (!stream->putBytes((const U8*)"LASV", 4)) { fprintf(stderr,"ERROR (LASinterval): writing signature\n"); return FALSE; } U32 version = 0; if (!stream->put32bitsLE((const U8*)&version)) { fprintf(stderr,"ERROR (LASinterval): writing version\n"); return FALSE; } // write number of cells U32 number_cells = (U32)((my_cell_hash*)cells)->size(); if (!stream->put32bitsLE((const U8*)&number_cells)) { fprintf(stderr,"ERROR (LASinterval): writing number of cells %d\n", number_cells); return FALSE; } // loop over all cells my_cell_hash::iterator hash_element = ((my_cell_hash*)cells)->begin(); while (hash_element != ((my_cell_hash*)cells)->end()) { LASintervalCell* cell = (*hash_element).second; // count number of intervals and points in cell U32 number_intervals = 0; U32 number_points = ((LASintervalStartCell*)cell)->full; while (cell) { number_intervals++; cell = cell->next; } // write index of cell I32 cell_index = (*hash_element).first; if (!stream->put32bitsLE((const U8*)&cell_index)) { fprintf(stderr,"ERROR (LASinterval): writing cell index %d\n", cell_index); return FALSE; } // write number of intervals in cell if (!stream->put32bitsLE((const U8*)&number_intervals)) { fprintf(stderr,"ERROR (LASinterval): writing number of intervals %d in cell\n", number_intervals); return FALSE; } // write number of points in cell if (!stream->put32bitsLE((const U8*)&number_points)) { fprintf(stderr,"ERROR (LASinterval): writing number of points %d in cell\n", number_points); return FALSE; } // write intervals cell = (*hash_element).second; while (cell) { // write start of interval if (!stream->put32bitsLE((const U8*)&(cell->start))) { fprintf(stderr,"ERROR (LASinterval): writing start %d of interval\n", cell->start); return FALSE; } // write end of interval if (!stream->put32bitsLE((const U8*)&(cell->end))) { fprintf(stderr,"ERROR (LASinterval): writing end %d of interval\n", cell->end); return FALSE; } cell = cell->next; } hash_element++; } return TRUE; } LASzip-3.4.3/src/lasinterval.hpp000066400000000000000000000061121356234217100165130ustar00rootroot00000000000000/* =============================================================================== FILE: lasinterval.hpp CONTENTS: Used by lasindex to manage intervals of consecutive LiDAR points that are read sequentially. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2015, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 20 October 2018 -- fixed rare bug in merge_intervals() when verbose is TRUE 29 April 2011 -- created after cable outage during the royal wedding (-: =============================================================================== */ #ifndef LAS_INTERVAL_HPP #define LAS_INTERVAL_HPP #include "mydefs.hpp" class ByteStreamIn; class ByteStreamOut; class LASintervalCell { public: U32 start; U32 end; LASintervalCell* next; LASintervalCell(); LASintervalCell(const U32 p_index); LASintervalCell(const LASintervalCell* cell); }; class LASintervalStartCell : public LASintervalCell { public: U32 full; U32 total; LASintervalCell* last; LASintervalStartCell(); LASintervalStartCell(const U32 p_index); BOOL add(const U32 p_index, const U32 threshold=1000); }; class LASinterval { public: LASinterval(const U32 threshold=1000); ~LASinterval(); // add points and create cells with intervals BOOL add(const U32 p_index, const I32 c_index); // get total number of cells U32 get_number_cells() const; // get total number of intervals U32 get_number_intervals() const; // merge cells (and their intervals) into one cell BOOL merge_cells(const U32 num_indices, const I32* indices, const I32 new_index); // merge adjacent intervals with small gaps in cells to reduce total interval number to maximum void merge_intervals(U32 maximum, const BOOL verbose=TRUE); // read from file or write to file BOOL read(ByteStreamIn* stream); BOOL write(ByteStreamOut* stream) const; // get one cell after the other void get_cells(); BOOL has_cells(); // get a particular cell BOOL get_cell(const I32 c_index); // add cell's intervals to those that will be merged BOOL add_current_cell_to_merge_cell_set(); BOOL add_cell_to_merge_cell_set(const I32 c_index, const BOOL erase=FALSE); BOOL merge(const BOOL erase=FALSE); void clear_merge_cell_set(); BOOL get_merged_cell(); // iterate intervals of current cell (or over merged intervals) BOOL has_intervals(); I32 index; U32 start; U32 end; U32 full; U32 total; private: void* cells; void* cells_to_merge; U32 threshold; U32 number_intervals; I32 last_index; LASintervalStartCell* last_cell; LASintervalCell* current_cell; LASintervalStartCell* merged_cells; BOOL merged_cells_temporary; }; #endif LASzip-3.4.3/src/laspoint.hpp000066400000000000000000000624731356234217100160340ustar00rootroot00000000000000/* =============================================================================== FILE: laspoint.hpp CONTENTS: This class describes an LAS point and offers helper functions to access, convert, and set the default (and any additional) point attributes. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 10 May 2019 -- checking for overflows in X, Y, Z of I32 of fixed-point LAS 15 June 2018 -- fix in flag copy from legacy (0-5) to extended (6-10) type 10 March 2017 -- fix in copy_to() and copy_from() new LAS 1.4 point types 10 October 2016 -- small fixes for NIR and extended scanner channel 19 July 2015 -- created after FOSS4GE in the train back from Lake Como =============================================================================== */ #ifndef LAS_POINT_HPP #define LAS_POINT_HPP #include "lasquantizer.hpp" #include "lasattributer.hpp" class LASwavepacket { public: LASwavepacket() {zero();}; void zero() {memset(data, 0, 29);}; inline U8 getIndex() const {return data[0];}; inline U64 getOffset() const {return ((U64*)&(data[1]))[0];}; inline U32 getSize() const {return ((U32*)&(data[9]))[0];}; inline F32 getLocation() const {return ((F32*)&(data[13]))[0];}; inline F32 getXt() const {return ((F32*)&(data[17]))[0];}; inline F32 getYt() const {return ((F32*)&(data[21]))[0];}; inline F32 getZt() const {return ((F32*)&(data[25]))[0];}; inline void setIndex(U8 index) {data[0] = index;}; inline void setOffset(U64 offset) {((U64*)&(data[1]))[0] = offset;}; inline void setSize(U32 size) {((U32*)&(data[9]))[0] = size;}; inline void setLocation(F32 location) { ((F32*)&(data[13]))[0] = location;}; inline void setXt(F32 xt) {((F32*)&(data[17]))[0] = xt;}; inline void setYt(F32 yt) {((F32*)&(data[21]))[0] = yt;}; inline void setZt(F32 zt) {((F32*)&(data[25]))[0] = zt;}; inline void flipDirection() {((F32*)&(data[17]))[0] *= -1; ((F32*)&(data[21]))[0] *= -1; ((F32*)&(data[25]))[0] *= -1;}; private: U8 data[29]; }; class LASpoint { public: // these fields contain the data that describe each point I32 X; I32 Y; I32 Z; U16 intensity; U8 return_number : 3; U8 number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification : 5; U8 synthetic_flag : 1; U8 keypoint_flag : 1; U8 withheld_flag : 1; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 extended_scan_angle; U8 extended_point_type : 2; U8 extended_scanner_channel : 2; U8 extended_classification_flags : 4; U8 extended_classification; U8 extended_return_number : 4; U8 extended_number_of_returns : 4; // LASlib internal use only U8 deleted_flag; // for 8 byte alignment of the GPS time U8 dummy[2]; // compressed LASzip 1.4 points only BOOL gps_time_change; F64 gps_time; U16 rgb[4]; LASwavepacket wavepacket; U8* extra_bytes; // for converting between x,y,z integers and scaled/translated coordinates const LASquantizer* quantizer; F64 coordinates[3]; // for attributed access to the extra bytes const LASattributer* attributer; // this field provides generic access to the point data U8** point; // these fields describe the point format LAS specific BOOL have_gps_time; BOOL have_rgb; BOOL have_nir; BOOL have_wavepacket; I32 extra_bytes_number; U32 total_point_size; // these fields describe the point format terms of generic items U16 num_items; LASitem* items; // copy functions LASpoint(const LASpoint & other) { *this = other; } LASpoint & operator=(const LASpoint & other) { X = other.X; Y = other.Y; Z = other.Z; intensity = other.intensity; return_number = other.return_number; number_of_returns = other.number_of_returns; scan_direction_flag = other.scan_direction_flag; edge_of_flight_line = other.edge_of_flight_line; classification = other.classification; synthetic_flag = other.synthetic_flag; keypoint_flag = other.keypoint_flag; withheld_flag = other.withheld_flag; scan_angle_rank = other.scan_angle_rank; user_data = other.user_data; point_source_ID = other.point_source_ID; deleted_flag = other.deleted_flag; if (other.have_gps_time) { gps_time = other.gps_time; } if (other.have_rgb) { rgb[0] = other.rgb[0]; rgb[1] = other.rgb[1]; rgb[2] = other.rgb[2]; if (other.have_nir) { rgb[3] = other.rgb[3]; } } if (other.have_wavepacket) { wavepacket = other.wavepacket; } if (other.extra_bytes && extra_bytes) { memcpy(extra_bytes, other.extra_bytes, extra_bytes_number); } if (other.extended_point_type) { extended_classification = other.extended_classification; extended_classification_flags = other.extended_classification_flags; extended_number_of_returns = other.extended_number_of_returns; extended_return_number = other.extended_return_number; extended_scan_angle = other.extended_scan_angle; extended_scanner_channel = other.extended_scanner_channel; } else if (extended_point_type) { extended_classification = other.classification; extended_classification_flags = ((other.withheld_flag) << 2) | ((other.keypoint_flag) << 1) | (other.synthetic_flag); extended_number_of_returns = other.number_of_returns; extended_return_number = other.return_number; extended_scan_angle = I16_QUANTIZE(((F32)other.scan_angle_rank)/0.006); extended_scanner_channel = other.extended_scanner_channel; } return *this; }; void copy_to(U8* buffer) const { if (extended_point_type) { memcpy(buffer, &X, 14); buffer[14] = ((U8*)&X)[24]; // extended return number and number of returns buffer[15] = (((U8*)&X)[14] & 0xC0) | (extended_scanner_channel << 4) | (extended_classification_flags & 0x08) | ((((U8*)&X)[15]) >> 5); buffer[16] = ((U8*)&X)[23]; // extended classification buffer[17] = ((U8*)&X)[17]; // user data ((I16*)buffer)[9] = ((I16*)&X)[10]; // extended scan angle ((U16*)buffer)[10] = ((U16*)&X)[9]; // point source ID memcpy(buffer+22, &gps_time, 8); } else { memcpy(buffer, &X, 20); } U32 i; U32 b = items[0].size; for (i = 1; i < num_items; i++) { memcpy(&buffer[b], point[i], items[i].size); b += items[i].size; } }; void copy_from(const U8* buffer) { if (extended_point_type) { memcpy(&X, buffer, 14); ((U8*)&X)[24] = buffer[14]; // extended return number and number of returns extended_classification_flags = buffer[15] & 0x0F; ((U8*)&X)[15] = (buffer[15] & 0x07) << 5; // legacy classification flags extended_scanner_channel = (buffer[15] >> 4) & 0x03; scan_direction_flag = (buffer[15] >> 6) & 0x01; edge_of_flight_line = (buffer[15] >> 7) & 0x01; ((U8*)&X)[23] = buffer[16]; // extended classification if (extended_classification < 32) classification = extended_classification; ((U8*)&X)[17] = buffer[17]; // user data ((I16*)&X)[10] = ((I16*)buffer)[9]; // extended scan angle ((U16*)&X)[9] = ((U16*)buffer)[10]; // point source ID memcpy(&gps_time, buffer+22, 8); } else { memcpy(&X, buffer, 20); } U32 i; U32 b = items[0].size; for (i = 1; i < num_items; i++) { memcpy(point[i], &buffer[b], items[i].size); b += items[i].size; } }; // these functions set the desired point format (and maybe add on attributes in extra bytes) BOOL init(const LASquantizer* quantizer, const U8 point_type, const U16 point_size, const LASattributer* attributer=0) { // clean the point clean(); // switch over the point types we know if (!LASzip().setup(&num_items, &items, point_type, point_size, LASZIP_COMPRESSOR_NONE)) { fprintf(stderr,"ERROR: unknown point type %d with point size %d\n", (I32)point_type, (I32)point_size); return FALSE; } // create point's item pointers point = new U8*[num_items]; U16 i; for (i = 0; i < num_items; i++) { total_point_size += items[i].size; switch (items[i].type) { case LASitem::POINT14: have_gps_time = TRUE; extended_point_type = 1; case LASitem::POINT10: this->point[i] = (U8*)&(this->X); break; case LASitem::GPSTIME11: have_gps_time = TRUE; this->point[i] = (U8*)&(this->gps_time); break; case LASitem::RGBNIR14: have_nir = TRUE; case LASitem::RGB12: case LASitem::RGB14: have_rgb = TRUE; this->point[i] = (U8*)(this->rgb); break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: have_wavepacket = TRUE; this->point[i] = (U8*)&(this->wavepacket); break; case LASitem::BYTE: case LASitem::BYTE14: extra_bytes_number = items[i].size; extra_bytes = new U8[extra_bytes_number]; this->point[i] = extra_bytes; break; default: return FALSE; } } this->quantizer = quantizer; this->attributer = attributer; return TRUE; }; BOOL init(const LASquantizer* quantizer, const U32 num_items, const LASitem* items, const LASattributer* attributer=0) { U32 i; // clean the point clean(); // create item description this->num_items = num_items; if (this->items) delete [] this->items; this->items = new LASitem[num_items]; if (this->point) delete [] this->point; this->point = new U8*[num_items]; for (i = 0; i < num_items; i++) { this->items[i] = items[i]; total_point_size += items[i].size; switch (items[i].type) { case LASitem::POINT14: have_gps_time = TRUE; extended_point_type = 1; case LASitem::POINT10: this->point[i] = (U8*)&(this->X); break; case LASitem::GPSTIME11: have_gps_time = TRUE; this->point[i] = (U8*)&(this->gps_time); break; case LASitem::RGBNIR14: have_nir = TRUE; case LASitem::RGB12: case LASitem::RGB14: have_rgb = TRUE; this->point[i] = (U8*)(this->rgb); break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: have_wavepacket = TRUE; this->point[i] = (U8*)&(this->wavepacket); break; case LASitem::BYTE: case LASitem::BYTE14: extra_bytes_number = items[i].size; extra_bytes = new U8[extra_bytes_number]; this->point[i] = extra_bytes; break; default: return FALSE; } } this->quantizer = quantizer; this->attributer = attributer; return TRUE; }; BOOL inside_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y) const { F64 xy; xy = get_x(); if (xy < r_min_x || xy >= r_max_x) return FALSE; xy = get_y(); if (xy < r_min_y || xy >= r_max_y) return FALSE; return TRUE; } BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 ur_x, const F32 ur_y) const { F64 xy; xy = get_x(); if (xy < ll_x || xy >= ur_x) return FALSE; xy = get_y(); if (xy < ll_y || xy >= ur_y) return FALSE; return TRUE; } BOOL inside_circle(const F64 center_x, const F64 center_y, F64 squared_radius) const { F64 dx = center_x - get_x(); F64 dy = center_y - get_y(); return ((dx*dx+dy*dy) < squared_radius); } BOOL inside_box(const F64 min_x, const F64 min_y, const F64 min_z, const F64 max_x, const F64 max_y, const F64 max_z) const { F64 xyz; xyz = get_x(); if (xyz < min_x || xyz >= max_x) return FALSE; xyz = get_y(); if (xyz < min_y || xyz >= max_y) return FALSE; xyz = get_z(); if (xyz < min_z || xyz >= max_z) return FALSE; return TRUE; } BOOL inside_bounding_box(const F64 min_x, const F64 min_y, const F64 min_z, const F64 max_x, const F64 max_y, const F64 max_z) const { F64 xyz; xyz = get_x(); if (xyz < min_x || xyz > max_x) return FALSE; xyz = get_y(); if (xyz < min_y || xyz > max_y) return FALSE; xyz = get_z(); if (xyz < min_z || xyz > max_z) return FALSE; return TRUE; } BOOL is_zero() const { if (((U32*)&(this->X))[0] || ((U32*)&(this->X))[1] || ((U32*)&(this->X))[2] || ((U32*)&(this->X))[3] || ((U32*)&(this->X))[4]) { return FALSE; } if (have_gps_time) { if (this->gps_time) { return FALSE; } } if (have_rgb) { if (this->rgb[0] || this->rgb[1] || this->rgb[2]) { return FALSE; } if (have_nir) { if (this->rgb[3]) { return FALSE; } } } return TRUE; } void zero() { X = 0; Y = 0; Z = 0; intensity = 0; return_number = 1; number_of_returns = 1; scan_direction_flag = 0; edge_of_flight_line = 0; classification = 0; synthetic_flag = 0; keypoint_flag = 0; withheld_flag = 0; scan_angle_rank = 0; user_data = 0; point_source_ID = 0; // LAS 1.4 only extended_scan_angle = 0; extended_scanner_channel = 0; extended_classification_flags = 0; extended_classification = 0; extended_return_number = 1; extended_number_of_returns = 1; // LASlib only deleted_flag = 0; gps_time = 0.0; rgb[0] = rgb[1] = rgb[2] = rgb[3] = 0; wavepacket.zero(); }; void clean() { zero(); if (extra_bytes) { delete [] extra_bytes; extra_bytes = 0; }; if (point) delete [] point; point = 0; have_gps_time = FALSE; have_rgb = FALSE; have_wavepacket = FALSE; have_nir = FALSE; extra_bytes_number = 0; total_point_size = 0; num_items = 0; if (items) delete [] items; items = 0; // LAS 1.4 only extended_point_type = 0; }; LASpoint() { extra_bytes = 0; point = 0; items = 0; clean(); }; inline BOOL is_first() const { return get_return_number() <= 1; }; inline BOOL is_intermediate() const { return (!is_first() && !is_last()); }; inline BOOL is_last() const { return get_return_number() >= get_number_of_returns(); }; inline BOOL is_single() const { return get_number_of_returns() <= 1; }; inline BOOL is_first_of_many() const { return !is_single() && is_first(); }; inline BOOL is_last_of_many() const { return !is_single() && is_last(); }; inline I32 get_X() const { return X; }; inline I32 get_Y() const { return Y; }; inline I32 get_Z() const { return Z; }; inline U16 get_intensity() const { return intensity; }; inline U8 get_return_number() const { return return_number; }; inline U8 get_number_of_returns() const { return number_of_returns; }; inline U8 get_scan_direction_flag() const { return scan_direction_flag; }; inline U8 get_edge_of_flight_line() const { return edge_of_flight_line; }; inline U8 get_classification() const { return classification; }; inline U8 get_synthetic_flag() const { return synthetic_flag; }; inline U8 get_keypoint_flag() const { return keypoint_flag; }; inline U8 get_withheld_flag() const { return withheld_flag; }; inline I8 get_scan_angle_rank() const { return scan_angle_rank; }; inline U8 get_user_data() const { return user_data; }; inline U16 get_point_source_ID() const { return point_source_ID; }; inline U8 get_deleted_flag() const { return deleted_flag; }; inline F64 get_gps_time() const { return gps_time; }; inline const U16* get_RGB() const { return rgb; }; inline const U16* get_RGBI() const { return rgb; }; inline U16 get_RGBI(const U32 band) const { return rgb[band]; }; inline U16 get_R() const { return rgb[0]; }; inline U16 get_G() const { return rgb[1]; }; inline U16 get_B() const { return rgb[2]; }; inline U16 get_I() const { return rgb[3]; }; inline U16 get_NIR() const { return rgb[3]; }; inline void set_X(const I32 X) { this->X = X; }; inline void set_Y(const I32 Y) { this->Y = Y; }; inline void set_Z(const I32 Z) { this->Z = Z; }; inline void set_intensity(const U16 intensity) { this->intensity = intensity; }; inline void set_return_number(const U8 return_number) { this->return_number = (return_number > 7 ? 7 : return_number); }; inline void set_number_of_returns(const U8 number_of_returns) { this->number_of_returns = (number_of_returns > 7 ? 7 : number_of_returns); }; inline void set_scan_direction_flag(const U8 scan_direction_flag) { this->scan_direction_flag = scan_direction_flag; }; inline void set_edge_of_flight_line(const U8 edge_of_flight_line) { this->edge_of_flight_line = edge_of_flight_line; }; inline void set_classification(U8 classification) { if (classification < 32) { this->classification = classification; this->extended_classification = classification; } }; inline void set_synthetic_flag(U8 synthetic_flag) { if (synthetic_flag) { this->synthetic_flag = 1; this->extended_classification_flags |= 0x01; } else { this->synthetic_flag = 0; this->extended_classification_flags &= 0x0E; } }; inline void set_keypoint_flag(U8 keypoint_flag) { if (keypoint_flag) { this->keypoint_flag = 1; this->extended_classification_flags |= 0x02; } else { this->keypoint_flag = 0; this->extended_classification_flags &= 0x0D; } }; inline void set_withheld_flag(U8 withheld_flag) { if (withheld_flag) { this->withheld_flag = 1; this->extended_classification_flags |= 0x04; } else { this->withheld_flag = 0; this->extended_classification_flags &= 0x0B; } }; inline void set_scan_angle_rank(I8 scan_angle_rank) { this->scan_angle_rank = scan_angle_rank; }; inline void set_user_data(U8 user_data) { this->user_data = user_data; }; inline void set_point_source_ID(U16 point_source_ID) { this->point_source_ID = point_source_ID; }; inline void set_deleted_flag(U8 deleted_flag) { this->deleted_flag = deleted_flag; }; inline void set_gps_time(const F64 gps_time) { this->gps_time = gps_time; }; inline void set_RGB(const U16* rgb) { memcpy(this->rgb, rgb, sizeof(U16) * 3); }; inline void set_RGBI(const U16* rgb) { memcpy(this->rgb, rgb, sizeof(U16) * 4); }; inline void set_RGBI(const U32 band, const U16 value) { rgb[band] = value; }; inline void set_R(const U16 R) { this->rgb[0] = R; }; inline void set_G(const U16 G) { this->rgb[1] = G; }; inline void set_B(const U16 B) { this->rgb[2] = B; }; inline void set_I(const U16 I) { this->rgb[3] = I; }; inline void set_NIR(const U16 NIR) { this->rgb[3] = NIR; }; inline F64 get_x() const { return quantizer->get_x(X); }; inline F64 get_y() const { return quantizer->get_y(Y); }; inline F64 get_z() const { return quantizer->get_z(Z); }; inline BOOL set_x(const F64 x) { I64 X = quantizer->get_X(x); this->X = (I32)(X); return I32_FITS_IN_RANGE(X); }; inline BOOL set_y(const F64 y) { I64 Y = quantizer->get_Y(y); this->Y = (I32)(Y); return I32_FITS_IN_RANGE(Y); }; inline BOOL set_z(const F64 z) { I64 Z = quantizer->get_Z(z); this->Z = (I32)(Z); return I32_FITS_IN_RANGE(Z); }; inline BOOL is_extended_point_type() const { return extended_point_type; }; inline U8 get_extended_classification() const { return extended_classification; }; inline U8 get_extended_return_number() const { return extended_return_number; }; inline U8 get_extended_number_of_returns() const { return extended_number_of_returns; }; inline I16 get_extended_scan_angle() const { return extended_scan_angle; }; inline U8 get_extended_overlap_flag() const { return (extended_classification_flags >> 3); }; inline U8 get_extended_scanner_channel() const { return extended_scanner_channel; }; inline void set_extended_classification(U8 extended_classification) { this->extended_classification = extended_classification; if (extended_classification > 31) this->classification = 0; else this->classification = extended_classification; }; inline void set_extended_return_number(U8 extended_return_number) { this->extended_return_number = extended_return_number; }; inline void set_extended_number_of_returns(U8 extended_number_of_returns) { this->extended_number_of_returns = extended_number_of_returns; }; inline void set_extended_scan_angle(I16 extended_scan_angle) { this->extended_scan_angle = extended_scan_angle; }; inline void set_extended_overlap_flag(U8 extended_overlap_flag) { this->extended_classification_flags = (extended_overlap_flag << 3) | (this->extended_classification_flags & 7); }; inline void set_extended_scanner_channel(U8 extended_scanner_channel) { this->extended_scanner_channel = extended_scanner_channel; }; inline F32 get_scan_angle() const { if (extended_point_type) return 0.006f*extended_scan_angle; else return (F32)scan_angle_rank; }; inline F32 get_abs_scan_angle() const { if (extended_point_type) return (extended_scan_angle < 0 ? -0.006f*extended_scan_angle : 0.006f*extended_scan_angle) ; else return (scan_angle_rank < 0 ? (F32)-scan_angle_rank : (F32)scan_angle_rank); }; inline void set_scan_angle(F32 scan_angle) { if (extended_point_type) set_extended_scan_angle(I16_QUANTIZE(scan_angle/0.006f)); else set_scan_angle_rank(I8_QUANTIZE(scan_angle)); }; inline void compute_coordinates() { coordinates[0] = get_x(); coordinates[1] = get_y(); coordinates[2] = get_z(); }; inline BOOL compute_XYZ() { BOOL retX = set_x(coordinates[0]); BOOL retY = set_y(coordinates[1]); BOOL retZ = set_z(coordinates[2]); return (retX && retY && retZ); }; inline BOOL compute_XYZ(const LASquantizer* quantizer) { I64 X = quantizer->get_X(coordinates[0]); I64 Y = quantizer->get_Y(coordinates[1]); I64 Z = quantizer->get_Z(coordinates[2]); this->X = (I32)(X); this->Y = (I32)(Y); this->Z = (I32)(Z); return (I32_FITS_IN_RANGE(X) && I32_FITS_IN_RANGE(Y) && I32_FITS_IN_RANGE(Z)); }; // generic functions for attributes in extra bytes inline BOOL has_attribute(U32 index) const { if (attributer) { if (((I32)index) < attributer->number_attributes) { return TRUE; } } return FALSE; }; inline BOOL get_attribute(U32 index, U8* data) const { if (has_attribute(index)) { memcpy(data, extra_bytes + attributer->attribute_starts[index], attributer->attribute_sizes[index]); return TRUE; } return FALSE; }; inline BOOL set_attribute(U32 index, const U8* data) { if (has_attribute(index)) { memcpy(extra_bytes + attributer->attribute_starts[index], data, attributer->attribute_sizes[index]); return TRUE; } return FALSE; }; inline const CHAR* get_attribute_name(U32 index) const { if (has_attribute(index)) { return attributer->attributes[index].name; } return 0; }; inline F64 get_attribute_as_float(U32 index) const { if (has_attribute(index)) { return attributer->attributes[index].get_value_as_float(extra_bytes + attributer->attribute_starts[index]); } return 0.0; }; inline void set_attribute_as_float(U32 index, F64 value) const { if (has_attribute(index)) { attributer->attributes[index].set_value_as_float(extra_bytes + attributer->attribute_starts[index], value); } }; // typed and offset functions for attributes in extra bytes (more efficient) inline void get_attribute(I32 start, U8 &data) const { data = extra_bytes[start]; }; inline void set_attribute(I32 start, U8 data) { extra_bytes[start] = data; }; inline void get_attribute(I32 start, I8 &data) const { data = (I8)(extra_bytes[start]); }; inline void set_attribute(I32 start, I8 data) { extra_bytes[start] = data; }; inline void get_attribute(I32 start, U16 &data) const { data = *((U16*)(extra_bytes + start)); }; inline void set_attribute(I32 start, U16 data) { *((U16*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, I16 &data) const { data = *((I16*)(extra_bytes + start)); }; inline void set_attribute(I32 start, I16 data) { *((I16*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, U32 &data) const { data = *((U32*)(extra_bytes + start)); }; inline void set_attribute(I32 start, U32 data) { *((U32*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, I32 &data) const { data = *((I32*)(extra_bytes + start)); }; inline void set_attribute(I32 start, I32 data) { *((I32*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, U64 &data) const { data = *((U64*)(extra_bytes + start)); }; inline void set_attribute(I32 start, U64 data) { *((U64*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, I64 &data) const { data = *((I64*)(extra_bytes + start)); }; inline void set_attribute(I32 start, I64 data) { *((I64*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, F32 &data) const { data = *((F32*)(extra_bytes + start)); }; inline void set_attribute(I32 start, F32 data) { *((F32*)(extra_bytes + start)) = data; }; inline void get_attribute(I32 start, F64 &data) const { data = *((F64*)(extra_bytes + start)); }; inline void set_attribute(I32 start, F64 data) { *((F64*)(extra_bytes + start)) = data; }; ~LASpoint() { clean(); }; }; #endif LASzip-3.4.3/src/lasquadtree.cpp000066400000000000000000001523221356234217100165010ustar00rootroot00000000000000/* =============================================================================== FILE: lasquadtree.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2015, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasquadtree.hpp" #include "bytestreamin.hpp" #include "bytestreamout.hpp" #include #include #include #include using namespace std; typedef vector my_cell_vector; /* class LAScell { public: LAScell* parent; LAScell* child[4]; U32 num_children : 3; U32 level : 5; U32 idx : 24; F32 mid_x; F32 mid_y; F32 half_size; F32 get_min_x() const { return mid_x - half_size; }; F32 get_min_y() const { return mid_y - half_size; }; F32 get_max_x() const { return mid_x + half_size; }; F32 get_max_y() const { return mid_y + half_size; }; LAScell(); }; LAScell::LAScell() { memset(this, 0, sizeof(LAScell)); } LAScell* get_cell(const F64 x, const F64 y); LAScell* LASquadtree::get_cell(const F64 x, const F64 y) { LAScell* cell = &root; while (cell && cell->num_children) { int child = 0; if (x < cell->mid_x) // only if strictly less { child |= 1; } if (!(y < cell->mid_y)) // only if not strictly less { child |= 2; } cell = cell->child[child]; } return cell; } static bool intersect_point(LAScell* cell, const float* p_pos) { if (cell->num_children) // check if cell has children { int idx = 0; if (p_pos[0] < cell->r_mid[0]) idx |= 1; if (!(p_pos[1] < cell->r_mid[1])) idx |= 2; if (cell->child[idx] && intersect_point(cell->child[idx], p_pos)) return true; return false; } return true; } */ // returns the bounding box of the cell that x & y fall into at the specified level void LASquadtree::get_cell_bounding_box(const F64 x, const F64 y, U32 level, F32* min, F32* max) const { volatile float cell_mid_x; volatile float cell_mid_y; float cell_min_x, cell_max_x; float cell_min_y, cell_max_y; cell_min_x = min_x; cell_max_x = max_x; cell_min_y = min_y; cell_max_y = max_y; while (level) { cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (x < cell_mid_x) { cell_max_x = cell_mid_x; } else { cell_min_x = cell_mid_x; } if (y < cell_mid_y) { cell_max_y = cell_mid_y; } else { cell_min_y = cell_mid_y; } level--; } if (min) { min[0] = cell_min_x; min[1] = cell_min_y; } if (max) { max[0] = cell_max_x; max[1] = cell_max_y; } } // returns the bounding box of the cell that x & y fall into void LASquadtree::get_cell_bounding_box(const F64 x, const F64 y, F32* min, F32* max) const { get_cell_bounding_box(x, y, levels, min, max); } // returns the bounding box of the cell with the specified level_index at the specified level void LASquadtree::get_cell_bounding_box(U32 level_index, U32 level, F32* min, F32* max) const { volatile F32 cell_mid_x; volatile F32 cell_mid_y; F32 cell_min_x, cell_max_x; F32 cell_min_y, cell_max_y; cell_min_x = min_x; cell_max_x = max_x; cell_min_y = min_y; cell_max_y = max_y; U32 index; while (level) { index = (level_index >>(2*(level-1)))&3; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (index & 1) { cell_min_x = cell_mid_x; } else { cell_max_x = cell_mid_x; } if (index & 2) { cell_min_y = cell_mid_y; } else { cell_max_y = cell_mid_y; } level--; } if (min) { min[0] = cell_min_x; min[1] = cell_min_y; } if (max) { max[0] = cell_max_x; max[1] = cell_max_y; } } // returns the bounding box of the cell with the specified level_index at the specified level void LASquadtree::get_cell_bounding_box(U32 level_index, U32 level, F64* min, F64* max) const { volatile F64 cell_mid_x; volatile F64 cell_mid_y; F64 cell_min_x, cell_max_x; F64 cell_min_y, cell_max_y; cell_min_x = min_x; cell_max_x = max_x; cell_min_y = min_y; cell_max_y = max_y; U32 index; while (level) { index = (level_index >>(2*(level-1)))&3; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (index & 1) { cell_min_x = cell_mid_x; } else { cell_max_x = cell_mid_x; } if (index & 2) { cell_min_y = cell_mid_y; } else { cell_max_y = cell_mid_y; } level--; } if (min) { min[0] = cell_min_x; min[1] = cell_min_y; } if (max) { max[0] = cell_max_x; max[1] = cell_max_y; } } // returns the bounding box of the cell with the specified level_index void LASquadtree::get_cell_bounding_box(U32 level_index, F32* min, F32* max) const { get_cell_bounding_box(level_index, levels, min, max); } // returns the bounding box of the cell with the specified level_index void LASquadtree::get_cell_bounding_box(U32 level_index, F64* min, F64* max) const { get_cell_bounding_box(level_index, levels, min, max); } // returns the bounding box of the cell with the specified cell_index void LASquadtree::get_cell_bounding_box(const I32 cell_index, F32* min, F32* max) const { U32 level = get_level((U32)cell_index); U32 level_index = get_level_index((U32)cell_index, level); get_cell_bounding_box(level_index, level, min, max); } // returns the (sub-)level index of the cell that x & y fall into at the specified level U32 LASquadtree::get_level_index(const F64 x, const F64 y, U32 level) const { volatile float cell_mid_x; volatile float cell_mid_y; float cell_min_x, cell_max_x; float cell_min_y, cell_max_y; cell_min_x = min_x; cell_max_x = max_x; cell_min_y = min_y; cell_max_y = max_y; U32 level_index = 0; while (level) { level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (x < cell_mid_x) { cell_max_x = cell_mid_x; } else { cell_min_x = cell_mid_x; level_index |= 1; } if (y < cell_mid_y) { cell_max_y = cell_mid_y; } else { cell_min_y = cell_mid_y; level_index |= 2; } level--; } return level_index; } // returns the (sub-)level index of the cell that x & y fall into U32 LASquadtree::get_level_index(const F64 x, const F64 y) const { return get_level_index(x, y, levels); } // returns the (sub-)level index and the bounding box of the cell that x & y fall into at the specified level U32 LASquadtree::get_level_index(const F64 x, const F64 y, U32 level, F32* min, F32* max) const { volatile float cell_mid_x; volatile float cell_mid_y; float cell_min_x, cell_max_x; float cell_min_y, cell_max_y; cell_min_x = min_x; cell_max_x = max_x; cell_min_y = min_y; cell_max_y = max_y; U32 level_index = 0; while (level) { level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (x < cell_mid_x) { cell_max_x = cell_mid_x; } else { cell_min_x = cell_mid_x; level_index |= 1; } if (y < cell_mid_y) { cell_max_y = cell_mid_y; } else { cell_min_y = cell_mid_y; level_index |= 2; } level--; } if (min) { min[0] = cell_min_x; min[1] = cell_min_y; } if (max) { max[0] = cell_max_x; max[1] = cell_max_y; } return level_index; } // returns the (sub-)level index and the bounding box of the cell that x & y fall into U32 LASquadtree::get_level_index(const F64 x, const F64 y, F32* min, F32* max) const { return get_level_index(x, y, levels, min, max); } // returns the index of the cell that x & y fall into at the specified level U32 LASquadtree::get_cell_index(const F64 x, const F64 y, U32 level) const { if (sub_level) { return level_offset[sub_level+level] + (sub_level_index << (level*2)) + get_level_index(x, y, level); } else { return level_offset[level]+get_level_index(x, y, level); } } // returns the index of the cell that x & y fall into U32 LASquadtree::get_cell_index(const F64 x, const F64 y) const { return get_cell_index(x, y, levels); } // returns the indices of parent and siblings for the specified cell index BOOL LASquadtree::coarsen(const I32 cell_index, I32* coarser_cell_index, U32* num_cell_indices, I32** cell_indices) { if (cell_index < 0) return FALSE; U32 level = get_level((U32)cell_index); if (level == 0) return FALSE; U32 level_index = get_level_index((U32)cell_index, level); level_index = level_index >> 2; if (coarser_cell_index) (*coarser_cell_index) = get_cell_index(level_index, level-1); if (num_cell_indices && cell_indices) { (*num_cell_indices) = 4; (*cell_indices) = (I32*)coarser_indices; level_index = level_index << 2; (*cell_indices)[0] = get_cell_index(level_index + 0, level); (*cell_indices)[1] = get_cell_index(level_index + 1, level); (*cell_indices)[2] = get_cell_index(level_index + 2, level); (*cell_indices)[3] = get_cell_index(level_index + 3, level); } return TRUE; } // returns the level index of the cell index at the specified level U32 LASquadtree::get_level_index(U32 cell_index, U32 level) const { if (sub_level) { return cell_index - (sub_level_index << (level*2)) - level_offset[sub_level+level]; } else { return cell_index - level_offset[level]; } } // returns the level index of the cell index U32 LASquadtree::get_level_index(U32 cell_index) const { return get_level_index(cell_index, levels); } // returns the level the cell index U32 LASquadtree::get_level(U32 cell_index) const { int level = 0; while (cell_index >= level_offset[level+1]) level++; return level; } // returns the cell index of the level index at the specified level U32 LASquadtree::get_cell_index(U32 level_index, U32 level) const { if (sub_level) { return level_index + (sub_level_index << (level*2)) + level_offset[sub_level+level]; } else { return level_index + level_offset[level]; } } // returns the cell index of the level index U32 LASquadtree::get_cell_index(U32 level_index) const { return get_cell_index(level_index, levels); } // returns the maximal level index at the specified level U32 LASquadtree::get_max_level_index(U32 level) const { return (1<getBytes((U8*)signature, 4); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading LASspatial signature\n"); return FALSE; } if (strncmp(signature, "LASS", 4) != 0) { fprintf(stderr,"ERROR (LASquadtree): wrong LASspatial signature %4s instead of 'LASS'\n", signature); return FALSE; } U32 type; try { stream->getBytes((U8*)&type, 4); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading LASspatial type\n"); return 0; } if (type != LAS_SPATIAL_QUAD_TREE) { fprintf(stderr,"ERROR (LASquadtree): unknown LASspatial type %u\n", type); return 0; } try { stream->getBytes((U8*)signature, 4); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading signature\n"); return FALSE; } if (strncmp(signature, "LASQ", 4) != 0) { // fprintf(stderr,"ERROR (LASquadtree): wrong signature %4s instead of 'LASV'\n", signature); // return FALSE; levels = ((U32*)signature)[0]; } else { U32 version; try { stream->get32bitsLE((U8*)&version); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading version\n"); return FALSE; } try { stream->get32bitsLE((U8*)&levels); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading levels\n"); return FALSE; } } U32 level_index; try { stream->get32bitsLE((U8*)&level_index); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading level_index\n"); return FALSE; } U32 implicit_levels; try { stream->get32bitsLE((U8*)&implicit_levels); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading implicit_levels\n"); return FALSE; } try { stream->get32bitsLE((U8*)&min_x); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading min_x\n"); return FALSE; } try { stream->get32bitsLE((U8*)&max_x); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading max_x\n"); return FALSE; } try { stream->get32bitsLE((U8*)&min_y); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading min_y\n"); return FALSE; } try { stream->get32bitsLE((U8*)&max_y); } catch(...) { fprintf(stderr,"ERROR (LASquadtree): reading max_y\n"); return FALSE; } return TRUE; } BOOL LASquadtree::write(ByteStreamOut* stream) const { // which totals 28 bytes // U32 levels 4 bytes // U32 level_index 4 bytes (default 0) // U32 implicit_levels 4 bytes (only used when level_index != 0)) // F32 min_x 4 bytes // F32 max_x 4 bytes // F32 min_y 4 bytes // F32 max_y 4 bytes // which totals 28 bytes if (!stream->putBytes((const U8*)"LASS", 4)) { fprintf(stderr,"ERROR (LASquadtree): writing LASspatial signature\n"); return FALSE; } U32 type = LAS_SPATIAL_QUAD_TREE; if (!stream->put32bitsLE((U8*)&type)) { fprintf(stderr,"ERROR (LASquadtree): writing LASspatial type %u\n", type); return FALSE; } if (!stream->putBytes((const U8*)"LASQ", 4)) { fprintf(stderr,"ERROR (LASquadtree): writing signature\n"); return FALSE; } U32 version = 0; if (!stream->put32bitsLE((const U8*)&version)) { fprintf(stderr,"ERROR (LASquadtree): writing version\n"); return FALSE; } if (!stream->put32bitsLE((const U8*)&levels)) { fprintf(stderr,"ERROR (LASquadtree): writing levels %u\n", levels); return FALSE; } U32 level_index = 0; if (!stream->put32bitsLE((const U8*)&level_index)) { fprintf(stderr,"ERROR (LASquadtree): writing level_index %u\n", level_index); return FALSE; } U32 implicit_levels = 0; if (!stream->put32bitsLE((const U8*)&implicit_levels)) { fprintf(stderr,"ERROR (LASquadtree): writing implicit_levels %u\n", implicit_levels); return FALSE; } if (!stream->put32bitsLE((const U8*)&min_x)) { fprintf(stderr,"ERROR (LASquadtree): writing min_x %g\n", min_x); return FALSE; } if (!stream->put32bitsLE((const U8*)&max_x)) { fprintf(stderr,"ERROR (LASquadtree): writing max_x %g\n", max_x); return FALSE; } if (!stream->put32bitsLE((const U8*)&min_y)) { fprintf(stderr,"ERROR (LASquadtree): writing min_y %g\n", min_y); return FALSE; } if (!stream->put32bitsLE((const U8*)&max_y)) { fprintf(stderr,"ERROR (LASquadtree): writing max_y %g\n", max_y); return FALSE; } return TRUE; } // create or finalize the cell (in the spatial hierarchy) BOOL LASquadtree::manage_cell(const U32 cell_index, const BOOL finalize) { U32 adaptive_pos = cell_index/32; U32 adaptive_bit = ((U32)1) << (cell_index%32); if (adaptive_pos >= adaptive_alloc) { if (adaptive) { adaptive = (U32*)realloc(adaptive, adaptive_pos*2*sizeof(U32)); for (U32 i = adaptive_alloc; i < adaptive_pos*2; i++) adaptive[i] = 0; adaptive_alloc = adaptive_pos*2; } else { adaptive = (U32*)malloc((adaptive_pos+1)*sizeof(U32)); for (U32 i = adaptive_alloc; i <= adaptive_pos; i++) adaptive[i] = 0; adaptive_alloc = adaptive_pos+1; } } adaptive[adaptive_pos] &= ~adaptive_bit; U32 index; U32 level = get_level(cell_index); U32 level_index = get_level_index(cell_index, level); while (level) { level--; level_index = level_index >> 2; index = get_cell_index(level_index, level); adaptive_pos = index/32; adaptive_bit = ((U32)1) << (index%32); if (adaptive[adaptive_pos] & adaptive_bit) break; adaptive[adaptive_pos] |= adaptive_bit; } return TRUE; } // check whether the x & y coordinates fall into the tiling BOOL LASquadtree::inside(const F64 x, const F64 y) const { return ((min_x <= x) && (x < max_x) && (min_y <= y) && (y < max_y)); } U32 LASquadtree::intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y, U32 level) { if (current_cells == 0) { current_cells = (void*) new my_cell_vector; } else { ((my_cell_vector*)current_cells)->clear(); } if (r_max_x <= min_x || !(r_min_x <= max_x) || r_max_y <= min_y || !(r_min_y <= max_y)) { return 0; } if (adaptive) { intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, min_x, max_x, min_y, max_y, 0, 0); } else { intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, min_x, max_x, min_y, max_y, level, 0); } return (U32)(((my_cell_vector*)current_cells)->size()); } U32 LASquadtree::intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y) { return intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y, levels); } U32 LASquadtree::intersect_tile(const F32 ll_x, const F32 ll_y, const F32 size, U32 level) { if (current_cells == 0) { current_cells = (void*) new my_cell_vector; } else { ((my_cell_vector*)current_cells)->clear(); } volatile F32 ur_x = ll_x + size; volatile F32 ur_y = ll_y + size; if (ur_x <= min_x || !(ll_x <= max_x) || ur_y <= min_y || !(ll_y <= max_y)) { return 0; } if (adaptive) { intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, min_x, max_x, min_y, max_y, 0, 0); } else { intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, min_x, max_x, min_y, max_y, level, 0); } return (U32)(((my_cell_vector*)current_cells)->size()); } U32 LASquadtree::intersect_tile(const F32 ll_x, const F32 ll_y, const F32 size) { return intersect_tile(ll_x, ll_y, size, levels); } U32 LASquadtree::intersect_circle(const F64 center_x, const F64 center_y, const F64 radius, U32 level) { if (current_cells == 0) { current_cells = (void*) new my_cell_vector; } else { ((my_cell_vector*)current_cells)->clear(); } F64 r_min_x = center_x - radius; F64 r_min_y = center_y - radius; F64 r_max_x = center_x + radius; F64 r_max_y = center_y + radius; if (r_max_x <= min_x || !(r_min_x <= max_x) || r_max_y <= min_y || !(r_min_y <= max_y)) { return 0; } if (adaptive) { intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, min_x, max_x, min_y, max_y, 0, 0); } else { intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, min_x, max_x, min_y, max_y, level, 0); } return (U32)(((my_cell_vector*)current_cells)->size()); } U32 LASquadtree::intersect_circle(const F64 center_x, const F64 center_y, const F64 radius) { return intersect_circle(center_x, center_y, radius, levels); } void LASquadtree::intersect_rectangle_with_cells(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; if (level) { level--; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (r_max_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(r_min_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_rectangle_with_cells(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { ((my_cell_vector*)current_cells)->push_back(level_index); } } void LASquadtree::intersect_rectangle_with_cells_adaptive(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; U32 cell_index = get_cell_index(level_index, level); U32 adaptive_pos = cell_index/32; U32 adaptive_bit = ((U32)1) << (cell_index%32); if ((level < levels) && (adaptive[adaptive_pos] & adaptive_bit)) { level++; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (r_max_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(r_min_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_rectangle_with_cells_adaptive(r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { ((my_cell_vector*)current_cells)->push_back(cell_index); } } void LASquadtree::intersect_tile_with_cells(const F32 ll_x, const F32 ll_y, const F32 ur_x, const F32 ur_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; if (level) { level--; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (ur_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(ll_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_tile_with_cells(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { ((my_cell_vector*)current_cells)->push_back(level_index); } } void LASquadtree::intersect_tile_with_cells_adaptive(const F32 ll_x, const F32 ll_y, const F32 ur_x, const F32 ur_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; U32 cell_index = get_cell_index(level_index, level); U32 adaptive_pos = cell_index/32; U32 adaptive_bit = ((U32)1) << (cell_index%32); if ((level < levels) && (adaptive[adaptive_pos] & adaptive_bit)) { level++; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (ur_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(ll_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (ur_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(ll_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_tile_with_cells_adaptive(ll_x, ll_y, ur_x, ur_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { ((my_cell_vector*)current_cells)->push_back(cell_index); } } void LASquadtree::intersect_circle_with_cells(const F64 center_x, const F64 center_y, const F64 radius, const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; if (level) { level--; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (r_max_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(r_min_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_circle_with_cells(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { if (intersect_circle_with_rectangle(center_x, center_y, radius, cell_min_x, cell_max_x, cell_min_y, cell_max_y)) { ((my_cell_vector*)current_cells)->push_back(level_index); } } } void LASquadtree::intersect_circle_with_cells_adaptive(const F64 center_x, const F64 center_y, const F64 radius, const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y, const F32 cell_min_x, const F32 cell_max_x, const F32 cell_min_y, const F32 cell_max_y, U32 level, U32 level_index) { volatile float cell_mid_x; volatile float cell_mid_y; U32 cell_index = get_cell_index(level_index, level); U32 adaptive_pos = cell_index/32; U32 adaptive_bit = ((U32)1) << (cell_index%32); if ((level < levels) && (adaptive[adaptive_pos] & adaptive_bit)) { level++; level_index <<= 2; cell_mid_x = (cell_min_x + cell_max_x)/2; cell_mid_y = (cell_min_y + cell_max_y)/2; if (r_max_x <= cell_mid_x) { // cell_max_x = cell_mid_x; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } else { intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); } } else if (!(r_min_x < cell_mid_x)) { // cell_min_x = cell_mid_x; // level_index |= 1; if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } else { if (r_max_y <= cell_mid_y) { // cell_max_y = cell_mid_y; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); } else if (!(r_min_y < cell_mid_y)) { // cell_min_y = cell_mid_y; // level_index |= 1; intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } else { intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_min_y, cell_mid_y, level, level_index); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_min_y, cell_mid_y, level, level_index | 1); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_min_x, cell_mid_x, cell_mid_y, cell_max_y, level, level_index | 2); intersect_circle_with_cells_adaptive(center_x, center_y, radius, r_min_x, r_min_y, r_max_x, r_max_y, cell_mid_x, cell_max_x, cell_mid_y, cell_max_y, level, level_index | 3); } } } else { if (intersect_circle_with_rectangle(center_x, center_y, radius, cell_min_x, cell_max_x, cell_min_y, cell_max_y)) { ((my_cell_vector*)current_cells)->push_back(cell_index); } } } BOOL LASquadtree::intersect_circle_with_rectangle(const F64 center_x, const F64 center_y, const F64 radius, const F32 r_min_x, const F32 r_max_x, const F32 r_min_y, const F32 r_max_y) { F64 r_diff_x, r_diff_y; F64 radius_squared = radius * radius; if (r_max_x < center_x) // R to left of circle center { r_diff_x = center_x - r_max_x; if (r_max_y < center_y) // R in lower left corner { r_diff_y = center_y - r_max_y; return ((r_diff_x * r_diff_x + r_diff_y * r_diff_y) < radius_squared); } else if (r_min_y > center_y) // R in upper left corner { r_diff_y = -center_y + r_min_y; return ((r_diff_x * r_diff_x + r_diff_y * r_diff_y) < radius_squared); } else // R due West of circle { return (r_diff_x < radius); } } else if (r_min_x > center_x) // R to right of circle center { r_diff_x = -center_x + r_min_x; if (r_max_y < center_y) // R in lower right corner { r_diff_y = center_y - r_max_y; return ((r_diff_x * r_diff_x + r_diff_y * r_diff_y) < radius_squared); } else if (r_min_y > center_y) // R in upper right corner { r_diff_y = -center_y + r_min_y; return ((r_diff_x * r_diff_x + r_diff_y * r_diff_y) < radius_squared); } else // R due East of circle { return (r_diff_x < radius); } } else // R on circle vertical centerline { if (r_max_y < center_y) // R due South of circle { r_diff_y = center_y - r_max_y; return (r_diff_y < radius); } else if (r_min_y > center_y) // R due North of circle { r_diff_y = -center_y + r_min_y; return (r_diff_y < radius); } else // R contains circle centerpoint { return TRUE; } } } BOOL LASquadtree::get_all_cells() { intersect_rectangle(min_x, min_y, max_x, max_y); return get_intersected_cells(); } BOOL LASquadtree::get_intersected_cells() { next_cell_index = 0; if (current_cells == 0) { return FALSE; } if (((my_cell_vector*)current_cells)->size() == 0) { return FALSE; } return TRUE; } BOOL LASquadtree::has_more_cells() { if (current_cells == 0) { return FALSE; } if (next_cell_index >= ((my_cell_vector*)current_cells)->size()) { return FALSE; } if (adaptive) { current_cell = ((my_cell_vector*)current_cells)->at(next_cell_index); } else { current_cell = level_offset[levels] + ((my_cell_vector*)current_cells)->at(next_cell_index); } next_cell_index++; return TRUE; } BOOL LASquadtree::setup(F64 bb_min_x, F64 bb_max_x, F64 bb_min_y, F64 bb_max_y, F32 cell_size) { this->cell_size = cell_size; this->sub_level = 0; this->sub_level_index = 0; // enlarge bounding box to units of cells if (bb_min_x >= 0) min_x = cell_size*((I32)(bb_min_x/cell_size)); else min_x = cell_size*((I32)(bb_min_x/cell_size)-1); if (bb_max_x >= 0) max_x = cell_size*((I32)(bb_max_x/cell_size)+1); else max_x = cell_size*((I32)(bb_max_x/cell_size)); if (bb_min_y >= 0) min_y = cell_size*((I32)(bb_min_y/cell_size)); else min_y = cell_size*((I32)(bb_min_y/cell_size)-1); if (bb_max_y >= 0) max_y = cell_size*((I32)(bb_max_y/cell_size)+1); else max_y = cell_size*((I32)(bb_max_y/cell_size)); // how many cells minimally in each direction cells_x = U32_QUANTIZE((max_x - min_x)/cell_size); cells_y = U32_QUANTIZE((max_y - min_y)/cell_size); if (cells_x == 0 || cells_y == 0) { fprintf(stderr, "ERROR: cells_x %d cells_y %d\n", cells_x, cells_y); return FALSE; } // how many quad tree levels to get to that many cells U32 c = ((cells_x > cells_y) ? cells_x - 1 : cells_y - 1); levels = 0; while (c) { c = c >> 1; levels++; } // enlarge bounding box to quad tree size U32 c1, c2; c = (1 << levels) - cells_x; c1 = c/2; c2 = c - c1; min_x -= (c2 * cell_size); max_x += (c1 * cell_size); c = (1 << levels) - cells_y; c1 = c/2; c2 = c - c1; min_y -= (c2 * cell_size); max_y += (c1 * cell_size); return TRUE; } BOOL LASquadtree::setup(F64 bb_min_x, F64 bb_max_x, F64 bb_min_y, F64 bb_max_y, F32 cell_size, F32 offset_x, F32 offset_y) { this->cell_size = cell_size; this->sub_level = 0; this->sub_level_index = 0; // enlarge bounding box to units of cells if ((bb_min_x-offset_x) >= 0) min_x = cell_size*((I32)((bb_min_x-offset_x)/cell_size)) + offset_x; else min_x = cell_size*((I32)((bb_min_x-offset_x)/cell_size)-1) + offset_x; if ((bb_max_x-offset_x) >= 0) max_x = cell_size*((I32)((bb_max_x-offset_x)/cell_size)+1) + offset_x; else max_x = cell_size*((I32)((bb_max_x-offset_x)/cell_size)) + offset_x; if ((bb_min_y-offset_y) >= 0) min_y = cell_size*((I32)((bb_min_y-offset_y)/cell_size)) + offset_y; else min_y = cell_size*((I32)((bb_min_y-offset_y)/cell_size)-1) + offset_y; if ((bb_max_y-offset_y) >= 0) max_y = cell_size*((I32)((bb_max_y-offset_y)/cell_size)+1) + offset_y; else max_y = cell_size*((I32)((bb_max_y-offset_y)/cell_size)) + offset_y; // how many cells minimally in each direction cells_x = U32_QUANTIZE((max_x - min_x)/cell_size); cells_y = U32_QUANTIZE((max_y - min_y)/cell_size); if (cells_x == 0 || cells_y == 0) { fprintf(stderr, "ERROR: cells_x %d cells_y %d\n", cells_x, cells_y); return FALSE; } // how many quad tree levels to get to that many cells U32 c = ((cells_x > cells_y) ? cells_x - 1 : cells_y - 1); levels = 0; while (c) { c = c >> 1; levels++; } // enlarge bounding box to quad tree size U32 c1, c2; c = (1 << levels) - cells_x; c1 = c/2; c2 = c - c1; min_x -= (c2 * cell_size); max_x += (c1 * cell_size); c = (1 << levels) - cells_y; c1 = c/2; c2 = c - c1; min_y -= (c2 * cell_size); max_y += (c1 * cell_size); return TRUE; } BOOL LASquadtree::tiling_setup(F32 min_x, F32 max_x, F32 min_y, F32 max_y, U32 levels) { this->min_x = min_x; this->max_x = max_x; this->min_y = min_y; this->max_y = max_y; this->levels = levels; this->sub_level = 0; this->sub_level_index = 0; return TRUE; } BOOL LASquadtree::subtiling_setup(F32 min_x, F32 max_x, F32 min_y, F32 max_y, U32 sub_level, U32 sub_level_index, U32 levels) { this->min_x = min_x; this->max_x = max_x; this->min_y = min_y; this->max_y = max_y; F32 min[2]; F32 max[2]; get_cell_bounding_box(sub_level_index, sub_level, min, max); this->min_x = min[0]; this->max_x = max[0]; this->min_y = min[1]; this->max_y = max[1]; this->sub_level = sub_level; this->sub_level_index = sub_level_index; this->levels = levels; return TRUE; } LASquadtree::LASquadtree() { U32 l; levels = 0; cell_size = 0; min_x = 0; max_x = 0; min_y = 0; max_y = 0; cells_x = 0; cells_y = 0; sub_level = 0; sub_level_index = 0; level_offset[0] = 0; for (l = 0; l < 23; l++) { level_offset[l+1] = level_offset[l] + ((1<= x_offset) return (I64)(((x-x_offset)/x_scale_factor)+0.5); else return (I64)(((x-x_offset)/x_scale_factor)-0.5); }; inline I64 get_Y(const F64 y) const { if (y >= y_offset) return (I64)(((y-y_offset)/y_scale_factor)+0.5); else return (I64)(((y-y_offset)/y_scale_factor)-0.5); }; inline I64 get_Z(const F64 z) const { if (z >= z_offset) return (I64)(((z-z_offset)/z_scale_factor)+0.5); else return (I64)(((z-z_offset)/z_scale_factor)-0.5); }; LASquantizer() { x_scale_factor = 0.01; y_scale_factor = 0.01; z_scale_factor = 0.01; x_offset = 0.0; y_offset = 0.0; z_offset = 0.0; }; LASquantizer & operator=(const LASquantizer & quantizer) { this->x_scale_factor = quantizer.x_scale_factor; this->y_scale_factor = quantizer.y_scale_factor; this->z_scale_factor = quantizer.z_scale_factor; this->x_offset = quantizer.x_offset; this->y_offset = quantizer.y_offset; this->z_offset = quantizer.z_offset; return *this; }; }; #endif LASzip-3.4.3/src/lasreaditem.hpp000066400000000000000000000036251356234217100164670ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditem.hpp CONTENTS: Common interface for all classes that read the items that compose a point. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 23 August 2016 -- layering of items for selective decompression in LAS 1.4 10 January 2011 -- licensing change for LGPL release and liblas integration 7 December 2010 -- refactored after getting invited to KAUST in Saudi Arabia =============================================================================== */ #ifndef LAS_READ_ITEM_HPP #define LAS_READ_ITEM_HPP #include "mydefs.hpp" class ByteStreamIn; class LASreadItem { public: virtual void read(U8* item, U32& context)=0; virtual ~LASreadItem(){}; }; class LASreadItemRaw : public LASreadItem { public: LASreadItemRaw() { instream = 0; }; BOOL init(ByteStreamIn* instream) { if (!instream) return FALSE; this->instream = instream; return TRUE; }; virtual ~LASreadItemRaw(){}; protected: ByteStreamIn* instream; }; class LASreadItemCompressed : public LASreadItem { public: virtual BOOL chunk_sizes() { return FALSE; }; virtual BOOL init(const U8* item, U32& context)=0; virtual ~LASreadItemCompressed(){}; }; #endif LASzip-3.4.3/src/lasreaditemcompressed_v1.cpp000066400000000000000000000415361356234217100211600ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v1.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasreaditemcompressed_v1.hpp" #include "laszip_common_v1.hpp" #include #include /* =============================================================================== LASreadItemCompressed_POINT10_v1 =============================================================================== */ struct LASpoint10 { I32 x; I32 y; I32 z; U16 intensity; U8 return_number : 3; U8 number_of_returns_of_given_pulse : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; }; LASreadItemCompressed_POINT10_v1::LASreadItemCompressed_POINT10_v1(ArithmeticDecoder* dec) { U32 i; /* set decoder */ assert(dec); this->dec = dec; /* create models and integer compressors */ ic_dx = new IntegerCompressor(dec, 32); // 32 bits, 1 context ic_dy = new IntegerCompressor(dec, 32, 20); // 32 bits, 20 contexts ic_z = new IntegerCompressor(dec, 32, 20); // 32 bits, 20 contexts ic_intensity = new IntegerCompressor(dec, 16); ic_scan_angle_rank = new IntegerCompressor(dec, 8, 2); ic_point_source_ID = new IntegerCompressor(dec, 16); m_changed_values = dec->createSymbolModel(64); for (i = 0; i < 256; i++) { m_bit_byte[i] = 0; m_classification[i] = 0; m_user_data[i] = 0; } } LASreadItemCompressed_POINT10_v1::~LASreadItemCompressed_POINT10_v1() { U32 i; delete ic_dx; delete ic_dy; delete ic_z; delete ic_intensity; delete ic_scan_angle_rank; delete ic_point_source_ID; dec->destroySymbolModel(m_changed_values); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) dec->destroySymbolModel(m_bit_byte[i]); if (m_classification[i]) dec->destroySymbolModel(m_classification[i]); if (m_user_data[i]) dec->destroySymbolModel(m_user_data[i]); } } BOOL LASreadItemCompressed_POINT10_v1::init(const U8* item, U32& context) { U32 i; /* init state */ last_x_diff[0] = last_x_diff[1] = last_x_diff[2] = 0; last_y_diff[0] = last_y_diff[1] = last_y_diff[2] = 0; last_incr = 0; /* init models and integer compressors */ ic_dx->initDecompressor(); ic_dy->initDecompressor(); ic_z->initDecompressor(); ic_intensity->initDecompressor(); ic_scan_angle_rank->initDecompressor(); ic_point_source_ID->initDecompressor(); dec->initSymbolModel(m_changed_values); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) dec->initSymbolModel(m_bit_byte[i]); if (m_classification[i]) dec->initSymbolModel(m_classification[i]); if (m_user_data[i]) dec->initSymbolModel(m_user_data[i]); } /* init last item */ memcpy(last_item, item, 20); return TRUE; } inline void LASreadItemCompressed_POINT10_v1::read(U8* item, U32& context) { // find median difference for x and y from 3 preceding differences I32 median_x; if (last_x_diff[0] < last_x_diff[1]) { if (last_x_diff[1] < last_x_diff[2]) median_x = last_x_diff[1]; else if (last_x_diff[0] < last_x_diff[2]) median_x = last_x_diff[2]; else median_x = last_x_diff[0]; } else { if (last_x_diff[0] < last_x_diff[2]) median_x = last_x_diff[0]; else if (last_x_diff[1] < last_x_diff[2]) median_x = last_x_diff[2]; else median_x = last_x_diff[1]; } I32 median_y; if (last_y_diff[0] < last_y_diff[1]) { if (last_y_diff[1] < last_y_diff[2]) median_y = last_y_diff[1]; else if (last_y_diff[0] < last_y_diff[2]) median_y = last_y_diff[2]; else median_y = last_y_diff[0]; } else { if (last_y_diff[0] < last_y_diff[2]) median_y = last_y_diff[0]; else if (last_y_diff[1] < last_y_diff[2]) median_y = last_y_diff[2]; else median_y = last_y_diff[1]; } // decompress x y z coordinates I32 x_diff = ic_dx->decompress(median_x); ((LASpoint10*)last_item)->x += x_diff; // we use the number k of bits corrector bits to switch contexts U32 k_bits = ic_dx->getK(); I32 y_diff = ic_dy->decompress(median_y, (k_bits < 19 ? k_bits : 19)); ((LASpoint10*)last_item)->y += y_diff; k_bits = (k_bits + ic_dy->getK())/2; ((LASpoint10*)last_item)->z = ic_z->decompress(((LASpoint10*)last_item)->z, (k_bits < 19 ? k_bits : 19)); // decompress which other values have changed I32 changed_values = dec->decodeSymbol(m_changed_values); if (changed_values) { // decompress the intensity if it has changed if (changed_values & 32) { ((LASpoint10*)last_item)->intensity = (U16)ic_intensity->decompress(((LASpoint10*)last_item)->intensity); } // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed if (changed_values & 16) { if (m_bit_byte[last_item[14]] == 0) { m_bit_byte[last_item[14]] = dec->createSymbolModel(256); dec->initSymbolModel(m_bit_byte[last_item[14]]); } last_item[14] = (U8)dec->decodeSymbol(m_bit_byte[last_item[14]]); } // decompress the classification ... if it has changed if (changed_values & 8) { if (m_classification[last_item[15]] == 0) { m_classification[last_item[15]] = dec->createSymbolModel(256); dec->initSymbolModel(m_classification[last_item[15]]); } last_item[15] = (U8)dec->decodeSymbol(m_classification[last_item[15]]); } // decompress the scan_angle_rank ... if it has changed if (changed_values & 4) { last_item[16] = (U8)ic_scan_angle_rank->decompress(last_item[16], k_bits < 3); } // decompress the user_data ... if it has changed if (changed_values & 2) { if (m_user_data[last_item[17]] == 0) { m_user_data[last_item[17]] = dec->createSymbolModel(256); dec->initSymbolModel(m_user_data[last_item[17]]); } last_item[17] = (U8)dec->decodeSymbol(m_user_data[last_item[17]]); } // decompress the point_source_ID ... if it has changed if (changed_values & 1) { ((LASpoint10*)last_item)->point_source_ID = (U16)ic_point_source_ID->decompress(((LASpoint10*)last_item)->point_source_ID); } } // record the difference last_x_diff[last_incr] = x_diff; last_y_diff[last_incr] = y_diff; last_incr++; if (last_incr > 2) last_incr = 0; // copy the last point memcpy(item, last_item, 20); } /* =============================================================================== LASreadItemCompressed_GPSTIME11_v1 =============================================================================== */ #define LASZIP_GPSTIME_MULTIMAX 512 LASreadItemCompressed_GPSTIME11_v1::LASreadItemCompressed_GPSTIME11_v1(ArithmeticDecoder* dec) { /* set decoder */ assert(dec); this->dec = dec; /* create entropy models and integer compressors */ m_gpstime_multi = dec->createSymbolModel(LASZIP_GPSTIME_MULTIMAX); m_gpstime_0diff = dec->createSymbolModel(3); ic_gpstime = new IntegerCompressor(dec, 32, 6); // 32 bits, 6 contexts } LASreadItemCompressed_GPSTIME11_v1::~LASreadItemCompressed_GPSTIME11_v1() { dec->destroySymbolModel(m_gpstime_multi); dec->destroySymbolModel(m_gpstime_0diff); delete ic_gpstime; } BOOL LASreadItemCompressed_GPSTIME11_v1::init(const U8* item, U32& context) { /* init state */ last_gpstime_diff = 0; multi_extreme_counter = 0; /* init models and integer compressors */ dec->initSymbolModel(m_gpstime_multi); dec->initSymbolModel(m_gpstime_0diff); ic_gpstime->initDecompressor(); /* init last item */ last_gpstime.u64 = *((U64*)item); return TRUE; } inline void LASreadItemCompressed_GPSTIME11_v1::read(U8* item, U32& context) { I32 multi; if (last_gpstime_diff == 0) // if the last integer difference was zero { multi = dec->decodeSymbol(m_gpstime_0diff); if (multi == 1) // the difference can be represented with 32 bits { last_gpstime_diff = ic_gpstime->decompress(0, 0); last_gpstime.i64 += last_gpstime_diff; } else if (multi == 2) // the difference is huge { last_gpstime.u64 = dec->readInt64(); } } else { multi = dec->decodeSymbol(m_gpstime_multi); if (multi < LASZIP_GPSTIME_MULTIMAX-2) { I32 gpstime_diff; if (multi == 1) { gpstime_diff = ic_gpstime->decompress(last_gpstime_diff, 1); last_gpstime_diff = gpstime_diff; multi_extreme_counter = 0; } else if (multi == 0) { gpstime_diff = ic_gpstime->decompress(last_gpstime_diff/4, 2); multi_extreme_counter++; if (multi_extreme_counter > 3) { last_gpstime_diff = gpstime_diff; multi_extreme_counter = 0; } } else if (multi < 10) { gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff, 3); } else if (multi < 50) { gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff, 4); } else { gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff, 5); if (multi == LASZIP_GPSTIME_MULTIMAX-3) { multi_extreme_counter++; if (multi_extreme_counter > 3) { last_gpstime_diff = gpstime_diff; multi_extreme_counter = 0; } } } last_gpstime.i64 += gpstime_diff; } else if (multi < LASZIP_GPSTIME_MULTIMAX-1) { last_gpstime.u64 = dec->readInt64(); } } *((I64*)item) = last_gpstime.i64; } /* =============================================================================== LASreadItemCompressed_RGB12_v1 =============================================================================== */ LASreadItemCompressed_RGB12_v1::LASreadItemCompressed_RGB12_v1(ArithmeticDecoder* dec) { /* set decoder */ assert(dec); this->dec = dec; /* create models and integer compressors */ m_byte_used = dec->createSymbolModel(64); ic_rgb = new IntegerCompressor(dec, 8, 6); /* create last item */ last_item = new U8[6]; } LASreadItemCompressed_RGB12_v1::~LASreadItemCompressed_RGB12_v1() { dec->destroySymbolModel(m_byte_used); delete ic_rgb; delete [] last_item; } BOOL LASreadItemCompressed_RGB12_v1::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ dec->initSymbolModel(m_byte_used); ic_rgb->initDecompressor(); /* init last item */ memcpy(last_item, item, 6); return TRUE; } inline void LASreadItemCompressed_RGB12_v1::read(U8* item, U32& context) { U32 sym = dec->decodeSymbol(m_byte_used); if (sym & (1 << 0)) ((U16*)item)[0] = (U16)ic_rgb->decompress(((U16*)last_item)[0]&255, 0); else ((U16*)item)[0] = (U16)(((U16*)last_item)[0]&0xFF); if (sym & (1 << 1)) ((U16*)item)[0] |= (((U16)ic_rgb->decompress(((U16*)last_item)[0]>>8, 1)) << 8); else ((U16*)item)[0] |= (((U16*)last_item)[0]&0xFF00); if (sym & (1 << 2)) ((U16*)item)[1] = (U16)ic_rgb->decompress(((U16*)last_item)[1]&255, 2); else ((U16*)item)[1] = (U16)(((U16*)last_item)[1]&0xFF); if (sym & (1 << 3)) ((U16*)item)[1] |= (((U16)ic_rgb->decompress(((U16*)last_item)[1]>>8, 3)) << 8); else ((U16*)item)[1] |= (((U16*)last_item)[1]&0xFF00); if (sym & (1 << 4)) ((U16*)item)[2] = (U16)ic_rgb->decompress(((U16*)last_item)[2]&255, 4); else ((U16*)item)[2] = (U16)(((U16*)last_item)[2]&0xFF); if (sym & (1 << 5)) ((U16*)item)[2] |= (((U16)ic_rgb->decompress(((U16*)last_item)[2]>>8, 5)) << 8); else ((U16*)item)[2] |= (((U16*)last_item)[2]&0xFF00); memcpy(last_item, item, 6); } /* =============================================================================== LASreadItemCompressed_WAVEPACKET13_v1 =============================================================================== */ LASreadItemCompressed_WAVEPACKET13_v1::LASreadItemCompressed_WAVEPACKET13_v1(ArithmeticDecoder* dec) { /* set decoder */ assert(dec); this->dec = dec; /* create models and integer compressors */ m_packet_index = dec->createSymbolModel(256); m_offset_diff[0] = dec->createSymbolModel(4); m_offset_diff[1] = dec->createSymbolModel(4); m_offset_diff[2] = dec->createSymbolModel(4); m_offset_diff[3] = dec->createSymbolModel(4); ic_offset_diff = new IntegerCompressor(dec, 32); ic_packet_size = new IntegerCompressor(dec, 32); ic_return_point = new IntegerCompressor(dec, 32); ic_xyz = new IntegerCompressor(dec, 32, 3); /* create last item */ last_item = new U8[28]; } LASreadItemCompressed_WAVEPACKET13_v1::~LASreadItemCompressed_WAVEPACKET13_v1() { dec->destroySymbolModel(m_packet_index); dec->destroySymbolModel(m_offset_diff[0]); dec->destroySymbolModel(m_offset_diff[1]); dec->destroySymbolModel(m_offset_diff[2]); dec->destroySymbolModel(m_offset_diff[3]); delete ic_offset_diff; delete ic_packet_size; delete ic_return_point; delete ic_xyz; delete [] last_item; } BOOL LASreadItemCompressed_WAVEPACKET13_v1::init(const U8* item, U32& context) { /* init state */ last_diff_32 = 0; sym_last_offset_diff = 0; /* init models and integer compressors */ dec->initSymbolModel(m_packet_index); dec->initSymbolModel(m_offset_diff[0]); dec->initSymbolModel(m_offset_diff[1]); dec->initSymbolModel(m_offset_diff[2]); dec->initSymbolModel(m_offset_diff[3]); ic_offset_diff->initDecompressor(); ic_packet_size->initDecompressor(); ic_return_point->initDecompressor(); ic_xyz->initDecompressor(); /* init last item */ item++; memcpy(last_item, item, 28); return TRUE; } inline void LASreadItemCompressed_WAVEPACKET13_v1::read(U8* item, U32& context) { item[0] = (U8)(dec->decodeSymbol(m_packet_index)); item++; LASwavepacket13 this_item_m; LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item); sym_last_offset_diff = dec->decodeSymbol(m_offset_diff[sym_last_offset_diff]); if (sym_last_offset_diff == 0) { this_item_m.offset = last_item_m.offset; } else if (sym_last_offset_diff == 1) { this_item_m.offset = last_item_m.offset + last_item_m.packet_size; } else if (sym_last_offset_diff == 2) { last_diff_32 = ic_offset_diff->decompress(last_diff_32); this_item_m.offset = last_item_m.offset + last_diff_32; } else { this_item_m.offset = dec->readInt64(); } this_item_m.packet_size = ic_packet_size->decompress(last_item_m.packet_size); this_item_m.return_point.i32 = ic_return_point->decompress(last_item_m.return_point.i32); this_item_m.x.i32 = ic_xyz->decompress(last_item_m.x.i32, 0); this_item_m.y.i32 = ic_xyz->decompress(last_item_m.y.i32, 1); this_item_m.z.i32 = ic_xyz->decompress(last_item_m.z.i32, 2); this_item_m.pack(item); memcpy(last_item, item, 28); } /* =============================================================================== LASreadItemCompressed_BYTE_v1 =============================================================================== */ LASreadItemCompressed_BYTE_v1::LASreadItemCompressed_BYTE_v1(ArithmeticDecoder* dec, U32 number) { /* set decoder */ assert(dec); this->dec = dec; assert(number); this->number = number; /* create models and integer compressors */ ic_byte = new IntegerCompressor(dec, 8, number); /* create last item */ last_item = new U8[number]; } LASreadItemCompressed_BYTE_v1::~LASreadItemCompressed_BYTE_v1() { delete ic_byte; delete [] last_item; } BOOL LASreadItemCompressed_BYTE_v1::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ ic_byte->initDecompressor(); /* init last item */ memcpy(last_item, item, number); return TRUE; } inline void LASreadItemCompressed_BYTE_v1::read(U8* item, U32& context) { U32 i; for (i = 0; i < number; i++) { item[i] = (U8)(ic_byte->decompress(last_item[i], i)); } memcpy(last_item, item, number); } // vim: set ts=2 sw=2 expandtabs LASzip-3.4.3/src/lasreaditemcompressed_v1.hpp000066400000000000000000000103271356234217100211570ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v1.hpp CONTENTS: Implementation of LASitemReadCompressed for *all* items (version 1). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 10 January 2011 -- licensing change for LGPL release and liblas integration 7 December 2010 -- refactored after getting invited to KAUST in Saudi Arabia =============================================================================== */ #ifndef LAS_READ_ITEM_COMPRESSED_V1_HPP #define LAS_READ_ITEM_COMPRESSED_V1_HPP #include "lasreaditem.hpp" #include "arithmeticdecoder.hpp" #include "integercompressor.hpp" class LASreadItemCompressed_POINT10_v1 : public LASreadItemCompressed { public: LASreadItemCompressed_POINT10_v1(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_POINT10_v1(); private: ArithmeticDecoder* dec; U8 last_item[20]; I32 last_x_diff[3]; I32 last_y_diff[3]; I32 last_incr; IntegerCompressor* ic_dx; IntegerCompressor* ic_dy; IntegerCompressor* ic_z; IntegerCompressor* ic_intensity; IntegerCompressor* ic_scan_angle_rank; IntegerCompressor* ic_point_source_ID; ArithmeticModel* m_changed_values; ArithmeticModel* m_bit_byte[256]; ArithmeticModel* m_classification[256]; ArithmeticModel* m_user_data[256]; }; class LASreadItemCompressed_GPSTIME11_v1 : public LASreadItemCompressed { public: LASreadItemCompressed_GPSTIME11_v1(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_GPSTIME11_v1(); private: ArithmeticDecoder* dec; U64I64F64 last_gpstime; ArithmeticModel* m_gpstime_multi; ArithmeticModel* m_gpstime_0diff; IntegerCompressor* ic_gpstime; I32 multi_extreme_counter; I32 last_gpstime_diff; }; class LASreadItemCompressed_RGB12_v1 : public LASreadItemCompressed { public: LASreadItemCompressed_RGB12_v1(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_RGB12_v1(); private: ArithmeticDecoder* dec; U8* last_item; ArithmeticModel* m_byte_used; IntegerCompressor* ic_rgb; }; class LASreadItemCompressed_WAVEPACKET13_v1 : public LASreadItemCompressed { public: LASreadItemCompressed_WAVEPACKET13_v1(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_WAVEPACKET13_v1(); private: ArithmeticDecoder* dec; U8* last_item; I32 last_diff_32; U32 sym_last_offset_diff; ArithmeticModel* m_packet_index; ArithmeticModel* m_offset_diff[4]; IntegerCompressor* ic_offset_diff; IntegerCompressor* ic_packet_size; IntegerCompressor* ic_return_point; IntegerCompressor* ic_xyz; }; class LASreadItemCompressed_BYTE_v1 : public LASreadItemCompressed { public: LASreadItemCompressed_BYTE_v1(ArithmeticDecoder* dec, U32 number); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_BYTE_v1(); private: ArithmeticDecoder* dec; U32 number; U8* last_item; IntegerCompressor* ic_byte; }; #endif LASzip-3.4.3/src/lasreaditemcompressed_v2.cpp000066400000000000000000000423211356234217100211520ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v2.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasreaditemcompressed_v2.hpp" #include #include struct LASpoint10 { I32 x; I32 y; I32 z; U16 intensity; U8 return_number : 3; U8 number_of_returns_of_given_pulse : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; }; LASreadItemCompressed_POINT10_v2::LASreadItemCompressed_POINT10_v2(ArithmeticDecoder* dec) { U32 i; /* set decoder */ assert(dec); this->dec = dec; /* create models and integer compressors */ m_changed_values = dec->createSymbolModel(64); ic_intensity = new IntegerCompressor(dec, 16, 4); m_scan_angle_rank[0] = dec->createSymbolModel(256); m_scan_angle_rank[1] = dec->createSymbolModel(256); ic_point_source_ID = new IntegerCompressor(dec, 16); for (i = 0; i < 256; i++) { m_bit_byte[i] = 0; m_classification[i] = 0; m_user_data[i] = 0; } ic_dx = new IntegerCompressor(dec, 32, 2); // 32 bits, 2 context ic_dy = new IntegerCompressor(dec, 32, 22); // 32 bits, 22 contexts ic_z = new IntegerCompressor(dec, 32, 20); // 32 bits, 20 contexts } LASreadItemCompressed_POINT10_v2::~LASreadItemCompressed_POINT10_v2() { U32 i; dec->destroySymbolModel(m_changed_values); delete ic_intensity; dec->destroySymbolModel(m_scan_angle_rank[0]); dec->destroySymbolModel(m_scan_angle_rank[1]); delete ic_point_source_ID; for (i = 0; i < 256; i++) { if (m_bit_byte[i]) dec->destroySymbolModel(m_bit_byte[i]); if (m_classification[i]) dec->destroySymbolModel(m_classification[i]); if (m_user_data[i]) dec->destroySymbolModel(m_user_data[i]); } delete ic_dx; delete ic_dy; delete ic_z; } BOOL LASreadItemCompressed_POINT10_v2::init(const U8* item, U32& context) { U32 i; /* init state */ for (i=0; i < 16; i++) { last_x_diff_median5[i].init(); last_y_diff_median5[i].init(); last_intensity[i] = 0; last_height[i/2] = 0; } /* init models and integer compressors */ dec->initSymbolModel(m_changed_values); ic_intensity->initDecompressor(); dec->initSymbolModel(m_scan_angle_rank[0]); dec->initSymbolModel(m_scan_angle_rank[1]); ic_point_source_ID->initDecompressor(); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) dec->initSymbolModel(m_bit_byte[i]); if (m_classification[i]) dec->initSymbolModel(m_classification[i]); if (m_user_data[i]) dec->initSymbolModel(m_user_data[i]); } ic_dx->initDecompressor(); ic_dy->initDecompressor(); ic_z->initDecompressor(); /* init last item */ memcpy(last_item, item, 20); /* but set intensity to zero */ last_item[12] = 0; last_item[13] = 0; return TRUE; } inline void LASreadItemCompressed_POINT10_v2::read(U8* item, U32& context) { U32 r, n, m, l; U32 k_bits; I32 median, diff; // decompress which other values have changed I32 changed_values = dec->decodeSymbol(m_changed_values); if (changed_values) { // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed if (changed_values & 32) { if (m_bit_byte[last_item[14]] == 0) { m_bit_byte[last_item[14]] = dec->createSymbolModel(256); dec->initSymbolModel(m_bit_byte[last_item[14]]); } last_item[14] = (U8)dec->decodeSymbol(m_bit_byte[last_item[14]]); } r = ((LASpoint10*)last_item)->return_number; n = ((LASpoint10*)last_item)->number_of_returns_of_given_pulse; m = number_return_map[n][r]; l = number_return_level[n][r]; // decompress the intensity if it has changed if (changed_values & 16) { ((LASpoint10*)last_item)->intensity = (U16)ic_intensity->decompress(last_intensity[m], (m < 3 ? m : 3)); last_intensity[m] = ((LASpoint10*)last_item)->intensity; } else { ((LASpoint10*)last_item)->intensity = last_intensity[m]; } // decompress the classification ... if it has changed if (changed_values & 8) { if (m_classification[last_item[15]] == 0) { m_classification[last_item[15]] = dec->createSymbolModel(256); dec->initSymbolModel(m_classification[last_item[15]]); } last_item[15] = (U8)dec->decodeSymbol(m_classification[last_item[15]]); } // decompress the scan_angle_rank ... if it has changed if (changed_values & 4) { I32 val = dec->decodeSymbol(m_scan_angle_rank[((LASpoint10*)last_item)->scan_direction_flag]); last_item[16] = U8_FOLD(val + last_item[16]); } // decompress the user_data ... if it has changed if (changed_values & 2) { if (m_user_data[last_item[17]] == 0) { m_user_data[last_item[17]] = dec->createSymbolModel(256); dec->initSymbolModel(m_user_data[last_item[17]]); } last_item[17] = (U8)dec->decodeSymbol(m_user_data[last_item[17]]); } // decompress the point_source_ID ... if it has changed if (changed_values & 1) { ((LASpoint10*)last_item)->point_source_ID = (U16)ic_point_source_ID->decompress(((LASpoint10*)last_item)->point_source_ID); } } else { r = ((LASpoint10*)last_item)->return_number; n = ((LASpoint10*)last_item)->number_of_returns_of_given_pulse; m = number_return_map[n][r]; l = number_return_level[n][r]; } // decompress x coordinate median = last_x_diff_median5[m].get(); diff = ic_dx->decompress(median, n==1); ((LASpoint10*)last_item)->x += diff; last_x_diff_median5[m].add(diff); // decompress y coordinate median = last_y_diff_median5[m].get(); k_bits = ic_dx->getK(); diff = ic_dy->decompress(median, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); ((LASpoint10*)last_item)->y += diff; last_y_diff_median5[m].add(diff); // decompress z coordinate k_bits = (ic_dx->getK() + ic_dy->getK()) / 2; ((LASpoint10*)last_item)->z = ic_z->decompress(last_height[l], (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); last_height[l] = ((LASpoint10*)last_item)->z; // copy the last point memcpy(item, last_item, 20); } /* =============================================================================== LASreadItemCompressed_GPSTIME11_v2 =============================================================================== */ #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_UNCHANGED (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 2) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 6) LASreadItemCompressed_GPSTIME11_v2::LASreadItemCompressed_GPSTIME11_v2(ArithmeticDecoder* dec) { /* set decoder */ assert(dec); this->dec = dec; /* create entropy models and integer compressors */ m_gpstime_multi = dec->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); m_gpstime_0diff = dec->createSymbolModel(6); ic_gpstime = new IntegerCompressor(dec, 32, 9); // 32 bits, 9 contexts } LASreadItemCompressed_GPSTIME11_v2::~LASreadItemCompressed_GPSTIME11_v2() { dec->destroySymbolModel(m_gpstime_multi); dec->destroySymbolModel(m_gpstime_0diff); delete ic_gpstime; } BOOL LASreadItemCompressed_GPSTIME11_v2::init(const U8* item, U32& context) { /* init state */ last = 0, next = 0; last_gpstime_diff[0] = 0; last_gpstime_diff[1] = 0; last_gpstime_diff[2] = 0; last_gpstime_diff[3] = 0; multi_extreme_counter[0] = 0; multi_extreme_counter[1] = 0; multi_extreme_counter[2] = 0; multi_extreme_counter[3] = 0; /* init models and integer compressors */ dec->initSymbolModel(m_gpstime_multi); dec->initSymbolModel(m_gpstime_0diff); ic_gpstime->initDecompressor(); /* init last item */ last_gpstime[0].u64 = *((U64*)item); last_gpstime[1].u64 = 0; last_gpstime[2].u64 = 0; last_gpstime[3].u64 = 0; return TRUE; } inline void LASreadItemCompressed_GPSTIME11_v2::read(U8* item, U32& context) { I32 multi; if (last_gpstime_diff[last] == 0) // if the last integer difference was zero { multi = dec->decodeSymbol(m_gpstime_0diff); if (multi == 1) // the difference can be represented with 32 bits { last_gpstime_diff[last] = ic_gpstime->decompress(0, 0); last_gpstime[last].i64 += last_gpstime_diff[last]; multi_extreme_counter[last] = 0; } else if (multi == 2) // the difference is huge { next = (next+1)&3; last_gpstime[next].u64 = ic_gpstime->decompress((I32)(last_gpstime[last].u64 >> 32), 8); last_gpstime[next].u64 = last_gpstime[next].u64 << 32; last_gpstime[next].u64 |= dec->readInt(); last = next; last_gpstime_diff[last] = 0; multi_extreme_counter[last] = 0; } else if (multi > 2) // we switch to another sequence { last = (last+multi-2)&3; read(item, context); } } else { multi = dec->decodeSymbol(m_gpstime_multi); if (multi == 1) { last_gpstime[last].i64 += ic_gpstime->decompress(last_gpstime_diff[last], 1);; multi_extreme_counter[last] = 0; } else if (multi < LASZIP_GPSTIME_MULTI_UNCHANGED) { I32 gpstime_diff; if (multi == 0) { gpstime_diff = ic_gpstime->decompress(0, 7); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = gpstime_diff; multi_extreme_counter[last] = 0; } } else if (multi < LASZIP_GPSTIME_MULTI) { if (multi < 10) gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff[last], 2); else gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff[last], 3); } else if (multi == LASZIP_GPSTIME_MULTI) { gpstime_diff = ic_gpstime->decompress(LASZIP_GPSTIME_MULTI*last_gpstime_diff[last], 4); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = gpstime_diff; multi_extreme_counter[last] = 0; } } else { multi = LASZIP_GPSTIME_MULTI - multi; if (multi > LASZIP_GPSTIME_MULTI_MINUS) { gpstime_diff = ic_gpstime->decompress(multi*last_gpstime_diff[last], 5); } else { gpstime_diff = ic_gpstime->decompress(LASZIP_GPSTIME_MULTI_MINUS*last_gpstime_diff[last], 6); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = gpstime_diff; multi_extreme_counter[last] = 0; } } } last_gpstime[last].i64 += gpstime_diff; } else if (multi == LASZIP_GPSTIME_MULTI_CODE_FULL) { next = (next+1)&3; last_gpstime[next].u64 = ic_gpstime->decompress((I32)(last_gpstime[last].u64 >> 32), 8); last_gpstime[next].u64 = last_gpstime[next].u64 << 32; last_gpstime[next].u64 |= dec->readInt(); last = next; last_gpstime_diff[last] = 0; multi_extreme_counter[last] = 0; } else if (multi >= LASZIP_GPSTIME_MULTI_CODE_FULL) { last = (last+multi-LASZIP_GPSTIME_MULTI_CODE_FULL)&3; read(item, context); } } *((I64*)item) = last_gpstime[last].i64; } /* =============================================================================== LASreadItemCompressed_RGB12_v2 =============================================================================== */ LASreadItemCompressed_RGB12_v2::LASreadItemCompressed_RGB12_v2(ArithmeticDecoder* dec) { /* set decoder */ assert(dec); this->dec = dec; /* create models and integer compressors */ m_byte_used = dec->createSymbolModel(128); m_rgb_diff_0 = dec->createSymbolModel(256); m_rgb_diff_1 = dec->createSymbolModel(256); m_rgb_diff_2 = dec->createSymbolModel(256); m_rgb_diff_3 = dec->createSymbolModel(256); m_rgb_diff_4 = dec->createSymbolModel(256); m_rgb_diff_5 = dec->createSymbolModel(256); } LASreadItemCompressed_RGB12_v2::~LASreadItemCompressed_RGB12_v2() { dec->destroySymbolModel(m_byte_used); dec->destroySymbolModel(m_rgb_diff_0); dec->destroySymbolModel(m_rgb_diff_1); dec->destroySymbolModel(m_rgb_diff_2); dec->destroySymbolModel(m_rgb_diff_3); dec->destroySymbolModel(m_rgb_diff_4); dec->destroySymbolModel(m_rgb_diff_5); } BOOL LASreadItemCompressed_RGB12_v2::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ dec->initSymbolModel(m_byte_used); dec->initSymbolModel(m_rgb_diff_0); dec->initSymbolModel(m_rgb_diff_1); dec->initSymbolModel(m_rgb_diff_2); dec->initSymbolModel(m_rgb_diff_3); dec->initSymbolModel(m_rgb_diff_4); dec->initSymbolModel(m_rgb_diff_5); /* init last item */ memcpy(last_item, item, 6); return TRUE; } inline void LASreadItemCompressed_RGB12_v2::read(U8* item, U32& context) { U8 corr; I32 diff = 0; U32 sym = dec->decodeSymbol(m_byte_used); if (sym & (1 << 0)) { corr = dec->decodeSymbol(m_rgb_diff_0); ((U16*)item)[0] = (U16)U8_FOLD(corr + (last_item[0]&255)); } else { ((U16*)item)[0] = last_item[0]&0xFF; } if (sym & (1 << 1)) { corr = dec->decodeSymbol(m_rgb_diff_1); ((U16*)item)[0] |= (((U16)U8_FOLD(corr + (last_item[0]>>8))) << 8); } else { ((U16*)item)[0] |= (last_item[0]&0xFF00); } if (sym & (1 << 6)) { diff = (((U16*)item)[0]&0x00FF) - (last_item[0]&0x00FF); if (sym & (1 << 2)) { corr = dec->decodeSymbol(m_rgb_diff_2); ((U16*)item)[1] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]&255))); } else { ((U16*)item)[1] = last_item[1]&0xFF; } if (sym & (1 << 4)) { corr = dec->decodeSymbol(m_rgb_diff_4); diff = (diff + ((((U16*)item)[1]&0x00FF) - (last_item[1]&0x00FF))) / 2; ((U16*)item)[2] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]&255))); } else { ((U16*)item)[2] = last_item[2]&0xFF; } diff = (((U16*)item)[0]>>8) - (last_item[0]>>8); if (sym & (1 << 3)) { corr = dec->decodeSymbol(m_rgb_diff_3); ((U16*)item)[1] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]>>8))))<<8); } else { ((U16*)item)[1] |= (last_item[1]&0xFF00); } if (sym & (1 << 5)) { corr = dec->decodeSymbol(m_rgb_diff_5); diff = (diff + ((((U16*)item)[1]>>8) - (last_item[1]>>8))) / 2; ((U16*)item)[2] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]>>8))))<<8); } else { ((U16*)item)[2] |= (last_item[2]&0xFF00); } } else { ((U16*)item)[1] = ((U16*)item)[0]; ((U16*)item)[2] = ((U16*)item)[0]; } memcpy(last_item, item, 6); } /* =============================================================================== LASreadItemCompressed_BYTE_v2 =============================================================================== */ LASreadItemCompressed_BYTE_v2::LASreadItemCompressed_BYTE_v2(ArithmeticDecoder* dec, U32 number) { U32 i; /* set decoder */ assert(dec); this->dec = dec; assert(number); this->number = number; /* create models and integer compressors */ m_byte = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { m_byte[i] = dec->createSymbolModel(256); } /* create last item */ last_item = new U8[number]; } LASreadItemCompressed_BYTE_v2::~LASreadItemCompressed_BYTE_v2() { U32 i; for (i = 0; i < number; i++) { dec->destroySymbolModel(m_byte[i]); } delete [] m_byte; delete [] last_item; } BOOL LASreadItemCompressed_BYTE_v2::init(const U8* item, U32& context) { U32 i; /* init state */ /* init models and integer compressors */ for (i = 0; i < number; i++) { dec->initSymbolModel(m_byte[i]); } /* init last item */ memcpy(last_item, item, number); return TRUE; } inline void LASreadItemCompressed_BYTE_v2::read(U8* item, U32& context) { U32 i; I32 value; for (i = 0; i < number; i++) { value = last_item[i] + dec->decodeSymbol(m_byte[i]); item[i] = U8_FOLD(value); } memcpy(last_item, item, number); } LASzip-3.4.3/src/lasreaditemcompressed_v2.hpp000066400000000000000000000074441356234217100211660ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v2.hpp CONTENTS: Implementation of LASitemReadCompressed for *all* items (version 2). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 5 March 2011 -- created first night in ibiza to improve the RGB compressor =============================================================================== */ #ifndef LAS_READ_ITEM_COMPRESSED_V2_HPP #define LAS_READ_ITEM_COMPRESSED_V2_HPP #include "lasreaditem.hpp" #include "arithmeticdecoder.hpp" #include "integercompressor.hpp" #include "laszip_common_v2.hpp" class LASreadItemCompressed_POINT10_v2 : public LASreadItemCompressed { public: LASreadItemCompressed_POINT10_v2(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_POINT10_v2(); private: ArithmeticDecoder* dec; U8 last_item[20]; U16 last_intensity[16]; StreamingMedian5 last_x_diff_median5[16]; StreamingMedian5 last_y_diff_median5[16]; I32 last_height[8]; ArithmeticModel* m_changed_values; IntegerCompressor* ic_intensity; ArithmeticModel* m_scan_angle_rank[2]; IntegerCompressor* ic_point_source_ID; ArithmeticModel* m_bit_byte[256]; ArithmeticModel* m_classification[256]; ArithmeticModel* m_user_data[256]; IntegerCompressor* ic_dx; IntegerCompressor* ic_dy; IntegerCompressor* ic_z; }; class LASreadItemCompressed_GPSTIME11_v2 : public LASreadItemCompressed { public: LASreadItemCompressed_GPSTIME11_v2(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_GPSTIME11_v2(); private: ArithmeticDecoder* dec; U32 last, next; U64I64F64 last_gpstime[4]; I32 last_gpstime_diff[4]; I32 multi_extreme_counter[4]; ArithmeticModel* m_gpstime_multi; ArithmeticModel* m_gpstime_0diff; IntegerCompressor* ic_gpstime; }; class LASreadItemCompressed_RGB12_v2 : public LASreadItemCompressed { public: LASreadItemCompressed_RGB12_v2(ArithmeticDecoder* dec); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_RGB12_v2(); private: ArithmeticDecoder* dec; U16 last_item[3]; ArithmeticModel* m_byte_used; ArithmeticModel* m_rgb_diff_0; ArithmeticModel* m_rgb_diff_1; ArithmeticModel* m_rgb_diff_2; ArithmeticModel* m_rgb_diff_3; ArithmeticModel* m_rgb_diff_4; ArithmeticModel* m_rgb_diff_5; }; class LASreadItemCompressed_BYTE_v2 : public LASreadItemCompressed { public: LASreadItemCompressed_BYTE_v2(ArithmeticDecoder* dec, U32 number); BOOL init(const U8* item, U32& context); // context is unused void read(U8* item, U32& context); // context is unused ~LASreadItemCompressed_BYTE_v2(); private: ArithmeticDecoder* dec; U32 number; U8* last_item; ArithmeticModel** m_byte; }; #endif LASzip-3.4.3/src/lasreaditemcompressed_v3.cpp000066400000000000000000002170371356234217100211630ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v3.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasreaditemcompressed_v3.hpp" #include #include typedef struct LASpoint14 { I32 X; I32 Y; I32 Z; U16 intensity; U8 legacy_return_number : 3; U8 legacy_number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 legacy_classification : 5; U8 legacy_flags : 3; I8 legacy_scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 scan_angle; U8 legacy_point_type : 2; U8 scanner_channel : 2; U8 classification_flags : 4; U8 classification; U8 return_number : 4; U8 number_of_returns : 4; // LASlib internal use only U8 deleted_flag; // for 8 byte alignment of the GPS time U8 dummy[2]; // compressed LASzip 1.4 points only BOOL gps_time_change; F64 gps_time; U16 rgb[4]; // LASwavepacket wavepacket; } LASpoint14; #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 5) LASreadItemCompressed_POINT14_v3::LASreadItemCompressed_POINT14_v3(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_channel_returns_XY = 0; instream_Z = 0; instream_classification = 0; instream_flags = 0; instream_intensity = 0; instream_scan_angle = 0; instream_user_data = 0; instream_point_source = 0; instream_gps_time = 0; dec_channel_returns_XY = 0; dec_Z = 0; dec_classification = 0; dec_flags = 0; dec_intensity = 0; dec_scan_angle = 0; dec_user_data = 0; dec_point_source = 0; dec_gps_time = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_changed_values[0] = 0; } current_context = 0; /* zero num_bytes and init booleans */ num_bytes_channel_returns_XY = 0; num_bytes_Z = 0; num_bytes_classification = 0; num_bytes_flags = 0; num_bytes_intensity = 0; num_bytes_scan_angle = 0; num_bytes_user_data = 0; num_bytes_point_source = 0; num_bytes_gps_time = 0; changed_Z = FALSE; changed_classification = FALSE; changed_flags = FALSE; changed_intensity = FALSE; changed_scan_angle = FALSE; changed_user_data = FALSE; changed_point_source = FALSE; changed_gps_time = FALSE; requested_Z = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_Z ? TRUE : FALSE); requested_classification = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION ? TRUE : FALSE); requested_flags = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_FLAGS ? TRUE : FALSE); requested_intensity = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_INTENSITY ? TRUE : FALSE); requested_scan_angle = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE ? TRUE : FALSE); requested_user_data = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_USER_DATA ? TRUE : FALSE); requested_point_source = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE ? TRUE : FALSE); requested_gps_time = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_GPS_TIME ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; } LASreadItemCompressed_POINT14_v3::~LASreadItemCompressed_POINT14_v3() { U32 c, i; /* destroy all initialized scanner channel contexts */ for (c = 0; c < 4; c++) { if (contexts[c].m_changed_values[0]) { dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[0]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[1]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[2]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[3]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[4]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[5]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[6]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[7]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[c].m_number_of_returns[i]) dec_channel_returns_XY->destroySymbolModel(contexts[c].m_number_of_returns[i]); if (contexts[c].m_return_number[i]) dec_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number[i]); } dec_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number_gps_same); delete contexts[c].ic_dX; delete contexts[c].ic_dY; delete contexts[c].ic_Z; for (i = 0; i < 64; i++) { if (contexts[c].m_classification[i]) dec_classification->destroySymbolModel(contexts[c].m_classification[i]); if (contexts[c].m_flags[i]) dec_flags->destroySymbolModel(contexts[c].m_flags[i]); if (contexts[c].m_user_data[i]) dec_user_data->destroySymbolModel(contexts[c].m_user_data[i]); } delete contexts[c].ic_intensity; delete contexts[c].ic_scan_angle; delete contexts[c].ic_point_source_ID; dec_gps_time->destroySymbolModel(contexts[c].m_gpstime_multi); dec_gps_time->destroySymbolModel(contexts[c].m_gpstime_0diff); delete contexts[c].ic_gpstime; } } /* destroy all decoders and instreams */ if (instream_channel_returns_XY) { delete dec_channel_returns_XY; delete dec_Z; delete dec_classification; delete dec_flags; delete dec_intensity; delete dec_scan_angle; delete dec_user_data; delete dec_gps_time; delete instream_channel_returns_XY; delete instream_Z; delete instream_classification; delete instream_flags; delete instream_intensity; delete instream_scan_angle; delete instream_user_data; delete instream_gps_time; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_POINT14_v3::createAndInitModelsAndDecompressors(U32 context, const U8* item) { I32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and integer decompressors (if needed) */ if (contexts[context].m_changed_values[0] == 0) { /* for the channel_returns_XY layer */ contexts[context].m_changed_values[0] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[1] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[2] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[3] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[4] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[5] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[6] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[7] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_scanner_channel = dec_channel_returns_XY->createSymbolModel(3); for (i = 0; i < 16; i++) { contexts[context].m_number_of_returns[i] = 0; contexts[context].m_return_number[i] = 0; } contexts[context].m_return_number_gps_same = dec_channel_returns_XY->createSymbolModel(13); contexts[context].ic_dX = new IntegerCompressor(dec_channel_returns_XY, 32, 2); // 32 bits, 2 context contexts[context].ic_dY = new IntegerCompressor(dec_channel_returns_XY, 32, 22); // 32 bits, 22 contexts /* for the Z layer */ contexts[context].ic_Z = new IntegerCompressor(dec_Z, 32, 20); // 32 bits, 20 contexts /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { contexts[context].m_classification[i] = 0; contexts[context].m_flags[i] = 0; contexts[context].m_user_data[i] = 0; } /* for the intensity layer */ contexts[context].ic_intensity = new IntegerCompressor(dec_intensity, 16, 4); /* for the scan_angle layer */ contexts[context].ic_scan_angle = new IntegerCompressor(dec_scan_angle, 16, 2); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID = new IntegerCompressor(dec_point_source, 16); /* for the gps_time layer */ contexts[context].m_gpstime_multi = dec_gps_time->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); contexts[context].m_gpstime_0diff = dec_gps_time->createSymbolModel(5); contexts[context].ic_gpstime = new IntegerCompressor(dec_gps_time, 32, 9); // 32 bits, 9 contexts } /* then init entropy models and integer compressors */ /* for the channel_returns_XY layer */ dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[0]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[1]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[2]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[3]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[4]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[5]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[6]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[7]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[context].m_number_of_returns[i]) dec_channel_returns_XY->initSymbolModel(contexts[context].m_number_of_returns[i]); if (contexts[context].m_return_number[i]) dec_channel_returns_XY->initSymbolModel(contexts[context].m_return_number[i]); } dec_channel_returns_XY->initSymbolModel(contexts[context].m_return_number_gps_same); contexts[context].ic_dX->initDecompressor(); contexts[context].ic_dY->initDecompressor(); for (i = 0; i < 12; i++) { contexts[context].last_X_diff_median5[i].init(); contexts[context].last_Y_diff_median5[i].init(); } /* for the Z layer */ contexts[context].ic_Z->initDecompressor(); for (i = 0; i < 8; i++) { contexts[context].last_Z[i] = ((LASpoint14*)item)->Z; } /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { if (contexts[context].m_classification[i]) dec_classification->initSymbolModel(contexts[context].m_classification[i]); if (contexts[context].m_flags[i]) dec_flags->initSymbolModel(contexts[context].m_flags[i]); if (contexts[context].m_user_data[i]) dec_user_data->initSymbolModel(contexts[context].m_user_data[i]); } /* for the intensity layer */ contexts[context].ic_intensity->initDecompressor(); for (i = 0; i < 8; i++) { contexts[context].last_intensity[i] = ((LASpoint14*)item)->intensity; } /* for the scan_angle layer */ contexts[context].ic_scan_angle->initDecompressor(); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID->initDecompressor(); /* for the gps_time layer */ dec_gps_time->initSymbolModel(contexts[context].m_gpstime_multi); dec_gps_time->initSymbolModel(contexts[context].m_gpstime_0diff); contexts[context].ic_gpstime->initDecompressor(); contexts[context].last = 0, contexts[context].next = 0; contexts[context].last_gpstime_diff[0] = 0; contexts[context].last_gpstime_diff[1] = 0; contexts[context].last_gpstime_diff[2] = 0; contexts[context].last_gpstime_diff[3] = 0; contexts[context].multi_extreme_counter[0] = 0; contexts[context].multi_extreme_counter[1] = 0; contexts[context].multi_extreme_counter[2] = 0; contexts[context].multi_extreme_counter[3] = 0; contexts[context].last_gpstime[0].f64 = ((LASpoint14*)item)->gps_time; contexts[context].last_gpstime[1].u64 = 0; contexts[context].last_gpstime[2].u64 = 0; contexts[context].last_gpstime[3].u64 = 0; /* init current context from last item */ memcpy(contexts[context].last_item, item, sizeof(LASpoint14)); ((LASpoint14*)contexts[context].last_item)->gps_time_change = FALSE; // fprintf(stderr, "INIT: current_context %d last item %.14g %d %d %d %d %d %d\n", current_context, ((LASpoint14*)item)->gps_time, ((LASpoint14*)item)->X, ((LASpoint14*)item)->Y, ((LASpoint14*)item)->Z, ((LASpoint14*)item)->intensity, ((LASpoint14*)item)->return_number, ((LASpoint14*)item)->number_of_returns); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_POINT14_v3::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_channel_returns_XY)); instream->get32bitsLE(((U8*)&num_bytes_Z)); instream->get32bitsLE(((U8*)&num_bytes_classification)); instream->get32bitsLE(((U8*)&num_bytes_flags)); instream->get32bitsLE(((U8*)&num_bytes_intensity)); instream->get32bitsLE(((U8*)&num_bytes_scan_angle)); instream->get32bitsLE(((U8*)&num_bytes_user_data)); instream->get32bitsLE(((U8*)&num_bytes_point_source)); instream->get32bitsLE(((U8*)&num_bytes_gps_time)); return TRUE; } BOOL LASreadItemCompressed_POINT14_v3::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_channel_returns_XY == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_channel_returns_XY = new ByteStreamInArrayLE(); instream_Z = new ByteStreamInArrayLE(); instream_classification = new ByteStreamInArrayLE(); instream_flags = new ByteStreamInArrayLE(); instream_intensity = new ByteStreamInArrayLE(); instream_scan_angle = new ByteStreamInArrayLE(); instream_user_data = new ByteStreamInArrayLE(); instream_point_source = new ByteStreamInArrayLE(); instream_gps_time = new ByteStreamInArrayLE(); } else { instream_channel_returns_XY = new ByteStreamInArrayBE(); instream_Z = new ByteStreamInArrayBE(); instream_classification = new ByteStreamInArrayBE(); instream_flags = new ByteStreamInArrayBE(); instream_intensity = new ByteStreamInArrayBE(); instream_scan_angle = new ByteStreamInArrayBE(); instream_user_data = new ByteStreamInArrayBE(); instream_point_source = new ByteStreamInArrayBE(); instream_gps_time = new ByteStreamInArrayBE(); } /* create decoders */ dec_channel_returns_XY = new ArithmeticDecoder(); dec_Z = new ArithmeticDecoder(); dec_classification = new ArithmeticDecoder(); dec_flags = new ArithmeticDecoder(); dec_intensity = new ArithmeticDecoder(); dec_scan_angle = new ArithmeticDecoder(); dec_user_data = new ArithmeticDecoder(); dec_point_source = new ArithmeticDecoder(); dec_gps_time = new ArithmeticDecoder(); } /* how many bytes do we need to read */ U32 num_bytes = num_bytes_channel_returns_XY; if (requested_Z) num_bytes += num_bytes_Z; if (requested_classification) num_bytes += num_bytes_classification; if (requested_flags) num_bytes += num_bytes_flags; if (requested_intensity) num_bytes += num_bytes_intensity; if (requested_scan_angle) num_bytes += num_bytes_scan_angle; if (requested_user_data) num_bytes += num_bytes_user_data; if (requested_point_source) num_bytes += num_bytes_point_source; if (requested_gps_time) num_bytes += num_bytes_gps_time; /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams and decoders */ num_bytes = 0; instream->getBytes(bytes, num_bytes_channel_returns_XY); instream_channel_returns_XY->init(bytes, num_bytes_channel_returns_XY); dec_channel_returns_XY->init(instream_channel_returns_XY); num_bytes += num_bytes_channel_returns_XY; if (requested_Z) { if (num_bytes_Z) { instream->getBytes(&(bytes[num_bytes]), num_bytes_Z); instream_Z->init(&(bytes[num_bytes]), num_bytes_Z); dec_Z->init(instream_Z); num_bytes += num_bytes_Z; changed_Z = TRUE; } else { instream_Z->init(0, 0); changed_Z = FALSE; } } else { if (num_bytes_Z) { instream->skipBytes(num_bytes_Z); } changed_Z = FALSE; } if (requested_classification) { if (num_bytes_classification) { instream->getBytes(&(bytes[num_bytes]), num_bytes_classification); instream_classification->init(&(bytes[num_bytes]), num_bytes_classification); dec_classification->init(instream_classification); num_bytes += num_bytes_classification; changed_classification = TRUE; } else { instream_classification->init(0, 0); changed_classification = FALSE; } } else { if (num_bytes_classification) { instream->skipBytes(num_bytes_classification); } changed_classification = FALSE; } if (requested_flags) { if (num_bytes_flags) { instream->getBytes(&(bytes[num_bytes]), num_bytes_flags); instream_flags->init(&(bytes[num_bytes]), num_bytes_flags); dec_flags->init(instream_flags); num_bytes += num_bytes_flags; changed_flags = TRUE; } else { instream_flags->init(0, 0); changed_flags = FALSE; } } else { if (num_bytes_flags) { instream->skipBytes(num_bytes_flags); } changed_flags = FALSE; } if (requested_intensity) { if (num_bytes_intensity) { instream->getBytes(&(bytes[num_bytes]), num_bytes_intensity); instream_intensity->init(&(bytes[num_bytes]), num_bytes_intensity); dec_intensity->init(instream_intensity); num_bytes += num_bytes_intensity; changed_intensity = TRUE; } else { instream_intensity->init(0, 0); changed_intensity = FALSE; } } else { if (num_bytes_intensity) { instream->skipBytes(num_bytes_intensity); } changed_intensity = FALSE; } if (requested_scan_angle) { if (num_bytes_scan_angle) { instream->getBytes(&(bytes[num_bytes]), num_bytes_scan_angle); instream_scan_angle->init(&(bytes[num_bytes]), num_bytes_scan_angle); dec_scan_angle->init(instream_scan_angle); num_bytes += num_bytes_scan_angle; changed_scan_angle = TRUE; } else { instream_scan_angle->init(0, 0); changed_scan_angle = FALSE; } } else { if (num_bytes_scan_angle) { instream->skipBytes(num_bytes_scan_angle); } changed_scan_angle = FALSE; } if (requested_user_data) { if (num_bytes_user_data) { instream->getBytes(&(bytes[num_bytes]), num_bytes_user_data); instream_user_data->init(&(bytes[num_bytes]), num_bytes_user_data); dec_user_data->init(instream_user_data); num_bytes += num_bytes_user_data; changed_user_data = TRUE; } else { instream_user_data->init(0, 0); changed_user_data = FALSE; } } else { if (num_bytes_user_data) { instream->skipBytes(num_bytes_user_data); } changed_user_data = FALSE; } if (requested_point_source) { if (num_bytes_point_source) { instream->getBytes(&(bytes[num_bytes]), num_bytes_point_source); instream_point_source->init(&(bytes[num_bytes]), num_bytes_point_source); dec_point_source->init(instream_point_source); num_bytes += num_bytes_point_source; changed_point_source = TRUE; } else { instream_point_source->init(0, 0); changed_point_source = FALSE; } } else { if (num_bytes_point_source) { instream->skipBytes(num_bytes_point_source); } changed_point_source = FALSE; } if (requested_gps_time) { if (num_bytes_gps_time) { instream->getBytes(&(bytes[num_bytes]), num_bytes_gps_time); instream_gps_time->init(&(bytes[num_bytes]), num_bytes_gps_time); dec_gps_time->init(instream_gps_time); num_bytes += num_bytes_gps_time; changed_gps_time = TRUE; } else { instream_gps_time->init(0, 0); changed_gps_time = FALSE; } } else { if (num_bytes_gps_time) { instream->skipBytes(num_bytes_gps_time); } changed_gps_time = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = ((LASpoint14*)item)->scanner_channel; context = current_context; // the POINT14 reader sets context for all other items /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_POINT14_v3::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; //////////////////////////////////////// // decompress returns_XY layer //////////////////////////////////////// // create single (3) / first (1) / last (2) / intermediate (0) context from last point return I32 lpr = (((LASpoint14*)last_item)->return_number == 1 ? 1 : 0); // first? lpr += (((LASpoint14*)last_item)->return_number >= ((LASpoint14*)last_item)->number_of_returns ? 2 : 0); // last? // add info whether the GPS time changed in the last return to the context lpr += (((LASpoint14*)last_item)->gps_time_change ? 4 : 0); // decompress which values have changed with last point return context I32 changed_values = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_changed_values[lpr]); // if scanner channel has changed if (changed_values & (1 << 6)) { U32 diff = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_scanner_channel); // curr = last + (sym + 1) U32 scanner_channel = (current_context + diff + 1) % 4; // maybe create and init entropy models and integer compressors if (contexts[scanner_channel].unused) { // create and init entropy models and integer decompressors createAndInitModelsAndDecompressors(scanner_channel, contexts[current_context].last_item); } // switch context to current scanner channel current_context = scanner_channel; context = current_context; // the POINT14 reader sets context for all other items // get last for new context last_item = contexts[current_context].last_item; ((LASpoint14*)last_item)->scanner_channel = scanner_channel; } // determine changed attributes BOOL point_source_change = (changed_values & (1 << 5) ? TRUE : FALSE); BOOL gps_time_change = (changed_values & (1 << 4) ? TRUE : FALSE); BOOL scan_angle_change = (changed_values & (1 << 3) ? TRUE : FALSE); // get last return counts U32 last_n = ((LASpoint14*)last_item)->number_of_returns; U32 last_r = ((LASpoint14*)last_item)->return_number; // if number of returns is different we decompress it U32 n; if (changed_values & (1 << 2)) { if (contexts[current_context].m_number_of_returns[last_n] == 0) { contexts[current_context].m_number_of_returns[last_n] = dec_channel_returns_XY->createSymbolModel(16); dec_channel_returns_XY->initSymbolModel(contexts[current_context].m_number_of_returns[last_n]); } n = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_number_of_returns[last_n]); ((LASpoint14*)last_item)->number_of_returns = n; } else { n = last_n; } // how is the return number different U32 r; if ((changed_values & 3) == 0) // same return number { r = last_r; } else if ((changed_values & 3) == 1) // return number plus 1 mod 16 { r = ((last_r + 1) % 16); ((LASpoint14*)last_item)->return_number = r; } else if ((changed_values & 3) == 2) // return number minus 1 mod 16 { r = ((last_r + 15) % 16); ((LASpoint14*)last_item)->return_number = r; } else { // the return number difference is bigger than +1 / -1 so we decompress how it is different if (gps_time_change) // if the GPS time has changed { if (contexts[current_context].m_return_number[last_r] == 0) { contexts[current_context].m_return_number[last_r] = dec_channel_returns_XY->createSymbolModel(16); dec_channel_returns_XY->initSymbolModel(contexts[current_context].m_return_number[last_r]); } r = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_return_number[last_r]); } else // if the GPS time has not changed { I32 sym = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_return_number_gps_same); r = (last_r + (sym + 2)) % 16; } ((LASpoint14*)last_item)->return_number = r; } // set legacy return counts and number of returns if (n > 7) { if (r > 6) { if (r >= n) { ((LASpoint14*)last_item)->legacy_return_number = 7; } else { ((LASpoint14*)last_item)->legacy_return_number = 6; } } else { ((LASpoint14*)last_item)->legacy_return_number = r; } ((LASpoint14*)last_item)->legacy_number_of_returns = 7; } else { ((LASpoint14*)last_item)->legacy_return_number = r; ((LASpoint14*)last_item)->legacy_number_of_returns = n; } // get return map m and return level l context for current point U32 m = number_return_map_6ctx[n][r]; U32 l = number_return_level_8ctx[n][r]; // create single (3) / first (1) / last (2) / intermediate (0) return context for current point I32 cpr = (r == 1 ? 2 : 0); // first ? cpr += (r >= n ? 1 : 0); // last ? U32 k_bits; I32 median, diff; // decompress X coordinate median = contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].get(); diff = contexts[current_context].ic_dX->decompress(median, n==1); ((LASpoint14*)last_item)->X += diff; contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].add(diff); // decompress Y coordinate median = contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].get(); k_bits = contexts[current_context].ic_dX->getK(); diff = contexts[current_context].ic_dY->decompress(median, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); ((LASpoint14*)last_item)->Y += diff; contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].add(diff); //////////////////////////////////////// // decompress Z layer (if changed and requested) //////////////////////////////////////// if (changed_Z) // if the Z coordinate should be decompressed and changes within this chunk { k_bits = (contexts[current_context].ic_dX->getK() + contexts[current_context].ic_dY->getK()) / 2; ((LASpoint14*)last_item)->Z = contexts[current_context].ic_Z->decompress(contexts[current_context].last_Z[l], (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); contexts[current_context].last_Z[l] = ((LASpoint14*)last_item)->Z; } //////////////////////////////////////// // decompress classifications layer (if changed and requested) //////////////////////////////////////// if (changed_classification) // if the classification should be decompressed and changes within this chunk { U32 last_classification = ((LASpoint14*)last_item)->classification; I32 ccc = ((last_classification & 0x1F) << 1) + (cpr == 3 ? 1 : 0); if (contexts[current_context].m_classification[ccc] == 0) { contexts[current_context].m_classification[ccc] = dec_classification->createSymbolModel(256); dec_classification->initSymbolModel(contexts[current_context].m_classification[ccc]); } ((LASpoint14*)last_item)->classification = dec_classification->decodeSymbol(contexts[current_context].m_classification[ccc]); // update the legacy copy if (((LASpoint14*)last_item)->classification < 32) { ((LASpoint14*)last_item)->legacy_classification = ((LASpoint14*)last_item)->classification; } else { ((LASpoint14*)last_item)->legacy_classification = 0; } } //////////////////////////////////////// // decompress flags layer (if changed and requested) //////////////////////////////////////// if (changed_flags) // if the flags should be decompressed and change within this chunk { U32 last_flags = (((LASpoint14*)last_item)->edge_of_flight_line << 5) | (((LASpoint14*)last_item)->scan_direction_flag << 4) | ((LASpoint14*)last_item)->classification_flags; if (contexts[current_context].m_flags[last_flags] == 0) { contexts[current_context].m_flags[last_flags] = dec_flags->createSymbolModel(64); dec_flags->initSymbolModel(contexts[current_context].m_flags[last_flags]); } U32 flags = dec_flags->decodeSymbol(contexts[current_context].m_flags[last_flags]); ((LASpoint14*)last_item)->edge_of_flight_line = !!(flags & (1 << 5)); ((LASpoint14*)last_item)->scan_direction_flag = !!(flags & (1 << 4)); ((LASpoint14*)last_item)->classification_flags = (flags & 0x0F); // legacy copies ((LASpoint14*)last_item)->legacy_flags = (flags & 0x07); } //////////////////////////////////////// // decompress intensity layer (if changed and requested) //////////////////////////////////////// if (changed_intensity) // if the intensity should be decompressed and changes within this chunk { U16 intensity = contexts[current_context].ic_intensity->decompress(contexts[current_context].last_intensity[(cpr<<1) | gps_time_change], cpr); contexts[current_context].last_intensity[(cpr<<1) | gps_time_change] = intensity; ((LASpoint14*)last_item)->intensity = intensity; } //////////////////////////////////////// // decompress scan_angle layer (if changed and requested) //////////////////////////////////////// if (changed_scan_angle) // if the scan angle should be decompressed and changes within this chunk { if (scan_angle_change) // if the scan angle has actually changed { ((LASpoint14*)last_item)->scan_angle = contexts[current_context].ic_scan_angle->decompress(((LASpoint14*)last_item)->scan_angle, gps_time_change); // if the GPS time has changed ((LASpoint14*)last_item)->legacy_scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*((LASpoint14*)last_item)->scan_angle)); } } //////////////////////////////////////// // decompress user_data layer (if changed and requested) //////////////////////////////////////// if (changed_user_data) // if the user data should be decompressed and changes within this chunk { if (contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] == 0) { contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] = dec_user_data->createSymbolModel(256); dec_user_data->initSymbolModel(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } ((LASpoint14*)last_item)->user_data = dec_user_data->decodeSymbol(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } //////////////////////////////////////// // decompress point_source layer (if changed and requested) //////////////////////////////////////// if (changed_point_source) // if the point source ID should be decompressed and changes within this chunk { if (point_source_change) // if the point source ID has actually changed { ((LASpoint14*)last_item)->point_source_ID = contexts[current_context].ic_point_source_ID->decompress(((LASpoint14*)last_item)->point_source_ID); } } //////////////////////////////////////// // decompress gps_time layer (if changed and requested) //////////////////////////////////////// if (changed_gps_time) // if the GPS time should be decompressed and changes within this chunk { if (gps_time_change) // if the GPS time has actually changed { read_gps_time(); ((LASpoint14*)last_item)->gps_time = contexts[current_context].last_gpstime[contexts[current_context].last].f64; } } // copy the last item memcpy(item, last_item, sizeof(LASpoint14)); // remember if the last point had a gps_time_change ((LASpoint14*)last_item)->gps_time_change = gps_time_change; } void LASreadItemCompressed_POINT14_v3::read_gps_time() { I32 multi; if (contexts[current_context].last_gpstime_diff[contexts[current_context].last] == 0) // if the last integer difference was zero { multi = dec_gps_time->decodeSymbol(contexts[current_context].m_gpstime_0diff); if (multi == 0) // the difference can be represented with 32 bits { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = contexts[current_context].ic_gpstime->decompress(0, 0); contexts[current_context].last_gpstime[contexts[current_context].last].i64 += contexts[current_context].last_gpstime_diff[contexts[current_context].last]; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi == 1) // the difference is huge { contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].ic_gpstime->decompress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), 8); contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].last_gpstime[contexts[current_context].next].u64 << 32; contexts[current_context].last_gpstime[contexts[current_context].next].u64 |= dec_gps_time->readInt(); contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else // we switch to another sequence { contexts[current_context].last = (contexts[current_context].last+multi-1)&3; read_gps_time(); } } else { multi = dec_gps_time->decodeSymbol(contexts[current_context].m_gpstime_multi); if (multi == 1) { contexts[current_context].last_gpstime[contexts[current_context].last].i64 += contexts[current_context].ic_gpstime->decompress(contexts[current_context].last_gpstime_diff[contexts[current_context].last], 1);; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi < LASZIP_GPSTIME_MULTI_CODE_FULL) { I32 gpstime_diff; if (multi == 0) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(0, 7); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } else if (multi < LASZIP_GPSTIME_MULTI) { if (multi < 10) gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 2); else gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 3); } else if (multi == LASZIP_GPSTIME_MULTI) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(LASZIP_GPSTIME_MULTI*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 4); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } else { multi = LASZIP_GPSTIME_MULTI - multi; if (multi > LASZIP_GPSTIME_MULTI_MINUS) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 5); } else { gpstime_diff = contexts[current_context].ic_gpstime->decompress(LASZIP_GPSTIME_MULTI_MINUS*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 6); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } contexts[current_context].last_gpstime[contexts[current_context].last].i64 += gpstime_diff; } else if (multi == LASZIP_GPSTIME_MULTI_CODE_FULL) { contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].ic_gpstime->decompress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), 8); contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].last_gpstime[contexts[current_context].next].u64 << 32; contexts[current_context].last_gpstime[contexts[current_context].next].u64 |= dec_gps_time->readInt(); contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi >= LASZIP_GPSTIME_MULTI_CODE_FULL) { contexts[current_context].last = (contexts[current_context].last+multi-LASZIP_GPSTIME_MULTI_CODE_FULL)&3; read_gps_time(); } } } /* =============================================================================== LASreadItemCompressed_RGB14_v3 =============================================================================== */ LASreadItemCompressed_RGB14_v3::LASreadItemCompressed_RGB14_v3(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_RGB = 0; dec_RGB = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; changed_RGB = FALSE; requested_RGB = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_RGB ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_byte_used = 0; } current_context = 0; } LASreadItemCompressed_RGB14_v3::~LASreadItemCompressed_RGB14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_byte_used) { dec_RGB->destroySymbolModel(contexts[c].m_byte_used); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } } /* destroy all instreams and decoders */ if (instream_RGB) { delete instream_RGB; delete dec_RGB; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_RGB14_v3::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_byte_used == 0) { contexts[context].m_byte_used = dec_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = dec_RGB->createSymbolModel(256); } /* then init entropy models */ dec_RGB->initSymbolModel(contexts[context].m_byte_used); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); /* init current context from item */ memcpy(contexts[context].last_item, item, 6); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_RGB14_v3::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_RGB)); return TRUE; } BOOL LASreadItemCompressed_RGB14_v3::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_RGB == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_RGB = new ByteStreamInArrayLE(); } else { instream_RGB = new ByteStreamInArrayBE(); } /* create decoders */ dec_RGB = new ArithmeticDecoder(); } /* make sure the buffer is sufficiently large */ if (num_bytes_RGB > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes_RGB]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes_RGB; } /* load the requested bytes and init the corresponding instreams an decoders */ if (requested_RGB) { if (num_bytes_RGB) { instream->getBytes(bytes, num_bytes_RGB); instream_RGB->init(bytes, num_bytes_RGB); dec_RGB->init(instream_RGB); changed_RGB = TRUE; } else { instream_RGB->init(0, 0); changed_RGB = FALSE; } } else { if (num_bytes_RGB) { instream->skipBytes(num_bytes_RGB); } changed_RGB = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_RGB14_v3::read(U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } // decompress if (changed_RGB) { U8 corr; I32 diff = 0; U32 sym = dec_RGB->decodeSymbol(contexts[current_context].m_byte_used); if (sym & (1 << 0)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_0); ((U16*)item)[0] = (U16)U8_FOLD(corr + (last_item[0]&255)); } else { ((U16*)item)[0] = last_item[0]&0xFF; } if (sym & (1 << 1)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_1); ((U16*)item)[0] |= (((U16)U8_FOLD(corr + (last_item[0]>>8))) << 8); } else { ((U16*)item)[0] |= (last_item[0]&0xFF00); } if (sym & (1 << 6)) { diff = (((U16*)item)[0]&0x00FF) - (last_item[0]&0x00FF); if (sym & (1 << 2)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_2); ((U16*)item)[1] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]&255))); } else { ((U16*)item)[1] = last_item[1]&0xFF; } if (sym & (1 << 4)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_4); diff = (diff + ((((U16*)item)[1]&0x00FF) - (last_item[1]&0x00FF))) / 2; ((U16*)item)[2] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]&255))); } else { ((U16*)item)[2] = last_item[2]&0xFF; } diff = (((U16*)item)[0]>>8) - (last_item[0]>>8); if (sym & (1 << 3)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_3); ((U16*)item)[1] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]>>8))))<<8); } else { ((U16*)item)[1] |= (last_item[1]&0xFF00); } if (sym & (1 << 5)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_5); diff = (diff + ((((U16*)item)[1]>>8) - (last_item[1]>>8))) / 2; ((U16*)item)[2] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]>>8))))<<8); } else { ((U16*)item)[2] |= (last_item[2]&0xFF00); } } else { ((U16*)item)[1] = ((U16*)item)[0]; ((U16*)item)[2] = ((U16*)item)[0]; } memcpy(last_item, item, 6); } else { memcpy(item, last_item, 6); } } /* =============================================================================== LASreadItemCompressed_RGBNIR14_v3 =============================================================================== */ LASreadItemCompressed_RGBNIR14_v3::LASreadItemCompressed_RGBNIR14_v3(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_RGB = 0; instream_NIR = 0; dec_RGB = 0; dec_NIR = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; num_bytes_NIR = 0; changed_RGB = FALSE; changed_NIR = FALSE; requested_RGB = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_RGB ? TRUE : FALSE); requested_NIR = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_NIR ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_rgb_bytes_used = 0; contexts[c].m_nir_bytes_used = 0; } current_context = 0; } LASreadItemCompressed_RGBNIR14_v3::~LASreadItemCompressed_RGBNIR14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_rgb_bytes_used) { dec_RGB->destroySymbolModel(contexts[c].m_rgb_bytes_used); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } if (contexts[c].m_nir_bytes_used) { dec_NIR->destroySymbolModel(contexts[c].m_nir_bytes_used); dec_NIR->destroySymbolModel(contexts[c].m_nir_diff_0); dec_NIR->destroySymbolModel(contexts[c].m_nir_diff_1); } } /* destroy all instreams and decoders */ if (instream_RGB) { delete instream_RGB; delete dec_RGB; } if (instream_NIR) { delete instream_NIR; delete dec_NIR; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_RGBNIR14_v3::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (requested_RGB) { if (contexts[context].m_rgb_bytes_used == 0) { contexts[context].m_rgb_bytes_used = dec_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = dec_RGB->createSymbolModel(256); } /* then init entropy models */ dec_RGB->initSymbolModel(contexts[context].m_rgb_bytes_used); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); } if (requested_NIR) { if (contexts[context].m_nir_bytes_used == 0) { contexts[context].m_nir_bytes_used = dec_NIR->createSymbolModel(4); contexts[context].m_nir_diff_0 = dec_NIR->createSymbolModel(256); contexts[context].m_nir_diff_1 = dec_NIR->createSymbolModel(256); } /* then init entropy models */ dec_NIR->initSymbolModel(contexts[context].m_nir_bytes_used); dec_NIR->initSymbolModel(contexts[context].m_nir_diff_0); dec_NIR->initSymbolModel(contexts[context].m_nir_diff_1); } /* init current context from item */ memcpy(contexts[context].last_item, item, 8); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_RGBNIR14_v3::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_RGB)); instream->get32bitsLE(((U8*)&num_bytes_NIR)); return TRUE; } BOOL LASreadItemCompressed_RGBNIR14_v3::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_RGB == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_RGB = new ByteStreamInArrayLE(); instream_NIR = new ByteStreamInArrayLE(); } else { instream_RGB = new ByteStreamInArrayBE(); instream_NIR = new ByteStreamInArrayBE(); } /* create decoders */ dec_RGB = new ArithmeticDecoder(); dec_NIR = new ArithmeticDecoder(); } /* how many bytes do we need to read */ U32 num_bytes = 0; if (requested_RGB) num_bytes += num_bytes_RGB; if (requested_NIR) num_bytes += num_bytes_NIR; /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams an decoders */ num_bytes = 0; if (requested_RGB) { if (num_bytes_RGB) { instream->getBytes(bytes, num_bytes_RGB); num_bytes += num_bytes_RGB; instream_RGB->init(bytes, num_bytes_RGB); dec_RGB->init(instream_RGB); changed_RGB = TRUE; } else { instream_RGB->init(0, 0); changed_RGB = FALSE; } } else { if (num_bytes_RGB) { instream->skipBytes(num_bytes_RGB); } changed_RGB = FALSE; } if (requested_NIR) { if (num_bytes_NIR) { instream->getBytes(&bytes[num_bytes], num_bytes_NIR); instream_NIR->init(&bytes[num_bytes], num_bytes_NIR); dec_NIR->init(instream_NIR); changed_NIR = TRUE; } else { instream_NIR->init(0, 0); changed_NIR = FALSE; } } else { if (num_bytes_NIR) { instream->skipBytes(num_bytes_NIR); } changed_NIR = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_RGBNIR14_v3::read(U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } // decompress //////////////////////////////////////// // decompress RGB layer //////////////////////////////////////// if (changed_RGB) { U8 corr; I32 diff = 0; U32 sym = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_bytes_used); if (sym & (1 << 0)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_0); ((U16*)item)[0] = (U16)U8_FOLD(corr + (last_item[0]&255)); } else { ((U16*)item)[0] = last_item[0]&0xFF; } if (sym & (1 << 1)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_1); ((U16*)item)[0] |= (((U16)U8_FOLD(corr + (last_item[0]>>8))) << 8); } else { ((U16*)item)[0] |= (last_item[0]&0xFF00); } if (sym & (1 << 6)) { diff = (((U16*)item)[0]&0x00FF) - (last_item[0]&0x00FF); if (sym & (1 << 2)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_2); ((U16*)item)[1] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]&255))); } else { ((U16*)item)[1] = last_item[1]&0xFF; } if (sym & (1 << 4)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_4); diff = (diff + ((((U16*)item)[1]&0x00FF) - (last_item[1]&0x00FF))) / 2; ((U16*)item)[2] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]&255))); } else { ((U16*)item)[2] = last_item[2]&0xFF; } diff = (((U16*)item)[0]>>8) - (last_item[0]>>8); if (sym & (1 << 3)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_3); ((U16*)item)[1] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]>>8))))<<8); } else { ((U16*)item)[1] |= (last_item[1]&0xFF00); } if (sym & (1 << 5)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_5); diff = (diff + ((((U16*)item)[1]>>8) - (last_item[1]>>8))) / 2; ((U16*)item)[2] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]>>8))))<<8); } else { ((U16*)item)[2] |= (last_item[2]&0xFF00); } } else { ((U16*)item)[1] = ((U16*)item)[0]; ((U16*)item)[2] = ((U16*)item)[0]; } memcpy(last_item, item, 6); } else { memcpy(item, last_item, 6); } //////////////////////////////////////// // decompress NIR layer //////////////////////////////////////// if (changed_NIR) { U8 corr; U32 sym = dec_NIR->decodeSymbol(contexts[current_context].m_nir_bytes_used); if (sym & (1 << 0)) { corr = dec_NIR->decodeSymbol(contexts[current_context].m_nir_diff_0); ((U16*)item)[3] = (U16)U8_FOLD(corr + (last_item[3]&255)); } else { ((U16*)item)[3] = last_item[3]&0xFF; } if (sym & (1 << 1)) { corr = dec_NIR->decodeSymbol(contexts[current_context].m_nir_diff_1); ((U16*)item)[3] |= (((U16)U8_FOLD(corr + (last_item[3]>>8))) << 8); } else { ((U16*)item)[3] |= (last_item[3]&0xFF00); } last_item[3] = ((U16*)item)[3]; } else { ((U16*)item)[3] = last_item[3]; } } /* =============================================================================== LASreadItemCompressed_WAVEPACKET14_v3 =============================================================================== */ LASreadItemCompressed_WAVEPACKET14_v3::LASreadItemCompressed_WAVEPACKET14_v3(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_wavepacket = 0; dec_wavepacket = 0; /* zero num_bytes and init booleans */ num_bytes_wavepacket = 0; changed_wavepacket = FALSE; requested_wavepacket = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_WAVEPACKET ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_packet_index = 0; } current_context = 0; } LASreadItemCompressed_WAVEPACKET14_v3::~LASreadItemCompressed_WAVEPACKET14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_packet_index) { dec_wavepacket->destroySymbolModel(contexts[c].m_packet_index); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[0]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[1]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[2]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[3]); delete contexts[c].ic_offset_diff; delete contexts[c].ic_packet_size; delete contexts[c].ic_return_point; delete contexts[c].ic_xyz; } } /* destroy all instreams and decoders */ if (instream_wavepacket) { delete instream_wavepacket; delete dec_wavepacket; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_WAVEPACKET14_v3::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (requested_wavepacket) { if (contexts[context].m_packet_index == 0) { contexts[context].m_packet_index = dec_wavepacket->createSymbolModel(256); contexts[context].m_offset_diff[0] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[1] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[2] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[3] = dec_wavepacket->createSymbolModel(4); contexts[context].ic_offset_diff = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_packet_size = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_return_point = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_xyz = new IntegerCompressor(dec_wavepacket, 32, 3); } /* then init entropy models */ dec_wavepacket->initSymbolModel(contexts[context].m_packet_index); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[0]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[1]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[2]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[3]); contexts[context].ic_offset_diff->initDecompressor(); contexts[context].ic_packet_size->initDecompressor(); contexts[context].ic_return_point->initDecompressor(); contexts[context].ic_xyz->initDecompressor(); } /* init current context from item */ contexts[context].last_diff_32 = 0; contexts[context].sym_last_offset_diff = 0; memcpy(contexts[context].last_item, item, 29); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_WAVEPACKET14_v3::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_wavepacket)); return TRUE; } BOOL LASreadItemCompressed_WAVEPACKET14_v3::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_wavepacket == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_wavepacket = new ByteStreamInArrayLE(); } else { instream_wavepacket = new ByteStreamInArrayBE(); } /* create decoders */ dec_wavepacket = new ArithmeticDecoder(); } /* make sure the buffer is sufficiently large */ if (num_bytes_wavepacket > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes_wavepacket]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes_wavepacket; } /* load the requested bytes and init the corresponding instreams an decoders */ if (requested_wavepacket) { if (num_bytes_wavepacket) { instream->getBytes(bytes, num_bytes_wavepacket); instream_wavepacket->init(bytes, num_bytes_wavepacket); dec_wavepacket->init(instream_wavepacket); changed_wavepacket = TRUE; } else { instream_wavepacket->init(0, 0); changed_wavepacket = FALSE; } } else { if (num_bytes_wavepacket) { instream->skipBytes(num_bytes_wavepacket); } changed_wavepacket = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_WAVEPACKET14_v3::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, last_item); last_item = contexts[current_context].last_item; } } // decompress if (changed_wavepacket) { item[0] = (U8)(dec_wavepacket->decodeSymbol(contexts[current_context].m_packet_index)); LASwavepacket13 this_item_m; LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item+1); contexts[current_context].sym_last_offset_diff = dec_wavepacket->decodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff]); if (contexts[current_context].sym_last_offset_diff == 0) { this_item_m.offset = last_item_m.offset; } else if (contexts[current_context].sym_last_offset_diff == 1) { this_item_m.offset = last_item_m.offset + last_item_m.packet_size; } else if (contexts[current_context].sym_last_offset_diff == 2) { contexts[current_context].last_diff_32 = contexts[current_context].ic_offset_diff->decompress(contexts[current_context].last_diff_32); this_item_m.offset = last_item_m.offset + contexts[current_context].last_diff_32; } else { this_item_m.offset = dec_wavepacket->readInt64(); } this_item_m.packet_size = contexts[current_context].ic_packet_size->decompress(last_item_m.packet_size); this_item_m.return_point.i32 = contexts[current_context].ic_return_point->decompress(last_item_m.return_point.i32); this_item_m.x.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.x.i32, 0); this_item_m.y.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.y.i32, 1); this_item_m.z.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.z.i32, 2); this_item_m.pack(item+1); memcpy(last_item, item, 29); } } /* =============================================================================== LASreadItemCompressed_BYTE14_v3 =============================================================================== */ LASreadItemCompressed_BYTE14_v3::LASreadItemCompressed_BYTE14_v3(ArithmeticDecoder* dec, U32 number, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* must be more than one byte */ assert(number); this->number = number; /* zero instream and decoder pointer arrays */ instream_Bytes = 0; dec_Bytes = 0; /* create and init num_bytes and booleans arrays */ num_bytes_Bytes = new U32[number]; changed_Bytes = new BOOL[number]; requested_Bytes = new BOOL[number]; U32 i; for (i = 0; i < number; i++) { num_bytes_Bytes[i] = 0; changed_Bytes[i] = FALSE; if (i > 15) // currently only the first 16 extra bytes can be selectively decompressed { requested_Bytes[i] = TRUE; } else { requested_Bytes[i] = (decompress_selective & (LASZIP_DECOMPRESS_SELECTIVE_BYTE0 << i) ? TRUE : FALSE); } } /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_bytes = 0; } current_context = 0; } LASreadItemCompressed_BYTE14_v3::~LASreadItemCompressed_BYTE14_v3() { /* destroy all initialized scanner channel contexts */ U32 c, i; for (c = 0; c < 4; c++) { if (contexts[c].m_bytes) { for (i = 0; i < number; i++) { dec_Bytes[i]->destroySymbolModel(contexts[c].m_bytes[i]); } delete [] contexts[c].m_bytes; delete [] contexts[c].last_item; } } /* destroy all instream and decoder arrays */ if (instream_Bytes) { for (i = 0; i < number; i++) { if (instream_Bytes[i]) { delete instream_Bytes[i]; delete dec_Bytes[i]; } } delete [] instream_Bytes; delete [] dec_Bytes; } /* destroy all other arrays */ if (num_bytes_Bytes) delete [] num_bytes_Bytes; if (changed_Bytes) delete [] changed_Bytes; if (requested_Bytes) delete [] requested_Bytes; if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_BYTE14_v3::createAndInitModelsAndDecompressors(U32 context, const U8* item) { U32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and last items (if needed) */ if (contexts[context].m_bytes == 0) { contexts[context].m_bytes = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { contexts[context].m_bytes[i] = dec_Bytes[i]->createSymbolModel(256); dec_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* create last item */ contexts[context].last_item = new U8[number]; } /* then init entropy models */ for (i = 0; i < number; i++) { dec_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* init current context from item */ memcpy(contexts[context].last_item, item, number); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_BYTE14_v3::chunk_sizes() { U32 i; /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); for (i = 0; i < number; i++) { /* read bytes per layer */ instream->get32bitsLE(((U8*)&(num_bytes_Bytes[i]))); } return TRUE; } BOOL LASreadItemCompressed_BYTE14_v3::init(const U8* item, U32& context) { U32 i; /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_Bytes == 0) { /* create instream pointer array */ instream_Bytes = new ByteStreamInArray*[number]; /* create instreams */ if (IS_LITTLE_ENDIAN()) { for (i = 0; i < number; i++) { instream_Bytes[i] = new ByteStreamInArrayLE(); } } else { for (i = 0; i < number; i++) { instream_Bytes[i] = new ByteStreamInArrayBE(); } } /* create decoder pointer array */ dec_Bytes = new ArithmeticDecoder*[number]; /* create layer decoders */ for (i = 0; i < number; i++) { dec_Bytes[i] = new ArithmeticDecoder(); } } /* how many bytes do we need to read */ U32 num_bytes = 0; for (i = 0; i < number; i++) { if (requested_Bytes[i]) num_bytes += num_bytes_Bytes[i]; } /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams an decoders */ num_bytes = 0; for (i = 0; i < number; i++) { if (requested_Bytes[i]) { if (num_bytes_Bytes[i]) { instream->getBytes(&(bytes[num_bytes]), num_bytes_Bytes[i]); instream_Bytes[i]->init(&(bytes[num_bytes]), num_bytes_Bytes[i]); dec_Bytes[i]->init(instream_Bytes[i]); num_bytes += num_bytes_Bytes[i]; changed_Bytes[i] = TRUE; } else { dec_Bytes[i]->init(0, 0); changed_Bytes[i] = FALSE; } } else { if (num_bytes_Bytes[i]) { instream->skipBytes(num_bytes_Bytes[i]); } changed_Bytes[i] = FALSE; } } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_BYTE14_v3::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } // decompress U32 i; for (i = 0; i < number; i++) { if (changed_Bytes[i]) { I32 value = last_item[i] + dec_Bytes[i]->decodeSymbol(contexts[current_context].m_bytes[i]); item[i] = U8_FOLD(value); last_item[i] = item[i]; } else { item[i] = last_item[i]; } } } LASzip-3.4.3/src/lasreaditemcompressed_v3.hpp000066400000000000000000000155411356234217100211640ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v3.hpp CONTENTS: Native extension for decompressing the *new* point types 6 to 10 of LAS 1.4 PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 19 March 2019 -- set "legacy classification" to zero if "classification > 31" 28 August 2017 -- moving 'context' from global development hack to interface 19 April 2017 -- support for selective decompression for new LAS 1.4 points 22 June 2016 -- created after Island beat Austria 2:1 in the EM2016 =============================================================================== */ #ifndef LAS_READ_ITEM_COMPRESSED_V3_HPP #define LAS_READ_ITEM_COMPRESSED_V3_HPP #include "lasreaditem.hpp" #include "arithmeticdecoder.hpp" #include "integercompressor.hpp" #include "bytestreamin_array.hpp" #include "laszip_common_v3.hpp" #include "laszip_decompress_selective_v3.hpp" class LASreadItemCompressed_POINT14_v3 : public LASreadItemCompressed { public: LASreadItemCompressed_POINT14_v3(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is set void read(U8* item, U32& context); // context is set ~LASreadItemCompressed_POINT14_v3(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_channel_returns_XY; ByteStreamInArray* instream_Z; ByteStreamInArray* instream_classification; ByteStreamInArray* instream_flags; ByteStreamInArray* instream_intensity; ByteStreamInArray* instream_scan_angle; ByteStreamInArray* instream_user_data; ByteStreamInArray* instream_point_source; ByteStreamInArray* instream_gps_time; ArithmeticDecoder* dec_channel_returns_XY; ArithmeticDecoder* dec_Z; ArithmeticDecoder* dec_classification; ArithmeticDecoder* dec_flags; ArithmeticDecoder* dec_intensity; ArithmeticDecoder* dec_scan_angle; ArithmeticDecoder* dec_user_data; ArithmeticDecoder* dec_point_source; ArithmeticDecoder* dec_gps_time; BOOL changed_Z; BOOL changed_classification; BOOL changed_flags; BOOL changed_intensity; BOOL changed_scan_angle; BOOL changed_user_data; BOOL changed_point_source; BOOL changed_gps_time; U32 num_bytes_channel_returns_XY; U32 num_bytes_Z; U32 num_bytes_classification; U32 num_bytes_flags; U32 num_bytes_intensity; U32 num_bytes_scan_angle; U32 num_bytes_user_data; U32 num_bytes_point_source; U32 num_bytes_gps_time; BOOL requested_Z; BOOL requested_classification; BOOL requested_flags; BOOL requested_intensity; BOOL requested_scan_angle; BOOL requested_user_data; BOOL requested_point_source; BOOL requested_gps_time; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextPOINT14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); void read_gps_time(); }; class LASreadItemCompressed_RGB14_v3 : public LASreadItemCompressed { public: LASreadItemCompressed_RGB14_v3(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_RGB14_v3(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_RGB; ArithmeticDecoder* dec_RGB; BOOL changed_RGB; U32 num_bytes_RGB; BOOL requested_RGB; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextRGB14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_RGBNIR14_v3 : public LASreadItemCompressed { public: LASreadItemCompressed_RGBNIR14_v3(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_RGBNIR14_v3(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_RGB; ByteStreamInArray* instream_NIR; ArithmeticDecoder* dec_RGB; ArithmeticDecoder* dec_NIR; BOOL changed_RGB; BOOL changed_NIR; U32 num_bytes_RGB; U32 num_bytes_NIR; BOOL requested_RGB; BOOL requested_NIR; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextRGBNIR14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_WAVEPACKET14_v3 : public LASreadItemCompressed { public: LASreadItemCompressed_WAVEPACKET14_v3(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_WAVEPACKET14_v3(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_wavepacket; ArithmeticDecoder* dec_wavepacket; BOOL changed_wavepacket; U32 num_bytes_wavepacket; BOOL requested_wavepacket; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextWAVEPACKET14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_BYTE14_v3 : public LASreadItemCompressed { public: LASreadItemCompressed_BYTE14_v3(ArithmeticDecoder* dec, U32 number, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_BYTE14_v3(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray** instream_Bytes; ArithmeticDecoder** dec_Bytes; U32* num_bytes_Bytes; BOOL* changed_Bytes; BOOL* requested_Bytes; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextBYTE14 contexts[4]; U32 number; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; #endif LASzip-3.4.3/src/lasreaditemcompressed_v4.cpp000066400000000000000000002171111356234217100211550ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v4.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasreaditemcompressed_v4.hpp" #include #include typedef struct LASpoint14 { I32 X; I32 Y; I32 Z; U16 intensity; U8 legacy_return_number : 3; U8 legacy_number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 legacy_classification : 5; U8 legacy_flags : 3; I8 legacy_scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 scan_angle; U8 legacy_point_type : 2; U8 scanner_channel : 2; U8 classification_flags : 4; U8 classification; U8 return_number : 4; U8 number_of_returns : 4; // LASlib internal use only U8 deleted_flag; // for 8 byte alignment of the GPS time U8 dummy[2]; // compressed LASzip 1.4 points only BOOL gps_time_change; F64 gps_time; U16 rgb[4]; // LASwavepacket wavepacket; } LASpoint14; #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 5) LASreadItemCompressed_POINT14_v4::LASreadItemCompressed_POINT14_v4(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_channel_returns_XY = 0; instream_Z = 0; instream_classification = 0; instream_flags = 0; instream_intensity = 0; instream_scan_angle = 0; instream_user_data = 0; instream_point_source = 0; instream_gps_time = 0; dec_channel_returns_XY = 0; dec_Z = 0; dec_classification = 0; dec_flags = 0; dec_intensity = 0; dec_scan_angle = 0; dec_user_data = 0; dec_point_source = 0; dec_gps_time = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_changed_values[0] = 0; } current_context = 0; /* zero num_bytes and init booleans */ num_bytes_channel_returns_XY = 0; num_bytes_Z = 0; num_bytes_classification = 0; num_bytes_flags = 0; num_bytes_intensity = 0; num_bytes_scan_angle = 0; num_bytes_user_data = 0; num_bytes_point_source = 0; num_bytes_gps_time = 0; changed_Z = FALSE; changed_classification = FALSE; changed_flags = FALSE; changed_intensity = FALSE; changed_scan_angle = FALSE; changed_user_data = FALSE; changed_point_source = FALSE; changed_gps_time = FALSE; requested_Z = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_Z ? TRUE : FALSE); requested_classification = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION ? TRUE : FALSE); requested_flags = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_FLAGS ? TRUE : FALSE); requested_intensity = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_INTENSITY ? TRUE : FALSE); requested_scan_angle = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE ? TRUE : FALSE); requested_user_data = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_USER_DATA ? TRUE : FALSE); requested_point_source = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE ? TRUE : FALSE); requested_gps_time = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_GPS_TIME ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; } LASreadItemCompressed_POINT14_v4::~LASreadItemCompressed_POINT14_v4() { U32 c, i; /* destroy all initialized scanner channel contexts */ for (c = 0; c < 4; c++) { if (contexts[c].m_changed_values[0]) { dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[0]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[1]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[2]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[3]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[4]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[5]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[6]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[7]); dec_channel_returns_XY->destroySymbolModel(contexts[c].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[c].m_number_of_returns[i]) dec_channel_returns_XY->destroySymbolModel(contexts[c].m_number_of_returns[i]); if (contexts[c].m_return_number[i]) dec_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number[i]); } dec_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number_gps_same); delete contexts[c].ic_dX; delete contexts[c].ic_dY; delete contexts[c].ic_Z; for (i = 0; i < 64; i++) { if (contexts[c].m_classification[i]) dec_classification->destroySymbolModel(contexts[c].m_classification[i]); if (contexts[c].m_flags[i]) dec_flags->destroySymbolModel(contexts[c].m_flags[i]); if (contexts[c].m_user_data[i]) dec_user_data->destroySymbolModel(contexts[c].m_user_data[i]); } delete contexts[c].ic_intensity; delete contexts[c].ic_scan_angle; delete contexts[c].ic_point_source_ID; dec_gps_time->destroySymbolModel(contexts[c].m_gpstime_multi); dec_gps_time->destroySymbolModel(contexts[c].m_gpstime_0diff); delete contexts[c].ic_gpstime; } } /* destroy all decoders and instreams */ if (instream_channel_returns_XY) { delete dec_channel_returns_XY; delete dec_Z; delete dec_classification; delete dec_flags; delete dec_intensity; delete dec_scan_angle; delete dec_user_data; delete dec_gps_time; delete instream_channel_returns_XY; delete instream_Z; delete instream_classification; delete instream_flags; delete instream_intensity; delete instream_scan_angle; delete instream_user_data; delete instream_gps_time; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_POINT14_v4::createAndInitModelsAndDecompressors(U32 context, const U8* item) { I32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and integer decompressors (if needed) */ if (contexts[context].m_changed_values[0] == 0) { /* for the channel_returns_XY layer */ contexts[context].m_changed_values[0] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[1] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[2] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[3] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[4] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[5] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[6] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[7] = dec_channel_returns_XY->createSymbolModel(128); contexts[context].m_scanner_channel = dec_channel_returns_XY->createSymbolModel(3); for (i = 0; i < 16; i++) { contexts[context].m_number_of_returns[i] = 0; contexts[context].m_return_number[i] = 0; } contexts[context].m_return_number_gps_same = dec_channel_returns_XY->createSymbolModel(13); contexts[context].ic_dX = new IntegerCompressor(dec_channel_returns_XY, 32, 2); // 32 bits, 2 context contexts[context].ic_dY = new IntegerCompressor(dec_channel_returns_XY, 32, 22); // 32 bits, 22 contexts /* for the Z layer */ contexts[context].ic_Z = new IntegerCompressor(dec_Z, 32, 20); // 32 bits, 20 contexts /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { contexts[context].m_classification[i] = 0; contexts[context].m_flags[i] = 0; contexts[context].m_user_data[i] = 0; } /* for the intensity layer */ contexts[context].ic_intensity = new IntegerCompressor(dec_intensity, 16, 4); /* for the scan_angle layer */ contexts[context].ic_scan_angle = new IntegerCompressor(dec_scan_angle, 16, 2); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID = new IntegerCompressor(dec_point_source, 16); /* for the gps_time layer */ contexts[context].m_gpstime_multi = dec_gps_time->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); contexts[context].m_gpstime_0diff = dec_gps_time->createSymbolModel(5); contexts[context].ic_gpstime = new IntegerCompressor(dec_gps_time, 32, 9); // 32 bits, 9 contexts } /* then init entropy models and integer compressors */ /* for the channel_returns_XY layer */ dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[0]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[1]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[2]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[3]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[4]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[5]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[6]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[7]); dec_channel_returns_XY->initSymbolModel(contexts[context].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[context].m_number_of_returns[i]) dec_channel_returns_XY->initSymbolModel(contexts[context].m_number_of_returns[i]); if (contexts[context].m_return_number[i]) dec_channel_returns_XY->initSymbolModel(contexts[context].m_return_number[i]); } dec_channel_returns_XY->initSymbolModel(contexts[context].m_return_number_gps_same); contexts[context].ic_dX->initDecompressor(); contexts[context].ic_dY->initDecompressor(); for (i = 0; i < 12; i++) { contexts[context].last_X_diff_median5[i].init(); contexts[context].last_Y_diff_median5[i].init(); } /* for the Z layer */ contexts[context].ic_Z->initDecompressor(); for (i = 0; i < 8; i++) { contexts[context].last_Z[i] = ((LASpoint14*)item)->Z; } /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { if (contexts[context].m_classification[i]) dec_classification->initSymbolModel(contexts[context].m_classification[i]); if (contexts[context].m_flags[i]) dec_flags->initSymbolModel(contexts[context].m_flags[i]); if (contexts[context].m_user_data[i]) dec_user_data->initSymbolModel(contexts[context].m_user_data[i]); } /* for the intensity layer */ contexts[context].ic_intensity->initDecompressor(); for (i = 0; i < 8; i++) { contexts[context].last_intensity[i] = ((LASpoint14*)item)->intensity; } /* for the scan_angle layer */ contexts[context].ic_scan_angle->initDecompressor(); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID->initDecompressor(); /* for the gps_time layer */ dec_gps_time->initSymbolModel(contexts[context].m_gpstime_multi); dec_gps_time->initSymbolModel(contexts[context].m_gpstime_0diff); contexts[context].ic_gpstime->initDecompressor(); contexts[context].last = 0, contexts[context].next = 0; contexts[context].last_gpstime_diff[0] = 0; contexts[context].last_gpstime_diff[1] = 0; contexts[context].last_gpstime_diff[2] = 0; contexts[context].last_gpstime_diff[3] = 0; contexts[context].multi_extreme_counter[0] = 0; contexts[context].multi_extreme_counter[1] = 0; contexts[context].multi_extreme_counter[2] = 0; contexts[context].multi_extreme_counter[3] = 0; contexts[context].last_gpstime[0].f64 = ((LASpoint14*)item)->gps_time; contexts[context].last_gpstime[1].u64 = 0; contexts[context].last_gpstime[2].u64 = 0; contexts[context].last_gpstime[3].u64 = 0; /* init current context from last item */ memcpy(contexts[context].last_item, item, sizeof(LASpoint14)); ((LASpoint14*)contexts[context].last_item)->gps_time_change = FALSE; // fprintf(stderr, "INIT: current_context %d last item %.14g %d %d %d %d %d %d\n", current_context, ((LASpoint14*)item)->gps_time, ((LASpoint14*)item)->X, ((LASpoint14*)item)->Y, ((LASpoint14*)item)->Z, ((LASpoint14*)item)->intensity, ((LASpoint14*)item)->return_number, ((LASpoint14*)item)->number_of_returns); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_POINT14_v4::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_channel_returns_XY)); instream->get32bitsLE(((U8*)&num_bytes_Z)); instream->get32bitsLE(((U8*)&num_bytes_classification)); instream->get32bitsLE(((U8*)&num_bytes_flags)); instream->get32bitsLE(((U8*)&num_bytes_intensity)); instream->get32bitsLE(((U8*)&num_bytes_scan_angle)); instream->get32bitsLE(((U8*)&num_bytes_user_data)); instream->get32bitsLE(((U8*)&num_bytes_point_source)); instream->get32bitsLE(((U8*)&num_bytes_gps_time)); return TRUE; } BOOL LASreadItemCompressed_POINT14_v4::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_channel_returns_XY == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_channel_returns_XY = new ByteStreamInArrayLE(); instream_Z = new ByteStreamInArrayLE(); instream_classification = new ByteStreamInArrayLE(); instream_flags = new ByteStreamInArrayLE(); instream_intensity = new ByteStreamInArrayLE(); instream_scan_angle = new ByteStreamInArrayLE(); instream_user_data = new ByteStreamInArrayLE(); instream_point_source = new ByteStreamInArrayLE(); instream_gps_time = new ByteStreamInArrayLE(); } else { instream_channel_returns_XY = new ByteStreamInArrayBE(); instream_Z = new ByteStreamInArrayBE(); instream_classification = new ByteStreamInArrayBE(); instream_flags = new ByteStreamInArrayBE(); instream_intensity = new ByteStreamInArrayBE(); instream_scan_angle = new ByteStreamInArrayBE(); instream_user_data = new ByteStreamInArrayBE(); instream_point_source = new ByteStreamInArrayBE(); instream_gps_time = new ByteStreamInArrayBE(); } /* create decoders */ dec_channel_returns_XY = new ArithmeticDecoder(); dec_Z = new ArithmeticDecoder(); dec_classification = new ArithmeticDecoder(); dec_flags = new ArithmeticDecoder(); dec_intensity = new ArithmeticDecoder(); dec_scan_angle = new ArithmeticDecoder(); dec_user_data = new ArithmeticDecoder(); dec_point_source = new ArithmeticDecoder(); dec_gps_time = new ArithmeticDecoder(); } /* how many bytes do we need to read */ U32 num_bytes = num_bytes_channel_returns_XY; if (requested_Z) num_bytes += num_bytes_Z; if (requested_classification) num_bytes += num_bytes_classification; if (requested_flags) num_bytes += num_bytes_flags; if (requested_intensity) num_bytes += num_bytes_intensity; if (requested_scan_angle) num_bytes += num_bytes_scan_angle; if (requested_user_data) num_bytes += num_bytes_user_data; if (requested_point_source) num_bytes += num_bytes_point_source; if (requested_gps_time) num_bytes += num_bytes_gps_time; /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams and decoders */ num_bytes = 0; instream->getBytes(bytes, num_bytes_channel_returns_XY); instream_channel_returns_XY->init(bytes, num_bytes_channel_returns_XY); dec_channel_returns_XY->init(instream_channel_returns_XY); num_bytes += num_bytes_channel_returns_XY; if (requested_Z) { if (num_bytes_Z) { instream->getBytes(&(bytes[num_bytes]), num_bytes_Z); instream_Z->init(&(bytes[num_bytes]), num_bytes_Z); dec_Z->init(instream_Z); num_bytes += num_bytes_Z; changed_Z = TRUE; } else { instream_Z->init(0, 0); changed_Z = FALSE; } } else { if (num_bytes_Z) { instream->skipBytes(num_bytes_Z); } changed_Z = FALSE; } if (requested_classification) { if (num_bytes_classification) { instream->getBytes(&(bytes[num_bytes]), num_bytes_classification); instream_classification->init(&(bytes[num_bytes]), num_bytes_classification); dec_classification->init(instream_classification); num_bytes += num_bytes_classification; changed_classification = TRUE; } else { instream_classification->init(0, 0); changed_classification = FALSE; } } else { if (num_bytes_classification) { instream->skipBytes(num_bytes_classification); } changed_classification = FALSE; } if (requested_flags) { if (num_bytes_flags) { instream->getBytes(&(bytes[num_bytes]), num_bytes_flags); instream_flags->init(&(bytes[num_bytes]), num_bytes_flags); dec_flags->init(instream_flags); num_bytes += num_bytes_flags; changed_flags = TRUE; } else { instream_flags->init(0, 0); changed_flags = FALSE; } } else { if (num_bytes_flags) { instream->skipBytes(num_bytes_flags); } changed_flags = FALSE; } if (requested_intensity) { if (num_bytes_intensity) { instream->getBytes(&(bytes[num_bytes]), num_bytes_intensity); instream_intensity->init(&(bytes[num_bytes]), num_bytes_intensity); dec_intensity->init(instream_intensity); num_bytes += num_bytes_intensity; changed_intensity = TRUE; } else { instream_intensity->init(0, 0); changed_intensity = FALSE; } } else { if (num_bytes_intensity) { instream->skipBytes(num_bytes_intensity); } changed_intensity = FALSE; } if (requested_scan_angle) { if (num_bytes_scan_angle) { instream->getBytes(&(bytes[num_bytes]), num_bytes_scan_angle); instream_scan_angle->init(&(bytes[num_bytes]), num_bytes_scan_angle); dec_scan_angle->init(instream_scan_angle); num_bytes += num_bytes_scan_angle; changed_scan_angle = TRUE; } else { instream_scan_angle->init(0, 0); changed_scan_angle = FALSE; } } else { if (num_bytes_scan_angle) { instream->skipBytes(num_bytes_scan_angle); } changed_scan_angle = FALSE; } if (requested_user_data) { if (num_bytes_user_data) { instream->getBytes(&(bytes[num_bytes]), num_bytes_user_data); instream_user_data->init(&(bytes[num_bytes]), num_bytes_user_data); dec_user_data->init(instream_user_data); num_bytes += num_bytes_user_data; changed_user_data = TRUE; } else { instream_user_data->init(0, 0); changed_user_data = FALSE; } } else { if (num_bytes_user_data) { instream->skipBytes(num_bytes_user_data); } changed_user_data = FALSE; } if (requested_point_source) { if (num_bytes_point_source) { instream->getBytes(&(bytes[num_bytes]), num_bytes_point_source); instream_point_source->init(&(bytes[num_bytes]), num_bytes_point_source); dec_point_source->init(instream_point_source); num_bytes += num_bytes_point_source; changed_point_source = TRUE; } else { instream_point_source->init(0, 0); changed_point_source = FALSE; } } else { if (num_bytes_point_source) { instream->skipBytes(num_bytes_point_source); } changed_point_source = FALSE; } if (requested_gps_time) { if (num_bytes_gps_time) { instream->getBytes(&(bytes[num_bytes]), num_bytes_gps_time); instream_gps_time->init(&(bytes[num_bytes]), num_bytes_gps_time); dec_gps_time->init(instream_gps_time); num_bytes += num_bytes_gps_time; changed_gps_time = TRUE; } else { instream_gps_time->init(0, 0); changed_gps_time = FALSE; } } else { if (num_bytes_gps_time) { instream->skipBytes(num_bytes_gps_time); } changed_gps_time = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = ((LASpoint14*)item)->scanner_channel; context = current_context; // the POINT14 reader sets context for all other items /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_POINT14_v4::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; //////////////////////////////////////// // decompress returns_XY layer //////////////////////////////////////// // create single (3) / first (1) / last (2) / intermediate (0) context from last point return I32 lpr = (((LASpoint14*)last_item)->return_number == 1 ? 1 : 0); // first? lpr += (((LASpoint14*)last_item)->return_number >= ((LASpoint14*)last_item)->number_of_returns ? 2 : 0); // last? // add info whether the GPS time changed in the last return to the context lpr += (((LASpoint14*)last_item)->gps_time_change ? 4 : 0); // decompress which values have changed with last point return context I32 changed_values = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_changed_values[lpr]); // if scanner channel has changed if (changed_values & (1 << 6)) { U32 diff = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_scanner_channel); // curr = last + (sym + 1) U32 scanner_channel = (current_context + diff + 1) % 4; // maybe create and init entropy models and integer compressors if (contexts[scanner_channel].unused) { // create and init entropy models and integer decompressors createAndInitModelsAndDecompressors(scanner_channel, contexts[current_context].last_item); } // switch context to current scanner channel current_context = scanner_channel; // get last for new context last_item = contexts[current_context].last_item; ((LASpoint14*)last_item)->scanner_channel = scanner_channel; } context = current_context; // the POINT14 reader sets context for all other items // determine changed attributes BOOL point_source_change = (changed_values & (1 << 5) ? TRUE : FALSE); BOOL gps_time_change = (changed_values & (1 << 4) ? TRUE : FALSE); BOOL scan_angle_change = (changed_values & (1 << 3) ? TRUE : FALSE); // get last return counts U32 last_n = ((LASpoint14*)last_item)->number_of_returns; U32 last_r = ((LASpoint14*)last_item)->return_number; // if number of returns is different we decompress it U32 n; if (changed_values & (1 << 2)) { if (contexts[current_context].m_number_of_returns[last_n] == 0) { contexts[current_context].m_number_of_returns[last_n] = dec_channel_returns_XY->createSymbolModel(16); dec_channel_returns_XY->initSymbolModel(contexts[current_context].m_number_of_returns[last_n]); } n = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_number_of_returns[last_n]); ((LASpoint14*)last_item)->number_of_returns = n; } else { n = last_n; } // how is the return number different U32 r; if ((changed_values & 3) == 0) // same return number { r = last_r; } else if ((changed_values & 3) == 1) // return number plus 1 mod 16 { r = ((last_r + 1) % 16); ((LASpoint14*)last_item)->return_number = r; } else if ((changed_values & 3) == 2) // return number minus 1 mod 16 { r = ((last_r + 15) % 16); ((LASpoint14*)last_item)->return_number = r; } else { // the return number difference is bigger than +1 / -1 so we decompress how it is different if (gps_time_change) // if the GPS time has changed { if (contexts[current_context].m_return_number[last_r] == 0) { contexts[current_context].m_return_number[last_r] = dec_channel_returns_XY->createSymbolModel(16); dec_channel_returns_XY->initSymbolModel(contexts[current_context].m_return_number[last_r]); } r = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_return_number[last_r]); } else // if the GPS time has not changed { I32 sym = dec_channel_returns_XY->decodeSymbol(contexts[current_context].m_return_number_gps_same); r = (last_r + (sym + 2)) % 16; } ((LASpoint14*)last_item)->return_number = r; } // set legacy return counts and number of returns if (n > 7) { if (r > 6) { if (r >= n) { ((LASpoint14*)last_item)->legacy_return_number = 7; } else { ((LASpoint14*)last_item)->legacy_return_number = 6; } } else { ((LASpoint14*)last_item)->legacy_return_number = r; } ((LASpoint14*)last_item)->legacy_number_of_returns = 7; } else { ((LASpoint14*)last_item)->legacy_return_number = r; ((LASpoint14*)last_item)->legacy_number_of_returns = n; } // get return map m and return level l context for current point U32 m = number_return_map_6ctx[n][r]; U32 l = number_return_level_8ctx[n][r]; // create single (3) / first (1) / last (2) / intermediate (0) return context for current point I32 cpr = (r == 1 ? 2 : 0); // first ? cpr += (r >= n ? 1 : 0); // last ? U32 k_bits; I32 median, diff; // decompress X coordinate median = contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].get(); diff = contexts[current_context].ic_dX->decompress(median, n==1); ((LASpoint14*)last_item)->X += diff; contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].add(diff); // decompress Y coordinate median = contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].get(); k_bits = contexts[current_context].ic_dX->getK(); diff = contexts[current_context].ic_dY->decompress(median, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); ((LASpoint14*)last_item)->Y += diff; contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].add(diff); //////////////////////////////////////// // decompress Z layer (if changed and requested) //////////////////////////////////////// if (changed_Z) // if the Z coordinate should be decompressed and changes within this chunk { k_bits = (contexts[current_context].ic_dX->getK() + contexts[current_context].ic_dY->getK()) / 2; ((LASpoint14*)last_item)->Z = contexts[current_context].ic_Z->decompress(contexts[current_context].last_Z[l], (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); contexts[current_context].last_Z[l] = ((LASpoint14*)last_item)->Z; } //////////////////////////////////////// // decompress classifications layer (if changed and requested) //////////////////////////////////////// if (changed_classification) // if the classification should be decompressed and changes within this chunk { U32 last_classification = ((LASpoint14*)last_item)->classification; I32 ccc = ((last_classification & 0x1F) << 1) + (cpr == 3 ? 1 : 0); if (contexts[current_context].m_classification[ccc] == 0) { contexts[current_context].m_classification[ccc] = dec_classification->createSymbolModel(256); dec_classification->initSymbolModel(contexts[current_context].m_classification[ccc]); } ((LASpoint14*)last_item)->classification = dec_classification->decodeSymbol(contexts[current_context].m_classification[ccc]); // update the legacy copy if (((LASpoint14*)last_item)->classification < 32) { ((LASpoint14*)last_item)->legacy_classification = ((LASpoint14*)last_item)->classification; } else { ((LASpoint14*)last_item)->legacy_classification = 0; } } //////////////////////////////////////// // decompress flags layer (if changed and requested) //////////////////////////////////////// if (changed_flags) // if the flags should be decompressed and change within this chunk { U32 last_flags = (((LASpoint14*)last_item)->edge_of_flight_line << 5) | (((LASpoint14*)last_item)->scan_direction_flag << 4) | ((LASpoint14*)last_item)->classification_flags; if (contexts[current_context].m_flags[last_flags] == 0) { contexts[current_context].m_flags[last_flags] = dec_flags->createSymbolModel(64); dec_flags->initSymbolModel(contexts[current_context].m_flags[last_flags]); } U32 flags = dec_flags->decodeSymbol(contexts[current_context].m_flags[last_flags]); ((LASpoint14*)last_item)->edge_of_flight_line = !!(flags & (1 << 5)); ((LASpoint14*)last_item)->scan_direction_flag = !!(flags & (1 << 4)); ((LASpoint14*)last_item)->classification_flags = (flags & 0x0F); // legacy copies ((LASpoint14*)last_item)->legacy_flags = (flags & 0x07); } //////////////////////////////////////// // decompress intensity layer (if changed and requested) //////////////////////////////////////// if (changed_intensity) // if the intensity should be decompressed and changes within this chunk { U16 intensity = contexts[current_context].ic_intensity->decompress(contexts[current_context].last_intensity[(cpr<<1) | gps_time_change], cpr); contexts[current_context].last_intensity[(cpr<<1) | gps_time_change] = intensity; ((LASpoint14*)last_item)->intensity = intensity; } //////////////////////////////////////// // decompress scan_angle layer (if changed and requested) //////////////////////////////////////// if (changed_scan_angle) // if the scan angle should be decompressed and changes within this chunk { if (scan_angle_change) // if the scan angle has actually changed { ((LASpoint14*)last_item)->scan_angle = contexts[current_context].ic_scan_angle->decompress(((LASpoint14*)last_item)->scan_angle, gps_time_change); // if the GPS time has changed ((LASpoint14*)last_item)->legacy_scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*((LASpoint14*)last_item)->scan_angle)); } } //////////////////////////////////////// // decompress user_data layer (if changed and requested) //////////////////////////////////////// if (changed_user_data) // if the user data should be decompressed and changes within this chunk { if (contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] == 0) { contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] = dec_user_data->createSymbolModel(256); dec_user_data->initSymbolModel(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } ((LASpoint14*)last_item)->user_data = dec_user_data->decodeSymbol(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } //////////////////////////////////////// // decompress point_source layer (if changed and requested) //////////////////////////////////////// if (changed_point_source) // if the point source ID should be decompressed and changes within this chunk { if (point_source_change) // if the point source ID has actually changed { ((LASpoint14*)last_item)->point_source_ID = contexts[current_context].ic_point_source_ID->decompress(((LASpoint14*)last_item)->point_source_ID); } } //////////////////////////////////////// // decompress gps_time layer (if changed and requested) //////////////////////////////////////// if (changed_gps_time) // if the GPS time should be decompressed and changes within this chunk { if (gps_time_change) // if the GPS time has actually changed { read_gps_time(); ((LASpoint14*)last_item)->gps_time = contexts[current_context].last_gpstime[contexts[current_context].last].f64; } } // copy the last item memcpy(item, last_item, sizeof(LASpoint14)); // remember if the last point had a gps_time_change ((LASpoint14*)last_item)->gps_time_change = gps_time_change; } void LASreadItemCompressed_POINT14_v4::read_gps_time() { I32 multi; if (contexts[current_context].last_gpstime_diff[contexts[current_context].last] == 0) // if the last integer difference was zero { multi = dec_gps_time->decodeSymbol(contexts[current_context].m_gpstime_0diff); if (multi == 0) // the difference can be represented with 32 bits { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = contexts[current_context].ic_gpstime->decompress(0, 0); contexts[current_context].last_gpstime[contexts[current_context].last].i64 += contexts[current_context].last_gpstime_diff[contexts[current_context].last]; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi == 1) // the difference is huge { contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].ic_gpstime->decompress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), 8); contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].last_gpstime[contexts[current_context].next].u64 << 32; contexts[current_context].last_gpstime[contexts[current_context].next].u64 |= dec_gps_time->readInt(); contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else // we switch to another sequence { contexts[current_context].last = (contexts[current_context].last+multi-1)&3; read_gps_time(); } } else { multi = dec_gps_time->decodeSymbol(contexts[current_context].m_gpstime_multi); if (multi == 1) { contexts[current_context].last_gpstime[contexts[current_context].last].i64 += contexts[current_context].ic_gpstime->decompress(contexts[current_context].last_gpstime_diff[contexts[current_context].last], 1);; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi < LASZIP_GPSTIME_MULTI_CODE_FULL) { I32 gpstime_diff; if (multi == 0) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(0, 7); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } else if (multi < LASZIP_GPSTIME_MULTI) { if (multi < 10) gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 2); else gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 3); } else if (multi == LASZIP_GPSTIME_MULTI) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(LASZIP_GPSTIME_MULTI*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 4); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } else { multi = LASZIP_GPSTIME_MULTI - multi; if (multi > LASZIP_GPSTIME_MULTI_MINUS) { gpstime_diff = contexts[current_context].ic_gpstime->decompress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 5); } else { gpstime_diff = contexts[current_context].ic_gpstime->decompress(LASZIP_GPSTIME_MULTI_MINUS*contexts[current_context].last_gpstime_diff[contexts[current_context].last], 6); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } contexts[current_context].last_gpstime[contexts[current_context].last].i64 += gpstime_diff; } else if (multi == LASZIP_GPSTIME_MULTI_CODE_FULL) { contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].ic_gpstime->decompress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), 8); contexts[current_context].last_gpstime[contexts[current_context].next].u64 = contexts[current_context].last_gpstime[contexts[current_context].next].u64 << 32; contexts[current_context].last_gpstime[contexts[current_context].next].u64 |= dec_gps_time->readInt(); contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi >= LASZIP_GPSTIME_MULTI_CODE_FULL) { contexts[current_context].last = (contexts[current_context].last+multi-LASZIP_GPSTIME_MULTI_CODE_FULL)&3; read_gps_time(); } } } /* =============================================================================== LASreadItemCompressed_RGB14_v4 =============================================================================== */ LASreadItemCompressed_RGB14_v4::LASreadItemCompressed_RGB14_v4(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_RGB = 0; dec_RGB = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; changed_RGB = FALSE; requested_RGB = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_RGB ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_byte_used = 0; } current_context = 0; } LASreadItemCompressed_RGB14_v4::~LASreadItemCompressed_RGB14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_byte_used) { dec_RGB->destroySymbolModel(contexts[c].m_byte_used); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } } /* destroy all instreams and decoders */ if (instream_RGB) { delete instream_RGB; delete dec_RGB; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_RGB14_v4::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_byte_used == 0) { contexts[context].m_byte_used = dec_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = dec_RGB->createSymbolModel(256); } /* then init entropy models */ dec_RGB->initSymbolModel(contexts[context].m_byte_used); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); /* init current context from item */ memcpy(contexts[context].last_item, item, 6); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_RGB14_v4::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_RGB)); return TRUE; } BOOL LASreadItemCompressed_RGB14_v4::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_RGB == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_RGB = new ByteStreamInArrayLE(); } else { instream_RGB = new ByteStreamInArrayBE(); } /* create decoders */ dec_RGB = new ArithmeticDecoder(); } /* make sure the buffer is sufficiently large */ if (num_bytes_RGB > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes_RGB]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes_RGB; } /* load the requested bytes and init the corresponding instreams an decoders */ if (requested_RGB) { if (num_bytes_RGB) { instream->getBytes(bytes, num_bytes_RGB); instream_RGB->init(bytes, num_bytes_RGB); dec_RGB->init(instream_RGB); changed_RGB = TRUE; } else { instream_RGB->init(0, 0); changed_RGB = FALSE; } } else { if (num_bytes_RGB) { instream->skipBytes(num_bytes_RGB); } changed_RGB = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_RGB14_v4::read(U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } // decompress if (changed_RGB) { U8 corr; I32 diff = 0; U32 sym = dec_RGB->decodeSymbol(contexts[current_context].m_byte_used); if (sym & (1 << 0)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_0); ((U16*)item)[0] = (U16)U8_FOLD(corr + (last_item[0]&255)); } else { ((U16*)item)[0] = last_item[0]&0xFF; } if (sym & (1 << 1)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_1); ((U16*)item)[0] |= (((U16)U8_FOLD(corr + (last_item[0]>>8))) << 8); } else { ((U16*)item)[0] |= (last_item[0]&0xFF00); } if (sym & (1 << 6)) { diff = (((U16*)item)[0]&0x00FF) - (last_item[0]&0x00FF); if (sym & (1 << 2)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_2); ((U16*)item)[1] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]&255))); } else { ((U16*)item)[1] = last_item[1]&0xFF; } if (sym & (1 << 4)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_4); diff = (diff + ((((U16*)item)[1]&0x00FF) - (last_item[1]&0x00FF))) / 2; ((U16*)item)[2] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]&255))); } else { ((U16*)item)[2] = last_item[2]&0xFF; } diff = (((U16*)item)[0]>>8) - (last_item[0]>>8); if (sym & (1 << 3)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_3); ((U16*)item)[1] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]>>8))))<<8); } else { ((U16*)item)[1] |= (last_item[1]&0xFF00); } if (sym & (1 << 5)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_5); diff = (diff + ((((U16*)item)[1]>>8) - (last_item[1]>>8))) / 2; ((U16*)item)[2] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]>>8))))<<8); } else { ((U16*)item)[2] |= (last_item[2]&0xFF00); } } else { ((U16*)item)[1] = ((U16*)item)[0]; ((U16*)item)[2] = ((U16*)item)[0]; } memcpy(last_item, item, 6); } else { memcpy(item, last_item, 6); } } /* =============================================================================== LASreadItemCompressed_RGBNIR14_v4 =============================================================================== */ LASreadItemCompressed_RGBNIR14_v4::LASreadItemCompressed_RGBNIR14_v4(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_RGB = 0; instream_NIR = 0; dec_RGB = 0; dec_NIR = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; num_bytes_NIR = 0; changed_RGB = FALSE; changed_NIR = FALSE; requested_RGB = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_RGB ? TRUE : FALSE); requested_NIR = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_NIR ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_rgb_bytes_used = 0; contexts[c].m_nir_bytes_used = 0; } current_context = 0; } LASreadItemCompressed_RGBNIR14_v4::~LASreadItemCompressed_RGBNIR14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_rgb_bytes_used) { dec_RGB->destroySymbolModel(contexts[c].m_rgb_bytes_used); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); dec_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } if (contexts[c].m_nir_bytes_used) { dec_NIR->destroySymbolModel(contexts[c].m_nir_bytes_used); dec_NIR->destroySymbolModel(contexts[c].m_nir_diff_0); dec_NIR->destroySymbolModel(contexts[c].m_nir_diff_1); } } /* destroy all instreams and decoders */ if (instream_RGB) { delete instream_RGB; delete dec_RGB; } if (instream_NIR) { delete instream_NIR; delete dec_NIR; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_RGBNIR14_v4::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (requested_RGB) { if (contexts[context].m_rgb_bytes_used == 0) { contexts[context].m_rgb_bytes_used = dec_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = dec_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = dec_RGB->createSymbolModel(256); } /* then init entropy models */ dec_RGB->initSymbolModel(contexts[context].m_rgb_bytes_used); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); dec_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); } if (requested_NIR) { if (contexts[context].m_nir_bytes_used == 0) { contexts[context].m_nir_bytes_used = dec_NIR->createSymbolModel(4); contexts[context].m_nir_diff_0 = dec_NIR->createSymbolModel(256); contexts[context].m_nir_diff_1 = dec_NIR->createSymbolModel(256); } /* then init entropy models */ dec_NIR->initSymbolModel(contexts[context].m_nir_bytes_used); dec_NIR->initSymbolModel(contexts[context].m_nir_diff_0); dec_NIR->initSymbolModel(contexts[context].m_nir_diff_1); } /* init current context from item */ memcpy(contexts[context].last_item, item, 8); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_RGBNIR14_v4::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_RGB)); instream->get32bitsLE(((U8*)&num_bytes_NIR)); return TRUE; } BOOL LASreadItemCompressed_RGBNIR14_v4::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_RGB == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_RGB = new ByteStreamInArrayLE(); instream_NIR = new ByteStreamInArrayLE(); } else { instream_RGB = new ByteStreamInArrayBE(); instream_NIR = new ByteStreamInArrayBE(); } /* create decoders */ dec_RGB = new ArithmeticDecoder(); dec_NIR = new ArithmeticDecoder(); } /* how many bytes do we need to read */ U32 num_bytes = 0; if (requested_RGB) num_bytes += num_bytes_RGB; if (requested_NIR) num_bytes += num_bytes_NIR; /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams an decoders */ num_bytes = 0; if (requested_RGB) { if (num_bytes_RGB) { instream->getBytes(bytes, num_bytes_RGB); num_bytes += num_bytes_RGB; instream_RGB->init(bytes, num_bytes_RGB); dec_RGB->init(instream_RGB); changed_RGB = TRUE; } else { instream_RGB->init(0, 0); changed_RGB = FALSE; } } else { if (num_bytes_RGB) { instream->skipBytes(num_bytes_RGB); } changed_RGB = FALSE; } if (requested_NIR) { if (num_bytes_NIR) { instream->getBytes(&bytes[num_bytes], num_bytes_NIR); instream_NIR->init(&bytes[num_bytes], num_bytes_NIR); dec_NIR->init(instream_NIR); changed_NIR = TRUE; } else { instream_NIR->init(0, 0); changed_NIR = FALSE; } } else { if (num_bytes_NIR) { instream->skipBytes(num_bytes_NIR); } changed_NIR = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_RGBNIR14_v4::read(U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } // decompress //////////////////////////////////////// // decompress RGB layer //////////////////////////////////////// if (changed_RGB) { U8 corr; I32 diff = 0; U32 sym = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_bytes_used); if (sym & (1 << 0)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_0); ((U16*)item)[0] = (U16)U8_FOLD(corr + (last_item[0]&255)); } else { ((U16*)item)[0] = last_item[0]&0xFF; } if (sym & (1 << 1)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_1); ((U16*)item)[0] |= (((U16)U8_FOLD(corr + (last_item[0]>>8))) << 8); } else { ((U16*)item)[0] |= (last_item[0]&0xFF00); } if (sym & (1 << 6)) { diff = (((U16*)item)[0]&0x00FF) - (last_item[0]&0x00FF); if (sym & (1 << 2)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_2); ((U16*)item)[1] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]&255))); } else { ((U16*)item)[1] = last_item[1]&0xFF; } if (sym & (1 << 4)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_4); diff = (diff + ((((U16*)item)[1]&0x00FF) - (last_item[1]&0x00FF))) / 2; ((U16*)item)[2] = (U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]&255))); } else { ((U16*)item)[2] = last_item[2]&0xFF; } diff = (((U16*)item)[0]>>8) - (last_item[0]>>8); if (sym & (1 << 3)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_3); ((U16*)item)[1] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[1]>>8))))<<8); } else { ((U16*)item)[1] |= (last_item[1]&0xFF00); } if (sym & (1 << 5)) { corr = dec_RGB->decodeSymbol(contexts[current_context].m_rgb_diff_5); diff = (diff + ((((U16*)item)[1]>>8) - (last_item[1]>>8))) / 2; ((U16*)item)[2] |= (((U16)U8_FOLD(corr + U8_CLAMP(diff+(last_item[2]>>8))))<<8); } else { ((U16*)item)[2] |= (last_item[2]&0xFF00); } } else { ((U16*)item)[1] = ((U16*)item)[0]; ((U16*)item)[2] = ((U16*)item)[0]; } memcpy(last_item, item, 6); } else { memcpy(item, last_item, 6); } //////////////////////////////////////// // decompress NIR layer //////////////////////////////////////// if (changed_NIR) { U8 corr; U32 sym = dec_NIR->decodeSymbol(contexts[current_context].m_nir_bytes_used); if (sym & (1 << 0)) { corr = dec_NIR->decodeSymbol(contexts[current_context].m_nir_diff_0); ((U16*)item)[3] = (U16)U8_FOLD(corr + (last_item[3]&255)); } else { ((U16*)item)[3] = last_item[3]&0xFF; } if (sym & (1 << 1)) { corr = dec_NIR->decodeSymbol(contexts[current_context].m_nir_diff_1); ((U16*)item)[3] |= (((U16)U8_FOLD(corr + (last_item[3]>>8))) << 8); } else { ((U16*)item)[3] |= (last_item[3]&0xFF00); } contexts[current_context].last_item[3] = ((U16*)item)[3]; } else { ((U16*)item)[3] = contexts[current_context].last_item[3]; } } /* =============================================================================== LASreadItemCompressed_WAVEPACKET14_v4 =============================================================================== */ LASreadItemCompressed_WAVEPACKET14_v4::LASreadItemCompressed_WAVEPACKET14_v4(ArithmeticDecoder* dec, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* zero instreams and decoders */ instream_wavepacket = 0; dec_wavepacket = 0; /* zero num_bytes and init booleans */ num_bytes_wavepacket = 0; changed_wavepacket = FALSE; requested_wavepacket = (decompress_selective & LASZIP_DECOMPRESS_SELECTIVE_WAVEPACKET ? TRUE : FALSE); /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_packet_index = 0; } current_context = 0; } LASreadItemCompressed_WAVEPACKET14_v4::~LASreadItemCompressed_WAVEPACKET14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_packet_index) { dec_wavepacket->destroySymbolModel(contexts[c].m_packet_index); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[0]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[1]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[2]); dec_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[3]); delete contexts[c].ic_offset_diff; delete contexts[c].ic_packet_size; delete contexts[c].ic_return_point; delete contexts[c].ic_xyz; } } /* destroy all instreams and decoders */ if (instream_wavepacket) { delete instream_wavepacket; delete dec_wavepacket; } if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_WAVEPACKET14_v4::createAndInitModelsAndDecompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (requested_wavepacket) { if (contexts[context].m_packet_index == 0) { contexts[context].m_packet_index = dec_wavepacket->createSymbolModel(256); contexts[context].m_offset_diff[0] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[1] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[2] = dec_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[3] = dec_wavepacket->createSymbolModel(4); contexts[context].ic_offset_diff = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_packet_size = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_return_point = new IntegerCompressor(dec_wavepacket, 32); contexts[context].ic_xyz = new IntegerCompressor(dec_wavepacket, 32, 3); } /* then init entropy models */ dec_wavepacket->initSymbolModel(contexts[context].m_packet_index); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[0]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[1]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[2]); dec_wavepacket->initSymbolModel(contexts[context].m_offset_diff[3]); contexts[context].ic_offset_diff->initDecompressor(); contexts[context].ic_packet_size->initDecompressor(); contexts[context].ic_return_point->initDecompressor(); contexts[context].ic_xyz->initDecompressor(); } /* init current context from item */ contexts[context].last_diff_32 = 0; contexts[context].sym_last_offset_diff = 0; memcpy(contexts[context].last_item, item, 29); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_WAVEPACKET14_v4::chunk_sizes() { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* read bytes per layer */ instream->get32bitsLE(((U8*)&num_bytes_wavepacket)); return TRUE; } BOOL LASreadItemCompressed_WAVEPACKET14_v4::init(const U8* item, U32& context) { /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_wavepacket == 0) { /* create instreams */ if (IS_LITTLE_ENDIAN()) { instream_wavepacket = new ByteStreamInArrayLE(); } else { instream_wavepacket = new ByteStreamInArrayBE(); } /* create decoders */ dec_wavepacket = new ArithmeticDecoder(); } /* make sure the buffer is sufficiently large */ if (num_bytes_wavepacket > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes_wavepacket]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes_wavepacket; } /* load the requested bytes and init the corresponding instreams an decoders */ if (requested_wavepacket) { if (num_bytes_wavepacket) { instream->getBytes(bytes, num_bytes_wavepacket); instream_wavepacket->init(bytes, num_bytes_wavepacket); dec_wavepacket->init(instream_wavepacket); changed_wavepacket = TRUE; } else { instream_wavepacket->init(0, 0); changed_wavepacket = FALSE; } } else { if (num_bytes_wavepacket) { instream->skipBytes(num_bytes_wavepacket); } changed_wavepacket = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_WAVEPACKET14_v4::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, last_item); } last_item = contexts[current_context].last_item; } // decompress if (changed_wavepacket) { item[0] = (U8)(dec_wavepacket->decodeSymbol(contexts[current_context].m_packet_index)); LASwavepacket13 this_item_m; LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item+1); contexts[current_context].sym_last_offset_diff = dec_wavepacket->decodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff]); if (contexts[current_context].sym_last_offset_diff == 0) { this_item_m.offset = last_item_m.offset; } else if (contexts[current_context].sym_last_offset_diff == 1) { this_item_m.offset = last_item_m.offset + last_item_m.packet_size; } else if (contexts[current_context].sym_last_offset_diff == 2) { contexts[current_context].last_diff_32 = contexts[current_context].ic_offset_diff->decompress(contexts[current_context].last_diff_32); this_item_m.offset = last_item_m.offset + contexts[current_context].last_diff_32; } else { this_item_m.offset = dec_wavepacket->readInt64(); } this_item_m.packet_size = contexts[current_context].ic_packet_size->decompress(last_item_m.packet_size); this_item_m.return_point.i32 = contexts[current_context].ic_return_point->decompress(last_item_m.return_point.i32); this_item_m.x.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.x.i32, 0); this_item_m.y.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.y.i32, 1); this_item_m.z.i32 = contexts[current_context].ic_xyz->decompress(last_item_m.z.i32, 2); this_item_m.pack(item+1); memcpy(last_item, item, 29); } } /* =============================================================================== LASreadItemCompressed_BYTE14_v4 =============================================================================== */ LASreadItemCompressed_BYTE14_v4::LASreadItemCompressed_BYTE14_v4(ArithmeticDecoder* dec, U32 number, const U32 decompress_selective) { /* not used as a decoder. just gives access to instream */ assert(dec); this->dec = dec; /* must be more than one byte */ assert(number); this->number = number; /* zero instream and decoder pointer arrays */ instream_Bytes = 0; dec_Bytes = 0; /* create and init num_bytes and booleans arrays */ num_bytes_Bytes = new U32[number]; changed_Bytes = new BOOL[number]; requested_Bytes = new BOOL[number]; U32 i; for (i = 0; i < number; i++) { num_bytes_Bytes[i] = 0; changed_Bytes[i] = FALSE; if (i > 15) // currently only the first 16 extra bytes can be selectively decompressed { requested_Bytes[i] = TRUE; } else { requested_Bytes[i] = (decompress_selective & (LASZIP_DECOMPRESS_SELECTIVE_BYTE0 << i) ? TRUE : FALSE); } } /* init the bytes buffer to zero */ bytes = 0; num_bytes_allocated = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_bytes = 0; } current_context = 0; } LASreadItemCompressed_BYTE14_v4::~LASreadItemCompressed_BYTE14_v4() { /* destroy all initialized scanner channel contexts */ U32 c, i; for (c = 0; c < 4; c++) { if (contexts[c].m_bytes) { for (i = 0; i < number; i++) { dec_Bytes[i]->destroySymbolModel(contexts[c].m_bytes[i]); } delete [] contexts[c].m_bytes; delete [] contexts[c].last_item; } } /* destroy all instream and decoder arrays */ if (instream_Bytes) { for (i = 0; i < number; i++) { if (instream_Bytes[i]) { delete instream_Bytes[i]; delete dec_Bytes[i]; } } delete [] instream_Bytes; delete [] dec_Bytes; } /* destroy all other arrays */ if (num_bytes_Bytes) delete [] num_bytes_Bytes; if (changed_Bytes) delete [] changed_Bytes; if (requested_Bytes) delete [] requested_Bytes; if (bytes) delete [] bytes; } inline BOOL LASreadItemCompressed_BYTE14_v4::createAndInitModelsAndDecompressors(U32 context, const U8* item) { U32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and last items (if needed) */ if (contexts[context].m_bytes == 0) { contexts[context].m_bytes = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { contexts[context].m_bytes[i] = dec_Bytes[i]->createSymbolModel(256); dec_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* create last item */ contexts[context].last_item = new U8[number]; } /* then init entropy models */ for (i = 0; i < number; i++) { dec_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* init current context from item */ memcpy(contexts[context].last_item, item, number); contexts[context].unused = FALSE; return TRUE; } BOOL LASreadItemCompressed_BYTE14_v4::chunk_sizes() { U32 i; /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); for (i = 0; i < number; i++) { /* read bytes per layer */ instream->get32bitsLE(((U8*)&(num_bytes_Bytes[i]))); } return TRUE; } BOOL LASreadItemCompressed_BYTE14_v4::init(const U8* item, U32& context) { U32 i; /* for layered compression 'dec' only hands over the stream */ ByteStreamIn* instream = dec->getByteStreamIn(); /* on the first init create instreams and decoders */ if (instream_Bytes == 0) { /* create instream pointer array */ instream_Bytes = new ByteStreamInArray*[number]; /* create instreams */ if (IS_LITTLE_ENDIAN()) { for (i = 0; i < number; i++) { instream_Bytes[i] = new ByteStreamInArrayLE(); } } else { for (i = 0; i < number; i++) { instream_Bytes[i] = new ByteStreamInArrayBE(); } } /* create decoder pointer array */ dec_Bytes = new ArithmeticDecoder*[number]; /* create layer decoders */ for (i = 0; i < number; i++) { dec_Bytes[i] = new ArithmeticDecoder(); } } /* how many bytes do we need to read */ U32 num_bytes = 0; for (i = 0; i < number; i++) { if (requested_Bytes[i]) num_bytes += num_bytes_Bytes[i]; } /* make sure the buffer is sufficiently large */ if (num_bytes > num_bytes_allocated) { if (bytes) delete [] bytes; bytes = new U8[num_bytes]; if (bytes == 0) return FALSE; num_bytes_allocated = num_bytes; } /* load the requested bytes and init the corresponding instreams an decoders */ num_bytes = 0; for (i = 0; i < number; i++) { if (requested_Bytes[i]) { if (num_bytes_Bytes[i]) { instream->getBytes(&(bytes[num_bytes]), num_bytes_Bytes[i]); instream_Bytes[i]->init(&(bytes[num_bytes]), num_bytes_Bytes[i]); dec_Bytes[i]->init(instream_Bytes[i]); num_bytes += num_bytes_Bytes[i]; changed_Bytes[i] = TRUE; } else { dec_Bytes[i]->init(0, 0); changed_Bytes[i] = FALSE; } } else { if (num_bytes_Bytes[i]) { instream->skipBytes(num_bytes_Bytes[i]); } changed_Bytes[i] = FALSE; } } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 reader /* create and init models and decompressors */ createAndInitModelsAndDecompressors(current_context, item); return TRUE; } inline void LASreadItemCompressed_BYTE14_v4::read(U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 reader if (contexts[current_context].unused) { createAndInitModelsAndDecompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } // decompress U32 i; for (i = 0; i < number; i++) { if (changed_Bytes[i]) { I32 value = last_item[i] + dec_Bytes[i]->decodeSymbol(contexts[current_context].m_bytes[i]); item[i] = U8_FOLD(value); last_item[i] = item[i]; } else { item[i] = last_item[i]; } } } LASzip-3.4.3/src/lasreaditemcompressed_v4.hpp000066400000000000000000000156611356234217100211700ustar00rootroot00000000000000/* =============================================================================== FILE: lasreaditemcompressed_v4.hpp CONTENTS: Native extension for decompressing the *new* point types 6 to 10 of LAS 1.4 PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 19 March 2019 -- set "legacy classification" to zero if "classification > 31" 28 December 2017 -- fix incorrect 'context switch' reported by Wanwannodao 28 August 2017 -- moving 'context' from global development hack to interface 19 April 2017 -- support for selective decompression for new LAS 1.4 points 22 June 2016 -- created after Island beat Austria 2:1 in the EM2016 =============================================================================== */ #ifndef LAS_READ_ITEM_COMPRESSED_V4_HPP #define LAS_READ_ITEM_COMPRESSED_V4_HPP #include "lasreaditem.hpp" #include "arithmeticdecoder.hpp" #include "integercompressor.hpp" #include "bytestreamin_array.hpp" #include "laszip_common_v3.hpp" #include "laszip_decompress_selective_v3.hpp" class LASreadItemCompressed_POINT14_v4 : public LASreadItemCompressed { public: LASreadItemCompressed_POINT14_v4(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is set void read(U8* item, U32& context); // context is set ~LASreadItemCompressed_POINT14_v4(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_channel_returns_XY; ByteStreamInArray* instream_Z; ByteStreamInArray* instream_classification; ByteStreamInArray* instream_flags; ByteStreamInArray* instream_intensity; ByteStreamInArray* instream_scan_angle; ByteStreamInArray* instream_user_data; ByteStreamInArray* instream_point_source; ByteStreamInArray* instream_gps_time; ArithmeticDecoder* dec_channel_returns_XY; ArithmeticDecoder* dec_Z; ArithmeticDecoder* dec_classification; ArithmeticDecoder* dec_flags; ArithmeticDecoder* dec_intensity; ArithmeticDecoder* dec_scan_angle; ArithmeticDecoder* dec_user_data; ArithmeticDecoder* dec_point_source; ArithmeticDecoder* dec_gps_time; BOOL changed_Z; BOOL changed_classification; BOOL changed_flags; BOOL changed_intensity; BOOL changed_scan_angle; BOOL changed_user_data; BOOL changed_point_source; BOOL changed_gps_time; U32 num_bytes_channel_returns_XY; U32 num_bytes_Z; U32 num_bytes_classification; U32 num_bytes_flags; U32 num_bytes_intensity; U32 num_bytes_scan_angle; U32 num_bytes_user_data; U32 num_bytes_point_source; U32 num_bytes_gps_time; BOOL requested_Z; BOOL requested_classification; BOOL requested_flags; BOOL requested_intensity; BOOL requested_scan_angle; BOOL requested_user_data; BOOL requested_point_source; BOOL requested_gps_time; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextPOINT14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); void read_gps_time(); }; class LASreadItemCompressed_RGB14_v4 : public LASreadItemCompressed { public: LASreadItemCompressed_RGB14_v4(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_RGB14_v4(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_RGB; ArithmeticDecoder* dec_RGB; BOOL changed_RGB; U32 num_bytes_RGB; BOOL requested_RGB; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextRGB14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_RGBNIR14_v4 : public LASreadItemCompressed { public: LASreadItemCompressed_RGBNIR14_v4(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_RGBNIR14_v4(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_RGB; ByteStreamInArray* instream_NIR; ArithmeticDecoder* dec_RGB; ArithmeticDecoder* dec_NIR; BOOL changed_RGB; BOOL changed_NIR; U32 num_bytes_RGB; U32 num_bytes_NIR; BOOL requested_RGB; BOOL requested_NIR; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextRGBNIR14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_WAVEPACKET14_v4 : public LASreadItemCompressed { public: LASreadItemCompressed_WAVEPACKET14_v4(ArithmeticDecoder* dec, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_WAVEPACKET14_v4(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray* instream_wavepacket; ArithmeticDecoder* dec_wavepacket; BOOL changed_wavepacket; U32 num_bytes_wavepacket; BOOL requested_wavepacket; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextWAVEPACKET14 contexts[4]; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; class LASreadItemCompressed_BYTE14_v4 : public LASreadItemCompressed { public: LASreadItemCompressed_BYTE14_v4(ArithmeticDecoder* dec, U32 number, const U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL chunk_sizes(); BOOL init(const U8* item, U32& context); // context is only read void read(U8* item, U32& context); // context is only read ~LASreadItemCompressed_BYTE14_v4(); private: /* not used as a decoder. just gives access to instream */ ArithmeticDecoder* dec; ByteStreamInArray** instream_Bytes; ArithmeticDecoder** dec_Bytes; U32* num_bytes_Bytes; BOOL* changed_Bytes; BOOL* requested_Bytes; U8* bytes; U32 num_bytes_allocated; U32 current_context; LAScontextBYTE14 contexts[4]; U32 number; BOOL createAndInitModelsAndDecompressors(U32 context, const U8* item); }; #endif LASzip-3.4.3/src/lasreaditemraw.hpp000066400000000000000000000266751356234217100172130ustar00rootroot00000000000000/* =============================================================================== FILE: lasitemreadraw.hpp CONTENTS: Implementation of LASitemReadRaw for *all* items that compose a point. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 10 January 2011 -- licensing change for LGPL release and liblas integration 7 December 2010 -- refactored after getting invited to KAUST in Saudi Arabia =============================================================================== */ #ifndef LAS_READ_ITEM_RAW_HPP #define LAS_READ_ITEM_RAW_HPP #include "lasreaditem.hpp" #include class LASreadItemRaw_POINT10_LE : public LASreadItemRaw { public: LASreadItemRaw_POINT10_LE(){}; inline void read(U8* item, U32& context) { instream->getBytes(item, 20); } }; class LASreadItemRaw_POINT10_BE : public LASreadItemRaw { public: LASreadItemRaw_POINT10_BE(){}; inline void read(U8* item, U32& context) { instream->getBytes(swapped, 20); ENDIAN_SWAP_32(&swapped[ 0], &item[ 0]); // X ENDIAN_SWAP_32(&swapped[ 4], &item[ 4]); // Y ENDIAN_SWAP_32(&swapped[ 8], &item[ 8]); // Z ENDIAN_SWAP_16(&swapped[12], &item[12]); // intensity *((U32*)&item[14]) = *((U32*)&swapped[14]); // bitfield, classification, scan_angle_rank, user_data ENDIAN_SWAP_16(&swapped[18], &item[18]); // point_source_ID }; private: U8 swapped[20]; }; class LASreadItemRaw_GPSTIME11_LE : public LASreadItemRaw { public: LASreadItemRaw_GPSTIME11_LE(){}; inline void read(U8* item, U32& context) { instream->getBytes(item, 8); }; }; class LASreadItemRaw_GPSTIME11_BE : public LASreadItemRaw { public: LASreadItemRaw_GPSTIME11_BE(){}; inline void read(U8* item, U32& context) { instream->getBytes(swapped, 8); ENDIAN_SWAP_64(swapped, item); }; private: U8 swapped[8]; }; class LASreadItemRaw_RGB12_LE : public LASreadItemRaw { public: LASreadItemRaw_RGB12_LE(){}; inline void read(U8* item, U32& context) { instream->getBytes(item, 6); }; }; class LASreadItemRaw_RGB12_BE : public LASreadItemRaw { public: LASreadItemRaw_RGB12_BE(){}; inline void read(U8* item, U32& context) { instream->getBytes(swapped, 6); ENDIAN_SWAP_32(&swapped[ 0], &item[ 0]); // R ENDIAN_SWAP_32(&swapped[ 2], &item[ 2]); // G ENDIAN_SWAP_32(&swapped[ 4], &item[ 4]); // B }; private: U8 swapped[6]; }; class LASreadItemRaw_WAVEPACKET13_LE : public LASreadItemRaw { public: LASreadItemRaw_WAVEPACKET13_LE(){} inline void read(U8* item, U32& context) { instream->getBytes(item, 29); }; }; class LASreadItemRaw_WAVEPACKET13_BE : public LASreadItemRaw { public: LASreadItemRaw_WAVEPACKET13_BE(){} inline void read(U8* item, U32& context) { instream->getBytes(swapped, 29); item[0] = swapped[0]; // wavepacket descriptor index ENDIAN_SWAP_64(&swapped[ 1], &item[ 1]); // byte offset to waveform data ENDIAN_SWAP_32(&swapped[ 9], &item[ 9]); // waveform packet size in bytes ENDIAN_SWAP_32(&swapped[13], &item[13]); // return point waveform location ENDIAN_SWAP_32(&swapped[17], &item[17]); // X(t) ENDIAN_SWAP_32(&swapped[21], &item[21]); // Y(t) ENDIAN_SWAP_32(&swapped[25], &item[25]); // Z(t) }; private: U8 swapped[29]; }; class LASreadItemRaw_BYTE : public LASreadItemRaw { public: LASreadItemRaw_BYTE(U32 number) { this->number = number; } inline void read(U8* item, U32& context) { instream->getBytes(item, number); }; private: U32 number; }; class LAStempReadPoint10 { public: I32 X; I32 Y; I32 Z; U16 intensity; U8 return_number : 3; U8 number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 extended_scan_angle; U8 extended_point_type : 2; U8 extended_scanner_channel : 2; U8 extended_classification_flags : 4; U8 extended_classification; U8 extended_return_number : 4; U8 extended_number_of_returns : 4; // for 8 byte alignment of the GPS time U8 dummy[3]; // LASlib only U32 deleted_flag; F64 gps_time; }; class LAStempReadPoint14 { public: I32 X; I32 Y; I32 Z; U16 intensity; U8 return_number : 4; U8 number_of_returns : 4; U8 classification_flags : 4; U8 scanner_channel : 2; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; U8 user_data; I16 scan_angle; U16 point_source_ID; }; class LASreadItemRaw_POINT14_LE : public LASreadItemRaw { public: LASreadItemRaw_POINT14_LE(){}; inline void read(U8* item, U32& context) { instream->getBytes(buffer, 30); ((LAStempReadPoint10*)item)->X = ((LAStempReadPoint14*)buffer)->X; ((LAStempReadPoint10*)item)->Y = ((LAStempReadPoint14*)buffer)->Y; ((LAStempReadPoint10*)item)->Z = ((LAStempReadPoint14*)buffer)->Z; ((LAStempReadPoint10*)item)->intensity = ((LAStempReadPoint14*)buffer)->intensity; if (((LAStempReadPoint14*)buffer)->number_of_returns > 7) { if (((LAStempReadPoint14*)buffer)->return_number > 6) { if (((LAStempReadPoint14*)buffer)->return_number >= ((LAStempReadPoint14*)buffer)->number_of_returns) { ((LAStempReadPoint10*)item)->return_number = 7; } else { ((LAStempReadPoint10*)item)->return_number = 6; } } else { ((LAStempReadPoint10*)item)->return_number = ((LAStempReadPoint14*)buffer)->return_number; } ((LAStempReadPoint10*)item)->number_of_returns = 7; } else { ((LAStempReadPoint10*)item)->return_number = ((LAStempReadPoint14*)buffer)->return_number; ((LAStempReadPoint10*)item)->number_of_returns = ((LAStempReadPoint14*)buffer)->number_of_returns; } ((LAStempReadPoint10*)item)->scan_direction_flag = ((LAStempReadPoint14*)buffer)->scan_direction_flag; ((LAStempReadPoint10*)item)->edge_of_flight_line = ((LAStempReadPoint14*)buffer)->edge_of_flight_line; ((LAStempReadPoint10*)item)->classification = (U8)(((((LAStempReadPoint14*)buffer)->classification_flags) << 5) & 0xE0); if (((LAStempReadPoint14*)buffer)->classification < 32) ((LAStempReadPoint10*)item)->classification |= ((LAStempReadPoint14*)buffer)->classification; ((LAStempReadPoint10*)item)->scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*((LAStempReadPoint14*)buffer)->scan_angle)); ((LAStempReadPoint10*)item)->user_data = ((LAStempReadPoint14*)buffer)->user_data; ((LAStempReadPoint10*)item)->point_source_ID = ((LAStempReadPoint14*)buffer)->point_source_ID; ((LAStempReadPoint10*)item)->extended_scanner_channel = ((LAStempReadPoint14*)buffer)->scanner_channel; ((LAStempReadPoint10*)item)->extended_classification_flags = ((LAStempReadPoint14*)buffer)->classification_flags; ((LAStempReadPoint10*)item)->extended_classification = ((LAStempReadPoint14*)buffer)->classification; ((LAStempReadPoint10*)item)->extended_return_number = ((LAStempReadPoint14*)buffer)->return_number; ((LAStempReadPoint10*)item)->extended_number_of_returns = ((LAStempReadPoint14*)buffer)->number_of_returns; ((LAStempReadPoint10*)item)->extended_scan_angle = ((LAStempReadPoint14*)buffer)->scan_angle; ((LAStempReadPoint10*)item)->gps_time = *((F64*)&buffer[22]); } private: U8 buffer[30]; }; class LASreadItemRaw_POINT14_BE : public LASreadItemRaw { public: LASreadItemRaw_POINT14_BE(){}; inline void read(U8* item, U32& context) { instream->getBytes(swapped, 30); ENDIAN_SWAP_32(&swapped[ 0], &item[ 0]); // X ENDIAN_SWAP_32(&swapped[ 4], &item[ 4]); // Y ENDIAN_SWAP_32(&swapped[ 8], &item[ 8]); // Z ENDIAN_SWAP_16(&swapped[12], &item[12]); // intensity if (((LAStempReadPoint14*)swapped)->number_of_returns > 7) { if (((LAStempReadPoint14*)swapped)->return_number > 6) { if (((LAStempReadPoint14*)swapped)->return_number >= ((LAStempReadPoint14*)swapped)->number_of_returns) { ((LAStempReadPoint10*)item)->return_number = 7; } else { ((LAStempReadPoint10*)item)->return_number = 6; } } else { ((LAStempReadPoint10*)item)->return_number = ((LAStempReadPoint14*)swapped)->return_number; } ((LAStempReadPoint10*)item)->number_of_returns = 7; } else { ((LAStempReadPoint10*)item)->return_number = ((LAStempReadPoint14*)swapped)->return_number; ((LAStempReadPoint10*)item)->number_of_returns = ((LAStempReadPoint14*)swapped)->number_of_returns; } ((LAStempReadPoint10*)item)->scan_direction_flag = ((LAStempReadPoint14*)swapped)->scan_direction_flag; ((LAStempReadPoint10*)item)->edge_of_flight_line = ((LAStempReadPoint14*)swapped)->edge_of_flight_line; ((LAStempReadPoint10*)item)->classification = (((LAStempReadPoint14*)swapped)->classification_flags << 5); if (((LAStempReadPoint14*)swapped)->classification < 32) ((LAStempReadPoint10*)item)->classification |= ((LAStempReadPoint14*)swapped)->classification; ((LAStempReadPoint10*)item)->user_data = ((LAStempReadPoint14*)swapped)->user_data; ENDIAN_SWAP_16(&swapped[20], &item[18]); // point_source_ID ((LAStempReadPoint10*)item)->extended_scanner_channel = ((LAStempReadPoint14*)swapped)->scanner_channel; ((LAStempReadPoint10*)item)->extended_classification_flags = ((LAStempReadPoint14*)swapped)->classification_flags; ((LAStempReadPoint10*)item)->extended_classification = ((LAStempReadPoint14*)swapped)->classification; ((LAStempReadPoint10*)item)->extended_return_number = ((LAStempReadPoint14*)swapped)->return_number; ((LAStempReadPoint10*)item)->extended_number_of_returns = ((LAStempReadPoint14*)swapped)->number_of_returns; ENDIAN_SWAP_16(&swapped[18], (U8*)&(((LAStempReadPoint10*)item)->extended_scan_angle)); ((LAStempReadPoint10*)item)->scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*((LAStempReadPoint10*)item)->extended_scan_angle)); ENDIAN_SWAP_64(&swapped[22], (U8*)&(((LAStempReadPoint10*)item)->gps_time)); } private: U8 swapped[30]; }; class LASreadItemRaw_RGBNIR14_LE : public LASreadItemRaw { public: LASreadItemRaw_RGBNIR14_LE(){}; inline void read(U8* item, U32& context) { instream->getBytes(item, 8); }; }; class LASreadItemRaw_RGBNIR14_BE : public LASreadItemRaw { public: LASreadItemRaw_RGBNIR14_BE(){}; inline void read(U8* item, U32& context) { instream->getBytes(swapped, 8); ENDIAN_SWAP_32(&swapped[ 0], &item[ 0]); // R ENDIAN_SWAP_32(&swapped[ 2], &item[ 2]); // G ENDIAN_SWAP_32(&swapped[ 4], &item[ 4]); // B ENDIAN_SWAP_32(&swapped[ 6], &item[ 6]); // NIR }; private: U8 swapped[8]; }; #endif LASzip-3.4.3/src/lasreadpoint.cpp000066400000000000000000000545561356234217100166660ustar00rootroot00000000000000/* =============================================================================== FILE: lasreadpoint.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasreadpoint.hpp" #include "arithmeticdecoder.hpp" #include "lasreaditemraw.hpp" #include "lasreaditemcompressed_v1.hpp" #include "lasreaditemcompressed_v2.hpp" #include "lasreaditemcompressed_v3.hpp" #include "lasreaditemcompressed_v4.hpp" #include #include #include LASreadPoint::LASreadPoint(U32 decompress_selective) { point_size = 0; instream = 0; num_readers = 0; readers = 0; readers_raw = 0; readers_compressed = 0; dec = 0; layered_las14_compression = FALSE; // used for chunking chunk_size = U32_MAX; chunk_count = 0; current_chunk = 0; number_chunks = 0; tabled_chunks = 0; chunk_totals = 0; chunk_starts = 0; // used for selective decompression (new LAS 1.4 point types only) this->decompress_selective = decompress_selective; // used for seeking point_start = 0; seek_point = 0; // used for error and warning reporting last_error = 0; last_warning = 0; } BOOL LASreadPoint::setup(U32 num_items, const LASitem* items, const LASzip* laszip) { U32 i; // is laszip exists then we must use its items if (laszip) { if (num_items == 0) return FALSE; if (items == 0) return FALSE; if (num_items != laszip->num_items) return FALSE; if (items != laszip->items) return FALSE; } // delete old entropy decoder if (dec) { delete dec; dec = 0; layered_las14_compression = FALSE; } // is the content compressed? if (laszip && laszip->compressor) { // create new entropy decoder (if requested) switch (laszip->coder) { case LASZIP_CODER_ARITHMETIC: dec = new ArithmeticDecoder(); break; default: // entropy decoder not supported return FALSE; } // maybe layered compression for LAS 1.4 layered_las14_compression = (laszip->compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED); } // initizalize the readers readers = 0; num_readers = num_items; // disable chunking chunk_size = U32_MAX; // always create the raw readers readers_raw = new LASreadItem*[num_readers]; for (i = 0; i < num_readers; i++) { switch (items[i].type) { case LASitem::POINT10: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_POINT10_LE(); else readers_raw[i] = new LASreadItemRaw_POINT10_BE(); break; case LASitem::GPSTIME11: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_GPSTIME11_LE(); else readers_raw[i] = new LASreadItemRaw_GPSTIME11_BE(); break; case LASitem::RGB12: case LASitem::RGB14: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_RGB12_LE(); else readers_raw[i] = new LASreadItemRaw_RGB12_BE(); break; case LASitem::BYTE: case LASitem::BYTE14: readers_raw[i] = new LASreadItemRaw_BYTE(items[i].size); break; case LASitem::POINT14: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_POINT14_LE(); else readers_raw[i] = new LASreadItemRaw_POINT14_BE(); break; case LASitem::RGBNIR14: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_RGBNIR14_LE(); else readers_raw[i] = new LASreadItemRaw_RGBNIR14_BE(); break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: if (IS_LITTLE_ENDIAN()) readers_raw[i] = new LASreadItemRaw_WAVEPACKET13_LE(); else readers_raw[i] = new LASreadItemRaw_WAVEPACKET13_BE(); break; default: return FALSE; } point_size += items[i].size; } if (dec) { readers_compressed = new LASreadItem*[num_readers]; // seeks with compressed data need a seek point if (seek_point) { delete [] seek_point[0]; delete [] seek_point; } seek_point = new U8*[num_items]; if (!seek_point) return FALSE; if (layered_las14_compression) { // because combo LAS 1.0 - 1.4 point struct has padding seek_point[0] = new U8[(point_size*2)]; // because extended_point_type must be set seek_point[0][22] = 1; } else { seek_point[0] = new U8[point_size]; } if (!seek_point[0]) return FALSE; for (i = 0; i < num_readers; i++) { switch (items[i].type) { case LASitem::POINT10: if (items[i].version == 1) readers_compressed[i] = new LASreadItemCompressed_POINT10_v1(dec); else if (items[i].version == 2) readers_compressed[i] = new LASreadItemCompressed_POINT10_v2(dec); else return FALSE; break; case LASitem::GPSTIME11: if (items[i].version == 1) readers_compressed[i] = new LASreadItemCompressed_GPSTIME11_v1(dec); else if (items[i].version == 2) readers_compressed[i] = new LASreadItemCompressed_GPSTIME11_v2(dec); else return FALSE; break; case LASitem::RGB12: if (items[i].version == 1) readers_compressed[i] = new LASreadItemCompressed_RGB12_v1(dec); else if (items[i].version == 2) readers_compressed[i] = new LASreadItemCompressed_RGB12_v2(dec); else return FALSE; break; case LASitem::BYTE: if (items[i].version == 1) readers_compressed[i] = new LASreadItemCompressed_BYTE_v1(dec, items[i].size); else if (items[i].version == 2) readers_compressed[i] = new LASreadItemCompressed_BYTE_v2(dec, items[i].size); else return FALSE; break; case LASitem::POINT14: if ((items[i].version == 3) || (items[i].version == 2)) // version == 2 from lasproto readers_compressed[i] = new LASreadItemCompressed_POINT14_v3(dec, decompress_selective); else if (items[i].version == 4) readers_compressed[i] = new LASreadItemCompressed_POINT14_v4(dec, decompress_selective); else return FALSE; break; case LASitem::RGB14: if ((items[i].version == 3) || (items[i].version == 2)) // version == 2 from lasproto readers_compressed[i] = new LASreadItemCompressed_RGB14_v3(dec, decompress_selective); else if (items[i].version == 4) readers_compressed[i] = new LASreadItemCompressed_RGB14_v4(dec, decompress_selective); else return FALSE; break; case LASitem::RGBNIR14: if ((items[i].version == 3) || (items[i].version == 2)) // version == 2 from lasproto readers_compressed[i] = new LASreadItemCompressed_RGBNIR14_v3(dec, decompress_selective); else if (items[i].version == 4) readers_compressed[i] = new LASreadItemCompressed_RGBNIR14_v4(dec, decompress_selective); else return FALSE; break; case LASitem::BYTE14: if ((items[i].version == 3) || (items[i].version == 2)) // version == 2 from lasproto readers_compressed[i] = new LASreadItemCompressed_BYTE14_v3(dec, items[i].size, decompress_selective); else if (items[i].version == 4) readers_compressed[i] = new LASreadItemCompressed_BYTE14_v4(dec, items[i].size, decompress_selective); else return FALSE; break; case LASitem::WAVEPACKET13: if (items[i].version == 1) readers_compressed[i] = new LASreadItemCompressed_WAVEPACKET13_v1(dec); else return FALSE; break; case LASitem::WAVEPACKET14: if (items[i].version == 3) readers_compressed[i] = new LASreadItemCompressed_WAVEPACKET14_v3(dec, decompress_selective); else if (items[i].version == 4) readers_compressed[i] = new LASreadItemCompressed_WAVEPACKET14_v4(dec, decompress_selective); else return FALSE; break; default: return FALSE; } if (i) { if (layered_las14_compression) { // because combo LAS 1.0 - 1.4 point struct has padding seek_point[i] = seek_point[i-1]+(2*items[i-1].size); } else { seek_point[i] = seek_point[i-1]+items[i-1].size; } } } if (laszip->compressor != LASZIP_COMPRESSOR_POINTWISE) { if (laszip->chunk_size) chunk_size = laszip->chunk_size; number_chunks = U32_MAX; } } return TRUE; } BOOL LASreadPoint::init(ByteStreamIn* instream) { if (!instream) return FALSE; this->instream = instream; U32 i; for (i = 0; i < num_readers; i++) { ((LASreadItemRaw*)(readers_raw[i]))->init(instream); } if (dec) { chunk_count = chunk_size; point_start = 0; readers = 0; } else { point_start = instream->tell(); readers = readers_raw; } return TRUE; } BOOL LASreadPoint::seek(const U32 current, const U32 target) { if (!instream->isSeekable()) return FALSE; U32 delta = 0; if (dec) { if (point_start == 0) { init_dec(); chunk_count = 0; } if (chunk_starts) { U32 target_chunk; if (chunk_totals) { target_chunk = search_chunk_table(target, 0, number_chunks); chunk_size = chunk_totals[target_chunk+1]-chunk_totals[target_chunk]; delta = target - chunk_totals[target_chunk]; } else { target_chunk = target/chunk_size; delta = target%chunk_size; } if (target_chunk >= tabled_chunks) { if (current_chunk < (tabled_chunks-1)) { dec->done(); current_chunk = (tabled_chunks-1); instream->seek(chunk_starts[current_chunk]); init_dec(); chunk_count = 0; } delta += (chunk_size*(target_chunk-current_chunk) - chunk_count); } else if (current_chunk != target_chunk || current > target) { dec->done(); current_chunk = target_chunk; instream->seek(chunk_starts[current_chunk]); init_dec(); chunk_count = 0; } else { delta = target - current; } } else if (current > target) { dec->done(); instream->seek(point_start); init_dec(); delta = target; } else if (current < target) { delta = target - current; } while (delta) { read(seek_point); delta--; } } else { if (current != target) { instream->seek(point_start+(I64)point_size*target); } } return TRUE; } BOOL LASreadPoint::read(U8* const * point) { U32 i; U32 context = 0; try { if (dec) { if (chunk_count == chunk_size) { if (point_start != 0) { dec->done(); current_chunk++; // check integrity if (current_chunk < tabled_chunks) { I64 here = instream->tell(); if (chunk_starts[current_chunk] != here) { // previous chunk was corrupt current_chunk--; throw 4711; } } } init_dec(); if (current_chunk == tabled_chunks) // no or incomplete chunk table? { if (current_chunk == number_chunks) { number_chunks += 256; chunk_starts = (I64*)realloc(chunk_starts, sizeof(I64)*(number_chunks+1)); } chunk_starts[tabled_chunks] = point_start; // needs fixing tabled_chunks++; } else if (chunk_totals) // variable sized chunks? { chunk_size = chunk_totals[current_chunk+1]-chunk_totals[current_chunk]; } chunk_count = 0; } chunk_count++; if (readers) { for (i = 0; i < num_readers; i++) { readers[i]->read(point[i], context); } } else { for (i = 0; i < num_readers; i++) { readers_raw[i]->read(point[i], context); } if (layered_las14_compression) { // for layered compression 'dec' only hands over the stream dec->init(instream, FALSE); // read how many points are in the chunk U32 count; instream->get32bitsLE((U8*)&count); // read the sizes of all layers for (i = 0; i < num_readers; i++) { ((LASreadItemCompressed*)(readers_compressed[i]))->chunk_sizes(); } for (i = 0; i < num_readers; i++) { ((LASreadItemCompressed*)(readers_compressed[i]))->init(point[i], context); } if (DEBUG_OUTPUT_NUM_BYTES_DETAILS) fprintf(stderr, "\n"); } else { for (i = 0; i < num_readers; i++) { ((LASreadItemCompressed*)(readers_compressed[i]))->init(point[i], context); } dec->init(instream); } readers = readers_compressed; } } else { for (i = 0; i < num_readers; i++) { readers[i]->read(point[i], context); } } } catch (I32 exception) { // create error string if (last_error == 0) last_error = new CHAR[128]; // report error if (exception == EOF) { // end-of-file if (dec) { sprintf(last_error, "end-of-file during chunk with index %u", current_chunk); } else { sprintf(last_error, "end-of-file"); } } else { // decompression error sprintf(last_error, "chunk with index %u of %u is corrupt", current_chunk, tabled_chunks); // if we know where the next chunk starts ... if ((current_chunk+1) < tabled_chunks) { // ... try to seek to the next chunk instream->seek(chunk_starts[(current_chunk+1)]); // ... ready for next LASreadPoint::read() chunk_count = chunk_size; } } return FALSE; } return TRUE; } BOOL LASreadPoint::check_end() { if (readers == readers_compressed) { if (dec) { dec->done(); current_chunk++; // check integrity if (current_chunk < tabled_chunks) { I64 here = instream->tell(); if (chunk_starts[current_chunk] != here) // then last chunk was corrupt { // create error string if (last_error == 0) last_error = new CHAR[128]; // report error sprintf(last_error, "chunk with index %u of %u is corrupt", current_chunk, tabled_chunks); return FALSE; } } } } return TRUE; } BOOL LASreadPoint::done() { instream = 0; return TRUE; } BOOL LASreadPoint::init_dec() { // maybe read chunk table (only if chunking enabled) if (number_chunks == U32_MAX) { if (!read_chunk_table()) { return FALSE; } current_chunk = 0; if (chunk_totals) chunk_size = chunk_totals[1]; } point_start = instream->tell(); readers = 0; return TRUE; } BOOL LASreadPoint::read_chunk_table() { // read the 8 bytes that store the location of the chunk table I64 chunk_table_start_position; try { instream->get64bitsLE((U8*)&chunk_table_start_position); } catch(...) { return FALSE; } // this is where the chunks start I64 chunks_start = instream->tell(); // was compressor interrupted before getting a chance to write the chunk table? if ((chunk_table_start_position + 8) == chunks_start) { // no choice but to fail if adaptive chunking was used if (chunk_size == U32_MAX) { // create error string if (last_error == 0) last_error = new CHAR[128]; // report error sprintf(last_error, "compressor was interrupted before writing adaptive chunk table of LAZ file"); return FALSE; } // otherwise we build the chunk table as we read the file number_chunks = 256; chunk_starts = (I64*)malloc(sizeof(I64)*(number_chunks+1)); if (chunk_starts == 0) { return FALSE; } chunk_starts[0] = chunks_start; tabled_chunks = 1; // create warning string if (last_warning == 0) last_warning = new CHAR[128]; // report warning sprintf(last_warning, "compressor was interrupted before writing chunk table of LAZ file"); return TRUE; } // maybe the stream is not seekable if (!instream->isSeekable()) { // no choice but to fail if adaptive chunking was used if (chunk_size == U32_MAX) { return FALSE; } // then we cannot seek to the chunk table but won't need it anyways number_chunks = 0; tabled_chunks = 0; return TRUE; } if (chunk_table_start_position == -1) { // the compressor was writing to a non-seekable stream and wrote the chunk table start at the end if (!instream->seekEnd(8)) { return FALSE; } try { instream->get64bitsLE((U8*)&chunk_table_start_position); } catch(...) { return FALSE; } } // read the chunk table try { instream->seek(chunk_table_start_position); U32 version; instream->get32bitsLE((U8*)&version); if (version != 0) { throw 1; } instream->get32bitsLE((U8*)&number_chunks); if (chunk_totals) delete [] chunk_totals; chunk_totals = 0; if (chunk_starts) free(chunk_starts); chunk_starts = 0; if (chunk_size == U32_MAX) { chunk_totals = new U32[number_chunks+1]; if (chunk_totals == 0) { throw 1; } chunk_totals[0] = 0; } chunk_starts = (I64*)malloc(sizeof(I64)*(number_chunks+1)); if (chunk_starts == 0) { throw 1; } chunk_starts[0] = chunks_start; tabled_chunks = 1; if (number_chunks > 0) { U32 i; dec->init(instream); IntegerCompressor ic(dec, 32, 2); ic.initDecompressor(); for (i = 1; i <= number_chunks; i++) { if (chunk_size == U32_MAX) chunk_totals[i] = ic.decompress((i>1 ? chunk_totals[i-1] : 0), 0); chunk_starts[i] = ic.decompress((i>1 ? (U32)(chunk_starts[i-1]) : 0), 1); tabled_chunks++; } dec->done(); for (i = 1; i <= number_chunks; i++) { if (chunk_size == U32_MAX) chunk_totals[i] += chunk_totals[i-1]; chunk_starts[i] += chunk_starts[i-1]; if (chunk_starts[i] <= chunk_starts[i-1]) { throw 1; } } } } catch (...) { // something went wrong while reading the chunk table if (chunk_totals) delete [] chunk_totals; chunk_totals = 0; // no choice but to fail if adaptive chunking was used if (chunk_size == U32_MAX) { return FALSE; } // did we not even read the number of chunks if (number_chunks == U32_MAX) { // then compressor was interrupted before getting a chance to write the chunk table number_chunks = 256; chunk_starts = (I64*)malloc(sizeof(I64)*(number_chunks+1)); if (chunk_starts == 0) { return FALSE; } chunk_starts[0] = chunks_start; tabled_chunks = 1; } else { // otherwise fix as many additional chunk_starts as possible U32 i; for (i = 1; i < tabled_chunks; i++) { chunk_starts[i] += chunk_starts[i-1]; } } // create warning string if (last_warning == 0) last_warning = new CHAR[128]; // first seek to the end of the file instream->seekEnd(); // get position of last byte I64 last_position = instream->tell(); // warn if last byte position is before chunk table start position if (last_position <= chunk_table_start_position) { // report warning if (last_position == chunk_table_start_position) { sprintf(last_warning, "chunk table is missing. improper use of LAZ compressor?"); } else { #ifdef _WIN32 sprintf(last_warning, "chunk table and %I64d bytes are missing. LAZ file truncated during copy or transfer?", chunk_table_start_position - last_position); #else sprintf(last_warning, "chunk table and %lld bytes are missing. LAZ file truncated during copy or transfer?", chunk_table_start_position - last_position); #endif } } else { // report warning sprintf(last_warning, "corrupt chunk table"); } } if (!instream->seek(chunks_start)) { return FALSE; } return TRUE; } U32 LASreadPoint::search_chunk_table(const U32 index, const U32 lower, const U32 upper) { if (lower + 1 == upper) return lower; U32 mid = (lower+upper)/2; if (index >= chunk_totals[mid]) return search_chunk_table(index, mid, upper); else return search_chunk_table(index, lower, mid); } LASreadPoint::~LASreadPoint() { U32 i; if (readers_raw) { for (i = 0; i < num_readers; i++) { delete readers_raw[i]; } delete [] readers_raw; } if (readers_compressed) { for (i = 0; i < num_readers; i++) { delete readers_compressed[i]; } delete [] readers_compressed; } if (dec) { delete dec; } if (chunk_totals) delete [] chunk_totals; if (chunk_starts) free(chunk_starts); if (seek_point) { delete [] seek_point[0]; delete [] seek_point; } if (last_error) delete [] last_error; if (last_warning) delete [] last_warning; } LASzip-3.4.3/src/lasreadpoint.hpp000066400000000000000000000066551356234217100166700ustar00rootroot00000000000000/* =============================================================================== FILE: lasreadpoint.hpp CONTENTS: Common interface for the classes that read points raw or compressed. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 18 July 2017 -- bug fix for spatial-indexed reading of native compressed LAS 1.4 19 April 2017 -- support for selective decompression for new LAS 1.4 points 23 August 2016 -- layering of items for selective decompression in LAS 1.4 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 24 August 2014 -- delay read of chunk table until first read() or seek() is called 6 October 2011 -- large file support & reading with missing chunk table 9 May 2011 -- the chunked compressor now allows variable chunk sizes 25 April 2011 -- added chunked laszip for random access decompression 10 January 2011 -- licensing change for LGPL release and liblas integration 7 December 2010 -- adapted from LASpointReader for better code modularity 3 December 2010 -- updated to (somewhat) support LAS format 1.3 7 September 2008 -- updated to support LAS format 1.2 22 February 2007 -- created about an hour before henna's birthday =============================================================================== */ #ifndef LAS_READ_POINT_HPP #define LAS_READ_POINT_HPP #include "mydefs.hpp" #include "laszip.hpp" #include "laszip_decompress_selective_v3.hpp" #include "bytestreamin.hpp" class LASreadItem; class ArithmeticDecoder; class LASreadPoint { public: LASreadPoint(U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); ~LASreadPoint(); // should only be called *once* BOOL setup(const U32 num_items, const LASitem* items, const LASzip* laszip=0); BOOL init(ByteStreamIn* instream); BOOL seek(const U32 current, const U32 target); BOOL read(U8* const * point); BOOL check_end(); BOOL done(); inline const CHAR* error() const { return last_error; }; inline const CHAR* warning() const { return last_warning; }; private: ByteStreamIn* instream; U32 num_readers; LASreadItem** readers; LASreadItem** readers_raw; LASreadItem** readers_compressed; ArithmeticDecoder* dec; BOOL layered_las14_compression; // used for chunking U32 chunk_size; U32 chunk_count; U32 current_chunk; U32 number_chunks; U32 tabled_chunks; I64* chunk_starts; U32* chunk_totals; BOOL init_dec(); BOOL read_chunk_table(); U32 search_chunk_table(const U32 index, const U32 lower, const U32 upper); // used for selective decompression (new LAS 1.4 point types only) U32 decompress_selective; // used for seeking I64 point_start; U32 point_size; U8** seek_point; // used for error and warning reporting CHAR* last_error; CHAR* last_warning; }; #endif LASzip-3.4.3/src/lasunzipper.cpp000066400000000000000000000073701356234217100165450ustar00rootroot00000000000000/* =============================================================================== FILE: lasunzipper.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "lasunzipper.hpp" #include #include #include "bytestreamin_file.hpp" #include "bytestreamin_istream.hpp" #include "lasreadpoint.hpp" bool LASunzipper::open(FILE* infile, const LASzip* laszip) { if (!infile) return return_error("FILE* infile pointer is NULL"); if (!laszip) return return_error("const LASzip* laszip pointer is NULL"); count = 0; if (reader) delete reader; reader = new LASreadPoint(); if (!reader) return return_error("alloc of LASreadPoint failed"); if (!reader->setup(laszip->num_items, laszip->items, laszip)) return return_error("setup() of LASreadPoint failed"); if (stream) delete stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamInFileLE(infile); else stream = new ByteStreamInFileBE(infile); if (!stream) return return_error("alloc of ByteStreamInFile failed"); if (!reader->init(stream)) return return_error("init() of LASreadPoint failed"); return true; } bool LASunzipper::open(istream& instream, const LASzip* laszip) { if (!laszip) return return_error("const LASzip* laszip pointer is NULL"); count = 0; if (reader) delete reader; reader = new LASreadPoint(); if (!reader) return return_error("alloc of LASreadPoint failed"); if (!reader->setup(laszip->num_items, laszip->items, laszip)) return return_error("setup() of LASreadPoint failed"); if (stream) delete stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamInIstreamLE(instream); else stream = new ByteStreamInIstreamBE(instream); if (!stream) return return_error("alloc of ByteStreamInStream failed"); if (!reader->init(stream)) return return_error("init() of LASreadPoint failed"); return true; } bool LASunzipper::seek(const unsigned int position) { if (!reader->seek(count, position)) return return_error("seek() of LASreadPoint failed"); count = position; return true; } unsigned int LASunzipper::tell() const { return count; } bool LASunzipper::read(unsigned char * const * point) { count++; return (reader->read(point) == TRUE); } bool LASunzipper::close() { BOOL done = TRUE; if (reader) { done = reader->done(); delete reader; reader = 0; } if (stream) { delete stream; stream = 0; } if (!done) return return_error("done() of LASreadPoint failed"); return true; } const char* LASunzipper::get_error() const { return error_string; } bool LASunzipper::return_error(const char* error) { char err[256]; sprintf(err, "%s (LASzip v%d.%dr%d)", error, LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION); if (error_string) free(error_string); error_string = LASCopyString(err); return false; } LASunzipper::LASunzipper() { error_string = 0; count = 0; stream = 0; reader = 0; } LASunzipper::~LASunzipper() { if (error_string) free(error_string); if (reader || stream) close(); } LASzip-3.4.3/src/lasunzipper.hpp000066400000000000000000000040051356234217100165420ustar00rootroot00000000000000/* =============================================================================== FILE: lasunzipper.hpp CONTENTS: Reads (optionally compressed) LIDAR points to LAS formats 1.0 - 1.3. This particular class is only used for adding LASzip to libLAS (not to LASlib). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 23 April 2011 -- changed interface for easier future compressor support 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from LASwriter/LASreader after Howard got pushy (-; =============================================================================== */ #ifndef LAS_UNZIPPER_HPP #define LAS_UNZIPPER_HPP #include #include "laszip.hpp" #ifdef LZ_WIN32_VC6 #include #else #include #include using namespace std; #endif class ByteStreamIn; class LASreadPoint; class LASunzipper { public: bool open(FILE* file, const LASzip* laszip); bool open(istream& stream, const LASzip* laszip); unsigned int tell() const; bool seek(const unsigned int position); bool read(unsigned char * const * point); bool close(); LASunzipper(); ~LASunzipper(); // in case a function returns false this string describes the problem const char* get_error() const; private: unsigned int count; ByteStreamIn* stream; LASreadPoint* reader; bool return_error(const char* err); char* error_string; }; #endif LASzip-3.4.3/src/laswriteitem.hpp000066400000000000000000000037321356234217100167050ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitem.hpp CONTENTS: Common interface for all classes that write the items that compose a point. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 23 August 2016 -- layering of items for selective decompression in LAS 1.4 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- refactored after watching two movies with silke =============================================================================== */ #ifndef LAS_WRITE_ITEM_HPP #define LAS_WRITE_ITEM_HPP #include "mydefs.hpp" class ByteStreamOut; class LASwriteItem { public: virtual BOOL write(const U8* item, U32& context)=0; virtual ~LASwriteItem(){}; }; class LASwriteItemRaw : public LASwriteItem { public: LASwriteItemRaw() { outstream = 0; }; BOOL init(ByteStreamOut* outstream) { if (!outstream) return FALSE; this->outstream = outstream; return TRUE; }; virtual ~LASwriteItemRaw(){}; protected: ByteStreamOut* outstream; }; class LASwriteItemCompressed : public LASwriteItem { public: virtual BOOL init(const U8* item, U32& context)=0; virtual BOOL chunk_sizes() { return FALSE; }; virtual BOOL chunk_bytes() { return FALSE; }; virtual ~LASwriteItemCompressed(){}; }; #endif LASzip-3.4.3/src/laswriteitemcompressed_v1.cpp000066400000000000000000000472341356234217100214000ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v1.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laswriteitemcompressed_v1.hpp" #include "laszip_common_v1.hpp" #include #include /* =============================================================================== LASwriteItemCompressed_POINT10_v1 =============================================================================== */ struct LASpoint10 { I32 x; I32 y; I32 z; U16 intensity; U8 return_number : 3; U8 number_of_returns_of_given_pulse : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; }; LASwriteItemCompressed_POINT10_v1::LASwriteItemCompressed_POINT10_v1(ArithmeticEncoder* enc) { U32 i; /* set encoder */ assert(enc); this->enc = enc; /* create models and integer compressors */ ic_dx = new IntegerCompressor(enc, 32); // 32 bits, 1 context ic_dy = new IntegerCompressor(enc, 32, 20); // 32 bits, 20 contexts ic_z = new IntegerCompressor(enc, 32, 20); // 32 bits, 20 contexts ic_intensity = new IntegerCompressor(enc, 16); ic_scan_angle_rank = new IntegerCompressor(enc, 8, 2); ic_point_source_ID = new IntegerCompressor(enc, 16); m_changed_values = enc->createSymbolModel(64); for (i = 0; i < 256; i++) { m_bit_byte[i] = 0; m_classification[i] = 0; m_user_data[i] = 0; } } LASwriteItemCompressed_POINT10_v1::~LASwriteItemCompressed_POINT10_v1() { U32 i; delete ic_dx; delete ic_dy; delete ic_z; delete ic_intensity; delete ic_scan_angle_rank; delete ic_point_source_ID; enc->destroySymbolModel(m_changed_values); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) enc->destroySymbolModel(m_bit_byte[i]); if (m_classification[i]) enc->destroySymbolModel(m_classification[i]); if (m_user_data[i]) enc->destroySymbolModel(m_user_data[i]); } } BOOL LASwriteItemCompressed_POINT10_v1::init(const U8* item, U32& context) { U32 i; /* init state */ last_x_diff[0] = last_x_diff[1] = last_x_diff[2] = 0; last_y_diff[0] = last_y_diff[1] = last_y_diff[2] = 0; last_incr = 0; /* init models and integer compressors */ ic_dx->initCompressor(); ic_dy->initCompressor(); ic_z->initCompressor(); ic_intensity->initCompressor(); ic_scan_angle_rank->initCompressor(); ic_point_source_ID->initCompressor(); enc->initSymbolModel(m_changed_values); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) enc->initSymbolModel(m_bit_byte[i]); if (m_classification[i]) enc->initSymbolModel(m_classification[i]); if (m_user_data[i]) enc->initSymbolModel(m_user_data[i]); } /* init last item */ memcpy(last_item, item, 20); return TRUE; } inline BOOL LASwriteItemCompressed_POINT10_v1::write(const U8* item, U32& context) { // find median difference for x and y from 3 preceding differences I32 median_x; if (last_x_diff[0] < last_x_diff[1]) { if (last_x_diff[1] < last_x_diff[2]) median_x = last_x_diff[1]; else if (last_x_diff[0] < last_x_diff[2]) median_x = last_x_diff[2]; else median_x = last_x_diff[0]; } else { if (last_x_diff[0] < last_x_diff[2]) median_x = last_x_diff[0]; else if (last_x_diff[1] < last_x_diff[2]) median_x = last_x_diff[2]; else median_x = last_x_diff[1]; } I32 median_y; if (last_y_diff[0] < last_y_diff[1]) { if (last_y_diff[1] < last_y_diff[2]) median_y = last_y_diff[1]; else if (last_y_diff[0] < last_y_diff[2]) median_y = last_y_diff[2]; else median_y = last_y_diff[0]; } else { if (last_y_diff[0] < last_y_diff[2]) median_y = last_y_diff[0]; else if (last_y_diff[1] < last_y_diff[2]) median_y = last_y_diff[2]; else median_y = last_y_diff[1]; } // compress x y z coordinates I32 x_diff = ((LASpoint10*)item)->x - ((LASpoint10*)last_item)->x; I32 y_diff = ((LASpoint10*)item)->y - ((LASpoint10*)last_item)->y; ic_dx->compress(median_x, x_diff); // we use the number k of bits corrector bits to switch contexts U32 k_bits = ic_dx->getK(); ic_dy->compress(median_y, y_diff, (k_bits < 19 ? k_bits : 19)); k_bits = (k_bits + ic_dy->getK()) / 2; ic_z->compress(((LASpoint10*)last_item)->z, ((LASpoint10*)item)->z, (k_bits < 19 ? k_bits : 19)); // compress which other values have changed I32 changed_values = ((((LASpoint10*)last_item)->intensity != ((LASpoint10*)item)->intensity) << 5) | ((last_item[14] != item[14]) << 4) | // bit_byte ((last_item[15] != item[15]) << 3) | // classification ((last_item[16] != item[16]) << 2) | // scan_angle_rank ((last_item[17] != item[17]) << 1) | // user_data ((((LASpoint10*)last_item)->point_source_ID != ((LASpoint10*)item)->point_source_ID)); enc->encodeSymbol(m_changed_values, changed_values); // compress the intensity if it has changed if (changed_values & 32) { ic_intensity->compress(((LASpoint10*)last_item)->intensity, ((LASpoint10*)item)->intensity); } // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed if (changed_values & 16) { if (m_bit_byte[last_item[14]] == 0) { m_bit_byte[last_item[14]] = enc->createSymbolModel(256); enc->initSymbolModel(m_bit_byte[last_item[14]]); } enc->encodeSymbol(m_bit_byte[last_item[14]], item[14]); } // compress the classification ... if it has changed if (changed_values & 8) { if (m_classification[last_item[15]] == 0) { m_classification[last_item[15]] = enc->createSymbolModel(256); enc->initSymbolModel(m_classification[last_item[15]]); } enc->encodeSymbol(m_classification[last_item[15]], item[15]); } // compress the scan_angle_rank ... if it has changed if (changed_values & 4) { ic_scan_angle_rank->compress(last_item[16], item[16], k_bits < 3); } // compress the user_data ... if it has changed if (changed_values & 2) { if (m_user_data[last_item[17]] == 0) { m_user_data[last_item[17]] = enc->createSymbolModel(256); enc->initSymbolModel(m_user_data[last_item[17]]); } enc->encodeSymbol(m_user_data[last_item[17]], item[17]); } // compress the point_source_ID ... if it has changed if (changed_values & 1) { ic_point_source_ID->compress(((LASpoint10*)last_item)->point_source_ID, ((LASpoint10*)item)->point_source_ID); } // record the difference last_x_diff[last_incr] = x_diff; last_y_diff[last_incr] = y_diff; last_incr++; if (last_incr > 2) last_incr = 0; // copy the last item memcpy(last_item, item, 20); return TRUE; } /* =============================================================================== LASwriteItemCompressed_GPSTIME11_v1 =============================================================================== */ #define LASZIP_GPSTIME_MULTIMAX 512 LASwriteItemCompressed_GPSTIME11_v1::LASwriteItemCompressed_GPSTIME11_v1(ArithmeticEncoder* enc) { /* set encoder */ assert(enc); this->enc = enc; /* create entropy models and integer compressors */ m_gpstime_multi = enc->createSymbolModel(LASZIP_GPSTIME_MULTIMAX); m_gpstime_0diff = enc->createSymbolModel(3); ic_gpstime = new IntegerCompressor(enc, 32, 6); // 32 bits, 6 contexts } LASwriteItemCompressed_GPSTIME11_v1::~LASwriteItemCompressed_GPSTIME11_v1() { enc->destroySymbolModel(m_gpstime_multi); enc->destroySymbolModel(m_gpstime_0diff); delete ic_gpstime; } BOOL LASwriteItemCompressed_GPSTIME11_v1::init(const U8* item, U32& context) { /* init state */ last_gpstime_diff = 0; multi_extreme_counter = 0; /* init models and integer compressors */ enc->initSymbolModel(m_gpstime_multi); enc->initSymbolModel(m_gpstime_0diff); ic_gpstime->initCompressor(); /* init last item */ last_gpstime.u64 = *((U64*)item); return TRUE; } inline BOOL LASwriteItemCompressed_GPSTIME11_v1::write(const U8* item, U32& context) { U64I64F64 this_gpstime; this_gpstime.i64 = *((I64*)item); if (last_gpstime_diff == 0) // if the last integer difference was zero { if (this_gpstime.i64 == last_gpstime.i64) { enc->encodeSymbol(m_gpstime_0diff, 0); // the doubles have not changed } else { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime.i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { enc->encodeSymbol(m_gpstime_0diff, 1); // the difference can be represented with 32 bits ic_gpstime->compress(0, curr_gpstime_diff, 0); last_gpstime_diff = curr_gpstime_diff; } else { enc->encodeSymbol(m_gpstime_0diff, 2); // the difference is huge enc->writeInt64(this_gpstime.u64); } last_gpstime.i64 = this_gpstime.i64; } } else // the last integer difference was *not* zero { if (this_gpstime.i64 == last_gpstime.i64) { // if the doubles have not changed use a special symbol enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTIMAX-1); } else { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime.i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; // if the current gpstime difference can be represented with 32 bits if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { // compute multiplier between current and last integer difference I32 multi = (I32)(((F32)curr_gpstime_diff / (F32)last_gpstime_diff) + 0.5f); // limit the multiplier into some bounds if (multi >= LASZIP_GPSTIME_MULTIMAX-3) { multi = LASZIP_GPSTIME_MULTIMAX-3; } else if (multi <= 0) { multi = 0; } // compress this multiplier enc->encodeSymbol(m_gpstime_multi, multi); // compress the residual curr_gpstime_diff in dependance on the multiplier if (multi == 1) { // this is the case we assume we get most often ic_gpstime->compress(last_gpstime_diff, curr_gpstime_diff, 1); last_gpstime_diff = curr_gpstime_diff; multi_extreme_counter = 0; } else { if (multi == 0) { ic_gpstime->compress(last_gpstime_diff/4, curr_gpstime_diff, 2); multi_extreme_counter++; if (multi_extreme_counter > 3) { last_gpstime_diff = curr_gpstime_diff; multi_extreme_counter = 0; } } else if (multi < 10) { ic_gpstime->compress(multi*last_gpstime_diff, curr_gpstime_diff, 3); } else if (multi < 50) { ic_gpstime->compress(multi*last_gpstime_diff, curr_gpstime_diff, 4); } else { ic_gpstime->compress(multi*last_gpstime_diff, curr_gpstime_diff, 5); if (multi == LASZIP_GPSTIME_MULTIMAX-3) { multi_extreme_counter++; if (multi_extreme_counter > 3) { last_gpstime_diff = curr_gpstime_diff; multi_extreme_counter = 0; } } } } } else { // if difference is so huge ... we simply write the double enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTIMAX-2); enc->writeInt64(this_gpstime.u64); } last_gpstime.i64 = this_gpstime.i64; } } return TRUE; } /* =============================================================================== LASwriteItemCompressed_RGB12_v1 =============================================================================== */ LASwriteItemCompressed_RGB12_v1::LASwriteItemCompressed_RGB12_v1(ArithmeticEncoder* enc) { /* set encoder */ assert(enc); this->enc = enc; /* create models and integer compressors */ m_byte_used = enc->createSymbolModel(64); ic_rgb = new IntegerCompressor(enc, 8, 6); /* create last item */ last_item = new U8[6]; } LASwriteItemCompressed_RGB12_v1::~LASwriteItemCompressed_RGB12_v1() { enc->destroySymbolModel(m_byte_used); delete ic_rgb; delete [] last_item; } BOOL LASwriteItemCompressed_RGB12_v1::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ enc->initSymbolModel(m_byte_used); ic_rgb->initCompressor(); /* init last item */ memcpy(last_item, item, 6); return TRUE; } inline BOOL LASwriteItemCompressed_RGB12_v1::write(const U8* item, U32& context) { U32 sym = ((((U16*)last_item)[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((((U16*)last_item)[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((((U16*)last_item)[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((((U16*)last_item)[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((((U16*)last_item)[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((((U16*)last_item)[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; enc->encodeSymbol(m_byte_used, sym); if (sym & (1 << 0)) ic_rgb->compress(((U16*)last_item)[0]&255,((U16*)item)[0]&255, 0); if (sym & (1 << 1)) ic_rgb->compress(((U16*)last_item)[0]>>8,((U16*)item)[0]>>8, 1); if (sym & (1 << 2)) ic_rgb->compress(((U16*)last_item)[1]&255,((U16*)item)[1]&255, 2); if (sym & (1 << 3)) ic_rgb->compress(((U16*)last_item)[1]>>8,((U16*)item)[1]>>8, 3); if (sym & (1 << 4)) ic_rgb->compress(((U16*)last_item)[2]&255,((U16*)item)[2]&255, 4); if (sym & (1 << 5)) ic_rgb->compress(((U16*)last_item)[2]>>8,((U16*)item)[2]>>8, 5); memcpy(last_item, item, 6); return TRUE; } /* =============================================================================== LASwriteItemCompressed_WAVEPACKET13_v1 =============================================================================== */ LASwriteItemCompressed_WAVEPACKET13_v1::LASwriteItemCompressed_WAVEPACKET13_v1(ArithmeticEncoder* enc) { /* set encoder */ assert(enc); this->enc = enc; /* create models and integer compressors */ m_packet_index = enc->createSymbolModel(256); m_offset_diff[0] = enc->createSymbolModel(4); m_offset_diff[1] = enc->createSymbolModel(4); m_offset_diff[2] = enc->createSymbolModel(4); m_offset_diff[3] = enc->createSymbolModel(4); ic_offset_diff = new IntegerCompressor(enc, 32); ic_packet_size = new IntegerCompressor(enc, 32); ic_return_point = new IntegerCompressor(enc, 32); ic_xyz = new IntegerCompressor(enc, 32, 3); /* create last item */ last_item = new U8[28]; } LASwriteItemCompressed_WAVEPACKET13_v1::~LASwriteItemCompressed_WAVEPACKET13_v1() { enc->destroySymbolModel(m_packet_index); enc->destroySymbolModel(m_offset_diff[0]); enc->destroySymbolModel(m_offset_diff[1]); enc->destroySymbolModel(m_offset_diff[2]); enc->destroySymbolModel(m_offset_diff[3]); delete ic_offset_diff; delete ic_packet_size; delete ic_return_point; delete ic_xyz; delete [] last_item; } BOOL LASwriteItemCompressed_WAVEPACKET13_v1::init(const U8* item, U32& context) { /* init state */ last_diff_32 = 0; sym_last_offset_diff = 0; /* init models and integer compressors */ enc->initSymbolModel(m_packet_index); enc->initSymbolModel(m_offset_diff[0]); enc->initSymbolModel(m_offset_diff[1]); enc->initSymbolModel(m_offset_diff[2]); enc->initSymbolModel(m_offset_diff[3]); ic_offset_diff->initCompressor(); ic_packet_size->initCompressor(); ic_return_point->initCompressor(); ic_xyz->initCompressor(); /* init last item */ item++; memcpy(last_item, item, 28); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET13_v1::write(const U8* item, U32& context) { enc->encodeSymbol(m_packet_index, (U32)(item[0])); item++; LASwavepacket13 this_item_m = LASwavepacket13::unpack(item); LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item); // calculate the difference between the two offsets I64 curr_diff_64 = this_item_m.offset - last_item_m.offset; I32 curr_diff_32 = (I32)curr_diff_64; // if the current difference can be represented with 32 bits if (curr_diff_64 == (I64)(curr_diff_32)) { if (curr_diff_32 == 0) // current difference is zero { enc->encodeSymbol(m_offset_diff[sym_last_offset_diff], 0); sym_last_offset_diff = 0; } else if (curr_diff_32 == (I32)last_item_m.packet_size) { enc->encodeSymbol(m_offset_diff[sym_last_offset_diff], 1); sym_last_offset_diff = 1; } else // { enc->encodeSymbol(m_offset_diff[sym_last_offset_diff], 2); sym_last_offset_diff = 2; ic_offset_diff->compress(last_diff_32, curr_diff_32); last_diff_32 = curr_diff_32; } } else { enc->encodeSymbol(m_offset_diff[sym_last_offset_diff], 3); sym_last_offset_diff = 3; enc->writeInt64(this_item_m.offset); } ic_packet_size->compress(last_item_m.packet_size, this_item_m.packet_size); ic_return_point->compress(last_item_m.return_point.i32, this_item_m.return_point.i32); ic_xyz->compress(last_item_m.x.i32, this_item_m.x.i32, 0); ic_xyz->compress(last_item_m.y.i32, this_item_m.y.i32, 1); ic_xyz->compress(last_item_m.z.i32, this_item_m.z.i32, 2); memcpy(last_item, item, 28); return TRUE; } /* =============================================================================== LASwriteItemCompressed_BYTE_v1 =============================================================================== */ LASwriteItemCompressed_BYTE_v1::LASwriteItemCompressed_BYTE_v1(ArithmeticEncoder* enc, U32 number) { /* set encoder */ assert(enc); this->enc = enc; assert(number); this->number = number; /* create models and integer compressors */ ic_byte = new IntegerCompressor(enc, 8, number); /* create last item */ last_item = new U8[number]; } LASwriteItemCompressed_BYTE_v1::~LASwriteItemCompressed_BYTE_v1() { delete ic_byte; delete [] last_item; } BOOL LASwriteItemCompressed_BYTE_v1::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ ic_byte->initCompressor(); /* init last point */ memcpy(last_item, item, number); return TRUE; } inline BOOL LASwriteItemCompressed_BYTE_v1::write(const U8* item, U32& context) { U32 i; for (i = 0; i < number; i++) { ic_byte->compress(last_item[i], item[i], i); } memcpy(last_item, item, number); return TRUE; } // vim: set ts=2 sw=2 expandtabs LASzip-3.4.3/src/laswriteitemcompressed_v1.hpp000066400000000000000000000100321356234217100213670ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v1.hpp CONTENTS: Implementation of LASitemWriteCompressed for *all* items (version 1). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- refactored after watching two movies with silke =============================================================================== */ #ifndef LAS_WRITE_ITEM_COMPRESSED_V1_HPP #define LAS_WRITE_ITEM_COMPRESSED_V1_HPP #include "laswriteitem.hpp" #include "arithmeticencoder.hpp" #include "integercompressor.hpp" class LASwriteItemCompressed_POINT10_v1 : public LASwriteItemCompressed { public: LASwriteItemCompressed_POINT10_v1(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_POINT10_v1(); private: ArithmeticEncoder* enc; U8 last_item[20]; I32 last_x_diff[3]; I32 last_y_diff[3]; I32 last_incr; IntegerCompressor* ic_dx; IntegerCompressor* ic_dy; IntegerCompressor* ic_z; IntegerCompressor* ic_intensity; IntegerCompressor* ic_scan_angle_rank; IntegerCompressor* ic_point_source_ID; ArithmeticModel* m_changed_values; ArithmeticModel* m_bit_byte[256]; ArithmeticModel* m_classification[256]; ArithmeticModel* m_user_data[256]; }; class LASwriteItemCompressed_GPSTIME11_v1 : public LASwriteItemCompressed { public: LASwriteItemCompressed_GPSTIME11_v1(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_GPSTIME11_v1(); private: ArithmeticEncoder* enc; U64I64F64 last_gpstime; ArithmeticModel* m_gpstime_multi; ArithmeticModel* m_gpstime_0diff; IntegerCompressor* ic_gpstime; I32 multi_extreme_counter; I32 last_gpstime_diff; }; class LASwriteItemCompressed_RGB12_v1 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGB12_v1(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_RGB12_v1(); private: ArithmeticEncoder* enc; U8* last_item; ArithmeticModel* m_byte_used; IntegerCompressor* ic_rgb; }; class LASwriteItemCompressed_WAVEPACKET13_v1 : public LASwriteItemCompressed { public: LASwriteItemCompressed_WAVEPACKET13_v1(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_WAVEPACKET13_v1(); private: ArithmeticEncoder* enc; U8* last_item; I32 last_diff_32; U32 sym_last_offset_diff; ArithmeticModel* m_packet_index; ArithmeticModel* m_offset_diff[4]; IntegerCompressor* ic_offset_diff; IntegerCompressor* ic_packet_size; IntegerCompressor* ic_return_point; IntegerCompressor* ic_xyz; }; class LASwriteItemCompressed_BYTE_v1 : public LASwriteItemCompressed { public: LASwriteItemCompressed_BYTE_v1(ArithmeticEncoder* enc, U32 number); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_BYTE_v1(); private: ArithmeticEncoder* enc; U32 number; U8* last_item; IntegerCompressor* ic_byte; }; #endif LASzip-3.4.3/src/laswriteitemcompressed_v2.cpp000066400000000000000000000507151356234217100213770ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v2.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laswriteitemcompressed_v2.hpp" #include #include /* =============================================================================== LASwriteItemCompressed_POINT10_v2 =============================================================================== */ struct LASpoint10 { I32 x; I32 y; I32 z; U16 intensity; U8 return_number : 3; U8 number_of_returns_of_given_pulse : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; }; LASwriteItemCompressed_POINT10_v2::LASwriteItemCompressed_POINT10_v2(ArithmeticEncoder* enc) { U32 i; /* set encoder */ assert(enc); this->enc = enc; /* create models and integer compressors */ m_changed_values = enc->createSymbolModel(64); ic_intensity = new IntegerCompressor(enc, 16, 4); m_scan_angle_rank[0] = enc->createSymbolModel(256); m_scan_angle_rank[1] = enc->createSymbolModel(256); ic_point_source_ID = new IntegerCompressor(enc, 16); for (i = 0; i < 256; i++) { m_bit_byte[i] = 0; m_classification[i] = 0; m_user_data[i] = 0; } ic_dx = new IntegerCompressor(enc, 32, 2); // 32 bits, 2 context ic_dy = new IntegerCompressor(enc, 32, 22); // 32 bits, 22 contexts ic_z = new IntegerCompressor(enc, 32, 20); // 32 bits, 20 contexts } LASwriteItemCompressed_POINT10_v2::~LASwriteItemCompressed_POINT10_v2() { U32 i; enc->destroySymbolModel(m_changed_values); delete ic_intensity; enc->destroySymbolModel(m_scan_angle_rank[0]); enc->destroySymbolModel(m_scan_angle_rank[1]); delete ic_point_source_ID; for (i = 0; i < 256; i++) { if (m_bit_byte[i]) enc->destroySymbolModel(m_bit_byte[i]); if (m_classification[i]) enc->destroySymbolModel(m_classification[i]); if (m_user_data[i]) enc->destroySymbolModel(m_user_data[i]); } delete ic_dx; delete ic_dy; delete ic_z; } BOOL LASwriteItemCompressed_POINT10_v2::init(const U8* item, U32& context) { U32 i; /* init state */ for (i=0; i < 16; i++) { last_x_diff_median5[i].init(); last_y_diff_median5[i].init(); last_intensity[i] = 0; last_height[i/2] = 0; } /* init models and integer compressors */ enc->initSymbolModel(m_changed_values); ic_intensity->initCompressor(); enc->initSymbolModel(m_scan_angle_rank[0]); enc->initSymbolModel(m_scan_angle_rank[1]); ic_point_source_ID->initCompressor(); for (i = 0; i < 256; i++) { if (m_bit_byte[i]) enc->initSymbolModel(m_bit_byte[i]); if (m_classification[i]) enc->initSymbolModel(m_classification[i]); if (m_user_data[i]) enc->initSymbolModel(m_user_data[i]); } ic_dx->initCompressor(); ic_dy->initCompressor(); ic_z->initCompressor(); /* init last item */ memcpy(last_item, item, 20); return TRUE; } inline BOOL LASwriteItemCompressed_POINT10_v2::write(const U8* item, U32& context) { U32 r = ((LASpoint10*)item)->return_number; U32 n = ((LASpoint10*)item)->number_of_returns_of_given_pulse; U32 m = number_return_map[n][r]; U32 l = number_return_level[n][r]; U32 k_bits; I32 median, diff; // compress which other values have changed I32 changed_values = (((last_item[14] != item[14]) << 5) | // bit_byte ((last_intensity[m] != ((LASpoint10*)item)->intensity) << 4) | ((last_item[15] != item[15]) << 3) | // classification ((last_item[16] != item[16]) << 2) | // scan_angle_rank ((last_item[17] != item[17]) << 1) | // user_data (((LASpoint10*)last_item)->point_source_ID != ((LASpoint10*)item)->point_source_ID)); enc->encodeSymbol(m_changed_values, changed_values); // compress the bit_byte (edge_of_flight_line, scan_direction_flag, returns, ...) if it has changed if (changed_values & 32) { if (m_bit_byte[last_item[14]] == 0) { m_bit_byte[last_item[14]] = enc->createSymbolModel(256); enc->initSymbolModel(m_bit_byte[last_item[14]]); } enc->encodeSymbol(m_bit_byte[last_item[14]], item[14]); } // compress the intensity if it has changed if (changed_values & 16) { ic_intensity->compress(last_intensity[m], ((LASpoint10*)item)->intensity, (m < 3 ? m : 3)); last_intensity[m] = ((LASpoint10*)item)->intensity; } // compress the classification ... if it has changed if (changed_values & 8) { if (m_classification[last_item[15]] == 0) { m_classification[last_item[15]] = enc->createSymbolModel(256); enc->initSymbolModel(m_classification[last_item[15]]); } enc->encodeSymbol(m_classification[last_item[15]], item[15]); } // compress the scan_angle_rank ... if it has changed if (changed_values & 4) { enc->encodeSymbol(m_scan_angle_rank[((LASpoint10*)item)->scan_direction_flag], U8_FOLD(item[16]-last_item[16])); } // compress the user_data ... if it has changed if (changed_values & 2) { if (m_user_data[last_item[17]] == 0) { m_user_data[last_item[17]] = enc->createSymbolModel(256); enc->initSymbolModel(m_user_data[last_item[17]]); } enc->encodeSymbol(m_user_data[last_item[17]], item[17]); } // compress the point_source_ID ... if it has changed if (changed_values & 1) { ic_point_source_ID->compress(((LASpoint10*)last_item)->point_source_ID, ((LASpoint10*)item)->point_source_ID); } // compress x coordinate median = last_x_diff_median5[m].get(); diff = ((LASpoint10*)item)->x - ((LASpoint10*)last_item)->x; ic_dx->compress(median, diff, n==1); last_x_diff_median5[m].add(diff); // compress y coordinate k_bits = ic_dx->getK(); median = last_y_diff_median5[m].get(); diff = ((LASpoint10*)item)->y - ((LASpoint10*)last_item)->y; ic_dy->compress(median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); last_y_diff_median5[m].add(diff); // compress z coordinate k_bits = (ic_dx->getK() + ic_dy->getK()) / 2; ic_z->compress(last_height[l], ((LASpoint10*)item)->z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); last_height[l] = ((LASpoint10*)item)->z; // copy the last item memcpy(last_item, item, 20); return TRUE; } /* =============================================================================== LASwriteItemCompressed_GPSTIME11_v2 =============================================================================== */ #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_UNCHANGED (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 2) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 6) LASwriteItemCompressed_GPSTIME11_v2::LASwriteItemCompressed_GPSTIME11_v2(ArithmeticEncoder* enc) { /* set encoder */ assert(enc); this->enc = enc; /* create entropy models and integer compressors */ m_gpstime_multi = enc->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); m_gpstime_0diff = enc->createSymbolModel(6); ic_gpstime = new IntegerCompressor(enc, 32, 9); // 32 bits, 9 contexts } LASwriteItemCompressed_GPSTIME11_v2::~LASwriteItemCompressed_GPSTIME11_v2() { enc->destroySymbolModel(m_gpstime_multi); enc->destroySymbolModel(m_gpstime_0diff); delete ic_gpstime; } BOOL LASwriteItemCompressed_GPSTIME11_v2::init(const U8* item, U32& context) { /* init state */ last = 0, next = 0; last_gpstime_diff[0] = 0; last_gpstime_diff[1] = 0; last_gpstime_diff[2] = 0; last_gpstime_diff[3] = 0; multi_extreme_counter[0] = 0; multi_extreme_counter[1] = 0; multi_extreme_counter[2] = 0; multi_extreme_counter[3] = 0; /* init models and integer compressors */ enc->initSymbolModel(m_gpstime_multi); enc->initSymbolModel(m_gpstime_0diff); ic_gpstime->initCompressor(); /* init last item */ last_gpstime[0].u64 = *((U64*)item); last_gpstime[1].u64 = 0; last_gpstime[2].u64 = 0; last_gpstime[3].u64 = 0; return TRUE; } inline BOOL LASwriteItemCompressed_GPSTIME11_v2::write(const U8* item, U32& context) { U64I64F64 this_gpstime; this_gpstime.i64 = *((I64*)item); if (last_gpstime_diff[last] == 0) // if the last integer difference was zero { if (this_gpstime.i64 == last_gpstime[last].i64) { enc->encodeSymbol(m_gpstime_0diff, 0); // the doubles have not changed } else { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { enc->encodeSymbol(m_gpstime_0diff, 1); // the difference can be represented with 32 bits ic_gpstime->compress(0, curr_gpstime_diff, 0); last_gpstime_diff[last] = curr_gpstime_diff; multi_extreme_counter[last] = 0; } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[(last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { enc->encodeSymbol(m_gpstime_0diff, i+2); // it belongs to another sequence last = (last+i)&3; return write(item, context); } } // no other sequence found. start new sequence. enc->encodeSymbol(m_gpstime_0diff, 2); ic_gpstime->compress((I32)(last_gpstime[last].u64 >> 32), (I32)(this_gpstime.u64 >> 32), 8); enc->writeInt((U32)(this_gpstime.u64)); next = (next+1)&3; last = next; last_gpstime_diff[last] = 0; multi_extreme_counter[last] = 0; } last_gpstime[last].i64 = this_gpstime.i64; } } else // the last integer difference was *not* zero { if (this_gpstime.i64 == last_gpstime[last].i64) { // if the doubles have not changed use a special symbol enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_UNCHANGED); } else { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; // if the current gpstime difference can be represented with 32 bits if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { // compute multiplier between current and last integer difference F32 multi_f = (F32)curr_gpstime_diff / (F32)(last_gpstime_diff[last]); I32 multi = I32_QUANTIZE(multi_f); // compress the residual curr_gpstime_diff in dependance on the multiplier if (multi == 1) { // this is the case we assume we get most often for regular spaced pulses enc->encodeSymbol(m_gpstime_multi, 1); ic_gpstime->compress(last_gpstime_diff[last], curr_gpstime_diff, 1); multi_extreme_counter[last] = 0; } else if (multi > 0) { if (multi < LASZIP_GPSTIME_MULTI) // positive multipliers up to LASZIP_GPSTIME_MULTI are compressed directly { enc->encodeSymbol(m_gpstime_multi, multi); if (multi < 10) ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 2); else ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 3); } else { enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI); ic_gpstime->compress(LASZIP_GPSTIME_MULTI*last_gpstime_diff[last], curr_gpstime_diff, 4); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = curr_gpstime_diff; multi_extreme_counter[last] = 0; } } } else if (multi < 0) { if (multi > LASZIP_GPSTIME_MULTI_MINUS) // negative multipliers larger than LASZIP_GPSTIME_MULTI_MINUS are compressed directly { enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI - multi); ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 5); } else { enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS); ic_gpstime->compress(LASZIP_GPSTIME_MULTI_MINUS*last_gpstime_diff[last], curr_gpstime_diff, 6); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = curr_gpstime_diff; multi_extreme_counter[last] = 0; } } } else { enc->encodeSymbol(m_gpstime_multi, 0); ic_gpstime->compress(0, curr_gpstime_diff, 7); multi_extreme_counter[last]++; if (multi_extreme_counter[last] > 3) { last_gpstime_diff[last] = curr_gpstime_diff; multi_extreme_counter[last] = 0; } } } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[(last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { // it belongs to this sequence enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL+i); last = (last+i)&3; return write(item, context); } } // no other sequence found. start new sequence. enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL); ic_gpstime->compress((I32)(last_gpstime[last].u64 >> 32), (I32)(this_gpstime.u64 >> 32), 8); enc->writeInt((U32)(this_gpstime.u64)); next = (next+1)&3; last = next; last_gpstime_diff[last] = 0; multi_extreme_counter[last] = 0; } last_gpstime[last].i64 = this_gpstime.i64; } } return TRUE; } /* =============================================================================== LASwriteItemCompressed_RGB12_v2 =============================================================================== */ LASwriteItemCompressed_RGB12_v2::LASwriteItemCompressed_RGB12_v2(ArithmeticEncoder* enc) { /* set encoder */ assert(enc); this->enc = enc; /* create models and integer compressors */ m_byte_used = enc->createSymbolModel(128); m_rgb_diff_0 = enc->createSymbolModel(256); m_rgb_diff_1 = enc->createSymbolModel(256); m_rgb_diff_2 = enc->createSymbolModel(256); m_rgb_diff_3 = enc->createSymbolModel(256); m_rgb_diff_4 = enc->createSymbolModel(256); m_rgb_diff_5 = enc->createSymbolModel(256); } LASwriteItemCompressed_RGB12_v2::~LASwriteItemCompressed_RGB12_v2() { enc->destroySymbolModel(m_byte_used); enc->destroySymbolModel(m_rgb_diff_0); enc->destroySymbolModel(m_rgb_diff_1); enc->destroySymbolModel(m_rgb_diff_2); enc->destroySymbolModel(m_rgb_diff_3); enc->destroySymbolModel(m_rgb_diff_4); enc->destroySymbolModel(m_rgb_diff_5); } BOOL LASwriteItemCompressed_RGB12_v2::init(const U8* item, U32& context) { /* init state */ /* init models and integer compressors */ enc->initSymbolModel(m_byte_used); enc->initSymbolModel(m_rgb_diff_0); enc->initSymbolModel(m_rgb_diff_1); enc->initSymbolModel(m_rgb_diff_2); enc->initSymbolModel(m_rgb_diff_3); enc->initSymbolModel(m_rgb_diff_4); enc->initSymbolModel(m_rgb_diff_5); /* init last item */ memcpy(last_item, item, 6); return TRUE; } inline BOOL LASwriteItemCompressed_RGB12_v2::write(const U8* item, U32& context) { I32 diff_l = 0; I32 diff_h = 0; I32 corr; U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6; enc->encodeSymbol(m_byte_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255); enc->encodeSymbol(m_rgb_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8); enc->encodeSymbol(m_rgb_diff_1, U8_FOLD(diff_h)); } if (sym & (1 << 6)) { if (sym & (1 << 2)) { corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255)); enc->encodeSymbol(m_rgb_diff_2, U8_FOLD(corr)); } if (sym & (1 << 4)) { diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2; corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255)); enc->encodeSymbol(m_rgb_diff_4, U8_FOLD(corr)); } if (sym & (1 << 3)) { corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8)); enc->encodeSymbol(m_rgb_diff_3, U8_FOLD(corr)); } if (sym & (1 << 5)) { diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2; corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8)); enc->encodeSymbol(m_rgb_diff_5, U8_FOLD(corr)); } } memcpy(last_item, item, 6); return TRUE; } /* =============================================================================== LASwriteItemCompressed_BYTE_v2 =============================================================================== */ LASwriteItemCompressed_BYTE_v2::LASwriteItemCompressed_BYTE_v2(ArithmeticEncoder* enc, U32 number) { U32 i; /* set encoder */ assert(enc); this->enc = enc; assert(number); this->number = number; /* create models and integer compressors */ m_byte = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { m_byte[i] = enc->createSymbolModel(256); } /* create last item */ last_item = new U8[number]; } LASwriteItemCompressed_BYTE_v2::~LASwriteItemCompressed_BYTE_v2() { U32 i; for (i = 0; i < number; i++) { enc->destroySymbolModel(m_byte[i]); } delete [] m_byte; delete [] last_item; } BOOL LASwriteItemCompressed_BYTE_v2::init(const U8* item, U32& context) { U32 i; /* init state */ /* init models and integer compressors */ for (i = 0; i < number; i++) { enc->initSymbolModel(m_byte[i]); } /* init last point */ memcpy(last_item, item, number); return TRUE; } inline BOOL LASwriteItemCompressed_BYTE_v2::write(const U8* item, U32& context) { U32 i; I32 diff; for (i = 0; i < number; i++) { diff = item[i] - last_item[i]; enc->encodeSymbol(m_byte[i], U8_FOLD(diff)); } memcpy(last_item, item, number); return TRUE; } LASzip-3.4.3/src/laswriteitemcompressed_v2.hpp000066400000000000000000000072231356234217100214000ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v2.hpp CONTENTS: Implementation of LASitemWriteCompressed for *all* items (version 2). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 5 March 2011 -- created first night in ibiza to improve the RGB compressor =============================================================================== */ #ifndef LAS_WRITE_ITEM_COMPRESSED_V2_HPP #define LAS_WRITE_ITEM_COMPRESSED_V2_HPP #include "laswriteitem.hpp" #include "arithmeticencoder.hpp" #include "integercompressor.hpp" #include "laszip_common_v2.hpp" class LASwriteItemCompressed_POINT10_v2 : public LASwriteItemCompressed { public: LASwriteItemCompressed_POINT10_v2(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_POINT10_v2(); private: ArithmeticEncoder* enc; U8 last_item[20]; U16 last_intensity[16]; StreamingMedian5 last_x_diff_median5[16]; StreamingMedian5 last_y_diff_median5[16]; I32 last_height[8]; ArithmeticModel* m_changed_values; IntegerCompressor* ic_intensity; ArithmeticModel* m_scan_angle_rank[2]; IntegerCompressor* ic_point_source_ID; ArithmeticModel* m_bit_byte[256]; ArithmeticModel* m_classification[256]; ArithmeticModel* m_user_data[256]; IntegerCompressor* ic_dx; IntegerCompressor* ic_dy; IntegerCompressor* ic_z; }; class LASwriteItemCompressed_GPSTIME11_v2 : public LASwriteItemCompressed { public: LASwriteItemCompressed_GPSTIME11_v2(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_GPSTIME11_v2(); private: ArithmeticEncoder* enc; U32 last, next; U64I64F64 last_gpstime[4]; I32 last_gpstime_diff[4]; I32 multi_extreme_counter[4]; ArithmeticModel* m_gpstime_multi; ArithmeticModel* m_gpstime_0diff; IntegerCompressor* ic_gpstime; }; class LASwriteItemCompressed_RGB12_v2 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGB12_v2(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_RGB12_v2(); private: ArithmeticEncoder* enc; U16 last_item[3]; ArithmeticModel* m_byte_used; ArithmeticModel* m_rgb_diff_0; ArithmeticModel* m_rgb_diff_1; ArithmeticModel* m_rgb_diff_2; ArithmeticModel* m_rgb_diff_3; ArithmeticModel* m_rgb_diff_4; ArithmeticModel* m_rgb_diff_5; }; class LASwriteItemCompressed_BYTE_v2 : public LASwriteItemCompressed { public: LASwriteItemCompressed_BYTE_v2(ArithmeticEncoder* enc, U32 number); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); ~LASwriteItemCompressed_BYTE_v2(); private: ArithmeticEncoder* enc; U32 number; U8* last_item; ArithmeticModel** m_byte; }; #endif LASzip-3.4.3/src/laswriteitemcompressed_v3.cpp000066400000000000000000002130701356234217100213730ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v3.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laswriteitemcompressed_v3.hpp" #include #include #include /* =============================================================================== LASwriteItemCompressed_POINT14_v3 =============================================================================== */ typedef struct LASpoint14 { I32 X; I32 Y; I32 Z; U16 intensity; U8 legacy_return_number : 3; U8 legacy_number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 legacy_classification : 5; U8 legacy_flags : 3; I8 legacy_scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 scan_angle; U8 legacy_point_type : 2; U8 scanner_channel : 2; U8 classification_flags : 4; U8 classification; U8 return_number : 4; U8 number_of_returns : 4; // LASlib internal use only U8 deleted_flag; // for 8 byte alignment of the GPS time U8 dummy[2]; // compressed LASzip 1.4 points only BOOL gps_time_change; F64 gps_time; U16 rgb[4]; // LASwavepacket wavepacket; } LASpoint14; #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 5) LASwriteItemCompressed_POINT14_v3::LASwriteItemCompressed_POINT14_v3(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_channel_returns_XY = 0; outstream_Z = 0; outstream_classification = 0; outstream_flags = 0; outstream_intensity = 0; outstream_scan_angle = 0; outstream_user_data = 0; outstream_point_source = 0; outstream_gps_time = 0; enc_channel_returns_XY = 0; enc_Z = 0; enc_classification = 0; enc_flags = 0; enc_intensity = 0; enc_scan_angle = 0; enc_user_data = 0; enc_point_source = 0; enc_gps_time = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_changed_values[0] = 0; } current_context = 0; /* number of bytes per layer */ num_bytes_channel_returns_XY = 0; num_bytes_Z = 0; num_bytes_classification = 0; num_bytes_flags = 0; num_bytes_intensity = 0; num_bytes_scan_angle = 0; num_bytes_user_data = 0; num_bytes_point_source = 0; num_bytes_gps_time = 0; } LASwriteItemCompressed_POINT14_v3::~LASwriteItemCompressed_POINT14_v3() { U32 c, i; /* destroy all initialized scanner channel contexts */ for (c = 0; c < 4; c++) { if (contexts[c].m_changed_values[0]) { enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[0]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[1]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[2]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[3]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[4]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[5]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[6]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[7]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[c].m_number_of_returns[i]) enc_channel_returns_XY->destroySymbolModel(contexts[c].m_number_of_returns[i]); if (contexts[c].m_return_number[i]) enc_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number[i]); } enc_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number_gps_same); delete contexts[c].ic_dX; delete contexts[c].ic_dY; delete contexts[c].ic_Z; for (i = 0; i < 64; i++) { if (contexts[c].m_classification[i]) enc_classification->destroySymbolModel(contexts[c].m_classification[i]); if (contexts[c].m_flags[i]) enc_flags->destroySymbolModel(contexts[c].m_flags[i]); if (contexts[c].m_user_data[i]) enc_user_data->destroySymbolModel(contexts[c].m_user_data[i]); } delete contexts[c].ic_intensity; delete contexts[c].ic_scan_angle; delete contexts[c].ic_point_source_ID; enc_gps_time->destroySymbolModel(contexts[c].m_gpstime_multi); enc_gps_time->destroySymbolModel(contexts[c].m_gpstime_0diff); delete contexts[c].ic_gpstime; } } /* destroy all encoders and outstreams */ if (outstream_channel_returns_XY) { delete enc_channel_returns_XY; delete enc_Z; delete enc_classification; delete enc_flags; delete enc_intensity; delete enc_scan_angle; delete enc_user_data; delete enc_point_source; delete enc_gps_time; delete outstream_channel_returns_XY; delete outstream_Z; delete outstream_classification; delete outstream_flags; delete outstream_intensity; delete outstream_scan_angle; delete outstream_user_data; delete outstream_point_source; delete outstream_gps_time; } // fprintf(stderr, "%u %u %u %u %u %u %u %u %u\n", num_bytes_channel_returns_XY, num_bytes_Z, num_bytes_classification, num_bytes_flags, num_bytes_intensity, num_bytes_scan_angle, num_bytes_user_data, num_bytes_point_source, num_bytes_gps_time); } inline BOOL LASwriteItemCompressed_POINT14_v3::createAndInitModelsAndCompressors(U32 context, const U8* item) { I32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and integer compressors (if needed) */ if (contexts[context].m_changed_values[0] == 0) { /* for the channel_returns_XY layer */ contexts[context].m_changed_values[0] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[1] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[2] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[3] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[4] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[5] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[6] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[7] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_scanner_channel = enc_channel_returns_XY->createSymbolModel(3); for (i = 0; i < 16; i++) { contexts[context].m_number_of_returns[i] = 0; contexts[context].m_return_number[i] = 0; } contexts[context].m_return_number_gps_same = enc_channel_returns_XY->createSymbolModel(13); contexts[context].ic_dX = new IntegerCompressor(enc_channel_returns_XY, 32, 2); // 32 bits, 2 context contexts[context].ic_dY = new IntegerCompressor(enc_channel_returns_XY, 32, 22); // 32 bits, 22 contexts /* for the Z layer */ contexts[context].ic_Z = new IntegerCompressor(enc_Z, 32, 20); // 32 bits, 20 contexts /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { contexts[context].m_classification[i] = 0; contexts[context].m_flags[i] = 0; contexts[context].m_user_data[i] = 0; } /* for the intensity layer */ contexts[context].ic_intensity = new IntegerCompressor(enc_intensity, 16, 4); /* for the scan_angle layer */ contexts[context].ic_scan_angle = new IntegerCompressor(enc_scan_angle, 16, 2); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID = new IntegerCompressor(enc_point_source, 16); /* for the gps_time layer */ contexts[context].m_gpstime_multi = enc_gps_time->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); contexts[context].m_gpstime_0diff = enc_gps_time->createSymbolModel(5); contexts[context].ic_gpstime = new IntegerCompressor(enc_gps_time, 32, 9); // 32 bits, 9 contexts } /* then init entropy models and integer compressors */ /* for the channel_returns_XY layer */ enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[0]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[1]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[2]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[3]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[4]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[5]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[6]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[7]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[context].m_number_of_returns[i]) enc_channel_returns_XY->initSymbolModel(contexts[context].m_number_of_returns[i]); if (contexts[context].m_return_number[i]) enc_channel_returns_XY->initSymbolModel(contexts[context].m_return_number[i]); } enc_channel_returns_XY->initSymbolModel(contexts[context].m_return_number_gps_same); contexts[context].ic_dX->initCompressor(); contexts[context].ic_dY->initCompressor(); for (i = 0; i < 12; i++) { contexts[context].last_X_diff_median5[i].init(); contexts[context].last_Y_diff_median5[i].init(); } /* for the Z layer */ contexts[context].ic_Z->initCompressor(); for (i = 0; i < 8; i++) { contexts[context].last_Z[i] = ((LASpoint14*)item)->Z; } /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { if (contexts[context].m_classification[i]) enc_classification->initSymbolModel(contexts[context].m_classification[i]); if (contexts[context].m_flags[i]) enc_flags->initSymbolModel(contexts[context].m_flags[i]); if (contexts[context].m_user_data[i]) enc_user_data->initSymbolModel(contexts[context].m_user_data[i]); } /* for the intensity layer */ contexts[context].ic_intensity->initCompressor(); for (i = 0; i < 8; i++) { contexts[context].last_intensity[i] = ((LASpoint14*)item)->intensity; } /* for the scan_angle layer */ contexts[context].ic_scan_angle->initCompressor(); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID->initCompressor(); /* for the gps_time layer */ enc_gps_time->initSymbolModel(contexts[context].m_gpstime_multi); enc_gps_time->initSymbolModel(contexts[context].m_gpstime_0diff); contexts[context].ic_gpstime->initCompressor(); contexts[context].last = 0, contexts[context].next = 0; contexts[context].last_gpstime_diff[0] = 0; contexts[context].last_gpstime_diff[1] = 0; contexts[context].last_gpstime_diff[2] = 0; contexts[context].last_gpstime_diff[3] = 0; contexts[context].multi_extreme_counter[0] = 0; contexts[context].multi_extreme_counter[1] = 0; contexts[context].multi_extreme_counter[2] = 0; contexts[context].multi_extreme_counter[3] = 0; contexts[context].last_gpstime[0].f64 = ((LASpoint14*)item)->gps_time; contexts[context].last_gpstime[1].u64 = 0; contexts[context].last_gpstime[2].u64 = 0; contexts[context].last_gpstime[3].u64 = 0; /* init current context from item */ memcpy(contexts[context].last_item, item, sizeof(LASpoint14)); ((LASpoint14*)contexts[context].last_item)->gps_time_change = FALSE; contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_POINT14_v3::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_channel_returns_XY == 0) { if (IS_LITTLE_ENDIAN()) { outstream_channel_returns_XY = new ByteStreamOutArrayLE(); outstream_Z = new ByteStreamOutArrayLE(); outstream_classification = new ByteStreamOutArrayLE(); outstream_flags = new ByteStreamOutArrayLE(); outstream_intensity = new ByteStreamOutArrayLE(); outstream_scan_angle = new ByteStreamOutArrayLE(); outstream_user_data = new ByteStreamOutArrayLE(); outstream_point_source = new ByteStreamOutArrayLE(); outstream_gps_time = new ByteStreamOutArrayLE(); } else { outstream_channel_returns_XY = new ByteStreamOutArrayBE(); outstream_Z = new ByteStreamOutArrayBE(); outstream_classification = new ByteStreamOutArrayBE(); outstream_flags = new ByteStreamOutArrayBE(); outstream_intensity = new ByteStreamOutArrayBE(); outstream_scan_angle = new ByteStreamOutArrayBE(); outstream_user_data = new ByteStreamOutArrayBE(); outstream_point_source = new ByteStreamOutArrayBE(); outstream_gps_time = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_channel_returns_XY = new ArithmeticEncoder(); enc_Z = new ArithmeticEncoder(); enc_classification = new ArithmeticEncoder(); enc_flags = new ArithmeticEncoder(); enc_intensity = new ArithmeticEncoder(); enc_scan_angle = new ArithmeticEncoder(); enc_user_data = new ArithmeticEncoder(); enc_point_source = new ArithmeticEncoder(); enc_gps_time = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_channel_returns_XY->seek(0); outstream_Z->seek(0); outstream_classification->seek(0); outstream_flags->seek(0); outstream_intensity->seek(0); outstream_scan_angle->seek(0); outstream_user_data->seek(0); outstream_point_source->seek(0); outstream_gps_time->seek(0); } /* init layer encoders */ enc_channel_returns_XY->init(outstream_channel_returns_XY); enc_Z->init(outstream_Z); enc_classification->init(outstream_classification); enc_flags->init(outstream_flags); enc_intensity->init(outstream_intensity); enc_scan_angle->init(outstream_scan_angle); enc_user_data->init(outstream_user_data); enc_point_source->init(outstream_point_source); enc_gps_time->init(outstream_gps_time); /* set changed booleans to FALSE */ changed_classification = FALSE; changed_flags = FALSE; changed_intensity = FALSE; changed_scan_angle = FALSE; changed_user_data = FALSE; changed_point_source = FALSE; changed_gps_time = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = ((LASpoint14*)item)->scanner_channel; context = current_context; // the POINT14 writer sets context for all other items /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v3::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; //////////////////////////////////////// // compress returns_XY layer //////////////////////////////////////// // create single (3) / first (1) / last (2) / intermediate (0) context from last point return I32 lpr = (((LASpoint14*)last_item)->return_number == 1 ? 1 : 0); // first? lpr += (((LASpoint14*)last_item)->return_number >= ((LASpoint14*)last_item)->number_of_returns ? 2 : 0); // last? // add info whether the GPS time changed in the last return to the context lpr += (((LASpoint14*)last_item)->gps_time_change ? 4 : 0); // get the (potentially new) context U32 scanner_channel = ((LASpoint14*)item)->scanner_channel; // if context has changed (and the new context already exists) get last for new context if (scanner_channel != current_context) { if (contexts[scanner_channel].unused == FALSE) { last_item = contexts[scanner_channel].last_item; } } // determine changed attributes BOOL point_source_change = (((LASpoint14*)item)->point_source_ID != ((LASpoint14*)last_item)->point_source_ID); BOOL gps_time_change = (((LASpoint14*)item)->gps_time != ((LASpoint14*)last_item)->gps_time); BOOL scan_angle_change = (((LASpoint14*)item)->scan_angle != ((LASpoint14*)last_item)->scan_angle); // get last and current return counts U32 last_n = ((LASpoint14*)last_item)->number_of_returns; U32 last_r = ((LASpoint14*)last_item)->return_number; U32 n = ((LASpoint14*)item)->number_of_returns; U32 r = ((LASpoint14*)item)->return_number; // create the 7 bit mask that encodes various changes (its value ranges from 0 to 127) I32 changed_values = ((scanner_channel != current_context) << 6) | // scanner channel compared to last point (same = 0 / different = 1) (point_source_change << 5) | // point source ID compared to last point from *same* scanner channel (same = 0 / different = 1) (gps_time_change << 4) | // GPS time stamp compared to last point from *same* scanner channel (same = 0 / different = 1) (scan_angle_change << 3) | // scan angle compared to last point from *same* scanner channel (same = 0 / different = 1) ((n != last_n) << 2); // number of returns compared to last point from *same* scanner channel (same = 0 / different = 1) // return number compared to last point of *same* scanner channel (same = 0 / plus one mod 16 = 1 / minus one mod 16 = 2 / other difference = 3) if (r != last_r) { if (r == ((last_r + 1) % 16)) { changed_values |= 1; } else if (r == ((last_r + 15) % 16)) { changed_values |= 2; } else { changed_values |= 3; } } // compress the 7 bit mask that encodes changes with last point return context enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_changed_values[lpr], changed_values); // if scanner channel has changed, record change if (changed_values & (1 << 6)) { I32 diff = scanner_channel - current_context; if (diff > 0) { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_scanner_channel, diff - 1); // curr = last + (sym + 1) } else { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_scanner_channel, diff + 4 - 1); // curr = (last + (sym + 1)) % 4 } // maybe create and init entropy models and integer compressors if (contexts[scanner_channel].unused) { // create and init entropy models and integer compressors (and init context from last item) createAndInitModelsAndCompressors(scanner_channel, contexts[current_context].last_item); // get last for new context last_item = contexts[scanner_channel].last_item; } // switch context to current scanner channel current_context = scanner_channel; context = current_context; // the POINT14 writer sets context for all other items } // if number of returns is different we compress it if (changed_values & (1 << 2)) { if (contexts[current_context].m_number_of_returns[last_n] == 0) { contexts[current_context].m_number_of_returns[last_n] = enc_channel_returns_XY->createSymbolModel(16); enc_channel_returns_XY->initSymbolModel(contexts[current_context].m_number_of_returns[last_n]); } enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_number_of_returns[last_n], n); } // if return number is different and difference is bigger than +1 / -1 we compress how it is different if ((changed_values & 3) == 3) { if (gps_time_change) // if the GPS time has changed { if (contexts[current_context].m_return_number[last_r] == 0) { contexts[current_context].m_return_number[last_r] = enc_channel_returns_XY->createSymbolModel(16); enc_channel_returns_XY->initSymbolModel(contexts[current_context].m_return_number[last_r]); } enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number[last_r], r); } else // if the GPS time has not changed { I32 diff = r - last_r; if (diff > 1) { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number_gps_same, diff - 2); // r = last_r + (sym + 2) with sym = diff - 2 } else { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number_gps_same, diff + 16 - 2); // r = (last_r + (sym + 2)) % 16 with sym = diff + 16 - 2 } } } // get return map m and return level l context for current point U32 m = number_return_map_6ctx[n][r]; U32 l = number_return_level_8ctx[n][r]; // create single (3) / first (1) / last (2) / intermediate (0) return context for current point I32 cpr = (r == 1 ? 2 : 0); // first ? cpr += (r >= n ? 1 : 0); // last ? U32 k_bits; I32 median, diff; // compress X coordinate median = contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].get(); diff = ((LASpoint14*)item)->X - ((LASpoint14*)last_item)->X; contexts[current_context].ic_dX->compress(median, diff, n==1); contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].add(diff); // compress Y coordinate k_bits = contexts[current_context].ic_dX->getK(); median = contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].get(); diff = ((LASpoint14*)item)->Y - ((LASpoint14*)last_item)->Y; contexts[current_context].ic_dY->compress(median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].add(diff); //////////////////////////////////////// // compress Z layer //////////////////////////////////////// k_bits = (contexts[current_context].ic_dX->getK() + contexts[current_context].ic_dY->getK()) / 2; contexts[current_context].ic_Z->compress(contexts[current_context].last_Z[l], ((LASpoint14*)item)->Z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); contexts[current_context].last_Z[l] = ((LASpoint14*)item)->Z; //////////////////////////////////////// // compress classifications layer //////////////////////////////////////// U32 last_classification = ((LASpoint14*)last_item)->classification; U32 classification = ((LASpoint14*)item)->classification; if (classification != last_classification) { changed_classification = TRUE; } I32 ccc = ((last_classification & 0x1F) << 1) + (cpr == 3 ? 1 : 0); if (contexts[current_context].m_classification[ccc] == 0) { contexts[current_context].m_classification[ccc] = enc_classification->createSymbolModel(256); enc_classification->initSymbolModel(contexts[current_context].m_classification[ccc]); } enc_classification->encodeSymbol(contexts[current_context].m_classification[ccc], classification); //////////////////////////////////////// // compress flags layer //////////////////////////////////////// U32 last_flags = (((LASpoint14*)last_item)->edge_of_flight_line << 5) | (((LASpoint14*)last_item)->scan_direction_flag << 4) | ((LASpoint14*)last_item)->classification_flags; U32 flags = (((LASpoint14*)item)->edge_of_flight_line << 5) | (((LASpoint14*)item)->scan_direction_flag << 4) | ((LASpoint14*)item)->classification_flags; if (flags != last_flags) { changed_flags = TRUE; } if (contexts[current_context].m_flags[last_flags] == 0) { contexts[current_context].m_flags[last_flags] = enc_flags->createSymbolModel(64); enc_flags->initSymbolModel(contexts[current_context].m_flags[last_flags]); } enc_flags->encodeSymbol(contexts[current_context].m_flags[last_flags], flags); //////////////////////////////////////// // compress intensity layer //////////////////////////////////////// if (((LASpoint14*)item)->intensity != ((LASpoint14*)last_item)->intensity) { changed_intensity = TRUE; } contexts[current_context].ic_intensity->compress(contexts[current_context].last_intensity[(cpr<<1) | gps_time_change], ((LASpoint14*)item)->intensity, cpr); contexts[current_context].last_intensity[(cpr<<1) | gps_time_change] = ((LASpoint14*)item)->intensity; //////////////////////////////////////// // compress scan_angle layer //////////////////////////////////////// if (scan_angle_change) { changed_scan_angle = TRUE; contexts[current_context].ic_scan_angle->compress(((LASpoint14*)last_item)->scan_angle, ((LASpoint14*)item)->scan_angle, gps_time_change); // if the GPS time has changed } //////////////////////////////////////// // compress user_data layer //////////////////////////////////////// if (((LASpoint14*)item)->user_data != ((LASpoint14*)last_item)->user_data) { changed_user_data = TRUE; } if (contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] == 0) { contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] = enc_user_data->createSymbolModel(256); enc_user_data->initSymbolModel(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } enc_user_data->encodeSymbol(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4], ((LASpoint14*)item)->user_data); //////////////////////////////////////// // compress point_source layer //////////////////////////////////////// if (point_source_change) { changed_point_source = TRUE; contexts[current_context].ic_point_source_ID->compress(((LASpoint14*)last_item)->point_source_ID, ((LASpoint14*)item)->point_source_ID); } //////////////////////////////////////// // compress gps_time layer //////////////////////////////////////// if (gps_time_change) // if the GPS time has changed { changed_gps_time = TRUE; U64I64F64 gps_time; gps_time.f64 = ((LASpoint14*)item)->gps_time; write_gps_time(gps_time); } // copy the last item memcpy(last_item, item, sizeof(LASpoint14)); // remember if the last point had a gps_time_change ((LASpoint14*)last_item)->gps_time_change = gps_time_change; return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v3::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_channel_returns_XY->done(); enc_Z->done(); if (changed_classification) { enc_classification->done(); } if (changed_flags) { enc_flags->done(); } if (changed_intensity) { enc_intensity->done(); } if (changed_scan_angle) { enc_scan_angle->done(); } if (changed_user_data) { enc_user_data->done(); } if (changed_point_source) { enc_point_source->done(); } if (changed_gps_time) { enc_gps_time->done(); } // output the sizes of all layer (i.e.. number of bytes per layer) num_bytes = (U32)outstream_channel_returns_XY->getCurr(); num_bytes_channel_returns_XY += num_bytes; outstream->put32bitsLE(((U8*)&num_bytes)); num_bytes = (U32)outstream_Z->getCurr(); num_bytes_Z += num_bytes; outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_classification) { num_bytes = (U32)outstream_classification->getCurr(); num_bytes_classification += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_flags) { num_bytes = (U32)outstream_flags->getCurr(); num_bytes_flags += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_intensity) { num_bytes = (U32)outstream_intensity->getCurr(); num_bytes_intensity += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_scan_angle) { num_bytes = (U32)outstream_scan_angle->getCurr(); num_bytes_scan_angle += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_user_data) { num_bytes = (U32)outstream_user_data->getCurr(); num_bytes_user_data += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_point_source) { num_bytes = (U32)outstream_point_source->getCurr(); num_bytes_point_source += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_gps_time) { num_bytes = (U32)outstream_gps_time->getCurr(); num_bytes_gps_time += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v3::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers num_bytes = (U32)outstream_channel_returns_XY->getCurr(); outstream->putBytes(outstream_channel_returns_XY->getData(), num_bytes); num_bytes = (U32)outstream_Z->getCurr(); outstream->putBytes(outstream_Z->getData(), num_bytes); if (changed_classification) { num_bytes = (U32)outstream_classification->getCurr(); outstream->putBytes(outstream_classification->getData(), num_bytes); } else { num_bytes = 0; } if (changed_flags) { num_bytes = (U32)outstream_flags->getCurr(); outstream->putBytes(outstream_flags->getData(), num_bytes); } else { num_bytes = 0; } if (changed_intensity) { num_bytes = (U32)outstream_intensity->getCurr(); outstream->putBytes(outstream_intensity->getData(), num_bytes); } else { num_bytes = 0; } if (changed_scan_angle) { num_bytes = (U32)outstream_scan_angle->getCurr(); outstream->putBytes(outstream_scan_angle->getData(), num_bytes); } else { num_bytes = 0; } if (changed_user_data) { num_bytes = (U32)outstream_user_data->getCurr(); outstream->putBytes(outstream_user_data->getData(), num_bytes); } else { num_bytes = 0; } if (changed_point_source) { num_bytes = (U32)outstream_point_source->getCurr(); outstream->putBytes(outstream_point_source->getData(), num_bytes); } else { num_bytes = 0; } if (changed_gps_time) { num_bytes = (U32)outstream_gps_time->getCurr(); outstream->putBytes(outstream_gps_time->getData(), num_bytes); } else { num_bytes = 0; } return TRUE; } void LASwriteItemCompressed_POINT14_v3::write_gps_time(const U64I64F64 gps_time) { if (contexts[current_context].last_gpstime_diff[contexts[current_context].last] == 0) // if the last integer difference was zero { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[contexts[current_context].last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, 0); // the difference can be represented with 32 bits contexts[current_context].ic_gpstime->compress(0, curr_gpstime_diff, 0); contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[(contexts[current_context].last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, i+1); // it belongs to another sequence contexts[current_context].last = (contexts[current_context].last+i)&3; write_gps_time(gps_time); return; } } // no other sequence found. start new sequence. enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, 1); contexts[current_context].ic_gpstime->compress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), (I32)(gps_time.u64 >> 32), 8); enc_gps_time->writeInt((U32)(gps_time.u64)); contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } contexts[current_context].last_gpstime[contexts[current_context].last].i64 = gps_time.i64; } else // the last integer difference was *not* zero { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[contexts[current_context].last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; // if the current gpstime difference can be represented with 32 bits if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { // compute multiplier between current and last integer difference F32 multi_f = (F32)curr_gpstime_diff / (F32)(contexts[current_context].last_gpstime_diff[contexts[current_context].last]); I32 multi = I32_QUANTIZE(multi_f); // compress the residual curr_gpstime_diff in dependance on the multiplier if (multi == 1) { // this is the case we assume we get most often for regular spaced pulses enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, 1); contexts[current_context].ic_gpstime->compress(contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 1); contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi > 0) { if (multi < LASZIP_GPSTIME_MULTI) // positive multipliers up to LASZIP_GPSTIME_MULTI are compressed directly { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, multi); if (multi < 10) contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 2); else contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 3); } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI); contexts[current_context].ic_gpstime->compress(LASZIP_GPSTIME_MULTI*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 4); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else if (multi < 0) { if (multi > LASZIP_GPSTIME_MULTI_MINUS) // negative multipliers larger than LASZIP_GPSTIME_MULTI_MINUS are compressed directly { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI - multi); contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 5); } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS); contexts[current_context].ic_gpstime->compress(LASZIP_GPSTIME_MULTI_MINUS*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 6); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, 0); contexts[current_context].ic_gpstime->compress(0, curr_gpstime_diff, 7); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[(contexts[current_context].last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { // it belongs to this sequence enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL+i); contexts[current_context].last = (contexts[current_context].last+i)&3; write_gps_time(gps_time); return; } } // no other sequence found. start new sequence. enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL); contexts[current_context].ic_gpstime->compress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), (I32)(gps_time.u64 >> 32), 8); enc_gps_time->writeInt((U32)(gps_time.u64)); contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } contexts[current_context].last_gpstime[contexts[current_context].last].i64 = gps_time.i64; } } /* =============================================================================== LASwriteItemCompressed_RGB14_v3 =============================================================================== */ LASwriteItemCompressed_RGB14_v3::LASwriteItemCompressed_RGB14_v3(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_RGB = 0; enc_RGB = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; changed_RGB = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_byte_used = 0; } current_context = 0; } LASwriteItemCompressed_RGB14_v3::~LASwriteItemCompressed_RGB14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_byte_used) { enc_RGB->destroySymbolModel(contexts[c].m_byte_used); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } } /* destroy all outstreams and encoders */ if (outstream_RGB) { delete outstream_RGB; delete enc_RGB; } } inline BOOL LASwriteItemCompressed_RGB14_v3::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_byte_used == 0) { contexts[context].m_byte_used = enc_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = enc_RGB->createSymbolModel(256); } /* then init entropy models */ enc_RGB->initSymbolModel(contexts[context].m_byte_used); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); /* init current context from item */ memcpy(contexts[context].last_item, item, 6); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_RGB14_v3::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_RGB == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_RGB = new ByteStreamOutArrayLE(); } else { outstream_RGB = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_RGB = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_RGB->seek(0); } /* init layer encoders */ enc_RGB->init(outstream_RGB); /* set changed booleans to FALSE */ changed_RGB = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init contect from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v3::write(const U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } // compress I32 diff_l = 0; I32 diff_h = 0; I32 corr; U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6; enc_RGB->encodeSymbol(contexts[current_context].m_byte_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_1, U8_FOLD(diff_h)); } if (sym & (1 << 6)) { if (sym & (1 << 2)) { corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_2, U8_FOLD(corr)); } if (sym & (1 << 4)) { diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2; corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_4, U8_FOLD(corr)); } if (sym & (1 << 3)) { corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_3, U8_FOLD(corr)); } if (sym & (1 << 5)) { diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2; corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_5, U8_FOLD(corr)); } } if (sym) { changed_RGB = TRUE; } memcpy(last_item, item, 6); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v3::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_RGB->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); num_bytes_RGB += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v3::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); outstream->putBytes(outstream_RGB->getData(), num_bytes); } return TRUE; } /* =============================================================================== LASwriteItemCompressed_RGBNIR14_v3 =============================================================================== */ LASwriteItemCompressed_RGBNIR14_v3::LASwriteItemCompressed_RGBNIR14_v3(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_RGB = 0; outstream_NIR = 0; enc_RGB = 0; enc_NIR = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; num_bytes_NIR = 0; changed_RGB = FALSE; changed_NIR = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_rgb_bytes_used = 0; } current_context = 0; } LASwriteItemCompressed_RGBNIR14_v3::~LASwriteItemCompressed_RGBNIR14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_rgb_bytes_used) { enc_RGB->destroySymbolModel(contexts[c].m_rgb_bytes_used); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); enc_NIR->destroySymbolModel(contexts[c].m_nir_bytes_used); enc_NIR->destroySymbolModel(contexts[c].m_nir_diff_0); enc_NIR->destroySymbolModel(contexts[c].m_nir_diff_1); } } /* destroy all outstreams and encoders */ if (outstream_RGB) { delete outstream_RGB; delete outstream_NIR; delete enc_RGB; delete enc_NIR; } } inline BOOL LASwriteItemCompressed_RGBNIR14_v3::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_rgb_bytes_used == 0) { contexts[context].m_rgb_bytes_used = enc_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = enc_RGB->createSymbolModel(256); contexts[context].m_nir_bytes_used = enc_RGB->createSymbolModel(4); contexts[context].m_nir_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_nir_diff_1 = enc_RGB->createSymbolModel(256); } /* then init entropy models */ enc_RGB->initSymbolModel(contexts[context].m_rgb_bytes_used); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); enc_NIR->initSymbolModel(contexts[context].m_nir_bytes_used); enc_NIR->initSymbolModel(contexts[context].m_nir_diff_0); enc_NIR->initSymbolModel(contexts[context].m_nir_diff_1); /* init current context from item */ memcpy(contexts[context].last_item, item, 8); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_RGBNIR14_v3::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_RGB == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_RGB = new ByteStreamOutArrayLE(); outstream_NIR = new ByteStreamOutArrayLE(); } else { outstream_RGB = new ByteStreamOutArrayBE(); outstream_NIR = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_RGB = new ArithmeticEncoder(); enc_NIR = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_RGB->seek(0); outstream_NIR->seek(0); } /* init layer encoders */ enc_RGB->init(outstream_RGB); enc_NIR->init(outstream_NIR); /* set changed booleans to FALSE */ changed_RGB = FALSE; changed_NIR = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // ll other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v3::write(const U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } // compress I32 diff_l = 0; I32 diff_h = 0; I32 corr; U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6; enc_RGB->encodeSymbol(contexts[current_context].m_rgb_bytes_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_1, U8_FOLD(diff_h)); } if (sym & (1 << 6)) { if (sym & (1 << 2)) { corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_2, U8_FOLD(corr)); } if (sym & (1 << 4)) { diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2; corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_4, U8_FOLD(corr)); } if (sym & (1 << 3)) { corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_3, U8_FOLD(corr)); } if (sym & (1 << 5)) { diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2; corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_5, U8_FOLD(corr)); } } if (sym) { changed_RGB = TRUE; } sym = ((last_item[3]&0x00FF) != (((U16*)item)[3]&0x00FF)) << 0; sym |= ((last_item[3]&0xFF00) != (((U16*)item)[3]&0xFF00)) << 1; enc_NIR->encodeSymbol(contexts[current_context].m_nir_bytes_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[3]&255)) - (last_item[3]&255); enc_NIR->encodeSymbol(contexts[current_context].m_nir_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[3]>>8)) - (last_item[3]>>8); enc_NIR->encodeSymbol(contexts[current_context].m_nir_diff_1, U8_FOLD(diff_h)); } if (sym) { changed_NIR = TRUE; } memcpy(last_item, item, 8); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v3::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_RGB->done(); enc_NIR->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); num_bytes_RGB += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_NIR) { num_bytes = (U32)outstream_NIR->getCurr(); num_bytes_NIR += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v3::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); outstream->putBytes(outstream_RGB->getData(), num_bytes); } else { num_bytes = 0; } if (changed_NIR) { num_bytes = (U32)outstream_NIR->getCurr(); outstream->putBytes(outstream_NIR->getData(), num_bytes); } else { num_bytes = 0; } return TRUE; } /* =============================================================================== LASwriteItemCompressed_WAVEPACKET14_v3 =============================================================================== */ LASwriteItemCompressed_WAVEPACKET14_v3::LASwriteItemCompressed_WAVEPACKET14_v3(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_wavepacket = 0; enc_wavepacket = 0; /* zero num_bytes and init booleans */ num_bytes_wavepacket = 0; changed_wavepacket = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_packet_index = 0; } current_context = 0; } LASwriteItemCompressed_WAVEPACKET14_v3::~LASwriteItemCompressed_WAVEPACKET14_v3() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_packet_index) { enc_wavepacket->destroySymbolModel(contexts[c].m_packet_index); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[0]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[1]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[2]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[3]); delete contexts[c].ic_offset_diff; delete contexts[c].ic_packet_size; delete contexts[c].ic_return_point; delete contexts[c].ic_xyz; } } /* destroy all outstreams and encoders */ if (outstream_wavepacket) { delete outstream_wavepacket; delete enc_wavepacket; } } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v3::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_packet_index == 0) { contexts[context].m_packet_index = enc_wavepacket->createSymbolModel(256); contexts[context].m_offset_diff[0] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[1] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[2] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[3] = enc_wavepacket->createSymbolModel(4); contexts[context].ic_offset_diff = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_packet_size = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_return_point = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_xyz = new IntegerCompressor(enc_wavepacket, 32, 3); } /* then init entropy models */ enc_wavepacket->initSymbolModel(contexts[context].m_packet_index); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[0]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[1]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[2]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[3]); contexts[context].ic_offset_diff->initCompressor(); contexts[context].ic_packet_size->initCompressor(); contexts[context].ic_return_point->initCompressor(); contexts[context].ic_xyz->initCompressor(); /* init current context from item */ contexts[context].last_diff_32 = 0; contexts[context].sym_last_offset_diff = 0; memcpy(contexts[context].last_item, item, 29); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_WAVEPACKET14_v3::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_wavepacket == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_wavepacket = new ByteStreamOutArrayLE(); } else { outstream_wavepacket = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_wavepacket = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_wavepacket->seek(0); } /* init layer encoders */ enc_wavepacket->init(outstream_wavepacket); /* set changed booleans to FALSE */ changed_wavepacket = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init contect from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v3::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); last_item = contexts[current_context].last_item; } } if (memcmp(item, last_item, 29) != 0) { changed_wavepacket = TRUE; } // compress enc_wavepacket->encodeSymbol(contexts[current_context].m_packet_index, (U32)(item[0])); LASwavepacket13 this_item_m = LASwavepacket13::unpack(item+1); LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item+1); // calculate the difference between the two offsets I64 curr_diff_64 = this_item_m.offset - last_item_m.offset; I32 curr_diff_32 = (I32)curr_diff_64; // if the current difference can be represented with 32 bits if (curr_diff_64 == (I64)(curr_diff_32)) { if (curr_diff_32 == 0) // current difference is zero { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 0); contexts[current_context].sym_last_offset_diff = 0; } else if (curr_diff_32 == (I32)last_item_m.packet_size) { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 1); contexts[current_context].sym_last_offset_diff = 1; } else // { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 2); contexts[current_context].sym_last_offset_diff = 2; contexts[current_context].ic_offset_diff->compress(contexts[current_context].last_diff_32, curr_diff_32); contexts[current_context].last_diff_32 = curr_diff_32; } } else { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 3); contexts[current_context].sym_last_offset_diff = 3; enc_wavepacket->writeInt64(this_item_m.offset); } contexts[current_context].ic_packet_size->compress(last_item_m.packet_size, this_item_m.packet_size); contexts[current_context].ic_return_point->compress(last_item_m.return_point.i32, this_item_m.return_point.i32); contexts[current_context].ic_xyz->compress(last_item_m.x.i32, this_item_m.x.i32, 0); contexts[current_context].ic_xyz->compress(last_item_m.y.i32, this_item_m.y.i32, 1); contexts[current_context].ic_xyz->compress(last_item_m.z.i32, this_item_m.z.i32, 2); memcpy(last_item, item, 29); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v3::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_wavepacket->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_wavepacket) { num_bytes = (U32)outstream_wavepacket->getCurr(); num_bytes_wavepacket += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v3::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_wavepacket) { num_bytes = (U32)outstream_wavepacket->getCurr(); outstream->putBytes(outstream_wavepacket->getData(), num_bytes); } return TRUE; } /* =============================================================================== LASwriteItemCompressed_BYTE14_v3 =============================================================================== */ LASwriteItemCompressed_BYTE14_v3::LASwriteItemCompressed_BYTE14_v3(ArithmeticEncoder* enc, U32 number) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* must be more than one byte */ assert(number); this->number = number; /* zero outstream and encoder pointer arrays */ outstream_Bytes = 0; enc_Bytes = 0; /* number of bytes per layer */ num_bytes_Bytes = new U32[number]; changed_Bytes = new BOOL[number]; U32 i; for (i = 0; i < number; i++) { num_bytes_Bytes[i] = 0; changed_Bytes[i] = FALSE; } /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_bytes = 0; } current_context = 0; } LASwriteItemCompressed_BYTE14_v3::~LASwriteItemCompressed_BYTE14_v3() { /* destroy all initialized scanner channel contexts */ U32 c, i; for (c = 0; c < 4; c++) { if (contexts[c].m_bytes) { for (i = 0; i < number; i++) { enc_Bytes[i]->destroySymbolModel(contexts[c].m_bytes[i]); } delete [] contexts[c].m_bytes; delete [] contexts[c].last_item; } } /* destroy all outstream and encoder arrays */ if (outstream_Bytes) { for (i = 0; i < number; i++) { if (outstream_Bytes[i]) { delete outstream_Bytes[i]; delete enc_Bytes[i]; } } delete [] outstream_Bytes; delete [] enc_Bytes; } /* destroy all other arrays */ if (num_bytes_Bytes) delete [] num_bytes_Bytes; if (changed_Bytes) delete [] changed_Bytes; } inline BOOL LASwriteItemCompressed_BYTE14_v3::createAndInitModelsAndCompressors(U32 context, const U8* item) { U32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and last items (if needed) */ if (contexts[context].m_bytes == 0) { contexts[context].m_bytes = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { contexts[context].m_bytes[i] = enc_Bytes[i]->createSymbolModel(256); enc_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* create last item */ contexts[context].last_item = new U8[number]; } /* then init entropy models */ for (i = 0; i < number; i++) { enc_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* init current context from item */ memcpy(contexts[context].last_item, item, number); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_BYTE14_v3::init(const U8* item, U32& context) { U32 i; /* on the first init create outstreams and encoders */ if (outstream_Bytes == 0) { /* create outstreams pointer array */ outstream_Bytes = new ByteStreamOutArray*[number]; /* create outstreams */ if (IS_LITTLE_ENDIAN()) { for (i = 0; i < number; i++) { outstream_Bytes[i] = new ByteStreamOutArrayLE(); } } else { for (i = 0; i < number; i++) { outstream_Bytes[i] = new ByteStreamOutArrayBE(); } } /* create encoder pointer array */ enc_Bytes = new ArithmeticEncoder*[number]; /* create layer encoders */ for (i = 0; i < number; i++) { enc_Bytes[i] = new ArithmeticEncoder(); } } else { /* otherwise just seek back */ for (i = 0; i < number; i++) { outstream_Bytes[i]->seek(0); } } /* init layer encoders */ for (i = 0; i < number; i++) { enc_Bytes[i]->init(outstream_Bytes[i]); } /* set changed booleans to FALSE */ for (i = 0; i < number; i++) { changed_Bytes[i] = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v3::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, last_item); last_item = contexts[current_context].last_item; } } // compress U32 i; I32 diff; for (i = 0; i < number; i++) { diff = item[i] - last_item[i]; enc_Bytes[i]->encodeSymbol(contexts[current_context].m_bytes[i], U8_FOLD(diff)); if (diff) { changed_Bytes[i] = TRUE; last_item[i] = item[i]; } } return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v3::chunk_sizes() { U32 i; U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the sizes of all layer (i.e.. number of bytes per layer) for (i = 0; i < number; i++) { // finish the encoders enc_Bytes[i]->done(); if (changed_Bytes[i]) { num_bytes = (U32)outstream_Bytes[i]->getCurr(); num_bytes_Bytes[i] += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); } return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v3::chunk_bytes() { U32 i; U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers for (i = 0; i < number; i++) { if (changed_Bytes[i]) { num_bytes = (U32)outstream_Bytes[i]->getCurr(); outstream->putBytes(outstream_Bytes[i]->getData(), num_bytes); } else { num_bytes = 0; } } return TRUE; } LASzip-3.4.3/src/laswriteitemcompressed_v3.hpp000066400000000000000000000134671356234217100214100ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v3.hpp CONTENTS: Native extension for compressing the *new* point types 6 to 10 of LAS 1.4 PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 August 2017 -- moving 'context' from global development hack to interface 22 August 2016 -- finalizing at Basecamp in Bonn during FOSS4g hackfest 23 February 2016 -- created at OSGeo Code Sprint in Paris to prototype =============================================================================== */ #ifndef LAS_WRITE_ITEM_COMPRESSED_V3_HPP #define LAS_WRITE_ITEM_COMPRESSED_V3_HPP #include "laswriteitem.hpp" #include "arithmeticencoder.hpp" #include "integercompressor.hpp" #include "bytestreamout_array.hpp" #include "laszip_common_v3.hpp" class LASwriteItemCompressed_POINT14_v3 : public LASwriteItemCompressed { public: LASwriteItemCompressed_POINT14_v3(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_POINT14_v3(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_channel_returns_XY; ByteStreamOutArray* outstream_Z; ByteStreamOutArray* outstream_classification; ByteStreamOutArray* outstream_flags; ByteStreamOutArray* outstream_intensity; ByteStreamOutArray* outstream_scan_angle; ByteStreamOutArray* outstream_user_data; ByteStreamOutArray* outstream_point_source; ByteStreamOutArray* outstream_gps_time; ArithmeticEncoder* enc_channel_returns_XY; ArithmeticEncoder* enc_Z; ArithmeticEncoder* enc_classification; ArithmeticEncoder* enc_flags; ArithmeticEncoder* enc_intensity; ArithmeticEncoder* enc_scan_angle; ArithmeticEncoder* enc_user_data; ArithmeticEncoder* enc_point_source; ArithmeticEncoder* enc_gps_time; BOOL changed_classification; BOOL changed_flags; BOOL changed_intensity; BOOL changed_scan_angle; BOOL changed_user_data; BOOL changed_point_source; BOOL changed_gps_time; U32 num_bytes_channel_returns_XY; U32 num_bytes_Z; U32 num_bytes_classification; U32 num_bytes_flags; U32 num_bytes_intensity; U32 num_bytes_scan_angle; U32 num_bytes_user_data; U32 num_bytes_point_source; U32 num_bytes_gps_time; U32 current_context; LAScontextPOINT14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); void write_gps_time(const U64I64F64 gps_time); }; class LASwriteItemCompressed_RGB14_v3 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGB14_v3(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_RGB14_v3(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_RGB; ArithmeticEncoder* enc_RGB; BOOL changed_RGB; U32 num_bytes_RGB; U32 current_context; LAScontextRGB14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_RGBNIR14_v3 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGBNIR14_v3(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_RGBNIR14_v3(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_RGB; ByteStreamOutArray* outstream_NIR; ArithmeticEncoder* enc_RGB; ArithmeticEncoder* enc_NIR; BOOL changed_RGB; BOOL changed_NIR; U32 num_bytes_RGB; U32 num_bytes_NIR; U32 current_context; LAScontextRGBNIR14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_WAVEPACKET14_v3 : public LASwriteItemCompressed { public: LASwriteItemCompressed_WAVEPACKET14_v3(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_WAVEPACKET14_v3(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_wavepacket; ArithmeticEncoder* enc_wavepacket; BOOL changed_wavepacket; U32 num_bytes_wavepacket; U32 current_context; LAScontextWAVEPACKET14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_BYTE14_v3 : public LASwriteItemCompressed { public: LASwriteItemCompressed_BYTE14_v3(ArithmeticEncoder* enc, U32 number); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_BYTE14_v3(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray** outstream_Bytes; ArithmeticEncoder** enc_Bytes; U32* num_bytes_Bytes; BOOL* changed_Bytes; U32 current_context; LAScontextBYTE14 contexts[4]; U32 number; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; #endif LASzip-3.4.3/src/laswriteitemcompressed_v4.cpp000066400000000000000000002124661356234217100214040ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v4.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laswriteitemcompressed_v4.hpp" #include #include #include /* =============================================================================== LASwriteItemCompressed_POINT14_v4 =============================================================================== */ typedef struct LASpoint14 { I32 X; I32 Y; I32 Z; U16 intensity; U8 legacy_return_number : 3; U8 legacy_number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 legacy_classification : 5; U8 legacy_flags : 3; I8 legacy_scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 scan_angle; U8 legacy_point_type : 2; U8 scanner_channel : 2; U8 classification_flags : 4; U8 classification; U8 return_number : 4; U8 number_of_returns : 4; // LASlib internal use only U8 deleted_flag; // for 8 byte alignment of the GPS time U8 dummy[2]; // compressed LASzip 1.4 points only BOOL gps_time_change; F64 gps_time; U16 rgb[4]; // LASwavepacket wavepacket; } LASpoint14; #define LASZIP_GPSTIME_MULTI 500 #define LASZIP_GPSTIME_MULTI_MINUS -10 #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1) #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 5) LASwriteItemCompressed_POINT14_v4::LASwriteItemCompressed_POINT14_v4(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_channel_returns_XY = 0; outstream_Z = 0; outstream_classification = 0; outstream_flags = 0; outstream_intensity = 0; outstream_scan_angle = 0; outstream_user_data = 0; outstream_point_source = 0; outstream_gps_time = 0; enc_channel_returns_XY = 0; enc_Z = 0; enc_classification = 0; enc_flags = 0; enc_intensity = 0; enc_scan_angle = 0; enc_user_data = 0; enc_point_source = 0; enc_gps_time = 0; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_changed_values[0] = 0; } current_context = 0; /* number of bytes per layer */ num_bytes_channel_returns_XY = 0; num_bytes_Z = 0; num_bytes_classification = 0; num_bytes_flags = 0; num_bytes_intensity = 0; num_bytes_scan_angle = 0; num_bytes_user_data = 0; num_bytes_point_source = 0; num_bytes_gps_time = 0; } LASwriteItemCompressed_POINT14_v4::~LASwriteItemCompressed_POINT14_v4() { U32 c, i; /* destroy all initialized scanner channel contexts */ for (c = 0; c < 4; c++) { if (contexts[c].m_changed_values[0]) { enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[0]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[1]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[2]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[3]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[4]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[5]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[6]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_changed_values[7]); enc_channel_returns_XY->destroySymbolModel(contexts[c].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[c].m_number_of_returns[i]) enc_channel_returns_XY->destroySymbolModel(contexts[c].m_number_of_returns[i]); if (contexts[c].m_return_number[i]) enc_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number[i]); } enc_channel_returns_XY->destroySymbolModel(contexts[c].m_return_number_gps_same); delete contexts[c].ic_dX; delete contexts[c].ic_dY; delete contexts[c].ic_Z; for (i = 0; i < 64; i++) { if (contexts[c].m_classification[i]) enc_classification->destroySymbolModel(contexts[c].m_classification[i]); if (contexts[c].m_flags[i]) enc_flags->destroySymbolModel(contexts[c].m_flags[i]); if (contexts[c].m_user_data[i]) enc_user_data->destroySymbolModel(contexts[c].m_user_data[i]); } delete contexts[c].ic_intensity; delete contexts[c].ic_scan_angle; delete contexts[c].ic_point_source_ID; enc_gps_time->destroySymbolModel(contexts[c].m_gpstime_multi); enc_gps_time->destroySymbolModel(contexts[c].m_gpstime_0diff); delete contexts[c].ic_gpstime; } } /* destroy all encoders and outstreams */ if (outstream_channel_returns_XY) { delete enc_channel_returns_XY; delete enc_Z; delete enc_classification; delete enc_flags; delete enc_intensity; delete enc_scan_angle; delete enc_user_data; delete enc_point_source; delete enc_gps_time; delete outstream_channel_returns_XY; delete outstream_Z; delete outstream_classification; delete outstream_flags; delete outstream_intensity; delete outstream_scan_angle; delete outstream_user_data; delete outstream_point_source; delete outstream_gps_time; } } inline BOOL LASwriteItemCompressed_POINT14_v4::createAndInitModelsAndCompressors(U32 context, const U8* item) { I32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and integer compressors (if needed) */ if (contexts[context].m_changed_values[0] == 0) { /* for the channel_returns_XY layer */ contexts[context].m_changed_values[0] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[1] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[2] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[3] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[4] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[5] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[6] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_changed_values[7] = enc_channel_returns_XY->createSymbolModel(128); contexts[context].m_scanner_channel = enc_channel_returns_XY->createSymbolModel(3); for (i = 0; i < 16; i++) { contexts[context].m_number_of_returns[i] = 0; contexts[context].m_return_number[i] = 0; } contexts[context].m_return_number_gps_same = enc_channel_returns_XY->createSymbolModel(13); contexts[context].ic_dX = new IntegerCompressor(enc_channel_returns_XY, 32, 2); // 32 bits, 2 context contexts[context].ic_dY = new IntegerCompressor(enc_channel_returns_XY, 32, 22); // 32 bits, 22 contexts /* for the Z layer */ contexts[context].ic_Z = new IntegerCompressor(enc_Z, 32, 20); // 32 bits, 20 contexts /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { contexts[context].m_classification[i] = 0; contexts[context].m_flags[i] = 0; contexts[context].m_user_data[i] = 0; } /* for the intensity layer */ contexts[context].ic_intensity = new IntegerCompressor(enc_intensity, 16, 4); /* for the scan_angle layer */ contexts[context].ic_scan_angle = new IntegerCompressor(enc_scan_angle, 16, 2); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID = new IntegerCompressor(enc_point_source, 16); /* for the gps_time layer */ contexts[context].m_gpstime_multi = enc_gps_time->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL); contexts[context].m_gpstime_0diff = enc_gps_time->createSymbolModel(5); contexts[context].ic_gpstime = new IntegerCompressor(enc_gps_time, 32, 9); // 32 bits, 9 contexts } /* then init entropy models and integer compressors */ /* for the channel_returns_XY layer */ enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[0]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[1]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[2]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[3]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[4]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[5]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[6]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_changed_values[7]); enc_channel_returns_XY->initSymbolModel(contexts[context].m_scanner_channel); for (i = 0; i < 16; i++) { if (contexts[context].m_number_of_returns[i]) enc_channel_returns_XY->initSymbolModel(contexts[context].m_number_of_returns[i]); if (contexts[context].m_return_number[i]) enc_channel_returns_XY->initSymbolModel(contexts[context].m_return_number[i]); } enc_channel_returns_XY->initSymbolModel(contexts[context].m_return_number_gps_same); contexts[context].ic_dX->initCompressor(); contexts[context].ic_dY->initCompressor(); for (i = 0; i < 12; i++) { contexts[context].last_X_diff_median5[i].init(); contexts[context].last_Y_diff_median5[i].init(); } /* for the Z layer */ contexts[context].ic_Z->initCompressor(); for (i = 0; i < 8; i++) { contexts[context].last_Z[i] = ((LASpoint14*)item)->Z; } /* for the classification layer */ /* for the flags layer */ /* for the user_data layer */ for (i = 0; i < 64; i++) { if (contexts[context].m_classification[i]) enc_classification->initSymbolModel(contexts[context].m_classification[i]); if (contexts[context].m_flags[i]) enc_flags->initSymbolModel(contexts[context].m_flags[i]); if (contexts[context].m_user_data[i]) enc_user_data->initSymbolModel(contexts[context].m_user_data[i]); } /* for the intensity layer */ contexts[context].ic_intensity->initCompressor(); for (i = 0; i < 8; i++) { contexts[context].last_intensity[i] = ((LASpoint14*)item)->intensity; } /* for the scan_angle layer */ contexts[context].ic_scan_angle->initCompressor(); /* for the point_source_ID layer */ contexts[context].ic_point_source_ID->initCompressor(); /* for the gps_time layer */ enc_gps_time->initSymbolModel(contexts[context].m_gpstime_multi); enc_gps_time->initSymbolModel(contexts[context].m_gpstime_0diff); contexts[context].ic_gpstime->initCompressor(); contexts[context].last = 0, contexts[context].next = 0; contexts[context].last_gpstime_diff[0] = 0; contexts[context].last_gpstime_diff[1] = 0; contexts[context].last_gpstime_diff[2] = 0; contexts[context].last_gpstime_diff[3] = 0; contexts[context].multi_extreme_counter[0] = 0; contexts[context].multi_extreme_counter[1] = 0; contexts[context].multi_extreme_counter[2] = 0; contexts[context].multi_extreme_counter[3] = 0; contexts[context].last_gpstime[0].f64 = ((LASpoint14*)item)->gps_time; contexts[context].last_gpstime[1].u64 = 0; contexts[context].last_gpstime[2].u64 = 0; contexts[context].last_gpstime[3].u64 = 0; /* init current context from item */ memcpy(contexts[context].last_item, item, sizeof(LASpoint14)); ((LASpoint14*)contexts[context].last_item)->gps_time_change = FALSE; contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_POINT14_v4::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_channel_returns_XY == 0) { if (IS_LITTLE_ENDIAN()) { outstream_channel_returns_XY = new ByteStreamOutArrayLE(); outstream_Z = new ByteStreamOutArrayLE(); outstream_classification = new ByteStreamOutArrayLE(); outstream_flags = new ByteStreamOutArrayLE(); outstream_intensity = new ByteStreamOutArrayLE(); outstream_scan_angle = new ByteStreamOutArrayLE(); outstream_user_data = new ByteStreamOutArrayLE(); outstream_point_source = new ByteStreamOutArrayLE(); outstream_gps_time = new ByteStreamOutArrayLE(); } else { outstream_channel_returns_XY = new ByteStreamOutArrayBE(); outstream_Z = new ByteStreamOutArrayBE(); outstream_classification = new ByteStreamOutArrayBE(); outstream_flags = new ByteStreamOutArrayBE(); outstream_intensity = new ByteStreamOutArrayBE(); outstream_scan_angle = new ByteStreamOutArrayBE(); outstream_user_data = new ByteStreamOutArrayBE(); outstream_point_source = new ByteStreamOutArrayBE(); outstream_gps_time = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_channel_returns_XY = new ArithmeticEncoder(); enc_Z = new ArithmeticEncoder(); enc_classification = new ArithmeticEncoder(); enc_flags = new ArithmeticEncoder(); enc_intensity = new ArithmeticEncoder(); enc_scan_angle = new ArithmeticEncoder(); enc_user_data = new ArithmeticEncoder(); enc_point_source = new ArithmeticEncoder(); enc_gps_time = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_channel_returns_XY->seek(0); outstream_Z->seek(0); outstream_classification->seek(0); outstream_flags->seek(0); outstream_intensity->seek(0); outstream_scan_angle->seek(0); outstream_user_data->seek(0); outstream_point_source->seek(0); outstream_gps_time->seek(0); } /* init layer encoders */ enc_channel_returns_XY->init(outstream_channel_returns_XY); enc_Z->init(outstream_Z); enc_classification->init(outstream_classification); enc_flags->init(outstream_flags); enc_intensity->init(outstream_intensity); enc_scan_angle->init(outstream_scan_angle); enc_user_data->init(outstream_user_data); enc_point_source->init(outstream_point_source); enc_gps_time->init(outstream_gps_time); /* set changed booleans to FALSE */ changed_classification = FALSE; changed_flags = FALSE; changed_intensity = FALSE; changed_scan_angle = FALSE; changed_user_data = FALSE; changed_point_source = FALSE; changed_gps_time = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = ((LASpoint14*)item)->scanner_channel; context = current_context; // the POINT14 writer sets context for all other items /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v4::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; //////////////////////////////////////// // compress returns_XY layer //////////////////////////////////////// // create single (3) / first (1) / last (2) / intermediate (0) context from last point return I32 lpr = (((LASpoint14*)last_item)->return_number == 1 ? 1 : 0); // first? lpr += (((LASpoint14*)last_item)->return_number >= ((LASpoint14*)last_item)->number_of_returns ? 2 : 0); // last? // add info whether the GPS time changed in the last return to the context lpr += (((LASpoint14*)last_item)->gps_time_change ? 4 : 0); // get the (potentially new) context U32 scanner_channel = ((LASpoint14*)item)->scanner_channel; // if context has changed (and the new context already exists) get last for new context if (scanner_channel != current_context) { if (contexts[scanner_channel].unused == FALSE) { last_item = contexts[scanner_channel].last_item; } } // determine changed attributes BOOL point_source_change = (((LASpoint14*)item)->point_source_ID != ((LASpoint14*)last_item)->point_source_ID); BOOL gps_time_change = (((LASpoint14*)item)->gps_time != ((LASpoint14*)last_item)->gps_time); BOOL scan_angle_change = (((LASpoint14*)item)->scan_angle != ((LASpoint14*)last_item)->scan_angle); // get last and current return counts U32 last_n = ((LASpoint14*)last_item)->number_of_returns; U32 last_r = ((LASpoint14*)last_item)->return_number; U32 n = ((LASpoint14*)item)->number_of_returns; U32 r = ((LASpoint14*)item)->return_number; // create the 7 bit mask that encodes various changes (its value ranges from 0 to 127) I32 changed_values = ((scanner_channel != current_context) << 6) | // scanner channel compared to last point (same = 0 / different = 1) (point_source_change << 5) | // point source ID compared to last point from *same* scanner channel (same = 0 / different = 1) (gps_time_change << 4) | // GPS time stamp compared to last point from *same* scanner channel (same = 0 / different = 1) (scan_angle_change << 3) | // scan angle compared to last point from *same* scanner channel (same = 0 / different = 1) ((n != last_n) << 2); // number of returns compared to last point from *same* scanner channel (same = 0 / different = 1) // return number compared to last point of *same* scanner channel (same = 0 / plus one mod 16 = 1 / minus one mod 16 = 2 / other difference = 3) if (r != last_r) { if (r == ((last_r + 1) % 16)) { changed_values |= 1; } else if (r == ((last_r + 15) % 16)) { changed_values |= 2; } else { changed_values |= 3; } } // compress the 7 bit mask that encodes changes with last point return context enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_changed_values[lpr], changed_values); // if scanner channel has changed, record change if (changed_values & (1 << 6)) { I32 diff = scanner_channel - current_context; if (diff > 0) { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_scanner_channel, diff - 1); // curr = last + (sym + 1) } else { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_scanner_channel, diff + 4 - 1); // curr = (last + (sym + 1)) % 4 } // maybe create and init entropy models and integer compressors if (contexts[scanner_channel].unused) { // create and init entropy models and integer compressors (and init context from last item) createAndInitModelsAndCompressors(scanner_channel, contexts[current_context].last_item); // get last for new context last_item = contexts[scanner_channel].last_item; } // switch context to current scanner channel current_context = scanner_channel; } context = current_context; // the POINT14 writer sets context for all other items // if number of returns is different we compress it if (changed_values & (1 << 2)) { if (contexts[current_context].m_number_of_returns[last_n] == 0) { contexts[current_context].m_number_of_returns[last_n] = enc_channel_returns_XY->createSymbolModel(16); enc_channel_returns_XY->initSymbolModel(contexts[current_context].m_number_of_returns[last_n]); } enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_number_of_returns[last_n], n); } // if return number is different and difference is bigger than +1 / -1 we compress how it is different if ((changed_values & 3) == 3) { if (gps_time_change) // if the GPS time has changed { if (contexts[current_context].m_return_number[last_r] == 0) { contexts[current_context].m_return_number[last_r] = enc_channel_returns_XY->createSymbolModel(16); enc_channel_returns_XY->initSymbolModel(contexts[current_context].m_return_number[last_r]); } enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number[last_r], r); } else // if the GPS time has not changed { I32 diff = r - last_r; if (diff > 1) { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number_gps_same, diff - 2); // r = last_r + (sym + 2) with sym = diff - 2 } else { enc_channel_returns_XY->encodeSymbol(contexts[current_context].m_return_number_gps_same, diff + 16 - 2); // r = (last_r + (sym + 2)) % 16 with sym = diff + 16 - 2 } } } // get return map m and return level l context for current point U32 m = number_return_map_6ctx[n][r]; U32 l = number_return_level_8ctx[n][r]; // create single (3) / first (1) / last (2) / intermediate (0) return context for current point I32 cpr = (r == 1 ? 2 : 0); // first ? cpr += (r >= n ? 1 : 0); // last ? U32 k_bits; I32 median, diff; // compress X coordinate median = contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].get(); diff = ((LASpoint14*)item)->X - ((LASpoint14*)last_item)->X; contexts[current_context].ic_dX->compress(median, diff, n==1); contexts[current_context].last_X_diff_median5[(m<<1) | gps_time_change].add(diff); // compress Y coordinate k_bits = contexts[current_context].ic_dX->getK(); median = contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].get(); diff = ((LASpoint14*)item)->Y - ((LASpoint14*)last_item)->Y; contexts[current_context].ic_dY->compress(median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 )); contexts[current_context].last_Y_diff_median5[(m<<1) | gps_time_change].add(diff); //////////////////////////////////////// // compress Z layer //////////////////////////////////////// k_bits = (contexts[current_context].ic_dX->getK() + contexts[current_context].ic_dY->getK()) / 2; contexts[current_context].ic_Z->compress(contexts[current_context].last_Z[l], ((LASpoint14*)item)->Z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18)); contexts[current_context].last_Z[l] = ((LASpoint14*)item)->Z; //////////////////////////////////////// // compress classifications layer //////////////////////////////////////// U32 last_classification = ((LASpoint14*)last_item)->classification; U32 classification = ((LASpoint14*)item)->classification; if (classification != last_classification) { changed_classification = TRUE; } I32 ccc = ((last_classification & 0x1F) << 1) + (cpr == 3 ? 1 : 0); if (contexts[current_context].m_classification[ccc] == 0) { contexts[current_context].m_classification[ccc] = enc_classification->createSymbolModel(256); enc_classification->initSymbolModel(contexts[current_context].m_classification[ccc]); } enc_classification->encodeSymbol(contexts[current_context].m_classification[ccc], classification); //////////////////////////////////////// // compress flags layer //////////////////////////////////////// U32 last_flags = (((LASpoint14*)last_item)->edge_of_flight_line << 5) | (((LASpoint14*)last_item)->scan_direction_flag << 4) | ((LASpoint14*)last_item)->classification_flags; U32 flags = (((LASpoint14*)item)->edge_of_flight_line << 5) | (((LASpoint14*)item)->scan_direction_flag << 4) | ((LASpoint14*)item)->classification_flags; if (flags != last_flags) { changed_flags = TRUE; } if (contexts[current_context].m_flags[last_flags] == 0) { contexts[current_context].m_flags[last_flags] = enc_flags->createSymbolModel(64); enc_flags->initSymbolModel(contexts[current_context].m_flags[last_flags]); } enc_flags->encodeSymbol(contexts[current_context].m_flags[last_flags], flags); //////////////////////////////////////// // compress intensity layer //////////////////////////////////////// if (((LASpoint14*)item)->intensity != ((LASpoint14*)last_item)->intensity) { changed_intensity = TRUE; } contexts[current_context].ic_intensity->compress(contexts[current_context].last_intensity[(cpr<<1) | gps_time_change], ((LASpoint14*)item)->intensity, cpr); contexts[current_context].last_intensity[(cpr<<1) | gps_time_change] = ((LASpoint14*)item)->intensity; //////////////////////////////////////// // compress scan_angle layer //////////////////////////////////////// if (scan_angle_change) { changed_scan_angle = TRUE; contexts[current_context].ic_scan_angle->compress(((LASpoint14*)last_item)->scan_angle, ((LASpoint14*)item)->scan_angle, gps_time_change); // if the GPS time has changed } //////////////////////////////////////// // compress user_data layer //////////////////////////////////////// if (((LASpoint14*)item)->user_data != ((LASpoint14*)last_item)->user_data) { changed_user_data = TRUE; } if (contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] == 0) { contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4] = enc_user_data->createSymbolModel(256); enc_user_data->initSymbolModel(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4]); } enc_user_data->encodeSymbol(contexts[current_context].m_user_data[((LASpoint14*)last_item)->user_data/4], ((LASpoint14*)item)->user_data); //////////////////////////////////////// // compress point_source layer //////////////////////////////////////// if (point_source_change) { changed_point_source = TRUE; contexts[current_context].ic_point_source_ID->compress(((LASpoint14*)last_item)->point_source_ID, ((LASpoint14*)item)->point_source_ID); } //////////////////////////////////////// // compress gps_time layer //////////////////////////////////////// if (gps_time_change) // if the GPS time has changed { changed_gps_time = TRUE; U64I64F64 gps_time; gps_time.f64 = ((LASpoint14*)item)->gps_time; write_gps_time(gps_time); } // copy the last item memcpy(last_item, item, sizeof(LASpoint14)); // remember if the last point had a gps_time_change ((LASpoint14*)last_item)->gps_time_change = gps_time_change; return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v4::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_channel_returns_XY->done(); enc_Z->done(); if (changed_classification) { enc_classification->done(); } if (changed_flags) { enc_flags->done(); } if (changed_intensity) { enc_intensity->done(); } if (changed_scan_angle) { enc_scan_angle->done(); } if (changed_user_data) { enc_user_data->done(); } if (changed_point_source) { enc_point_source->done(); } if (changed_gps_time) { enc_gps_time->done(); } // output the sizes of all layer (i.e.. number of bytes per layer) num_bytes = (U32)outstream_channel_returns_XY->getCurr(); num_bytes_channel_returns_XY += num_bytes; outstream->put32bitsLE(((U8*)&num_bytes)); num_bytes = (U32)outstream_Z->getCurr(); num_bytes_Z += num_bytes; outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_classification) { num_bytes = (U32)outstream_classification->getCurr(); num_bytes_classification += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_flags) { num_bytes = (U32)outstream_flags->getCurr(); num_bytes_flags += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_intensity) { num_bytes = (U32)outstream_intensity->getCurr(); num_bytes_intensity += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_scan_angle) { num_bytes = (U32)outstream_scan_angle->getCurr(); num_bytes_scan_angle += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_user_data) { num_bytes = (U32)outstream_user_data->getCurr(); num_bytes_user_data += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_point_source) { num_bytes = (U32)outstream_point_source->getCurr(); num_bytes_point_source += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_gps_time) { num_bytes = (U32)outstream_gps_time->getCurr(); num_bytes_gps_time += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_POINT14_v4::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers num_bytes = (U32)outstream_channel_returns_XY->getCurr(); outstream->putBytes(outstream_channel_returns_XY->getData(), num_bytes); num_bytes = (U32)outstream_Z->getCurr(); outstream->putBytes(outstream_Z->getData(), num_bytes); if (changed_classification) { num_bytes = (U32)outstream_classification->getCurr(); outstream->putBytes(outstream_classification->getData(), num_bytes); } else { num_bytes = 0; } if (changed_flags) { num_bytes = (U32)outstream_flags->getCurr(); outstream->putBytes(outstream_flags->getData(), num_bytes); } else { num_bytes = 0; } if (changed_intensity) { num_bytes = (U32)outstream_intensity->getCurr(); outstream->putBytes(outstream_intensity->getData(), num_bytes); } else { num_bytes = 0; } if (changed_scan_angle) { num_bytes = (U32)outstream_scan_angle->getCurr(); outstream->putBytes(outstream_scan_angle->getData(), num_bytes); } else { num_bytes = 0; } if (changed_user_data) { num_bytes = (U32)outstream_user_data->getCurr(); outstream->putBytes(outstream_user_data->getData(), num_bytes); } else { num_bytes = 0; } if (changed_point_source) { num_bytes = (U32)outstream_point_source->getCurr(); outstream->putBytes(outstream_point_source->getData(), num_bytes); } else { num_bytes = 0; } if (changed_gps_time) { num_bytes = (U32)outstream_gps_time->getCurr(); outstream->putBytes(outstream_gps_time->getData(), num_bytes); } else { num_bytes = 0; } return TRUE; } void LASwriteItemCompressed_POINT14_v4::write_gps_time(const U64I64F64 gps_time) { if (contexts[current_context].last_gpstime_diff[contexts[current_context].last] == 0) // if the last integer difference was zero { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[contexts[current_context].last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, 0); // the difference can be represented with 32 bits contexts[current_context].ic_gpstime->compress(0, curr_gpstime_diff, 0); contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[(contexts[current_context].last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, i+1); // it belongs to another sequence contexts[current_context].last = (contexts[current_context].last+i)&3; write_gps_time(gps_time); return; } } // no other sequence found. start new sequence. enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_0diff, 1); contexts[current_context].ic_gpstime->compress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), (I32)(gps_time.u64 >> 32), 8); enc_gps_time->writeInt((U32)(gps_time.u64)); contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } contexts[current_context].last_gpstime[contexts[current_context].last].i64 = gps_time.i64; } else // the last integer difference was *not* zero { // calculate the difference between the two doubles as an integer I64 curr_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[contexts[current_context].last].i64; I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64; // if the current gpstime difference can be represented with 32 bits if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff)) { // compute multiplier between current and last integer difference F32 multi_f = (F32)curr_gpstime_diff / (F32)(contexts[current_context].last_gpstime_diff[contexts[current_context].last]); I32 multi = I32_QUANTIZE(multi_f); // compress the residual curr_gpstime_diff in dependance on the multiplier if (multi == 1) { // this is the case we assume we get most often for regular spaced pulses enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, 1); contexts[current_context].ic_gpstime->compress(contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 1); contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } else if (multi > 0) { if (multi < LASZIP_GPSTIME_MULTI) // positive multipliers up to LASZIP_GPSTIME_MULTI are compressed directly { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, multi); if (multi < 10) contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 2); else contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 3); } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI); contexts[current_context].ic_gpstime->compress(LASZIP_GPSTIME_MULTI*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 4); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else if (multi < 0) { if (multi > LASZIP_GPSTIME_MULTI_MINUS) // negative multipliers larger than LASZIP_GPSTIME_MULTI_MINUS are compressed directly { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI - multi); contexts[current_context].ic_gpstime->compress(multi*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 5); } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS); contexts[current_context].ic_gpstime->compress(LASZIP_GPSTIME_MULTI_MINUS*contexts[current_context].last_gpstime_diff[contexts[current_context].last], curr_gpstime_diff, 6); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else { enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, 0); contexts[current_context].ic_gpstime->compress(0, curr_gpstime_diff, 7); contexts[current_context].multi_extreme_counter[contexts[current_context].last]++; if (contexts[current_context].multi_extreme_counter[contexts[current_context].last] > 3) { contexts[current_context].last_gpstime_diff[contexts[current_context].last] = curr_gpstime_diff; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } } } else // the difference is huge { U32 i; // maybe the double belongs to another time sequence for (i = 1; i < 4; i++) { I64 other_gpstime_diff_64 = gps_time.i64 - contexts[current_context].last_gpstime[(contexts[current_context].last+i)&3].i64; I32 other_gpstime_diff = (I32)other_gpstime_diff_64; if (other_gpstime_diff_64 == (I64)(other_gpstime_diff)) { // it belongs to this sequence enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL+i); contexts[current_context].last = (contexts[current_context].last+i)&3; write_gps_time(gps_time); return; } } // no other sequence found. start new sequence. enc_gps_time->encodeSymbol(contexts[current_context].m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL); contexts[current_context].ic_gpstime->compress((I32)(contexts[current_context].last_gpstime[contexts[current_context].last].u64 >> 32), (I32)(gps_time.u64 >> 32), 8); enc_gps_time->writeInt((U32)(gps_time.u64)); contexts[current_context].next = (contexts[current_context].next+1)&3; contexts[current_context].last = contexts[current_context].next; contexts[current_context].last_gpstime_diff[contexts[current_context].last] = 0; contexts[current_context].multi_extreme_counter[contexts[current_context].last] = 0; } contexts[current_context].last_gpstime[contexts[current_context].last].i64 = gps_time.i64; } } /* =============================================================================== LASwriteItemCompressed_RGB14_v4 =============================================================================== */ LASwriteItemCompressed_RGB14_v4::LASwriteItemCompressed_RGB14_v4(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_RGB = 0; enc_RGB = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; changed_RGB = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_byte_used = 0; } current_context = 0; } LASwriteItemCompressed_RGB14_v4::~LASwriteItemCompressed_RGB14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_byte_used) { enc_RGB->destroySymbolModel(contexts[c].m_byte_used); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); } } /* destroy all outstreams and encoders */ if (outstream_RGB) { delete outstream_RGB; delete enc_RGB; } } inline BOOL LASwriteItemCompressed_RGB14_v4::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_byte_used == 0) { contexts[context].m_byte_used = enc_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = enc_RGB->createSymbolModel(256); } /* then init entropy models */ enc_RGB->initSymbolModel(contexts[context].m_byte_used); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); /* init current context from item */ memcpy(contexts[context].last_item, item, 6); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_RGB14_v4::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_RGB == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_RGB = new ByteStreamOutArrayLE(); } else { outstream_RGB = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_RGB = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_RGB->seek(0); } /* init layer encoders */ enc_RGB->init(outstream_RGB); /* set changed booleans to FALSE */ changed_RGB = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init contect from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v4::write(const U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } // compress I32 diff_l = 0; I32 diff_h = 0; I32 corr; U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6; enc_RGB->encodeSymbol(contexts[current_context].m_byte_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_1, U8_FOLD(diff_h)); } if (sym & (1 << 6)) { if (sym & (1 << 2)) { corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_2, U8_FOLD(corr)); } if (sym & (1 << 4)) { diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2; corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_4, U8_FOLD(corr)); } if (sym & (1 << 3)) { corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_3, U8_FOLD(corr)); } if (sym & (1 << 5)) { diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2; corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_5, U8_FOLD(corr)); } } if (sym) { changed_RGB = TRUE; } memcpy(last_item, item, 6); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v4::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_RGB->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); num_bytes_RGB += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_RGB14_v4::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); outstream->putBytes(outstream_RGB->getData(), num_bytes); } return TRUE; } /* =============================================================================== LASwriteItemCompressed_RGBNIR14_v4 =============================================================================== */ LASwriteItemCompressed_RGBNIR14_v4::LASwriteItemCompressed_RGBNIR14_v4(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_RGB = 0; outstream_NIR = 0; enc_RGB = 0; enc_NIR = 0; /* zero num_bytes and init booleans */ num_bytes_RGB = 0; num_bytes_NIR = 0; changed_RGB = FALSE; changed_NIR = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_rgb_bytes_used = 0; } current_context = 0; } LASwriteItemCompressed_RGBNIR14_v4::~LASwriteItemCompressed_RGBNIR14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_rgb_bytes_used) { enc_RGB->destroySymbolModel(contexts[c].m_rgb_bytes_used); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_0); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_1); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_2); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_3); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_4); enc_RGB->destroySymbolModel(contexts[c].m_rgb_diff_5); enc_NIR->destroySymbolModel(contexts[c].m_nir_bytes_used); enc_NIR->destroySymbolModel(contexts[c].m_nir_diff_0); enc_NIR->destroySymbolModel(contexts[c].m_nir_diff_1); } } /* destroy all outstreams and encoders */ if (outstream_RGB) { delete outstream_RGB; delete outstream_NIR; delete enc_RGB; delete enc_NIR; } } inline BOOL LASwriteItemCompressed_RGBNIR14_v4::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_rgb_bytes_used == 0) { contexts[context].m_rgb_bytes_used = enc_RGB->createSymbolModel(128); contexts[context].m_rgb_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_1 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_2 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_3 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_4 = enc_RGB->createSymbolModel(256); contexts[context].m_rgb_diff_5 = enc_RGB->createSymbolModel(256); contexts[context].m_nir_bytes_used = enc_RGB->createSymbolModel(4); contexts[context].m_nir_diff_0 = enc_RGB->createSymbolModel(256); contexts[context].m_nir_diff_1 = enc_RGB->createSymbolModel(256); } /* then init entropy models */ enc_RGB->initSymbolModel(contexts[context].m_rgb_bytes_used); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_0); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_1); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_2); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_3); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_4); enc_RGB->initSymbolModel(contexts[context].m_rgb_diff_5); enc_NIR->initSymbolModel(contexts[context].m_nir_bytes_used); enc_NIR->initSymbolModel(contexts[context].m_nir_diff_0); enc_NIR->initSymbolModel(contexts[context].m_nir_diff_1); /* init current context from item */ memcpy(contexts[context].last_item, item, 8); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_RGBNIR14_v4::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_RGB == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_RGB = new ByteStreamOutArrayLE(); outstream_NIR = new ByteStreamOutArrayLE(); } else { outstream_RGB = new ByteStreamOutArrayBE(); outstream_NIR = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_RGB = new ArithmeticEncoder(); enc_NIR = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_RGB->seek(0); outstream_NIR->seek(0); } /* init layer encoders */ enc_RGB->init(outstream_RGB); enc_NIR->init(outstream_NIR); /* set changed booleans to FALSE */ changed_RGB = FALSE; changed_NIR = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // ll other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v4::write(const U8* item, U32& context) { // get last U16* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } // compress I32 diff_l = 0; I32 diff_h = 0; I32 corr; U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0; sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1; sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2; sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3; sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4; sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5; sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6; enc_RGB->encodeSymbol(contexts[current_context].m_rgb_bytes_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_1, U8_FOLD(diff_h)); } if (sym & (1 << 6)) { if (sym & (1 << 2)) { corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_2, U8_FOLD(corr)); } if (sym & (1 << 4)) { diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2; corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_4, U8_FOLD(corr)); } if (sym & (1 << 3)) { corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_3, U8_FOLD(corr)); } if (sym & (1 << 5)) { diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2; corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8)); enc_RGB->encodeSymbol(contexts[current_context].m_rgb_diff_5, U8_FOLD(corr)); } } if (sym) { changed_RGB = TRUE; } sym = ((last_item[3]&0x00FF) != (((U16*)item)[3]&0x00FF)) << 0; sym |= ((last_item[3]&0xFF00) != (((U16*)item)[3]&0xFF00)) << 1; enc_NIR->encodeSymbol(contexts[current_context].m_nir_bytes_used, sym); if (sym & (1 << 0)) { diff_l = ((int)(((U16*)item)[3]&255)) - (last_item[3]&255); enc_NIR->encodeSymbol(contexts[current_context].m_nir_diff_0, U8_FOLD(diff_l)); } if (sym & (1 << 1)) { diff_h = ((int)(((U16*)item)[3]>>8)) - (last_item[3]>>8); enc_NIR->encodeSymbol(contexts[current_context].m_nir_diff_1, U8_FOLD(diff_h)); } if (sym) { changed_NIR = TRUE; } memcpy(last_item, item, 8); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v4::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_RGB->done(); enc_NIR->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); num_bytes_RGB += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); if (changed_NIR) { num_bytes = (U32)outstream_NIR->getCurr(); num_bytes_NIR += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_RGBNIR14_v4::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_RGB) { num_bytes = (U32)outstream_RGB->getCurr(); outstream->putBytes(outstream_RGB->getData(), num_bytes); } else { num_bytes = 0; } if (changed_NIR) { num_bytes = (U32)outstream_NIR->getCurr(); outstream->putBytes(outstream_NIR->getData(), num_bytes); } else { num_bytes = 0; } return TRUE; } /* =============================================================================== LASwriteItemCompressed_WAVEPACKET14_v4 =============================================================================== */ LASwriteItemCompressed_WAVEPACKET14_v4::LASwriteItemCompressed_WAVEPACKET14_v4(ArithmeticEncoder* enc) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* zero outstreams and encoders */ outstream_wavepacket = 0; enc_wavepacket = 0; /* zero num_bytes and init booleans */ num_bytes_wavepacket = 0; changed_wavepacket = FALSE; /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_packet_index = 0; } current_context = 0; } LASwriteItemCompressed_WAVEPACKET14_v4::~LASwriteItemCompressed_WAVEPACKET14_v4() { /* destroy all initialized scanner channel contexts */ U32 c; for (c = 0; c < 4; c++) { if (contexts[c].m_packet_index) { enc_wavepacket->destroySymbolModel(contexts[c].m_packet_index); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[0]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[1]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[2]); enc_wavepacket->destroySymbolModel(contexts[c].m_offset_diff[3]); delete contexts[c].ic_offset_diff; delete contexts[c].ic_packet_size; delete contexts[c].ic_return_point; delete contexts[c].ic_xyz; } } /* destroy all outstreams and encoders */ if (outstream_wavepacket) { delete outstream_wavepacket; delete enc_wavepacket; } } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v4::createAndInitModelsAndCompressors(U32 context, const U8* item) { /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models (if needed) */ if (contexts[context].m_packet_index == 0) { contexts[context].m_packet_index = enc_wavepacket->createSymbolModel(256); contexts[context].m_offset_diff[0] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[1] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[2] = enc_wavepacket->createSymbolModel(4); contexts[context].m_offset_diff[3] = enc_wavepacket->createSymbolModel(4); contexts[context].ic_offset_diff = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_packet_size = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_return_point = new IntegerCompressor(enc_wavepacket, 32); contexts[context].ic_xyz = new IntegerCompressor(enc_wavepacket, 32, 3); } /* then init entropy models */ enc_wavepacket->initSymbolModel(contexts[context].m_packet_index); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[0]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[1]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[2]); enc_wavepacket->initSymbolModel(contexts[context].m_offset_diff[3]); contexts[context].ic_offset_diff->initCompressor(); contexts[context].ic_packet_size->initCompressor(); contexts[context].ic_return_point->initCompressor(); contexts[context].ic_xyz->initCompressor(); /* init current context from item */ contexts[context].last_diff_32 = 0; contexts[context].sym_last_offset_diff = 0; memcpy(contexts[context].last_item, item, 29); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_WAVEPACKET14_v4::init(const U8* item, U32& context) { /* on the first init create outstreams and encoders */ if (outstream_wavepacket == 0) { /* create outstreams */ if (IS_LITTLE_ENDIAN()) { outstream_wavepacket = new ByteStreamOutArrayLE(); } else { outstream_wavepacket = new ByteStreamOutArrayBE(); } /* create layer encoders */ enc_wavepacket = new ArithmeticEncoder(); } else { /* otherwise just seek back */ outstream_wavepacket->seek(0); } /* init layer encoders */ enc_wavepacket->init(outstream_wavepacket); /* set changed booleans to FALSE */ changed_wavepacket = FALSE; /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init contect from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v4::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, (U8*)last_item); } last_item = contexts[current_context].last_item; } if (memcmp(item, last_item, 29) != 0) { changed_wavepacket = TRUE; } // compress enc_wavepacket->encodeSymbol(contexts[current_context].m_packet_index, (U32)(item[0])); LASwavepacket13 this_item_m = LASwavepacket13::unpack(item+1); LASwavepacket13 last_item_m = LASwavepacket13::unpack(last_item+1); // calculate the difference between the two offsets I64 curr_diff_64 = this_item_m.offset - last_item_m.offset; I32 curr_diff_32 = (I32)curr_diff_64; // if the current difference can be represented with 32 bits if (curr_diff_64 == (I64)(curr_diff_32)) { if (curr_diff_32 == 0) // current difference is zero { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 0); contexts[current_context].sym_last_offset_diff = 0; } else if (curr_diff_32 == (I32)last_item_m.packet_size) { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 1); contexts[current_context].sym_last_offset_diff = 1; } else // { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 2); contexts[current_context].sym_last_offset_diff = 2; contexts[current_context].ic_offset_diff->compress(contexts[current_context].last_diff_32, curr_diff_32); contexts[current_context].last_diff_32 = curr_diff_32; } } else { enc_wavepacket->encodeSymbol(contexts[current_context].m_offset_diff[contexts[current_context].sym_last_offset_diff], 3); contexts[current_context].sym_last_offset_diff = 3; enc_wavepacket->writeInt64(this_item_m.offset); } contexts[current_context].ic_packet_size->compress(last_item_m.packet_size, this_item_m.packet_size); contexts[current_context].ic_return_point->compress(last_item_m.return_point.i32, this_item_m.return_point.i32); contexts[current_context].ic_xyz->compress(last_item_m.x.i32, this_item_m.x.i32, 0); contexts[current_context].ic_xyz->compress(last_item_m.y.i32, this_item_m.y.i32, 1); contexts[current_context].ic_xyz->compress(last_item_m.z.i32, this_item_m.z.i32, 2); memcpy(last_item, item, 29); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v4::chunk_sizes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // finish the encoders enc_wavepacket->done(); // output the sizes of all layer (i.e.. number of bytes per layer) if (changed_wavepacket) { num_bytes = (U32)outstream_wavepacket->getCurr(); num_bytes_wavepacket += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); return TRUE; } inline BOOL LASwriteItemCompressed_WAVEPACKET14_v4::chunk_bytes() { U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers if (changed_wavepacket) { num_bytes = (U32)outstream_wavepacket->getCurr(); outstream->putBytes(outstream_wavepacket->getData(), num_bytes); } return TRUE; } /* =============================================================================== LASwriteItemCompressed_BYTE14_v4 =============================================================================== */ LASwriteItemCompressed_BYTE14_v4::LASwriteItemCompressed_BYTE14_v4(ArithmeticEncoder* enc, U32 number) { /* not used as a encoder. just gives access to outstream */ assert(enc); this->enc = enc; /* must be more than one byte */ assert(number); this->number = number; /* zero outstream and encoder pointer arrays */ outstream_Bytes = 0; enc_Bytes = 0; /* number of bytes per layer */ num_bytes_Bytes = new U32[number]; changed_Bytes = new BOOL[number]; U32 i; for (i = 0; i < number; i++) { num_bytes_Bytes[i] = 0; changed_Bytes[i] = FALSE; } /* mark the four scanner channel contexts as uninitialized */ U32 c; for (c = 0; c < 4; c++) { contexts[c].m_bytes = 0; } current_context = 0; } LASwriteItemCompressed_BYTE14_v4::~LASwriteItemCompressed_BYTE14_v4() { /* destroy all initialized scanner channel contexts */ U32 c, i; for (c = 0; c < 4; c++) { if (contexts[c].m_bytes) { for (i = 0; i < number; i++) { enc_Bytes[i]->destroySymbolModel(contexts[c].m_bytes[i]); } delete [] contexts[c].m_bytes; delete [] contexts[c].last_item; } } /* destroy all outstream and encoder arrays */ if (outstream_Bytes) { for (i = 0; i < number; i++) { if (outstream_Bytes[i]) { delete outstream_Bytes[i]; delete enc_Bytes[i]; } } delete [] outstream_Bytes; delete [] enc_Bytes; } /* destroy all other arrays */ if (num_bytes_Bytes) delete [] num_bytes_Bytes; if (changed_Bytes) delete [] changed_Bytes; } inline BOOL LASwriteItemCompressed_BYTE14_v4::createAndInitModelsAndCompressors(U32 context, const U8* item) { U32 i; /* should only be called when context is unused */ assert(contexts[context].unused); /* first create all entropy models and last items (if needed) */ if (contexts[context].m_bytes == 0) { contexts[context].m_bytes = new ArithmeticModel*[number]; for (i = 0; i < number; i++) { contexts[context].m_bytes[i] = enc_Bytes[i]->createSymbolModel(256); enc_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* create last item */ contexts[context].last_item = new U8[number]; } /* then init entropy models */ for (i = 0; i < number; i++) { enc_Bytes[i]->initSymbolModel(contexts[context].m_bytes[i]); } /* init current context from item */ memcpy(contexts[context].last_item, item, number); contexts[context].unused = FALSE; return TRUE; } BOOL LASwriteItemCompressed_BYTE14_v4::init(const U8* item, U32& context) { U32 i; /* on the first init create outstreams and encoders */ if (outstream_Bytes == 0) { /* create outstreams pointer array */ outstream_Bytes = new ByteStreamOutArray*[number]; /* create outstreams */ if (IS_LITTLE_ENDIAN()) { for (i = 0; i < number; i++) { outstream_Bytes[i] = new ByteStreamOutArrayLE(); } } else { for (i = 0; i < number; i++) { outstream_Bytes[i] = new ByteStreamOutArrayBE(); } } /* create encoder pointer array */ enc_Bytes = new ArithmeticEncoder*[number]; /* create layer encoders */ for (i = 0; i < number; i++) { enc_Bytes[i] = new ArithmeticEncoder(); } } else { /* otherwise just seek back */ for (i = 0; i < number; i++) { outstream_Bytes[i]->seek(0); } } /* init layer encoders */ for (i = 0; i < number; i++) { enc_Bytes[i]->init(outstream_Bytes[i]); } /* set changed booleans to FALSE */ for (i = 0; i < number; i++) { changed_Bytes[i] = FALSE; } /* mark the four scanner channel contexts as unused */ U32 c; for (c = 0; c < 4; c++) { contexts[c].unused = TRUE; } /* set scanner channel as current context */ current_context = context; // all other items use context set by POINT14 writer /* create and init entropy models and integer compressors (and init context from item) */ createAndInitModelsAndCompressors(current_context, item); return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v4::write(const U8* item, U32& context) { // get last U8* last_item = contexts[current_context].last_item; // check for context switch if (current_context != context) { current_context = context; // all other items use context set by POINT14 writer if (contexts[current_context].unused) { createAndInitModelsAndCompressors(current_context, last_item); } last_item = contexts[current_context].last_item; } // compress U32 i; I32 diff; for (i = 0; i < number; i++) { diff = item[i] - last_item[i]; enc_Bytes[i]->encodeSymbol(contexts[current_context].m_bytes[i], U8_FOLD(diff)); if (diff) { changed_Bytes[i] = TRUE; last_item[i] = item[i]; } } return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v4::chunk_sizes() { U32 i; U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the sizes of all layer (i.e.. number of bytes per layer) for (i = 0; i < number; i++) { // finish the encoders enc_Bytes[i]->done(); if (changed_Bytes[i]) { num_bytes = (U32)outstream_Bytes[i]->getCurr(); num_bytes_Bytes[i] += num_bytes; } else { num_bytes = 0; } outstream->put32bitsLE(((U8*)&num_bytes)); } return TRUE; } inline BOOL LASwriteItemCompressed_BYTE14_v4::chunk_bytes() { U32 i; U32 num_bytes = 0; ByteStreamOut* outstream = enc->getByteStreamOut(); // output the bytes of all layers for (i = 0; i < number; i++) { if (changed_Bytes[i]) { num_bytes = (U32)outstream_Bytes[i]->getCurr(); outstream->putBytes(outstream_Bytes[i]->getData(), num_bytes); } else { num_bytes = 0; } } return TRUE; } LASzip-3.4.3/src/laswriteitemcompressed_v4.hpp000066400000000000000000000136071356234217100214050ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemcompressed_v4.hpp CONTENTS: Native extension for compressing the *new* point types 6 to 10 of LAS 1.4 PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 December 2017 -- fix incorrect 'context switch' reported by Wanwannodao 28 August 2017 -- moving 'context' from global development hack to interface 22 August 2016 -- finalizing at Basecamp in Bonn during FOSS4g hackfest 23 February 2016 -- created at OSGeo Code Sprint in Paris to prototype =============================================================================== */ #ifndef LAS_WRITE_ITEM_COMPRESSED_V4_HPP #define LAS_WRITE_ITEM_COMPRESSED_V4_HPP #include "laswriteitem.hpp" #include "arithmeticencoder.hpp" #include "integercompressor.hpp" #include "bytestreamout_array.hpp" #include "laszip_common_v3.hpp" class LASwriteItemCompressed_POINT14_v4 : public LASwriteItemCompressed { public: LASwriteItemCompressed_POINT14_v4(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_POINT14_v4(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_channel_returns_XY; ByteStreamOutArray* outstream_Z; ByteStreamOutArray* outstream_classification; ByteStreamOutArray* outstream_flags; ByteStreamOutArray* outstream_intensity; ByteStreamOutArray* outstream_scan_angle; ByteStreamOutArray* outstream_user_data; ByteStreamOutArray* outstream_point_source; ByteStreamOutArray* outstream_gps_time; ArithmeticEncoder* enc_channel_returns_XY; ArithmeticEncoder* enc_Z; ArithmeticEncoder* enc_classification; ArithmeticEncoder* enc_flags; ArithmeticEncoder* enc_intensity; ArithmeticEncoder* enc_scan_angle; ArithmeticEncoder* enc_user_data; ArithmeticEncoder* enc_point_source; ArithmeticEncoder* enc_gps_time; BOOL changed_classification; BOOL changed_flags; BOOL changed_intensity; BOOL changed_scan_angle; BOOL changed_user_data; BOOL changed_point_source; BOOL changed_gps_time; U32 num_bytes_channel_returns_XY; U32 num_bytes_Z; U32 num_bytes_classification; U32 num_bytes_flags; U32 num_bytes_intensity; U32 num_bytes_scan_angle; U32 num_bytes_user_data; U32 num_bytes_point_source; U32 num_bytes_gps_time; U32 current_context; LAScontextPOINT14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); void write_gps_time(const U64I64F64 gps_time); }; class LASwriteItemCompressed_RGB14_v4 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGB14_v4(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_RGB14_v4(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_RGB; ArithmeticEncoder* enc_RGB; BOOL changed_RGB; U32 num_bytes_RGB; U32 current_context; LAScontextRGB14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_RGBNIR14_v4 : public LASwriteItemCompressed { public: LASwriteItemCompressed_RGBNIR14_v4(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_RGBNIR14_v4(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_RGB; ByteStreamOutArray* outstream_NIR; ArithmeticEncoder* enc_RGB; ArithmeticEncoder* enc_NIR; BOOL changed_RGB; BOOL changed_NIR; U32 num_bytes_RGB; U32 num_bytes_NIR; U32 current_context; LAScontextRGBNIR14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_WAVEPACKET14_v4 : public LASwriteItemCompressed { public: LASwriteItemCompressed_WAVEPACKET14_v4(ArithmeticEncoder* enc); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_WAVEPACKET14_v4(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray* outstream_wavepacket; ArithmeticEncoder* enc_wavepacket; BOOL changed_wavepacket; U32 num_bytes_wavepacket; U32 current_context; LAScontextWAVEPACKET14 contexts[4]; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; class LASwriteItemCompressed_BYTE14_v4 : public LASwriteItemCompressed { public: LASwriteItemCompressed_BYTE14_v4(ArithmeticEncoder* enc, U32 number); BOOL init(const U8* item, U32& context); BOOL write(const U8* item, U32& context); BOOL chunk_sizes(); BOOL chunk_bytes(); ~LASwriteItemCompressed_BYTE14_v4(); private: /* not used as a encoder. just gives access to outstream */ ArithmeticEncoder* enc; ByteStreamOutArray** outstream_Bytes; ArithmeticEncoder** enc_Bytes; U32* num_bytes_Bytes; BOOL* changed_Bytes; U32 current_context; LAScontextBYTE14 contexts[4]; U32 number; BOOL createAndInitModelsAndCompressors(U32 context, const U8* item); }; #endif LASzip-3.4.3/src/laswriteitemraw.hpp000066400000000000000000000260661356234217100174240ustar00rootroot00000000000000/* =============================================================================== FILE: laswriteitemraw.hpp CONTENTS: Implementation of LASwriteItemRaw for *all* items that compose a point. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2018, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 29 September 2018 -- fix: extended_classification when classification not set 28 August 2017 -- moving 'context' from global development hack to interface 10 January 2011 -- licensing change for LGPL release and liblas integration 7 January 2011 -- introduced swap buffers to reduce number of fwrite calls 12 December 2010 -- refactored after watching two movies with silke =============================================================================== */ #ifndef LAS_WRITE_ITEM_RAW_HPP #define LAS_WRITE_ITEM_RAW_HPP #include "laswriteitem.hpp" #include class LASwriteItemRaw_POINT10_LE : public LASwriteItemRaw { public: LASwriteItemRaw_POINT10_LE(){}; inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, 20); }; }; class LASwriteItemRaw_POINT10_BE : public LASwriteItemRaw { public: LASwriteItemRaw_POINT10_BE(){}; inline BOOL write(const U8* item, U32& context) { ENDIAN_SWAP_32(&item[ 0], &swapped[ 0]); // X ENDIAN_SWAP_32(&item[ 4], &swapped[ 4]); // Y ENDIAN_SWAP_32(&item[ 8], &swapped[ 8]); // Z ENDIAN_SWAP_16(&item[12], &swapped[12]); // intensity *((U32*)&swapped[14]) = *((U32*)&item[14]); // bitfield, classification, scan_angle_rank, user_data ENDIAN_SWAP_16(&item[18], &swapped[18]); // point_source_ID return outstream->putBytes(swapped, 20); }; private: U8 swapped[20]; }; class LASwriteItemRaw_GPSTIME11_LE : public LASwriteItemRaw { public: LASwriteItemRaw_GPSTIME11_LE() {}; inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, 8); }; }; class LASwriteItemRaw_GPSTIME11_BE : public LASwriteItemRaw { public: LASwriteItemRaw_GPSTIME11_BE() {}; inline BOOL write(const U8* item, U32& context) { ENDIAN_SWAP_64(item, swapped); return outstream->putBytes(swapped, 8); }; private: U8 swapped[8]; }; class LASwriteItemRaw_RGB12_LE : public LASwriteItemRaw { public: LASwriteItemRaw_RGB12_LE(){} inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, 6); }; }; class LASwriteItemRaw_RGB12_BE : public LASwriteItemRaw { public: LASwriteItemRaw_RGB12_BE(){} inline BOOL write(const U8* item, U32& context) { ENDIAN_SWAP_32(&item[ 0], &swapped[ 0]); // R ENDIAN_SWAP_32(&item[ 2], &swapped[ 2]); // G ENDIAN_SWAP_32(&item[ 4], &swapped[ 4]); // B return outstream->putBytes(swapped, 6); }; private: U8 swapped[6]; }; class LASwriteItemRaw_WAVEPACKET13_LE : public LASwriteItemRaw { public: LASwriteItemRaw_WAVEPACKET13_LE(){} inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, 29); }; }; class LASwriteItemRaw_WAVEPACKET13_BE : public LASwriteItemRaw { public: LASwriteItemRaw_WAVEPACKET13_BE(){} inline BOOL write(const U8* item, U32& context) { swapped[0] = item[0]; // wavepacket descriptor index ENDIAN_SWAP_64(&item[ 1], &swapped[ 1]); // byte offset to waveform data ENDIAN_SWAP_32(&item[ 9], &swapped[ 9]); // waveform packet size in bytes ENDIAN_SWAP_32(&item[13], &swapped[13]); // return point waveform location ENDIAN_SWAP_32(&item[17], &swapped[17]); // X(t) ENDIAN_SWAP_32(&item[21], &swapped[21]); // Y(t) ENDIAN_SWAP_32(&item[25], &swapped[25]); // Z(t) return outstream->putBytes(swapped, 29); }; private: U8 swapped[29]; }; class LASwriteItemRaw_BYTE : public LASwriteItemRaw { public: LASwriteItemRaw_BYTE(U32 number) { this->number = number; } inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, number); }; private: U32 number; }; class LAStempWritePoint10 { public: I32 X; I32 Y; I32 Z; U16 intensity; U8 return_number : 3; U8 number_of_returns : 3; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; I8 scan_angle_rank; U8 user_data; U16 point_source_ID; // LAS 1.4 only I16 extended_scan_angle; U8 extended_point_type : 2; U8 extended_scanner_channel : 2; U8 extended_classification_flags : 4; U8 extended_classification; U8 extended_return_number : 4; U8 extended_number_of_returns : 4; // for 8 byte alignment of the GPS time U8 dummy[3]; // LASlib only U32 deleted_flag; F64 gps_time; }; class LAStempWritePoint14 { public: I32 X; I32 Y; I32 Z; U16 intensity; U8 return_number : 4; U8 number_of_returns : 4; U8 classification_flags : 4; U8 scanner_channel : 2; U8 scan_direction_flag : 1; U8 edge_of_flight_line : 1; U8 classification; U8 user_data; I16 scan_angle; U16 point_source_ID; }; class LASwriteItemRaw_POINT14_LE : public LASwriteItemRaw { public: LASwriteItemRaw_POINT14_LE(){}; inline BOOL write(const U8* item, U32& context) { ((LAStempWritePoint14*)buffer)->X = ((LAStempWritePoint10*)item)->X; ((LAStempWritePoint14*)buffer)->Y = ((LAStempWritePoint10*)item)->Y; ((LAStempWritePoint14*)buffer)->Z = ((LAStempWritePoint10*)item)->Z; ((LAStempWritePoint14*)buffer)->intensity = ((LAStempWritePoint10*)item)->intensity; ((LAStempWritePoint14*)buffer)->scan_direction_flag = ((LAStempWritePoint10*)item)->scan_direction_flag; ((LAStempWritePoint14*)buffer)->edge_of_flight_line = ((LAStempWritePoint10*)item)->edge_of_flight_line; ((LAStempWritePoint14*)buffer)->classification = (((LAStempWritePoint10*)item)->classification & 31); ((LAStempWritePoint14*)buffer)->user_data = ((LAStempWritePoint10*)item)->user_data; ((LAStempWritePoint14*)buffer)->point_source_ID = ((LAStempWritePoint10*)item)->point_source_ID; if (((LAStempWritePoint10*)item)->extended_point_type) { ((LAStempWritePoint14*)buffer)->classification_flags = (((LAStempWritePoint10*)item)->extended_classification_flags & 8) | (((LAStempWritePoint10*)item)->classification >> 5); if (((LAStempWritePoint14*)buffer)->classification == 0) ((LAStempWritePoint14*)buffer)->classification = ((LAStempWritePoint10*)item)->extended_classification; ((LAStempWritePoint14*)buffer)->scanner_channel = ((LAStempWritePoint10*)item)->extended_scanner_channel; ((LAStempWritePoint14*)buffer)->return_number = ((LAStempWritePoint10*)item)->extended_return_number; ((LAStempWritePoint14*)buffer)->number_of_returns = ((LAStempWritePoint10*)item)->extended_number_of_returns; ((LAStempWritePoint14*)buffer)->scan_angle = ((LAStempWritePoint10*)item)->extended_scan_angle; } else { ((LAStempWritePoint14*)buffer)->classification_flags = (((LAStempWritePoint10*)item)->classification >> 5); ((LAStempWritePoint14*)buffer)->scanner_channel = 0; ((LAStempWritePoint14*)buffer)->return_number = ((LAStempWritePoint10*)item)->return_number; ((LAStempWritePoint14*)buffer)->number_of_returns = ((LAStempWritePoint10*)item)->number_of_returns; ((LAStempWritePoint14*)buffer)->scan_angle = I16_QUANTIZE(((LAStempWritePoint10*)item)->scan_angle_rank/0.006f); } *((F64*)&buffer[22]) = ((LAStempWritePoint10*)item)->gps_time; return outstream->putBytes(buffer, 30); } private: U8 buffer[30]; }; class LASwriteItemRaw_POINT14_BE : public LASwriteItemRaw { public: LASwriteItemRaw_POINT14_BE(){}; inline BOOL write(const U8* item, U32& context) { ENDIAN_SWAP_32(&item[ 0], &swapped[ 0]); // X ENDIAN_SWAP_32(&item[ 4], &swapped[ 4]); // Y ENDIAN_SWAP_32(&item[ 8], &swapped[ 8]); // Z ENDIAN_SWAP_16(&item[12], &swapped[12]); // intensity ((LAStempWritePoint14*)swapped)->scan_direction_flag = ((LAStempWritePoint10*)item)->scan_direction_flag; ((LAStempWritePoint14*)swapped)->edge_of_flight_line = ((LAStempWritePoint10*)item)->edge_of_flight_line; ((LAStempWritePoint14*)swapped)->classification = (((LAStempWritePoint10*)item)->classification & 31); ((LAStempWritePoint14*)swapped)->user_data = ((LAStempWritePoint10*)item)->user_data; ENDIAN_SWAP_16(&item[18], &swapped[20]); // point_source_ID if (((LAStempWritePoint10*)item)->extended_point_type) { ((LAStempWritePoint14*)swapped)->classification_flags = (((LAStempWritePoint10*)item)->extended_classification_flags & 8) | (((LAStempWritePoint10*)item)->classification >> 5); if (((LAStempWritePoint14*)swapped)->classification == 0) ((LAStempWritePoint14*)swapped)->classification = ((LAStempWritePoint10*)item)->extended_classification; ((LAStempWritePoint14*)swapped)->scanner_channel = ((LAStempWritePoint10*)item)->extended_scanner_channel; ((LAStempWritePoint14*)swapped)->return_number = ((LAStempWritePoint10*)item)->extended_return_number; ((LAStempWritePoint14*)swapped)->number_of_returns = ((LAStempWritePoint10*)item)->extended_number_of_returns; ENDIAN_SWAP_16(&item[20], &swapped[18]); // scan_angle } else { ((LAStempWritePoint14*)swapped)->classification_flags = (((LAStempWritePoint10*)item)->classification >> 5); ((LAStempWritePoint14*)swapped)->scanner_channel = 0; ((LAStempWritePoint14*)swapped)->return_number = ((LAStempWritePoint10*)item)->return_number; ((LAStempWritePoint14*)swapped)->number_of_returns = ((LAStempWritePoint10*)item)->number_of_returns; I16 scan_angle = I16_QUANTIZE(((LAStempWritePoint10*)item)->scan_angle_rank/0.006f); ENDIAN_SWAP_16((U8*)(&scan_angle), &swapped[18]); // scan_angle } ENDIAN_SWAP_64((U8*)&(((LAStempWritePoint10*)item)->gps_time), &swapped[22]); return outstream->putBytes(swapped, 30); } private: U8 swapped[30]; }; class LASwriteItemRaw_RGBNIR14_LE : public LASwriteItemRaw { public: LASwriteItemRaw_RGBNIR14_LE(){} inline BOOL write(const U8* item, U32& context) { return outstream->putBytes(item, 8); }; }; class LASwriteItemRaw_RGBNIR14_BE : public LASwriteItemRaw { public: LASwriteItemRaw_RGBNIR14_BE(){} inline BOOL write(const U8* item, U32& context) { ENDIAN_SWAP_32(&item[ 0], &swapped[ 0]); // R ENDIAN_SWAP_32(&item[ 2], &swapped[ 2]); // G ENDIAN_SWAP_32(&item[ 4], &swapped[ 4]); // B ENDIAN_SWAP_32(&item[ 6], &swapped[ 6]); // NIR return outstream->putBytes(swapped, 8); }; private: U8 swapped[8]; }; #endif LASzip-3.4.3/src/laswritepoint.cpp000066400000000000000000000332151356234217100170720ustar00rootroot00000000000000/* =============================================================================== FILE: laswritepoint.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laswritepoint.hpp" #include "arithmeticencoder.hpp" #include "laswriteitemraw.hpp" #include "laswriteitemcompressed_v1.hpp" #include "laswriteitemcompressed_v2.hpp" #include "laswriteitemcompressed_v3.hpp" #include "laswriteitemcompressed_v4.hpp" #include #include #include LASwritePoint::LASwritePoint() { outstream = 0; num_writers = 0; writers = 0; writers_raw = 0; writers_compressed = 0; enc = 0; layered_las14_compression = FALSE; // used for chunking chunk_size = U32_MAX; chunk_count = 0; number_chunks = 0; alloced_chunks = 0; chunk_sizes = 0; chunk_bytes = 0; chunk_table_start_position = 0; chunk_start_position = 0; } BOOL LASwritePoint::setup(const U32 num_items, const LASitem* items, const LASzip* laszip) { U32 i; // is laszip exists then we must use its items if (laszip) { if (num_items == 0) return FALSE; if (items == 0) return FALSE; if (num_items != laszip->num_items) return FALSE; if (items != laszip->items) return FALSE; } // create entropy encoder (if requested) enc = 0; if (laszip && laszip->compressor) { switch (laszip->coder) { case LASZIP_CODER_ARITHMETIC: enc = new ArithmeticEncoder(); break; default: // entropy decoder not supported return FALSE; } // maybe layered compression for LAS 1.4 layered_las14_compression = (laszip->compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED); } // initizalize the writers writers = 0; num_writers = num_items; // disable chunking chunk_size = U32_MAX; // always create the raw writers writers_raw = new LASwriteItem*[num_writers]; memset(writers_raw, 0, num_writers*sizeof(LASwriteItem*)); for (i = 0; i < num_writers; i++) { switch (items[i].type) { case LASitem::POINT10: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_POINT10_LE(); else writers_raw[i] = new LASwriteItemRaw_POINT10_BE(); break; case LASitem::GPSTIME11: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_GPSTIME11_LE(); else writers_raw[i] = new LASwriteItemRaw_GPSTIME11_BE(); break; case LASitem::RGB12: case LASitem::RGB14: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_RGB12_LE(); else writers_raw[i] = new LASwriteItemRaw_RGB12_BE(); break; case LASitem::BYTE: case LASitem::BYTE14: writers_raw[i] = new LASwriteItemRaw_BYTE(items[i].size); break; case LASitem::POINT14: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_POINT14_LE(); else writers_raw[i] = new LASwriteItemRaw_POINT14_BE(); break; case LASitem::RGBNIR14: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_RGBNIR14_LE(); else writers_raw[i] = new LASwriteItemRaw_RGBNIR14_BE(); break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: if (IS_LITTLE_ENDIAN()) writers_raw[i] = new LASwriteItemRaw_WAVEPACKET13_LE(); else writers_raw[i] = new LASwriteItemRaw_WAVEPACKET13_BE(); break; default: return FALSE; } } // if needed create the compressed writers and set versions if (enc) { writers_compressed = new LASwriteItem*[num_writers]; memset(writers_compressed, 0, num_writers*sizeof(LASwriteItem*)); for (i = 0; i < num_writers; i++) { switch (items[i].type) { case LASitem::POINT10: if (items[i].version == 1) writers_compressed[i] = new LASwriteItemCompressed_POINT10_v1(enc); else if (items[i].version == 2) writers_compressed[i] = new LASwriteItemCompressed_POINT10_v2(enc); else return FALSE; break; case LASitem::GPSTIME11: if (items[i].version == 1) writers_compressed[i] = new LASwriteItemCompressed_GPSTIME11_v1(enc); else if (items[i].version == 2) writers_compressed[i] = new LASwriteItemCompressed_GPSTIME11_v2(enc); else return FALSE; break; case LASitem::RGB12: if (items[i].version == 1) writers_compressed[i] = new LASwriteItemCompressed_RGB12_v1(enc); else if (items[i].version == 2) writers_compressed[i] = new LASwriteItemCompressed_RGB12_v2(enc); else return FALSE; break; case LASitem::BYTE: if (items[i].version == 1) writers_compressed[i] = new LASwriteItemCompressed_BYTE_v1(enc, items[i].size); else if (items[i].version == 2) writers_compressed[i] = new LASwriteItemCompressed_BYTE_v2(enc, items[i].size); else return FALSE; break; case LASitem::POINT14: if (items[i].version == 3) writers_compressed[i] = new LASwriteItemCompressed_POINT14_v3(enc); else if (items[i].version == 4) writers_compressed[i] = new LASwriteItemCompressed_POINT14_v4(enc); else return FALSE; break; case LASitem::RGB14: if (items[i].version == 3) writers_compressed[i] = new LASwriteItemCompressed_RGB14_v3(enc); else if (items[i].version == 4) writers_compressed[i] = new LASwriteItemCompressed_RGB14_v4(enc); else return FALSE; break; case LASitem::RGBNIR14: if (items[i].version == 3) writers_compressed[i] = new LASwriteItemCompressed_RGBNIR14_v3(enc); else if (items[i].version == 4) writers_compressed[i] = new LASwriteItemCompressed_RGBNIR14_v4(enc); else return FALSE; break; case LASitem::BYTE14: if (items[i].version == 3) writers_compressed[i] = new LASwriteItemCompressed_BYTE14_v3(enc, items[i].size); else if (items[i].version == 4) writers_compressed[i] = new LASwriteItemCompressed_BYTE14_v4(enc, items[i].size); else return FALSE; break; case LASitem::WAVEPACKET13: if (items[i].version == 1) writers_compressed[i] = new LASwriteItemCompressed_WAVEPACKET13_v1(enc); else return FALSE; break; case LASitem::WAVEPACKET14: if (items[i].version == 3) writers_compressed[i] = new LASwriteItemCompressed_WAVEPACKET14_v3(enc); else if (items[i].version == 4) writers_compressed[i] = new LASwriteItemCompressed_WAVEPACKET14_v4(enc); else return FALSE; break; default: return FALSE; } } if (laszip->compressor != LASZIP_COMPRESSOR_POINTWISE) { if (laszip->chunk_size) chunk_size = laszip->chunk_size; chunk_count = 0; number_chunks = U32_MAX; } } return TRUE; } BOOL LASwritePoint::init(ByteStreamOut* outstream) { if (!outstream) return FALSE; this->outstream = outstream; // if chunking is enabled if (number_chunks == U32_MAX) { number_chunks = 0; if (outstream->isSeekable()) { chunk_table_start_position = outstream->tell(); } else { chunk_table_start_position = -1; } outstream->put64bitsLE((U8*)&chunk_table_start_position); chunk_start_position = outstream->tell(); } U32 i; for (i = 0; i < num_writers; i++) { ((LASwriteItemRaw*)(writers_raw[i]))->init(outstream); } if (enc) { writers = 0; } else { writers = writers_raw; } return TRUE; } BOOL LASwritePoint::write(const U8 * const * point) { U32 i; U32 context = 0; if (chunk_count == chunk_size) { if (enc) { if (layered_las14_compression) { // write how many points are in the chunk outstream->put32bitsLE((U8*)&chunk_count); // write all layers for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_sizes(); } for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_bytes(); } } else { enc->done(); } add_chunk_to_table(); init(outstream); } else { // happens *only* for uncompressed LAS with over U32_MAX points assert(chunk_size == U32_MAX); } chunk_count = 0; } chunk_count++; if (writers) { for (i = 0; i < num_writers; i++) { writers[i]->write(point[i], context); } } else { for (i = 0; i < num_writers; i++) { writers_raw[i]->write(point[i], context); ((LASwriteItemCompressed*)(writers_compressed[i]))->init(point[i], context); } writers = writers_compressed; enc->init(outstream); } return TRUE; } BOOL LASwritePoint::chunk() { if (chunk_start_position == 0 || chunk_size != U32_MAX) { return FALSE; } if (layered_las14_compression) { U32 i; // write how many points are in the chunk outstream->put32bitsLE((U8*)&chunk_count); // write all layers for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_sizes(); } for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_bytes(); } } else { enc->done(); } add_chunk_to_table(); init(outstream); chunk_count = 0; return TRUE; } BOOL LASwritePoint::done() { if (writers == writers_compressed) { if (layered_las14_compression) { U32 i; // write how many points are in the chunk outstream->put32bitsLE((U8*)&chunk_count); // write all layers for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_sizes(); } for (i = 0; i < num_writers; i++) { ((LASwriteItemCompressed*)writers[i])->chunk_bytes(); } } else { enc->done(); } if (chunk_start_position) { if (chunk_count) add_chunk_to_table(); return write_chunk_table(); } } else if (writers == 0) { if (chunk_start_position) { return write_chunk_table(); } } return TRUE; } BOOL LASwritePoint::add_chunk_to_table() { if (number_chunks == alloced_chunks) { if (chunk_bytes == 0) { alloced_chunks = 1024; if (chunk_size == U32_MAX) chunk_sizes = (U32*)malloc(sizeof(U32)*alloced_chunks); chunk_bytes = (U32*)malloc(sizeof(U32)*alloced_chunks); } else { alloced_chunks *= 2; if (chunk_size == U32_MAX) chunk_sizes = (U32*)realloc(chunk_sizes, sizeof(U32)*alloced_chunks); chunk_bytes = (U32*)realloc(chunk_bytes, sizeof(U32)*alloced_chunks); } if (chunk_size == U32_MAX && chunk_sizes == 0) return FALSE; if (chunk_bytes == 0) return FALSE; } I64 position = outstream->tell(); if (chunk_size == U32_MAX) chunk_sizes[number_chunks] = chunk_count; chunk_bytes[number_chunks] = (U32)(position - chunk_start_position); chunk_start_position = position; number_chunks++; return TRUE; } BOOL LASwritePoint::write_chunk_table() { U32 i; I64 position = outstream->tell(); if (chunk_table_start_position != -1) // stream is seekable { if (!outstream->seek(chunk_table_start_position)) { return FALSE; } if (!outstream->put64bitsLE((U8*)&position)) { return FALSE; } if (!outstream->seek(position)) { return FALSE; } } U32 version = 0; if (!outstream->put32bitsLE((U8*)&version)) { return FALSE; } if (!outstream->put32bitsLE((U8*)&number_chunks)) { return FALSE; } if (number_chunks > 0) { enc->init(outstream); IntegerCompressor ic(enc, 32, 2); ic.initCompressor(); for (i = 0; i < number_chunks; i++) { if (chunk_size == U32_MAX) ic.compress((i ? chunk_sizes[i-1] : 0), chunk_sizes[i], 0); ic.compress((i ? chunk_bytes[i-1] : 0), chunk_bytes[i], 1); } enc->done(); } if (chunk_table_start_position == -1) // stream is not-seekable { if (!outstream->put64bitsLE((U8*)&position)) { return FALSE; } } return TRUE; } LASwritePoint::~LASwritePoint() { U32 i; if (writers_raw) { for (i = 0; i < num_writers; i++) { delete writers_raw[i]; } delete [] writers_raw; } if (writers_compressed) { for (i = 0; i < num_writers; i++) { delete writers_compressed[i]; } delete [] writers_compressed; } if (enc) { delete enc; } if (chunk_bytes) free(chunk_bytes); } LASzip-3.4.3/src/laswritepoint.hpp000066400000000000000000000053361356234217100171020ustar00rootroot00000000000000/* =============================================================================== FILE: laswritepoint.hpp CONTENTS: Common interface for the classes that write points raw or compressed. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 21 February 2019 -- fix for writing 4294967295+ points uncompressed to LAS 28 August 2017 -- moving 'context' from global development hack to interface 23 August 2016 -- layering of items for selective decompression in LAS 1.4 6 September 2014 -- removed inheritance of EntropyEncoder and EntropyDecoder 6 October 2011 -- large file support & reading with missing chunk table 9 May 2011 -- the chunked compressor now allows variable chunk sizes 25 April 2011 -- added chunked laszip for random access decompression 10 January 2011 -- licensing change for LGPL release and liblas integration 7 December 2010 -- adapted from LASpointWriter for better code modularity 3 December 2010 -- updated to (somewhat) support LAS format 1.3 7 September 2008 -- updated to support LAS format 1.2 22 February 2007 -- created about an hour before henna's birthday =============================================================================== */ #ifndef LAS_WRITE_POINT_HPP #define LAS_WRITE_POINT_HPP #include "mydefs.hpp" #include "laszip.hpp" #include "bytestreamout.hpp" class LASwriteItem; class ArithmeticEncoder; class LASwritePoint { public: LASwritePoint(); ~LASwritePoint(); // should only be called *once* BOOL setup(const U32 num_items, const LASitem* items, const LASzip* laszip=0); BOOL init(ByteStreamOut* outstream); BOOL write(const U8 * const * point); BOOL chunk(); BOOL done(); private: ByteStreamOut* outstream; U32 num_writers; LASwriteItem** writers; LASwriteItem** writers_raw; LASwriteItem** writers_compressed; ArithmeticEncoder* enc; BOOL layered_las14_compression; // used for chunking U32 chunk_size; U32 chunk_count; U32 number_chunks; U32 alloced_chunks; U32* chunk_sizes; U32* chunk_bytes; I64 chunk_start_position; I64 chunk_table_start_position; BOOL add_chunk_to_table(); BOOL write_chunk_table(); }; #endif LASzip-3.4.3/src/laszip.cpp000066400000000000000000000654231356234217100154760ustar00rootroot00000000000000/* =============================================================================== FILE: laszip.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laszip.hpp" #include "mydefs.hpp" #include #include #include #include LASzip::LASzip() { compressor = LASZIP_COMPRESSOR_DEFAULT; coder = LASZIP_CODER_ARITHMETIC; version_major = LASZIP_VERSION_MAJOR; version_minor = LASZIP_VERSION_MINOR; version_revision = LASZIP_VERSION_REVISION; options = 0; num_items = 0; chunk_size = LASZIP_CHUNK_SIZE_DEFAULT; number_of_special_evlrs = -1; offset_to_special_evlrs = -1; error_string = 0; items = 0; bytes = 0; } LASzip::~LASzip() { if (error_string) free(error_string); if (items) delete [] items; if (bytes) delete [] bytes; } // the data of the LASzip VLR // U16 compressor 2 bytes // U16 coder 2 bytes // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes // U32 options 4 bytes // U32 chunk_size 4 bytes // I64 num_points 8 bytes // I64 num_bytes 8 bytes // U16 num_items 2 bytes // U16 type 2 bytes * num_items // U16 size 2 bytes * num_items // U16 version 2 bytes * num_items // which totals 34+6*num_items // unpack from VLR data bool LASzip::unpack(const U8* bytes, const I32 num) { // check input if (num < 34) return return_error("too few bytes to unpack"); if (((num - 34) % 6) != 0) return return_error("wrong number bytes to unpack"); if (((num - 34) / 6) == 0) return return_error("zero items to unpack"); num_items = (num - 34) / 6; // create item list if (items) delete [] items; items = new LASitem[num_items]; // do the unpacking U16 i; const U8* b = bytes; compressor = *((U16*)b); b += 2; coder = *((U16*)b); b += 2; version_major = *((U8*)b); b += 1; version_minor = *((U8*)b); b += 1; version_revision = *((U16*)b); b += 2; options = *((U32*)b); b += 4; chunk_size = *((U32*)b); b += 4; number_of_special_evlrs = *((I64*)b); b += 8; offset_to_special_evlrs = *((I64*)b); b += 8; num_items = *((U16*)b); b += 2; for (i = 0; i < num_items; i++) { items[i].type = (LASitem::Type)*((U16*)b); b += 2; items[i].size = *((U16*)b); b += 2; items[i].version = *((U16*)b); b += 2; } assert((bytes + num) == b); // check if we support the contents for (i = 0; i < num_items; i++) { if (!check_item(&items[i])) return false; } return true; } // pack to VLR data bool LASzip::pack(U8*& bytes, I32& num) { // check if we support the contents if (!check()) return false; // prepare output num = 34 + 6*num_items; if (this->bytes) delete [] this->bytes; this->bytes = bytes = new U8[num]; // pack U16 i; U8* b = bytes; *((U16*)b) = compressor; b += 2; *((U16*)b) = coder; b += 2; *((U8*)b) = version_major; b += 1; *((U8*)b) = version_minor; b += 1; *((U16*)b) = version_revision; b += 2; *((U32*)b) = options; b += 4; *((U32*)b) = chunk_size; b += 4; *((I64*)b) = number_of_special_evlrs; b += 8; *((I64*)b) = offset_to_special_evlrs; b += 8; *((U16*)b) = num_items; b += 2; for (i = 0; i < num_items; i++) { *((U16*)b) = (U16)items[i].type; b += 2; *((U16*)b) = items[i].size; b += 2; *((U16*)b) = items[i].version; b += 2; } assert((bytes + num) == b); return true; } const char* LASzip::get_error() const { return error_string; } bool LASzip::return_error(const char* error) { #if defined(_MSC_VER) && \ (_MSC_FULL_VER >= 150000000) #define CopyString _strdup #else #define CopyString strdup #endif char err[256]; sprintf(err, "%s (LASzip v%d.%dr%d)", error, LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION); if (error_string) free(error_string); error_string = CopyString(err); return false; } bool LASzip::check_compressor(const U16 compressor) { if (compressor < LASZIP_COMPRESSOR_TOTAL_NUMBER_OF) return true; char error[64]; sprintf(error, "compressor %d not supported", compressor); return return_error(error); } bool LASzip::check_coder(const U16 coder) { if (coder < LASZIP_CODER_TOTAL_NUMBER_OF) return true; char error[64]; sprintf(error, "coder %d not supported", coder); return return_error(error); } bool LASzip::check_item(const LASitem* item) { switch (item->type) { case LASitem::POINT10: if (item->size != 20) return return_error("POINT10 has size != 20"); if (item->version > 2) return return_error("POINT10 has version > 2"); break; case LASitem::GPSTIME11: if (item->size != 8) return return_error("GPSTIME11 has size != 8"); if (item->version > 2) return return_error("GPSTIME11 has version > 2"); break; case LASitem::RGB12: if (item->size != 6) return return_error("RGB12 has size != 6"); if (item->version > 2) return return_error("RGB12 has version > 2"); break; case LASitem::BYTE: if (item->size < 1) return return_error("BYTE has size < 1"); if (item->version > 2) return return_error("BYTE has version > 2"); break; case LASitem::POINT14: if (item->size != 30) return return_error("POINT14 has size != 30"); if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("POINT14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch break; case LASitem::RGB14: if (item->size != 6) return return_error("RGB14 has size != 6"); if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGB14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch break; case LASitem::RGBNIR14: if (item->size != 8) return return_error("RGBNIR14 has size != 8"); if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGBNIR14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch break; case LASitem::BYTE14: if (item->size < 1) return return_error("BYTE14 has size < 1"); if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("BYTE14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch break; case LASitem::WAVEPACKET13: if (item->size != 29) return return_error("WAVEPACKET13 has size != 29"); if (item->version > 1) return return_error("WAVEPACKET13 has version > 1"); break; case LASitem::WAVEPACKET14: if (item->size != 29) return return_error("WAVEPACKET14 has size != 29"); if ((item->version != 0) && (item->version != 3) && (item->version != 4)) return return_error("WAVEPACKET14 has version != 0 and != 3 and != 4"); // version == 4 fixes context-switch break; default: if (1) { char error[64]; sprintf(error, "item unknown (%d,%d,%d)", item->type, item->size, item->version); return return_error(error); } } return true; } bool LASzip::check_items(const U16 num_items, const LASitem* items, const U16 point_size) { if (num_items == 0) return return_error("number of items cannot be zero"); if (items == 0) return return_error("items pointer cannot be NULL"); U16 i; U16 size = 0; for (i = 0; i < num_items; i++) { if (!check_item(&items[i])) return false; size += items[i].size; } if (point_size && (point_size != size)) { CHAR temp[66]; sprintf(temp, "point has size of %d but items only add up to %d bytes", point_size, size); return return_error(temp); } return true; } bool LASzip::check(const U16 point_size) { if (!check_compressor(compressor)) return false; if (!check_coder(coder)) return false; if (!check_items(num_items, items, point_size)) return false; return true; } bool LASzip::request_compatibility_mode(const U16 requested_compatibility_mode) { if (num_items != 0) return return_error("request compatibility mode before calling setup()"); if (requested_compatibility_mode > 1) { return return_error("compatibility mode larger than 1 not supported"); } if (requested_compatibility_mode) { options = options | 0x00000001; } else { options = options & 0xFFFFFFFE; } return true; } bool LASzip::setup(const U8 point_type, const U16 point_size, const U16 compressor) { if (!check_compressor(compressor)) return false; this->num_items = 0; if (this->items) delete [] this->items; this->items = 0; if (!setup(&num_items, &items, point_type, point_size, compressor)) return false; if (compressor) { if (items[0].type == LASitem::POINT14) { if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED) { return false; } this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED; } else { if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED) { this->compressor = LASZIP_COMPRESSOR_CHUNKED; } else { this->compressor = compressor; } } if (compressor != LASZIP_COMPRESSOR_POINTWISE) { if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT; } } else { this->compressor = LASZIP_COMPRESSOR_NONE; } return true; } bool LASzip::setup(const U16 num_items, const LASitem* items, const U16 compressor) { // check input if (!check_compressor(compressor)) return false; if (!check_items(num_items, items)) return false; // setup compressor if (compressor) { if (items[0].type == LASitem::POINT14) { if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED) { return false; } this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED; } else { if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED) { this->compressor = LASZIP_COMPRESSOR_CHUNKED; } else { this->compressor = compressor; } } if (compressor != LASZIP_COMPRESSOR_POINTWISE) { if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT; } } else { this->compressor = LASZIP_COMPRESSOR_NONE; } // prepare items this->num_items = 0; if (this->items) delete [] this->items; this->items = 0; this->num_items = num_items; this->items = new LASitem[num_items]; // setup items U16 i; for (i = 0; i < num_items; i++) { this->items[i] = items[i]; } return true; } bool LASzip::setup(U16* num_items, LASitem** items, const U8 point_type, const U16 point_size, const U16 compressor) { BOOL compatible = FALSE; BOOL have_point14 = FALSE; BOOL have_gps_time = FALSE; BOOL have_rgb = FALSE; BOOL have_nir = FALSE; BOOL have_wavepacket = FALSE; I32 extra_bytes_number = 0; // turns on LAS 1.4 compatibility mode if (options & 1) compatible = TRUE; // switch over the point types we know switch (point_type) { case 0: extra_bytes_number = (I32)point_size - 20; break; case 1: have_gps_time = TRUE; extra_bytes_number = (I32)point_size - 28; break; case 2: have_rgb = TRUE; extra_bytes_number = (I32)point_size - 26; break; case 3: have_gps_time = TRUE; have_rgb = TRUE; extra_bytes_number = (I32)point_size - 34; break; case 4: have_gps_time = TRUE; have_wavepacket = TRUE; extra_bytes_number = (I32)point_size - 57; break; case 5: have_gps_time = TRUE; have_rgb = TRUE; have_wavepacket = TRUE; extra_bytes_number = (I32)point_size - 63; break; case 6: have_point14 = TRUE; extra_bytes_number = (I32)point_size - 30; break; case 7: have_point14 = TRUE; have_rgb = TRUE; extra_bytes_number = (I32)point_size - 36; break; case 8: have_point14 = TRUE; have_rgb = TRUE; have_nir = TRUE; extra_bytes_number = (I32)point_size - 38; break; case 9: have_point14 = TRUE; have_wavepacket = TRUE; extra_bytes_number = (I32)point_size - 59; break; case 10: have_point14 = TRUE; have_rgb = TRUE; have_nir = TRUE; have_wavepacket = TRUE; extra_bytes_number = (I32)point_size - 67; break; default: if (1) { char error[64]; sprintf(error, "point type %d unknown", point_type); return return_error(error); } } if (extra_bytes_number < 0) { fprintf(stderr, "WARNING: point size %d too small by %d bytes for point type %d. assuming point_size of %d\n", point_size, -extra_bytes_number, point_type, point_size-extra_bytes_number); extra_bytes_number = 0; } // maybe represent new LAS 1.4 as corresponding LAS 1.3 points plus extra bytes for compatibility if (have_point14 && compatible) { // we need 4 extra bytes for the new point attributes extra_bytes_number += 5; // we store the GPS time separately have_gps_time = TRUE; // we do not use the point14 item have_point14 = FALSE; // if we have NIR ... if (have_nir) { // we need another 2 extra bytes extra_bytes_number += 2; // we do not use the NIR item have_nir = FALSE; } } // create item description (*num_items) = 1 + !!(have_gps_time) + !!(have_rgb) + !!(have_wavepacket) + !!(extra_bytes_number); (*items) = new LASitem[*num_items]; U16 i = 1; if (have_point14) { (*items)[0].type = LASitem::POINT14; (*items)[0].size = 30; (*items)[0].version = 0; } else { (*items)[0].type = LASitem::POINT10; (*items)[0].size = 20; (*items)[0].version = 0; } if (have_gps_time) { (*items)[i].type = LASitem::GPSTIME11; (*items)[i].size = 8; (*items)[i].version = 0; i++; } if (have_rgb) { if (have_point14) { if (have_nir) { (*items)[i].type = LASitem::RGBNIR14; (*items)[i].size = 8; (*items)[i].version = 0; } else { (*items)[i].type = LASitem::RGB14; (*items)[i].size = 6; (*items)[i].version = 0; } } else { (*items)[i].type = LASitem::RGB12; (*items)[i].size = 6; (*items)[i].version = 0; } i++; } if (have_wavepacket) { if (have_point14) { (*items)[i].type = LASitem::WAVEPACKET14; (*items)[i].size = 29; (*items)[i].version = 0; } else { (*items)[i].type = LASitem::WAVEPACKET13; (*items)[i].size = 29; (*items)[i].version = 0; } i++; } if (extra_bytes_number) { if (have_point14) { (*items)[i].type = LASitem::BYTE14; (*items)[i].size = extra_bytes_number; (*items)[i].version = 0; } else { (*items)[i].type = LASitem::BYTE; (*items)[i].size = extra_bytes_number; (*items)[i].version = 0; } i++; } if (compressor) request_version(2); assert(i == *num_items); return true; } bool LASzip::set_chunk_size(const U32 chunk_size) { if (num_items == 0) return return_error("call setup() before setting chunk size"); if (this->compressor != LASZIP_COMPRESSOR_POINTWISE) { this->chunk_size = chunk_size; return true; } return false; } bool LASzip::request_version(const U16 requested_version) { if (num_items == 0) return return_error("call setup() before requesting version"); if (compressor == LASZIP_COMPRESSOR_NONE) { if (requested_version > 0) return return_error("without compression version is always 0"); } else { if (requested_version < 1) return return_error("with compression version is at least 1"); if (requested_version > 2) return return_error("version larger than 2 not supported"); } U16 i; for (i = 0; i < num_items; i++) { switch (items[i].type) { case LASitem::POINT10: case LASitem::GPSTIME11: case LASitem::RGB12: case LASitem::BYTE: items[i].version = requested_version; break; case LASitem::WAVEPACKET13: items[i].version = 1; // no version 2 break; case LASitem::POINT14: case LASitem::RGB14: case LASitem::RGBNIR14: case LASitem::WAVEPACKET14: case LASitem::BYTE14: items[i].version = 3; // no version 1 or 2 break; default: return return_error("item type not supported"); } } return true; } bool LASzip::is_standard(U8* point_type, U16* record_length) { return is_standard(num_items, items, point_type, record_length); } bool LASzip::is_standard(const U16 num_items, const LASitem* items, U8* point_type, U16* record_length) { if (items == 0) return return_error("LASitem array is zero"); // this is always true if (point_type) *point_type = 127; if (record_length) { U16 i; *record_length = 0; for (i = 0; i < num_items; i++) { *record_length += items[i].size; } } // the minimal number of items is 1 if (num_items < 1) return return_error("less than one LASitem entries"); // the maximal number of items is 5 if (num_items > 5) return return_error("more than five LASitem entries"); if (items[0].is_type(LASitem::POINT10)) { // consider all the POINT10 combinations if (num_items == 1) { if (point_type) *point_type = 0; if (record_length) assert(*record_length == 20); return true; } else { if (items[1].is_type(LASitem::GPSTIME11)) { if (num_items == 2) { if (point_type) *point_type = 1; if (record_length) assert(*record_length == 28); return true; } else { if (items[2].is_type(LASitem::RGB12)) { if (num_items == 3) { if (point_type) *point_type = 3; if (record_length) assert(*record_length == 34); return true; } else { if (items[3].is_type(LASitem::WAVEPACKET13)) { if (num_items == 4) { if (point_type) *point_type = 5; if (record_length) assert(*record_length == 63); return true; } else { if (items[4].is_type(LASitem::BYTE)) { if (num_items == 5) { if (point_type) *point_type = 5; if (record_length) assert(*record_length == (63 + items[4].size)); return true; } } } } else if (items[3].is_type(LASitem::BYTE)) { if (num_items == 4) { if (point_type) *point_type = 3; if (record_length) assert(*record_length == (34 + items[3].size)); return true; } } } } else if (items[2].is_type(LASitem::WAVEPACKET13)) { if (num_items == 3) { if (point_type) *point_type = 4; if (record_length) assert(*record_length == 57); return true; } else { if (items[3].is_type(LASitem::BYTE)) { if (num_items == 4) { if (point_type) *point_type = 4; if (record_length) assert(*record_length == (57 + items[3].size)); return true; } } } } else if (items[2].is_type(LASitem::BYTE)) { if (num_items == 3) { if (point_type) *point_type = 1; if (record_length) assert(*record_length == (28 + items[2].size)); return true; } } } } else if (items[1].is_type(LASitem::RGB12)) { if (num_items == 2) { if (point_type) *point_type = 2; if (record_length) assert(*record_length == 26); return true; } else { if (items[2].is_type(LASitem::BYTE)) { if (num_items == 3) { if (point_type) *point_type = 2; if (record_length) assert(*record_length == (26 + items[2].size)); return true; } } } } else if (items[1].is_type(LASitem::BYTE)) { if (num_items == 2) { if (point_type) *point_type = 0; if (record_length) assert(*record_length == (20 + items[1].size)); return true; } } } } else if (items[0].is_type(LASitem::POINT14)) { // consider all the POINT14 combinations if (num_items == 1) { if (point_type) *point_type = 6; if (record_length) assert(*record_length == 30); return true; } else { if (items[1].is_type(LASitem::RGB14)) { if (num_items == 2) { if (point_type) *point_type = 7; if (record_length) assert(*record_length == 36); return true; } else { if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14)) { if (num_items == 3) { if (point_type) *point_type = 7; if (record_length) assert(*record_length == (36 + items[2].size)); return true; } } } } else if (items[1].is_type(LASitem::RGBNIR14)) { if (num_items == 2) { if (point_type) *point_type = 8; if (record_length) assert(*record_length == 38); return true; } else { if (items[2].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14)) { if (num_items == 3) { if (point_type) *point_type = 10; if (record_length) assert(*record_length == 67); return true; } else { if (items[3].is_type(LASitem::BYTE) || items[3].is_type(LASitem::BYTE14)) { if (num_items == 4) { if (point_type) *point_type = 10; if (record_length) assert(*record_length == (67 + items[3].size)); return true; } } } } else if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14)) { if (num_items == 3) { if (point_type) *point_type = 8; if (record_length) assert(*record_length == (38 + items[2].size)); return true; } } } } else if (items[1].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14)) { if (num_items == 2) { if (point_type) *point_type = 9; if (record_length) assert(*record_length == 59); return true; } else { if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14)) { if (num_items == 3) { if (point_type) *point_type = 9; if (record_length) assert(*record_length == (59 + items[2].size)); return true; } } } } else if (items[1].is_type(LASitem::BYTE) || items[1].is_type(LASitem::BYTE14)) { if (num_items == 2) { if (point_type) *point_type = 6; if (record_length) assert(*record_length == (30 + items[1].size)); return true; } } } } else { return_error("first LASitem is neither POINT10 nor POINT14"); } return return_error("LASitem array does not match LAS specification 1.4"); } bool LASitem::is_type(LASitem::Type t) const { if (t != type) return false; switch (t) { case POINT10: if (size != 20) return false; break; case POINT14: if (size != 30) return false; break; case GPSTIME11: if (size != 8) return false; break; case RGB12: if (size != 6) return false; break; case BYTE: if (size < 1) return false; break; case RGB14: if (size != 6) return false; break; case RGBNIR14: if (size != 8) return false; break; case BYTE14: if (size < 1) return false; break; case WAVEPACKET13: if (size != 29) return false; break; case WAVEPACKET14: if (size != 29) return false; break; default: return false; } return true; } const char* LASitem::get_name() const { switch (type) { case POINT10: return "POINT10"; break; case POINT14: return "POINT14"; break; case GPSTIME11: return "GPSTIME11"; break; case RGB12: return "RGB12"; break; case BYTE: return "BYTE"; break; case RGB14: return "RGB14"; break; case RGBNIR14: return "RGBNIR14"; break; case BYTE14: return "BYTE14"; break; case WAVEPACKET13: return "WAVEPACKET13"; break; case WAVEPACKET14: return "WAVEPACKET14"; break; default: break; } return 0; } LASzip-3.4.3/src/laszip.hpp000066400000000000000000000151501356234217100154730ustar00rootroot00000000000000/* =============================================================================== FILE: laszip.hpp CONTENTS: Contains LASitem and LASchunk structs as well as the IDs of the currently supported entropy coding scheme PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 20 March 2019 -- upped to 3.3 r1 for consistent legacy and extended class check 21 February 2019 -- bug fix when writing 4294967295+ points uncompressed to LAS 28 December 2018 -- fix for v4 decompression of WavePacket part of PRDF 9 and 10 27 December 2018 -- upped to 3.2 r9 for bug fix in multi-channel NIR decompression 7 November 2018 -- upped to 3.2 r8 for identical legacy and extended flags check 20 October 2018 -- upped to 3.2 r7 for rare bug in LASinterval::merge_intervals() 5 October 2018 -- upped to 3.2 r6 for corrected 'is_empty' return value 28 September 2018 -- upped to 3.2 r5 for fix in extended classification writing 9 February 2018 -- minor version increment as it can read v4 compressed items 28 December 2017 -- fix incorrect 'context switch' reported by Wanwannodao 23 August 2017 -- minor version increment for C++ stream-based read/write API 28 May 2017 -- support for "LAS 1.4 selective decompression" added into DLL API 8 April 2017 -- new check for whether point size and total size of items match 30 March 2017 -- support for "native LAS 1.4 extension" added into main branch 7 January 2017 -- set reserved VLR field from 0xAABB to 0x0 in DLL 7 January 2017 -- consistent compatibility mode scan angle quantization in DLL 7 January 2017 -- compatibility mode *decompression* fix for waveforms in DLL 25 February 2016 -- depreciating old libLAS laszipper/lasunzipper binding 29 July 2013 -- reorganized to create an easy-to-use LASzip DLL 5 December 2011 -- learns the chunk table if it is missing (e.g. truncated LAZ) 6 October 2011 -- large file support, ability to read with missing chunk table 23 June 2011 -- turned on LASzip version 2.0 compressor with chunking 8 May 2011 -- added an option for variable chunking via chunk() 23 April 2011 -- changed interface for simplicity and chunking support 20 March 2011 -- incrementing LASZIP_VERSION to 1.2 for improved compression 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- refactored from lasdefinitions after movies with silke =============================================================================== */ #ifndef LASZIP_HPP #define LASZIP_HPP #if defined(_MSC_VER) && (_MSC_VER < 1300) #define LZ_WIN32_VC6 typedef __int64 SIGNED_INT64; #else typedef long long SIGNED_INT64; #endif #if defined(_MSC_VER) && (_MSC_FULL_VER >= 150000000) #define LASCopyString _strdup #else #define LASCopyString strdup #endif #define LASZIP_VERSION_MAJOR 3 #define LASZIP_VERSION_MINOR 4 #define LASZIP_VERSION_REVISION 3 #define LASZIP_VERSION_BUILD_DATE 191111 #define LASZIP_COMPRESSOR_NONE 0 #define LASZIP_COMPRESSOR_POINTWISE 1 #define LASZIP_COMPRESSOR_POINTWISE_CHUNKED 2 #define LASZIP_COMPRESSOR_LAYERED_CHUNKED 3 #define LASZIP_COMPRESSOR_TOTAL_NUMBER_OF 4 #define LASZIP_COMPRESSOR_CHUNKED LASZIP_COMPRESSOR_POINTWISE_CHUNKED #define LASZIP_COMPRESSOR_NOT_CHUNKED LASZIP_COMPRESSOR_POINTWISE #define LASZIP_COMPRESSOR_DEFAULT LASZIP_COMPRESSOR_CHUNKED #define LASZIP_CODER_ARITHMETIC 0 #define LASZIP_CODER_TOTAL_NUMBER_OF 1 #define LASZIP_CHUNK_SIZE_DEFAULT 50000 class LASitem { public: enum Type { BYTE = 0, SHORT, INT, LONG, FLOAT, DOUBLE, POINT10, GPSTIME11, RGB12, WAVEPACKET13, POINT14, RGB14, RGBNIR14, WAVEPACKET14, BYTE14 } type; unsigned short size; unsigned short version; bool is_type(LASitem::Type t) const; const char* get_name() const; }; class LASzip { public: // supported version control bool check_compressor(const unsigned short compressor); bool check_coder(const unsigned short coder); bool check_item(const LASitem* item); bool check_items(const unsigned short num_items, const LASitem* items, const unsigned short point_size=0); bool check(const unsigned short point_size=0); // go back and forth between item array and point type & size bool setup(unsigned short* num_items, LASitem** items, const unsigned char point_type, const unsigned short point_size, const unsigned short compressor=LASZIP_COMPRESSOR_NONE); bool is_standard(const unsigned short num_items, const LASitem* items, unsigned char* point_type=0, unsigned short* record_length=0); bool is_standard(unsigned char* point_type=0, unsigned short* record_length=0); // pack to and unpack from VLR unsigned char* bytes; bool unpack(const unsigned char* bytes, const int num); bool pack(unsigned char*& bytes, int& num); // setup bool request_compatibility_mode(const unsigned short requested_compatibility_mode=0); // 0 = none, 1 = LAS 1.4 compatibility mode bool setup(const unsigned char point_type, const unsigned short point_size, const unsigned short compressor=LASZIP_COMPRESSOR_DEFAULT); bool setup(const unsigned short num_items, const LASitem* items, const unsigned short compressor); bool set_chunk_size(const unsigned int chunk_size); /* for compressor only */ bool request_version(const unsigned short requested_version); /* for compressor only */ // in case a function returns false this string describes the problem const char* get_error() const; // stored in LASzip VLR data section unsigned short compressor; unsigned short coder; unsigned char version_major; unsigned char version_minor; unsigned short version_revision; unsigned int options; unsigned int chunk_size; SIGNED_INT64 number_of_special_evlrs; /* must be -1 if unused */ SIGNED_INT64 offset_to_special_evlrs; /* must be -1 if unused */ unsigned short num_items; LASitem* items; LASzip(); ~LASzip(); private: bool return_error(const char* err); char* error_string; }; #endif LASzip-3.4.3/src/laszip_common_v1.hpp000066400000000000000000000047711356234217100174600ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_common_v1.hpp CONTENTS: Common defines and functionalities for version 1 of LASitemReadCompressed and LASitemwriteCompressed. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com uday.karan@gmail.com - http://github.com/verma COPYRIGHT: (c) 2007-2014, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 10 April 2014 - refactor LASwavepacket13 and add other functions to it =============================================================================== */ #ifndef LASZIP_COMMON_V1_HPP #define LASZIP_COMMON_V1_HPP #include "mydefs.hpp" struct LASwavepacket13 { U64 offset; U32 packet_size; U32I32F32 return_point; U32I32F32 x; U32I32F32 y; U32I32F32 z; static inline LASwavepacket13 unpack(const U8* item) { // unpack a LAS wavepacket out of raw memory LASwavepacket13 r; r.offset = makeU64(item); r.packet_size = makeU32(item + 8); r.return_point.u32 = makeU32(item + 12); r.x.u32 = makeU32(item + 16); r.y.u32 = makeU32(item + 20); r.z.u32 = makeU32(item + 24); return r; } void inline pack(U8 *item) { // pack a LAS wavepacket into raw memory packU32((U32)(offset & 0xFFFFFFFF), item); packU32((U32)(offset >> 32), item+4); packU32(packet_size, item + 8); packU32(return_point.u32, item + 12); packU32(x.u32, item + 16); packU32(y.u32, item + 20); packU32(z.u32, item + 24); } private: static inline U64 makeU64(const U8* item) { U64 dw0 = (U64)makeU32(item); U64 dw1 = (U64)makeU32(item+4); return dw0 | (dw1 << 32); } static inline U32 makeU32(const U8 *item) { U32 b0 = (U32)item[0]; U32 b1 = (U32)item[1]; U32 b2 = (U32)item[2]; U32 b3 = (U32)item[3]; return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); } static inline void packU32(U32 v, U8 *item) { item[0] = v & 0xFF; item[1] = (v >> 8) & 0xFF; item[2] = (v >> 16) & 0xFF; item[3] = (v >> 24) & 0xFF; } }; #endif // LASZIP_COMMON_V1_HPP LASzip-3.4.3/src/laszip_common_v2.hpp000066400000000000000000000115551356234217100174570ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_common_v2.hpp CONTENTS: Common defines and functionalities for version 2 of LASitemReadCompressed and LASitemwriteCompressed. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 16 March 2011 -- created after designing the "streaming median" algorithm =============================================================================== */ #ifndef LASZIP_COMMON_V2_HPP #define LASZIP_COMMON_V2_HPP class StreamingMedian5 { public: I32 values[5]; BOOL high; void init() { values[0] = values[1] = values[2] = values[3] = values[4] = 0; high = true; } inline void add(I32 v) { if (high) { if (v < values[2]) { values[4] = values[3]; values[3] = values[2]; if (v < values[0]) { values[2] = values[1]; values[1] = values[0]; values[0] = v; } else if (v < values[1]) { values[2] = values[1]; values[1] = v; } else { values[2] = v; } } else { if (v < values[3]) { values[4] = values[3]; values[3] = v; } else { values[4] = v; } high = false; } } else { if (values[2] < v) { values[0] = values[1]; values[1] = values[2]; if (values[4] < v) { values[2] = values[3]; values[3] = values[4]; values[4] = v; } else if (values[3] < v) { values[2] = values[3]; values[3] = v; } else { values[2] = v; } } else { if (values[1] < v) { values[0] = values[1]; values[1] = v; } else { values[0] = v; } high = true; } } } I32 get() const { return values[2]; } StreamingMedian5() { init(); } }; // for LAS files with the return (r) and the number (n) of // returns field correctly populated the mapping should really // be only the following. // { 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 0, 15, 15, 15, 15, 15, 15 }, // { 15, 1, 2, 15, 15, 15, 15, 15 }, // { 15, 3, 4, 5, 15, 15, 15, 15 }, // { 15, 6, 7, 8, 9, 15, 15, 15 }, // { 15, 10, 11, 12, 13, 14, 15, 15 }, // { 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 15, 15, 15, 15, 15, 15, 15 } // however, some files start the numbering of r and n with 0, // only have return counts r, or only have number of return // counts n, or mix up the position of r and n. we therefore // "complete" the table to also map those "undesired" r & n // combinations to different contexts const U8 number_return_map[8][8] = { { 15, 14, 13, 12, 11, 10, 9, 8 }, { 14, 0, 1, 3, 6, 10, 10, 9 }, { 13, 1, 2, 4, 7, 11, 11, 10 }, { 12, 3, 4, 5, 8, 12, 12, 11 }, { 11, 6, 7, 8, 9, 13, 13, 12 }, { 10, 10, 11, 12, 13, 14, 14, 13 }, { 9, 10, 11, 12, 13, 14, 15, 14 }, { 8, 9, 10, 11, 12, 13, 14, 15 } }; // for LAS files with the return (r) and the number (n) of // returns field correctly populated the mapping should really // be only the following. // { 0, 7, 7, 7, 7, 7, 7, 7 }, // { 7, 0, 7, 7, 7, 7, 7, 7 }, // { 7, 1, 0, 7, 7, 7, 7, 7 }, // { 7, 2, 1, 0, 7, 7, 7, 7 }, // { 7, 3, 2, 1, 0, 7, 7, 7 }, // { 7, 4, 3, 2, 1, 0, 7, 7 }, // { 7, 5, 4, 3, 2, 1, 0, 7 }, // { 7, 6, 5, 4, 3, 2, 1, 0 } // however, some files start the numbering of r and n with 0, // only have return counts r, or only have number of return // counts n, or mix up the position of r and n. we therefore // "complete" the table to also map those "undesired" r & n // combinations to different contexts const U8 number_return_level[8][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 1, 0, 1, 2, 3, 4, 5, 6 }, { 2, 1, 0, 1, 2, 3, 4, 5 }, { 3, 2, 1, 0, 1, 2, 3, 4 }, { 4, 3, 2, 1, 0, 1, 2, 3 }, { 5, 4, 3, 2, 1, 0, 1, 2 }, { 6, 5, 4, 3, 2, 1, 0, 1 }, { 7, 6, 5, 4, 3, 2, 1, 0 } }; #endif LASzip-3.4.3/src/laszip_common_v3.hpp000066400000000000000000000340011356234217100174470ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_common_v3.hpp CONTENTS: Common defines and functionalities for version 3 of LASitemReadCompressed and LASitemwriteCompressed. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 27 June 2016 -- after Iceland forced England's BrExit with 2:1 at EURO2016 =============================================================================== */ #ifndef LASZIP_COMMON_V3_HPP #define LASZIP_COMMON_V3_HPP #include "laszip_common_v1.hpp" #include "laszip_common_v2.hpp" #define DEBUG_OUTPUT_NUM_BYTES_DETAILS 0 class LAScontextPOINT14 { public: BOOL unused; U8 last_item[128]; U16 last_intensity[8]; StreamingMedian5 last_X_diff_median5[12]; StreamingMedian5 last_Y_diff_median5[12]; I32 last_Z[8]; ArithmeticModel* m_changed_values[8]; ArithmeticModel* m_scanner_channel; ArithmeticModel* m_number_of_returns[16]; ArithmeticModel* m_return_number_gps_same; ArithmeticModel* m_return_number[16]; IntegerCompressor* ic_dX; IntegerCompressor* ic_dY; IntegerCompressor* ic_Z; ArithmeticModel* m_classification[64]; ArithmeticModel* m_flags[64]; ArithmeticModel* m_user_data[64]; IntegerCompressor* ic_intensity; IntegerCompressor* ic_scan_angle; IntegerCompressor* ic_point_source_ID; // GPS time stuff U32 last, next; U64I64F64 last_gpstime[4]; I32 last_gpstime_diff[4]; I32 multi_extreme_counter[4]; ArithmeticModel* m_gpstime_multi; ArithmeticModel* m_gpstime_0diff; IntegerCompressor* ic_gpstime; }; class LAScontextRGB14 { public: BOOL unused; U16 last_item[3]; ArithmeticModel* m_byte_used; ArithmeticModel* m_rgb_diff_0; ArithmeticModel* m_rgb_diff_1; ArithmeticModel* m_rgb_diff_2; ArithmeticModel* m_rgb_diff_3; ArithmeticModel* m_rgb_diff_4; ArithmeticModel* m_rgb_diff_5; }; class LAScontextRGBNIR14 { public: BOOL unused; U16 last_item[4]; ArithmeticModel* m_rgb_bytes_used; ArithmeticModel* m_rgb_diff_0; ArithmeticModel* m_rgb_diff_1; ArithmeticModel* m_rgb_diff_2; ArithmeticModel* m_rgb_diff_3; ArithmeticModel* m_rgb_diff_4; ArithmeticModel* m_rgb_diff_5; ArithmeticModel* m_nir_bytes_used; ArithmeticModel* m_nir_diff_0; ArithmeticModel* m_nir_diff_1; }; class LAScontextWAVEPACKET14 { public: BOOL unused; U8 last_item[29]; I32 last_diff_32; U32 sym_last_offset_diff; ArithmeticModel* m_packet_index; ArithmeticModel* m_offset_diff[4]; IntegerCompressor* ic_offset_diff; IntegerCompressor* ic_packet_size; IntegerCompressor* ic_return_point; IntegerCompressor* ic_xyz; }; class LAScontextBYTE14 { public: BOOL unused; U8* last_item; ArithmeticModel** m_bytes; }; // for LAS points with correctly populated return numbers (1 <= r <= n) and // number of returns of given pulse (1 <= n <= 15) the return mapping that // serializes the possible combinations into one number should be the following // // { ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 0, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 1, 2, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 3, 4, 5, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 6, 7, 8, 9, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 10, 11, 12, 13, 14, ---, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 15, 16, 17, 18, 19, 20, ---, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 21, 22, 23, 24, 25, 26, 27, ---, ---, ---, ---, ---, ---, ---, --- }, // { ---, 28, 29, 30, 31, 32, 33, 34, 35, ---, ---, ---, ---, ---, ---, --- }, // { ---, 36, 37, 38, 39, 40, 41, 42, 43, 44, ---, ---, ---, ---, ---, --- }, // { ---, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, ---, ---, ---, ---, --- }, // { ---, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, ---, ---, ---, --- }, // { ---, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, ---, ---, --- }, // { ---, 78, 89, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, ---, --- }, // { ---, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, --- }, // { ---, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 } // // we drastically simplify the number of return combinations that we want to distinguish // down to 16 as higher returns will not have significant entropy differences // // { --, --, --, --, --, --, --, --, --, --, --, --, --, --, --, -- }, // { --, 0, --, --, --, --, --, --, --, --, --, --, --, --, --, -- }, // { --, 1, 2, --, --, --, --, --, --, --, --, --, --, --, --, -- }, // { --, 3, 4, 5, --, --, --, --, --, --, --, --, --, --, --, -- }, // { --, 6, 7, 8, 9, --, --, --, --, --, --, --, --, --, --, -- }, // { --, 10, 11, 12, 13, 14, --, --, --, --, --, --, --, --, --, -- }, // { --, 10, 11, 12, 13, 14, 15, --, --, --, --, --, --, --, --, -- }, // { --, 10, 11, 12, 12, 13, 14, 15, --, --, --, --, --, --, --, -- }, // { --, 10, 11, 12, 12, 13, 13, 14, 15, --, --, --, --, --, --, -- }, // { --, 10, 11, 11, 12, 12, 13, 13, 14, 15, --, --, --, --, --, -- }, // { --, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, --, --, --, --, -- }, // { --, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, --, --, --, -- }, // { --, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, --, --, -- }, // { --, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, --, -- }, // { --, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, -- }, // { --, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15 } // however, as some files start the numbering of r and n with 0, only have return counts // r, only have number of return per pulse n, or mix up position of r and n, we complete // the table to also map those "undesired" r and n combinations to different contexts /* const U8 number_return_map_4bit[16][16] = { { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, { 14, 0, 1, 3, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, { 13, 1, 2, 4, 7, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10 }, { 12, 3, 4, 5, 8, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11 }, { 11, 6, 7, 8, 9, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 11 }, { 10, 10, 11, 12, 13, 14, 14, 13, 13, 12, 12, 12, 12, 12, 12, 12 }, { 9, 10, 11, 12, 13, 14, 15, 14, 13, 13, 13, 12, 12, 12, 12, 12 }, { 8, 10, 11, 12, 12, 13, 14, 15, 14, 13, 13, 13, 13, 12, 12, 12 }, { 7, 10, 11, 12, 12, 13, 13, 14, 15, 14, 14, 13, 13, 13, 13, 13 }, { 6, 10, 11, 11, 12, 12, 13, 13, 14, 15, 14, 14, 14, 13, 13, 13 }, { 5, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 14, 14, 14, 13, 13 }, { 4, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 14, 14, 14 }, { 3, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 14, 14 }, { 2, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 14 }, { 1, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15 }, { 0, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15 } }; // simplify down to 10 contexts const U8 number_return_map_10ctx[16][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9 }, { 1, 0, 1, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 2, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6 }, { 3, 3, 4, 5, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, { 4, 6, 7, 8, 9, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, { 5, 6, 7, 7, 8, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7 }, { 6, 6, 7, 7, 8, 8, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7 }, { 7, 6, 7, 7, 7, 8, 8, 9, 8, 8, 8, 8, 8, 7, 7, 7 }, { 8, 6, 7, 7, 7, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8 }, { 9, 6, 7, 7, 7, 7, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8 }, { 9, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8 }, { 9, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 8, 8, 8 }, { 9, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 8, 8 }, { 9, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 8 }, { 9, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9 }, { 9, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9 } }; // simplify even further down to 6 contexts */ const U8 number_return_map_6ctx[16][16] = { { 0, 1, 2, 3, 4, 5, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5 }, { 1, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, { 2, 1, 2, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3 }, { 3, 3, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 3, 3, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4 }, { 4, 3, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4 }, { 5, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 4, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 4 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5 }, { 5, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5 } }; // for LAS points with return number (1 <= r <= n) and a number of returns // of given pulse (1 <= n <= 15) the level of penetration counted in number // of returns should really simply be n - r with all invalid combinations // being mapped to 15 like shown below // // { 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, // { 15, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15 } // { 15, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15 } // { 15, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15 } // { 15, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15 } // { 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15 } // { 15, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15 } // { 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15 } // { 15, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15 } // { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } // // however, some files start the numbering of r and n with 0, only have // return counts r, or only have number of returns of given pulse n, or // mix up the position of r and n. we therefore "complete" the table to // also map those "undesired" r & n combinations to different contexts. // // We also stop the enumeration of the levels of penetration at 7 and // map all higher penetration levels also to 7 in order to keep the total // number of contexts reasonably small. // /* const U8 number_return_level_4bit[16][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, { 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }, { 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, { 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, { 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8 }, { 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7 }, { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6 }, { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5 }, { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4 }, { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3 }, { 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2 }, { 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1 }, { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } }; */ // simplify down to 8 contexts const U8 number_return_level_8ctx[16][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, { 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7 }, { 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7 }, { 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7 }, { 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7 }, { 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7 }, { 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7 }, { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 7 }, { 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7 }, { 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6 }, { 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5 }, { 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4 }, { 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3 }, { 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2 }, { 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1 }, { 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0 } }; #endif LASzip-3.4.3/src/laszip_decompress_selective_v3.hpp000066400000000000000000000047221356234217100223750ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_decompress_selective_v3.hpp CONTENTS: Contains bit mask definitions for selective decompression. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 14 April 2017 -- created at Lo Que Hay where Gui was having birthday dinner =============================================================================== */ #ifndef LASZIP_DECOMPRESS_SELECTIVE_V3_HPP #define LASZIP_DECOMPRESS_SELECTIVE_V3_HPP #define LASZIP_DECOMPRESS_SELECTIVE_ALL 0xFFFFFFFF #define LASZIP_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY 0x00000000 #define LASZIP_DECOMPRESS_SELECTIVE_Z 0x00000001 #define LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION 0x00000002 #define LASZIP_DECOMPRESS_SELECTIVE_FLAGS 0x00000004 #define LASZIP_DECOMPRESS_SELECTIVE_INTENSITY 0x00000008 #define LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE 0x00000010 #define LASZIP_DECOMPRESS_SELECTIVE_USER_DATA 0x00000020 #define LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE 0x00000040 #define LASZIP_DECOMPRESS_SELECTIVE_GPS_TIME 0x00000080 #define LASZIP_DECOMPRESS_SELECTIVE_RGB 0x00000100 #define LASZIP_DECOMPRESS_SELECTIVE_NIR 0x00000200 #define LASZIP_DECOMPRESS_SELECTIVE_WAVEPACKET 0x00000400 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE0 0x00010000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE1 0x00020000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE2 0x00040000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE3 0x00080000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE4 0x00100000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE5 0x00200000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE6 0x00400000 #define LASZIP_DECOMPRESS_SELECTIVE_BYTE7 0x00800000 #define LASZIP_DECOMPRESS_SELECTIVE_EXTRA_BYTES 0xFFFF0000 #endif // LASZIP_DECOMPRESS_SELECTIVE_V3_HPP LASzip-3.4.3/src/laszip_dll.cpp000066400000000000000000004714731356234217100163370ustar00rootroot00000000000000/* =============================================================================== FILE: laszip_dll.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 15 October 2019 -- support reading from and writing to unicode file names under Windows 20 March 2019 -- check consistent legacy and extended classification in laszip_write_point() 7 November 2018 -- assure identical legacy and extended flags in laszip_write_point() 20 October 2018 -- changed (U8*) to (const U8*) for all out->put___() calls 5 October 2018 -- corrected 'is_empty' return value in laszip_inside_rectangle() 29 September 2018 -- laszip_prepare_point_for_write() sets extended_point_type 19 September 2018 -- removed tuples and triple support from attributes 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro 6 April 2018 -- added zero() function to laszip_dll struct to fix memory leak 30 August 2017 -- completing stream-based writing (with writing LAS header) 23 August 2017 -- turn on "native" by default 3 August 2017 -- new 'laszip_create_laszip_vlr()' gets VLR as C++ std::vector 29 July 2017 -- integrating minimal stream-based reading/writing into branch 20 July 2017 -- Andrew Bell adds support for stream-based reading/writing 28 May 2017 -- support for "LAS 1.4 selective decompression" added into DLL API 25 April 2017 -- adding initial support for new "native LAS 1.4 extension" 8 January 2017 -- changed from "laszip_dll.h" to "laszip_api.h" for hobu =============================================================================== */ #define LASZIP_DYN_LINK #define LASZIP_SOURCE #include #include #include #include #include #include "laszip.hpp" #include "lasattributer.hpp" #include "bytestreamout_file.hpp" #include "bytestreamin_file.hpp" #include "bytestreamout_array.hpp" #include "bytestreamin_array.hpp" #include "bytestreamin_istream.hpp" #include "bytestreamout_ostream.hpp" #include "laswritepoint.hpp" #include "lasreadpoint.hpp" #include "lasquadtree.hpp" #include "lasindex.hpp" class laszip_dll_inventory { public: BOOL active() const { return (first == FALSE); }; U32 number_of_point_records; U32 number_of_points_by_return[16]; I32 max_X; I32 min_X; I32 max_Y; I32 min_Y; I32 max_Z; I32 min_Z; void add(const laszip_point_struct* point) { number_of_point_records++; if (point->extended_point_type) { number_of_points_by_return[point->extended_return_number]++; } else { number_of_points_by_return[point->return_number]++; } if (first) { min_X = max_X = point->X; min_Y = max_Y = point->Y; min_Z = max_Z = point->Z; first = FALSE; } else { if (point->X < min_X) min_X = point->X; else if (point->X > max_X) max_X = point->X; if (point->Y < min_Y) min_Y = point->Y; else if (point->Y > max_Y) max_Y = point->Y; if (point->Z < min_Z) min_Z = point->Z; else if (point->Z > max_Z) max_Z = point->Z; } } laszip_dll_inventory() { U32 i; number_of_point_records = 0; for (i = 0; i < 16; i++) number_of_points_by_return[i] = 0; max_X = min_X = 0; max_Y = min_Y = 0; max_Z = min_Z = 0; first = TRUE; } private: BOOL first; }; typedef struct laszip_dll { laszip_header_struct header; I64 p_count; I64 npoints; laszip_point_struct point; U8** point_items; FILE* file; ByteStreamIn* streamin; LASreadPoint* reader; ByteStreamOut* streamout; LASwritePoint* writer; LASattributer* attributer; CHAR error[1024]; CHAR warning[1024]; LASindex* lax_index; F64 lax_r_min_x; F64 lax_r_min_y; F64 lax_r_max_x; F64 lax_r_max_y; CHAR* lax_file_name; BOOL lax_create; BOOL lax_append; BOOL lax_exploit; U32 las14_decompress_selective; BOOL preserve_generating_software; BOOL request_native_extension; BOOL request_compatibility_mode; BOOL compatibility_mode; U32 set_chunk_size; I32 start_scan_angle; I32 start_extended_returns; I32 start_classification; I32 start_flags_and_channel; I32 start_NIR_band; laszip_dll_inventory* inventory; std::vector buffers; void zero() { memset(&header, 0, sizeof(laszip_header_struct)); p_count = 0; npoints = 0; memset(&point, 0, sizeof(laszip_point_struct)); point_items = NULL; file = NULL; streamin = NULL; reader = NULL; streamout = NULL; writer = NULL; attributer = NULL; memset(error, 0, 1024); memset(warning, 0, 1024); lax_index = NULL; lax_r_min_x = 0.0; lax_r_min_y = 0.0; lax_r_max_x = 0.0; lax_r_max_y = 0.0; lax_file_name = NULL; lax_create = FALSE; lax_append = FALSE; lax_exploit = FALSE; las14_decompress_selective = 0; preserve_generating_software = FALSE; request_native_extension = FALSE; request_compatibility_mode = FALSE; compatibility_mode = FALSE; set_chunk_size = 0; start_scan_angle = 0; start_extended_returns = 0; start_classification = 0; start_flags_and_channel = 0; start_NIR_band = 0; inventory = NULL; }; } laszip_dll_struct; /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_version( laszip_U8* version_major , laszip_U8* version_minor , laszip_U16* version_revision , laszip_U32* version_build ) { try { *version_major = LASZIP_VERSION_MAJOR; *version_minor = LASZIP_VERSION_MINOR; *version_revision = LASZIP_VERSION_REVISION; *version_build = LASZIP_VERSION_BUILD_DATE; } catch (...) { return 1; } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_error( laszip_POINTER pointer , laszip_CHAR** error ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { *error = laszip_dll->error; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_error"); return 1; } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_warning( laszip_POINTER pointer , laszip_CHAR** warning ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { *warning = laszip_dll->warning; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_warning"); return 1; } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_create( laszip_POINTER* pointer ) { if (pointer == 0) return 1; try { laszip_dll_struct* laszip_dll = new laszip_dll_struct; if (laszip_dll == 0) { return 1; } // zero every field of the laszip_dll struct laszip_dll->zero(); // create the default laszip_clean(laszip_dll); *pointer = laszip_dll; } catch (...) { return 1; } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_clean( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot clean while reader is open."); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot clean while writer is open."); return 1; } // dealloc everything alloc in the header if (laszip_dll->header.user_data_in_header) { delete [] laszip_dll->header.user_data_in_header; laszip_dll->header.user_data_in_header = 0; } if (laszip_dll->header.vlrs) { U32 i; for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if (laszip_dll->header.vlrs[i].data) { delete [] laszip_dll->header.vlrs[i].data; } } free(laszip_dll->header.vlrs); laszip_dll->header.vlrs = 0; } if (laszip_dll->header.user_data_after_header) { delete [] laszip_dll->header.user_data_after_header; laszip_dll->header.user_data_after_header = 0; } // dealloc everything alloc in the point if (laszip_dll->point.extra_bytes) { delete [] laszip_dll->point.extra_bytes; laszip_dll->point.extra_bytes = 0; } // dealloc point items although close_reader() / close_writer() call should have done this already if (laszip_dll->point_items) { delete [] laszip_dll->point_items; laszip_dll->point_items = 0; } // close file although close_reader() / close_writer() call should have done this already if (laszip_dll->file) { fclose(laszip_dll->file); laszip_dll->file = 0; } // dealloc streamin although close_reader() call should have done this already if (laszip_dll->streamin) { delete laszip_dll->streamin; laszip_dll->streamin = 0; } // dealloc streamout although close_writer() call should have done this already if (laszip_dll->streamout) { delete laszip_dll->streamout; laszip_dll->streamout = 0; } // dealloc the attributer if (laszip_dll->attributer) { delete laszip_dll->attributer; laszip_dll->attributer = 0; } // dealloc lax_index although close_reader() / close_writer() call should have done this already if (laszip_dll->lax_index) { delete laszip_dll->lax_index; laszip_dll->lax_index = 0; } // dealloc lax_file_name although close_writer() call should have done this already if (laszip_dll->lax_file_name) { free(laszip_dll->lax_file_name); laszip_dll->lax_file_name = 0; } // dealloc the inventory although close_writer() call should have done this already if (laszip_dll->inventory == 0) { delete laszip_dll->inventory; laszip_dll->inventory = 0; } // dealloc any data fields that were kept around in memory for others if (laszip_dll->buffers.size()) { for (size_t i = 0; i < laszip_dll->buffers.size(); i++) { free(laszip_dll->buffers[i]); } laszip_dll->buffers.clear(); } // zero every field of the laszip_dll struct laszip_dll->zero(); // create default header sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE); laszip_dll->header.version_major = 1; laszip_dll->header.version_minor = 2; laszip_dll->header.header_size = 227; laszip_dll->header.offset_to_point_data = 227; laszip_dll->header.point_data_format = 1; laszip_dll->header.point_data_record_length = 28; laszip_dll->header.x_scale_factor = 0.01; laszip_dll->header.y_scale_factor = 0.01; laszip_dll->header.z_scale_factor = 0.01; laszip_dll->set_chunk_size = LASZIP_CHUNK_SIZE_DEFAULT; laszip_dll->request_native_extension = TRUE; laszip_dll->las14_decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_clean"); return 1; } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_destroy( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; int err = 0; try { err = laszip_clean(laszip_dll); delete laszip_dll; } catch (...) { return 1; } return err; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_header_pointer( laszip_POINTER pointer , laszip_header_struct** header_pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (header_pointer == 0) { sprintf(laszip_dll->error, "laszip_header_struct pointer 'header_pointer' is zero"); return 1; } *header_pointer = &laszip_dll->header; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_header_pointer"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_point_pointer( laszip_POINTER pointer , laszip_point_struct** point_pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (point_pointer == 0) { sprintf(laszip_dll->error, "laszip_point_struct pointer 'point_pointer' is zero"); return 1; } *point_pointer = &laszip_dll->point; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_point_pointer"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_point_count( laszip_POINTER pointer , laszip_I64* count ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (count == 0) { sprintf(laszip_dll->error, "laszip_I64 pointer 'count' is zero"); return 1; } if ((laszip_dll->reader == 0) && (laszip_dll->writer == 0)) { sprintf(laszip_dll->error, "getting count before reader or writer was opened"); return 1; } *count = laszip_dll->p_count; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_point_count"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_header( laszip_POINTER pointer , const laszip_header_struct* header ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (header == 0) { sprintf(laszip_dll->error, "laszip_header_struct pointer 'header' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set header after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot set header after writer was opened"); return 1; } // dealloc the attributer (if needed) if (laszip_dll->attributer) { delete laszip_dll->attributer; laszip_dll->attributer = 0; } // populate the header U32 i; laszip_dll->header.file_source_ID = header->file_source_ID; laszip_dll->header.global_encoding = header->global_encoding; laszip_dll->header.project_ID_GUID_data_1 = header->project_ID_GUID_data_1; laszip_dll->header.project_ID_GUID_data_2 = header->project_ID_GUID_data_2; laszip_dll->header.project_ID_GUID_data_3 = header->project_ID_GUID_data_3; memcpy(laszip_dll->header.project_ID_GUID_data_4, header->project_ID_GUID_data_4, 8); laszip_dll->header.version_major = header->version_major; laszip_dll->header.version_minor = header->version_minor; memcpy(laszip_dll->header.system_identifier, header->system_identifier, 32); memcpy(laszip_dll->header.generating_software, header->generating_software, 32); laszip_dll->header.file_creation_day = header->file_creation_day; laszip_dll->header.file_creation_year = header->file_creation_year; laszip_dll->header.header_size = header->header_size; laszip_dll->header.offset_to_point_data = header->offset_to_point_data; laszip_dll->header.number_of_variable_length_records = header->number_of_variable_length_records; laszip_dll->header.point_data_format = header->point_data_format; laszip_dll->header.point_data_record_length = header->point_data_record_length; laszip_dll->header.number_of_point_records = header->number_of_point_records; for (i = 0; i < 5; i++) laszip_dll->header.number_of_points_by_return[i] = header->number_of_points_by_return[i]; laszip_dll->header.x_scale_factor = header->x_scale_factor; laszip_dll->header.y_scale_factor = header->y_scale_factor; laszip_dll->header.z_scale_factor = header->z_scale_factor; laszip_dll->header.x_offset = header->x_offset; laszip_dll->header.y_offset = header->y_offset; laszip_dll->header.z_offset = header->z_offset; laszip_dll->header.max_x = header->max_x; laszip_dll->header.min_x = header->min_x; laszip_dll->header.max_y = header->max_y; laszip_dll->header.min_y = header->min_y; laszip_dll->header.max_z = header->max_z; laszip_dll->header.min_z = header->min_z; if (laszip_dll->header.version_minor >= 3) { laszip_dll->header.start_of_waveform_data_packet_record = header->start_of_first_extended_variable_length_record; } if (laszip_dll->header.version_minor >= 4) { laszip_dll->header.start_of_first_extended_variable_length_record = header->start_of_first_extended_variable_length_record; laszip_dll->header.number_of_extended_variable_length_records = header->number_of_extended_variable_length_records; laszip_dll->header.extended_number_of_point_records = header->extended_number_of_point_records; for (i = 0; i < 15; i++) laszip_dll->header.extended_number_of_points_by_return[i] = header->extended_number_of_points_by_return[i]; } laszip_dll->header.user_data_in_header_size = header->user_data_in_header_size; if (laszip_dll->header.user_data_in_header) { delete [] laszip_dll->header.user_data_in_header; laszip_dll->header.user_data_in_header = 0; } if (header->user_data_in_header_size) { if (header->user_data_in_header == 0) { sprintf(laszip_dll->error, "header->user_data_in_header_size is %d but header->user_data_in_header is NULL", header->user_data_in_header_size); return 1; } laszip_dll->header.user_data_in_header = new U8[header->user_data_in_header_size]; memcpy(laszip_dll->header.user_data_in_header, header->user_data_in_header, header->user_data_in_header_size); } if (laszip_dll->header.vlrs) { for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if (laszip_dll->header.vlrs[i].data) { delete [] laszip_dll->header.vlrs[i].data; } } free(laszip_dll->header.vlrs); laszip_dll->header.vlrs = 0; } if (header->number_of_variable_length_records) { laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*header->number_of_variable_length_records); for (i = 0; i < header->number_of_variable_length_records; i++) { laszip_dll->header.vlrs[i].reserved = header->vlrs[i].reserved; memcpy(laszip_dll->header.vlrs[i].user_id, header->vlrs[i].user_id, 16); laszip_dll->header.vlrs[i].record_id = header->vlrs[i].record_id; laszip_dll->header.vlrs[i].record_length_after_header = header->vlrs[i].record_length_after_header; memcpy(laszip_dll->header.vlrs[i].description, header->vlrs[i].description, 32); if (header->vlrs[i].record_length_after_header) { if (header->vlrs[i].data == 0) { sprintf(laszip_dll->error, "header->vlrs[%d].record_length_after_header is %d but header->vlrs[%d].data is NULL", i, header->vlrs[i].record_length_after_header, i); return 1; } laszip_dll->header.vlrs[i].data = new U8[header->vlrs[i].record_length_after_header]; memcpy(laszip_dll->header.vlrs[i].data, header->vlrs[i].data, header->vlrs[i].record_length_after_header); } else { laszip_dll->header.vlrs[i].data = 0; } // populate the attributer if needed if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4)) { if (laszip_dll->attributer == 0) { laszip_dll->attributer = new LASattributer; if (laszip_dll->attributer == 0) { sprintf(laszip_dll->error, "cannot allocate LASattributer"); return 1; } } laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data); } } } laszip_dll->header.user_data_after_header_size = header->user_data_after_header_size; if (laszip_dll->header.user_data_after_header) { delete [] laszip_dll->header.user_data_after_header; laszip_dll->header.user_data_after_header = 0; } if (header->user_data_after_header_size) { if (header->user_data_after_header == 0) { sprintf(laszip_dll->error, "header->user_data_after_header_size is %d but header->user_data_after_header is NULL", header->user_data_after_header_size); return 1; } laszip_dll->header.user_data_after_header = new U8[header->user_data_after_header_size]; memcpy(laszip_dll->header.user_data_after_header, header->user_data_after_header, header->user_data_after_header_size); } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_header"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_point_type_and_size( laszip_POINTER pointer , laszip_U8 point_type , laszip_U16 point_size ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set point format and point size after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot set point format and point size after writer was opened"); return 1; } // check if point type and type are supported if (!LASzip().setup(point_type, point_size, LASZIP_COMPRESSOR_NONE)) { sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size); return 1; } // set point type and point size laszip_dll->header.point_data_format = point_type; laszip_dll->header.point_data_record_length = point_size; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_point_type_and_size"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_check_for_integer_overflow( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { // get a pointer to the header laszip_header_struct* header = &(laszip_dll->header); // quantize and dequantize the bounding box with current scale_factor and offset I32 quant_min_x = I32_QUANTIZE((header->min_x-header->x_offset)/header->x_scale_factor); I32 quant_max_x = I32_QUANTIZE((header->max_x-header->x_offset)/header->x_scale_factor); I32 quant_min_y = I32_QUANTIZE((header->min_y-header->y_offset)/header->y_scale_factor); I32 quant_max_y = I32_QUANTIZE((header->max_y-header->y_offset)/header->y_scale_factor); I32 quant_min_z = I32_QUANTIZE((header->min_z-header->z_offset)/header->z_scale_factor); I32 quant_max_z = I32_QUANTIZE((header->max_z-header->z_offset)/header->z_scale_factor); F64 dequant_min_x = header->x_scale_factor*quant_min_x+header->x_offset; F64 dequant_max_x = header->x_scale_factor*quant_max_x+header->x_offset; F64 dequant_min_y = header->y_scale_factor*quant_min_y+header->y_offset; F64 dequant_max_y = header->y_scale_factor*quant_max_y+header->y_offset; F64 dequant_min_z = header->z_scale_factor*quant_min_z+header->z_offset; F64 dequant_max_z = header->z_scale_factor*quant_max_z+header->z_offset; // make sure that there is not sign flip (a 32-bit integer overflow) for the bounding box if ((header->min_x > 0) != (dequant_min_x > 0)) { sprintf(laszip_dll->error, "quantization sign flip for min_x from %g to %g. set scale factor for x coarser than %g\n", header->min_x, dequant_min_x, header->x_scale_factor); return 1; } if ((header->max_x > 0) != (dequant_max_x > 0)) { sprintf(laszip_dll->error, "quantization sign flip for max_x from %g to %g. set scale factor for x coarser than %g\n", header->max_x, dequant_max_x, header->x_scale_factor); return 1; } if ((header->min_y > 0) != (dequant_min_y > 0)) { sprintf(laszip_dll->error, "quantization sign flip for min_y from %g to %g. set scale factor for y coarser than %g\n", header->min_y, dequant_min_y, header->y_scale_factor); return 1; } if ((header->max_y > 0) != (dequant_max_y > 0)) { sprintf(laszip_dll->error, "quantization sign flip for max_y from %g to %g. set scale factor for y coarser than %g\n", header->max_y, dequant_max_y, header->y_scale_factor); return 1; } if ((header->min_z > 0) != (dequant_min_z > 0)) { sprintf(laszip_dll->error, "quantization sign flip for min_z from %g to %g. set scale factor for z coarser than %g\n", header->min_z, dequant_min_z, header->z_scale_factor); return 1; } if ((header->max_z > 0) != (dequant_max_z > 0)) { sprintf(laszip_dll->error, "quantization sign flip for max_z from %g to %g. set scale factor for z coarser than %g\n", header->max_z, dequant_max_z, header->z_scale_factor); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_auto_offset"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_auto_offset( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot auto offset after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot auto offset after writer was opened"); return 1; } // get a pointer to the header laszip_header_struct* header = &(laszip_dll->header); // check scale factor F64 x_scale_factor = header->x_scale_factor; F64 y_scale_factor = header->y_scale_factor; F64 z_scale_factor = header->z_scale_factor; if ((x_scale_factor <= 0) || !F64_IS_FINITE(x_scale_factor)) { sprintf(laszip_dll->error, "invalid x scale_factor %g in header", header->x_scale_factor); return 1; } if ((y_scale_factor <= 0) || !F64_IS_FINITE(y_scale_factor)) { sprintf(laszip_dll->error, "invalid y scale_factor %g in header", header->y_scale_factor); return 1; } if ((z_scale_factor <= 0) || !F64_IS_FINITE(z_scale_factor)) { sprintf(laszip_dll->error, "invalid z scale_factor %g in header", header->z_scale_factor); return 1; } F64 center_bb_x = (header->min_x + header->max_x) / 2; F64 center_bb_y = (header->min_y + header->max_y) / 2; F64 center_bb_z = (header->min_z + header->max_z) / 2; if (!F64_IS_FINITE(center_bb_x)) { sprintf(laszip_dll->error, "invalid x coordinate at center of bounding box (min: %g max: %g)", header->min_x, header->max_x); return 1; } if (!F64_IS_FINITE(center_bb_y)) { sprintf(laszip_dll->error, "invalid y coordinate at center of bounding box (min: %g max: %g)", header->min_y, header->max_y); return 1; } if (!F64_IS_FINITE(center_bb_z)) { sprintf(laszip_dll->error, "invalid z coordinate at center of bounding box (min: %g max: %g)", header->min_z, header->max_z); return 1; } F64 x_offset = header->x_offset; F64 y_offset = header->y_offset; F64 z_offset = header->z_offset; header->x_offset = (I64_FLOOR(center_bb_x/x_scale_factor/10000000))*10000000*x_scale_factor; header->y_offset = (I64_FLOOR(center_bb_y/y_scale_factor/10000000))*10000000*y_scale_factor; header->z_offset = (I64_FLOOR(center_bb_z/z_scale_factor/10000000))*10000000*z_scale_factor; if (laszip_check_for_integer_overflow(pointer)) { header->x_offset = x_offset; header->y_offset = y_offset; header->z_offset = z_offset; return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_auto_offset"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_point( laszip_POINTER pointer , const laszip_point_struct* point ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (point == 0) { sprintf(laszip_dll->error, "laszip_point_struct pointer 'point' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set point for reader"); return 1; } memcpy(&laszip_dll->point, point, ((U8*)&(laszip_dll->point.extra_bytes)) - ((U8*)&(laszip_dll->point.X))); if (laszip_dll->point.extra_bytes) { if (point->extra_bytes) { if (laszip_dll->point.num_extra_bytes == point->num_extra_bytes) { memcpy(laszip_dll->point.extra_bytes, point->extra_bytes, laszip_dll->point.num_extra_bytes); } else { sprintf(laszip_dll->error, "target point has %d extra bytes but source point has %d", laszip_dll->point.num_extra_bytes, point->num_extra_bytes); return 1; } } else if (!laszip_dll->compatibility_mode) { sprintf(laszip_dll->error, "target point has extra bytes but source point does not"); return 1; } } /* else { if (point->extra_bytes) { sprintf(laszip_dll->error, "source point has extra bytes but target point does not"); return 1; } } */ } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_coordinates( laszip_POINTER pointer , const laszip_F64* coordinates ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (coordinates == 0) { sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set coordinates for reader"); return 1; } // get a pointer to the header laszip_header_struct* header = &(laszip_dll->header); // get a pointer to the point laszip_point_struct* point = &(laszip_dll->point); // set the coordinates point->X = I32_QUANTIZE((coordinates[0]-header->x_offset)/header->x_scale_factor); point->Y = I32_QUANTIZE((coordinates[1]-header->y_offset)/header->y_scale_factor); point->Z = I32_QUANTIZE((coordinates[2]-header->z_offset)/header->z_scale_factor); } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_coordinates"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_get_coordinates( laszip_POINTER pointer , laszip_F64* coordinates ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (coordinates == 0) { sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero"); return 1; } // get a pointer to the header laszip_header_struct* header = &(laszip_dll->header); // get a pointer to the point laszip_point_struct* point = &(laszip_dll->point); // get the coordinates coordinates[0] = header->x_scale_factor*point->X+header->x_offset; coordinates[1] = header->y_scale_factor*point->Y+header->y_offset; coordinates[2] = header->z_scale_factor*point->Z+header->z_offset; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_get_coordinates"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geokeys( laszip_POINTER pointer , laszip_U32 number , const laszip_geokey_struct* key_entries ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (number == 0) { sprintf(laszip_dll->error, "number of key_entries is zero"); return 1; } if (key_entries == 0) { sprintf(laszip_dll->error, "laszip_geokey_struct pointer 'key_entries' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set geokeys after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot set geokeys after writer was opened"); return 1; } // create the geokey directory laszip_geokey_struct* key_entries_plus_one = new laszip_geokey_struct[number+1]; if (key_entries_plus_one == 0) { sprintf(laszip_dll->error, "allocating laszip_geokey_struct[%u] array", number+1); return 1; } key_entries_plus_one[0].key_id = 1; // aka key_directory_version key_entries_plus_one[0].tiff_tag_location = 1; // aka key_revision key_entries_plus_one[0].count = 0; // aka minor_revision key_entries_plus_one[0].value_offset = number; // aka number_of_keys memcpy(key_entries_plus_one + 1, key_entries, sizeof(laszip_geokey_struct)*number); // add the VLR if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34735, (laszip_U16)(8 + number*8), 0, (laszip_U8*)key_entries_plus_one)) { sprintf(laszip_dll->error, "setting %u geodouble_params", number); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_geokey_entries"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geodouble_params( laszip_POINTER pointer , laszip_U32 number , const laszip_F64* geodouble_params ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (number == 0) { sprintf(laszip_dll->error, "number of geodouble_params is zero"); return 1; } if (geodouble_params == 0) { sprintf(laszip_dll->error, "laszip_F64 pointer 'geodouble_params' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set geodouble_params after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot set geodouble_params after writer was opened"); return 1; } // add the VLR if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34736, (laszip_U16)(number*8), 0, (laszip_U8*)geodouble_params)) { sprintf(laszip_dll->error, "setting %u geodouble_params", number); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_geodouble_params"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_geoascii_params( laszip_POINTER pointer , laszip_U32 number , const laszip_CHAR* geoascii_params ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (number == 0) { sprintf(laszip_dll->error, "number of geoascii_params is zero"); return 1; } if (geoascii_params == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'geoascii_params' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot set geoascii_params after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot set geoascii_params after writer was opened"); return 1; } // add the VLR if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34737, (laszip_U16)(number), 0, (laszip_U8*)geoascii_params)) { sprintf(laszip_dll->error, "setting %u geoascii_params", number); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_geoascii_params"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_add_attribute( laszip_POINTER pointer , laszip_U32 type , const laszip_CHAR* name , const laszip_CHAR* description , laszip_F64 scale , laszip_F64 offset ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (type > LAS_ATTRIBUTE_F64) { sprintf(laszip_dll->error, "laszip_U32 'type' is %u but needs to be between %d and %d", type, LAS_ATTRIBUTE_U8, LAS_ATTRIBUTE_F64); return 1; } if (name == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'name' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot add attribute after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot add attribute after writer was opened"); return 1; } LASattribute lasattribute(type, name, description); lasattribute.set_scale(scale); lasattribute.set_offset(offset); if (laszip_dll->attributer == 0) { laszip_dll->attributer = new LASattributer; if (laszip_dll->attributer == 0) { sprintf(laszip_dll->error, "cannot allocate LASattributer"); return 1; } } if (laszip_dll->attributer->add_attribute(lasattribute) == -1) { sprintf(laszip_dll->error, "cannot add attribute '%s' to attributer", name); return 1; } if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes)) { sprintf(laszip_dll->error, "adding the new extra bytes VLR with the additional attribute '%s'", name); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_add_attribute"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_add_vlr( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id , laszip_U16 record_length_after_header , const laszip_CHAR* description , const laszip_U8* data ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (user_id == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero"); return 1; } if ((record_length_after_header > 0) && (data == 0)) { sprintf(laszip_dll->error, "record_length_after_header of VLR is %u but data pointer is zero", (U32)record_length_after_header); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot add vlr after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot add vlr after writer was opened"); return 1; } U32 i = 0; if (laszip_dll->header.vlrs) { // overwrite existing VLR ? for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id)) { if (laszip_dll->header.vlrs[i].record_length_after_header) { laszip_dll->header.offset_to_point_data -= laszip_dll->header.vlrs[i].record_length_after_header; laszip_dll->header.vlrs[i].record_length_after_header = 0; delete [] laszip_dll->header.vlrs[i].data; laszip_dll->header.vlrs[i].data = 0; } break; } } // create new VLR if (i == laszip_dll->header.number_of_variable_length_records) { laszip_dll->header.number_of_variable_length_records++; laszip_dll->header.offset_to_point_data += 54; laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records); if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records); return 1; } } } else { laszip_dll->header.number_of_variable_length_records = 1; laszip_dll->header.offset_to_point_data += 54; laszip_dll->header.vlrs = (laszip_vlr_struct*)malloc(sizeof(laszip_vlr_struct)); if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "allocating vlrs[1] array"); return 1; } } // zero the VLR memset(&(laszip_dll->header.vlrs[i]), 0, sizeof(laszip_vlr_struct)); // copy the VLR laszip_dll->header.vlrs[i].reserved = 0x0; strncpy(laszip_dll->header.vlrs[i].user_id, user_id, 16); laszip_dll->header.vlrs[i].record_id = record_id; laszip_dll->header.vlrs[i].record_length_after_header = record_length_after_header; if (description) { strncpy(laszip_dll->header.vlrs[i].description, description, 32); } else { sprintf(laszip_dll->header.vlrs[i].description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE); } if (record_length_after_header) { laszip_dll->header.offset_to_point_data += record_length_after_header; laszip_dll->header.vlrs[i].data = new U8[record_length_after_header]; memcpy(laszip_dll->header.vlrs[i].data, data, record_length_after_header); } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_add_vlr"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_remove_vlr( laszip_POINTER pointer , const laszip_CHAR* user_id , laszip_U16 record_id ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (user_id == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "cannot remove vlr after reader was opened"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "cannot remove vlr after writer was opened"); return 1; } U32 i = 0; if (laszip_dll->header.vlrs) { for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id)) { if (laszip_dll->header.vlrs[i].record_length_after_header) { laszip_dll->header.offset_to_point_data -= (54 + laszip_dll->header.vlrs[i].record_length_after_header); delete [] laszip_dll->header.vlrs[i].data; laszip_dll->header.vlrs[i].data = 0; } laszip_dll->header.number_of_variable_length_records--; for (/*i = i*/; i < laszip_dll->header.number_of_variable_length_records; i++) { laszip_dll->header.vlrs[i] = laszip_dll->header.vlrs[i+1]; } if (laszip_dll->header.number_of_variable_length_records) { laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records); if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records); return 1; } } else { free(laszip_dll->header.vlrs); laszip_dll->header.vlrs = 0; } i = U32_MAX; break; } } if (i != U32_MAX) { sprintf(laszip_dll->error, "cannot find VLR with user_id '%s' and record_id %d among the %u VLRs in the header", user_id, (I32)record_id, laszip_dll->header.number_of_variable_length_records); return 1; } } else { sprintf(laszip_dll->error, "cannot remove VLR with user_id '%s' and record_id %d because header has no VLRs", user_id, (I32)record_id); return 1; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_add_vlr"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_preserve_generating_software( laszip_POINTER pointer , const laszip_BOOL preserve ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->preserve_generating_software = preserve; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_preserve_generating_software"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_request_native_extension( laszip_POINTER pointer , const laszip_BOOL request ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->request_native_extension = request; if (request) // only one should be on { laszip_dll->request_compatibility_mode = FALSE; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_request_native_extension"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_request_compatibility_mode( laszip_POINTER pointer , const laszip_BOOL request ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->request_compatibility_mode = request; if (request) // only one should be on { laszip_dll->request_native_extension = FALSE; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_request_compatibility_mode"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_set_chunk_size( laszip_POINTER pointer , const laszip_U32 chunk_size ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->set_chunk_size = chunk_size; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_set_chunk_size"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_create_spatial_index( laszip_POINTER pointer , const laszip_BOOL create , const laszip_BOOL append ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } if (append) { sprintf(laszip_dll->error, "appending of spatial index not (yet) supported in this version"); return 1; } laszip_dll->lax_create = create; laszip_dll->lax_append = append; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_create_spatial_index"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ static I32 laszip_prepare_header_for_write( laszip_dll_struct* laszip_dll ) { if ((laszip_dll->header.version_major != 1) || (laszip_dll->header.version_minor > 4)) { sprintf(laszip_dll->error, "unknown LAS version %d.%d", (I32)laszip_dll->header.version_major, (I32)laszip_dll->header.version_minor); return 1; } // check counters U32 i; if (laszip_dll->header.point_data_format > 5) { // legacy counters are zero for new point types laszip_dll->header.number_of_point_records = 0; for (i = 0; i < 5; i++) { laszip_dll->header.number_of_points_by_return[i] = 0; } } else if (laszip_dll->header.version_minor > 3) { // legacy counters must be zero or consistent for old point types if (laszip_dll->header.number_of_point_records != laszip_dll->header.extended_number_of_point_records) { if (laszip_dll->header.number_of_point_records != 0) { #ifdef _WIN32 sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %I64d", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records); #else sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %llu", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records); #endif return 1; } else if (laszip_dll->header.extended_number_of_point_records <= U32_MAX) { laszip_dll->header.number_of_point_records = (U32)laszip_dll->header.extended_number_of_point_records; } } for (i = 0; i < 5; i++) { if (laszip_dll->header.number_of_points_by_return[i] != laszip_dll->header.extended_number_of_points_by_return[i]) { if (laszip_dll->header.number_of_points_by_return[i] != 0) { #ifdef _WIN32 sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %I64d", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]); #else sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %llu", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]); #endif return 1; } else if (laszip_dll->header.extended_number_of_points_by_return[i] <= U32_MAX) { laszip_dll->header.number_of_points_by_return[i] = (U32)laszip_dll->header.extended_number_of_points_by_return[i]; } } } } return 0; } /*---------------------------------------------------------------------------*/ static I32 laszip_prepare_point_for_write( laszip_dll_struct* laszip_dll , const laszip_BOOL compress ) { U32 i; if (laszip_dll->header.point_data_format > 5) { // must be set for the new point types 6 or higher ... laszip_dll->point.extended_point_type = 1; if (laszip_dll->request_native_extension) { // we are *not* operating in compatibility mode laszip_dll->compatibility_mode = FALSE; } else if (laszip_dll->request_compatibility_mode) { // we are *not* using the native extension laszip_dll->request_native_extension = FALSE; // make sure there are no more than U32_MAX points if (laszip_dll->header.extended_number_of_point_records > U32_MAX) { #ifdef _WIN32 sprintf(laszip_dll->error, "extended_number_of_point_records of %I64d is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records); #else sprintf(laszip_dll->error, "extended_number_of_point_records of %llu is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records); #endif return 1; } // copy 64-bit extended counters back into 32-bit legacy counters laszip_dll->header.number_of_point_records = (U32)(laszip_dll->header.extended_number_of_point_records); for (i = 0; i < 5; i++) { laszip_dll->header.number_of_points_by_return[i] = (U32)(laszip_dll->header.extended_number_of_points_by_return[i]); } // are there any "extra bytes" already ... ? I32 number_of_existing_extrabytes = 0; switch (laszip_dll->header.point_data_format) { case 6: number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 30; break; case 7: number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 36; break; case 8: number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 38; break; case 9: number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 59; break; case 10: number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 67; break; default: sprintf(laszip_dll->error, "unknown point_data_format %d", laszip_dll->header.point_data_format); return 1; } if (number_of_existing_extrabytes < 0) { sprintf(laszip_dll->error, "bad point_data_format %d point_data_record_length %d combination", laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length); return 1; } // downgrade to LAS 1.2 or LAS 1.3 if (laszip_dll->header.point_data_format <= 8) { laszip_dll->header.version_minor = 2; // LAS 1.2 header is 148 bytes less than LAS 1.4+ header laszip_dll->header.header_size -= 148; laszip_dll->header.offset_to_point_data -= 148; } else { laszip_dll->header.version_minor = 3; // LAS 1.3 header is 140 bytes less than LAS 1.4+ header laszip_dll->header.header_size -= 140; laszip_dll->header.offset_to_point_data -= 140; } // turn off the bit indicating the presence of the OGC WKT laszip_dll->header.global_encoding &= ~(1<<4); // old point type is two bytes shorter laszip_dll->header.point_data_record_length -= 2; // but we add 5 bytes of attributes laszip_dll->header.point_data_record_length += 5; // create 2+2+4+148 bytes payload for compatibility VLR ByteStreamOutArray* out; if (IS_LITTLE_ENDIAN()) out = new ByteStreamOutArrayLE(); else out = new ByteStreamOutArrayBE(); // write control info U16 laszip_version = (U16)LASZIP_VERSION_BUILD_DATE; out->put16bitsLE((U8*)&laszip_version); U16 compatible_version = 3; out->put16bitsLE((U8*)&compatible_version); U32 unused = 0; out->put32bitsLE((U8*)&unused); // write the 148 bytes of the extended LAS 1.4 header U64 start_of_waveform_data_packet_record = laszip_dll->header.start_of_waveform_data_packet_record; if (start_of_waveform_data_packet_record != 0) { #ifdef _WIN32 fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %I64d. writing 0 instead.\n", start_of_waveform_data_packet_record); #else fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %llu. writing 0 instead.\n", start_of_waveform_data_packet_record); #endif start_of_waveform_data_packet_record = 0; } out->put64bitsLE((U8*)&start_of_waveform_data_packet_record); U64 start_of_first_extended_variable_length_record = laszip_dll->header.start_of_first_extended_variable_length_record; if (start_of_first_extended_variable_length_record != 0) { #ifdef _WIN32 fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %I64d. writing 0 instead.\n", start_of_first_extended_variable_length_record); #else fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %llu. writing 0 instead.\n", start_of_first_extended_variable_length_record); #endif start_of_first_extended_variable_length_record = 0; } out->put64bitsLE((U8*)&start_of_first_extended_variable_length_record); U32 number_of_extended_variable_length_records = laszip_dll->header.number_of_extended_variable_length_records; if (number_of_extended_variable_length_records != 0) { fprintf(stderr,"WARNING: EVLRs not supported. header->number_of_extended_variable_length_records is %u. writing 0 instead.\n", number_of_extended_variable_length_records); number_of_extended_variable_length_records = 0; } out->put32bitsLE((U8*)&number_of_extended_variable_length_records); U64 extended_number_of_point_records; if (laszip_dll->header.number_of_point_records) extended_number_of_point_records = laszip_dll->header.number_of_point_records; else extended_number_of_point_records = laszip_dll->header.extended_number_of_point_records; out->put64bitsLE((U8*)&extended_number_of_point_records); U64 extended_number_of_points_by_return; for (i = 0; i < 15; i++) { if ((i < 5) && laszip_dll->header.number_of_points_by_return[i]) extended_number_of_points_by_return = laszip_dll->header.number_of_points_by_return[i]; else extended_number_of_points_by_return = laszip_dll->header.extended_number_of_points_by_return[i]; out->put64bitsLE((U8*)&extended_number_of_points_by_return); } // add the compatibility VLR if (laszip_add_vlr(laszip_dll, "lascompatible\0\0", 22204, (laszip_U16)(2+2+4+148), 0, (laszip_U8*)out->takeData())) { sprintf(laszip_dll->error, "adding the compatibility VLR"); return 1; } delete out; // if needed create an attributer to describe the "extra bytes" if (laszip_dll->attributer == 0) { laszip_dll->attributer = new LASattributer; if (laszip_dll->attributer == 0) { sprintf(laszip_dll->error, "cannot allocate LASattributer"); return 1; } } // were there any pre-existing extra bytes if (number_of_existing_extrabytes > 0) { // make sure the existing "extra bytes" are documented if (laszip_dll->attributer->get_attributes_size() > number_of_existing_extrabytes) { sprintf(laszip_dll->error, "bad \"extra bytes\" VLR describes %d bytes more than points actually have", laszip_dll->attributer->get_attributes_size() - number_of_existing_extrabytes); return 1; } else if (laszip_dll->attributer->get_attributes_size() < number_of_existing_extrabytes) { // maybe the existing "extra bytes" are documented in a VLR if (laszip_dll->header.vlrs) { for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4)) { laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data); } } } // describe any undocumented "extra bytes" as "unknown" U8 attributes for (I32 i = (I32)(laszip_dll->attributer->get_attributes_size()); i < number_of_existing_extrabytes; i++) { CHAR unknown_name[16]; memset(unknown_name, 0, 16); sprintf(unknown_name, "unknown %d", i); LASattribute lasattribute_unknown(LAS_ATTRIBUTE_U8, unknown_name, unknown_name); if (laszip_dll->attributer->add_attribute(lasattribute_unknown) == -1) { sprintf(laszip_dll->error, "cannot add unknown U8 attribute '%s' of %d to attributer", unknown_name, number_of_existing_extrabytes); return 1; } } } } // create the "extra bytes" that store the newer LAS 1.4 point attributes // scan_angle (difference or remainder) is stored as a I16 LASattribute lasattribute_scan_angle(LAS_ATTRIBUTE_I16, "LAS 1.4 scan angle", "additional attributes"); lasattribute_scan_angle.set_scale(0.006); I32 index_scan_angle = laszip_dll->attributer->add_attribute(lasattribute_scan_angle); laszip_dll->start_scan_angle = laszip_dll->attributer->get_attribute_start(index_scan_angle); // extended returns stored as a U8 LASattribute lasattribute_extended_returns(LAS_ATTRIBUTE_U8, "LAS 1.4 extended returns", "additional attributes"); I32 index_extended_returns = laszip_dll->attributer->add_attribute(lasattribute_extended_returns); laszip_dll->start_extended_returns = laszip_dll->attributer->get_attribute_start(index_extended_returns); // classification stored as a U8 LASattribute lasattribute_classification(LAS_ATTRIBUTE_U8, "LAS 1.4 classification", "additional attributes"); I32 index_classification = laszip_dll->attributer->add_attribute(lasattribute_classification); laszip_dll->start_classification = laszip_dll->attributer->get_attribute_start(index_classification); // flags and channel stored as a U8 LASattribute lasattribute_flags_and_channel(LAS_ATTRIBUTE_U8, "LAS 1.4 flags and channel", "additional attributes"); I32 index_flags_and_channel = laszip_dll->attributer->add_attribute(lasattribute_flags_and_channel); laszip_dll->start_flags_and_channel = laszip_dll->attributer->get_attribute_start(index_flags_and_channel); // maybe store the NIR band as a U16 if (laszip_dll->header.point_data_format == 8 || laszip_dll->header.point_data_format == 10) { // the NIR band is stored as a U16 LASattribute lasattribute_NIR_band(LAS_ATTRIBUTE_U16, "LAS 1.4 NIR band", "additional attributes"); I32 index_NIR_band = laszip_dll->attributer->add_attribute(lasattribute_NIR_band); laszip_dll->start_NIR_band = laszip_dll->attributer->get_attribute_start(index_NIR_band); } else { laszip_dll->start_NIR_band = -1; } // add the extra bytes VLR with the additional attributes if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes)) { sprintf(laszip_dll->error, "adding the extra bytes VLR with the additional attributes"); return 1; } // update point type if (laszip_dll->header.point_data_format == 6) { laszip_dll->header.point_data_format = 1; } else if (laszip_dll->header.point_data_format <= 8) { laszip_dll->header.point_data_format = 3; } else // 9->4 and 10->5 { laszip_dll->header.point_data_format -= 5; } // we are operating in compatibility mode laszip_dll->compatibility_mode = TRUE; } else if (compress) { sprintf(laszip_dll->error, "LASzip DLL %d.%d r%d (%d) cannot compress point data format %d without requesting 'compatibility mode'", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE, (I32)laszip_dll->header.point_data_format); return 1; } } else { // must *not* be set for the old point type 5 or lower laszip_dll->point.extended_point_type = 0; // we are *not* operating in compatibility mode laszip_dll->compatibility_mode = FALSE; } return 0; } /*---------------------------------------------------------------------------*/ static I32 laszip_prepare_vlrs_for_write( laszip_dll_struct* laszip_dll ) { U32 i, vlrs_size = 0; if (laszip_dll->header.number_of_variable_length_records) { if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "number_of_variable_length_records is %u but vlrs pointer is zero", laszip_dll->header.number_of_variable_length_records); return 1; } for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { vlrs_size += 54; if (laszip_dll->header.vlrs[i].record_length_after_header) { if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "vlrs[%u].record_length_after_header is %u but vlrs[%u].data pointer is zero", i, laszip_dll->header.vlrs[i].record_length_after_header, i); return 1; } vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header; } } } if ((vlrs_size + laszip_dll->header.header_size + laszip_dll->header.user_data_after_header_size) != laszip_dll->header.offset_to_point_data) { sprintf(laszip_dll->error,"header_size (%u) plus vlrs_size (%u) plus user_data_after_header_size (%u) does not equal offset_to_point_data (%u)", (U32)laszip_dll->header.header_size, vlrs_size, laszip_dll->header.user_data_after_header_size, laszip_dll->header.offset_to_point_data); return 1; } return 0; } /*---------------------------------------------------------------------------*/ static U32 laszip_vrl_payload_size( const LASzip* laszip ) { return 34 + (6 * laszip->num_items); } /*---------------------------------------------------------------------------*/ static I32 write_laszip_vlr_header( laszip_dll_struct* laszip_dll , const LASzip* laszip , ByteStreamOut* out ) { // write the LASzip VLR header U16 reserved = 0x0; try { out->put16bitsLE((U8*)&reserved); } catch(...) { sprintf(laszip_dll->error, "writing LASzip VLR header.reserved"); return 1; } U8 user_id[16] = "laszip encoded\0"; try { out->putBytes((U8*)user_id, 16); } catch(...) { sprintf(laszip_dll->error, "writing LASzip VLR header.user_id"); return 1; } U16 record_id = 22204; try { out->put16bitsLE((U8*)&record_id); } catch(...) { sprintf(laszip_dll->error, "writing LASzip VLR header.record_id"); return 1; } U16 record_length_after_header = (U16)laszip_vrl_payload_size(laszip); try { out->put16bitsLE((U8*)&record_length_after_header); } catch(...) { sprintf(laszip_dll->error, "writing LASzip VLR header.record_length_after_header"); return 1; } CHAR description[32]; memset(description, 0, 32); sprintf(description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE); try { out->putBytes((U8*)description, 32); } catch(...) { sprintf(laszip_dll->error, "writing LASzip VLR header.description"); return 1; } return 0; } /*---------------------------------------------------------------------------*/ static I32 write_laszip_vlr_payload( laszip_dll_struct* laszip_dll , const LASzip* laszip , ByteStreamOut* out ) { // write the LASzip VLR payload // U16 compressor 2 bytes // U32 coder 2 bytes // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes // U16 num_items 2 bytes // U16 type 2 bytes * num_items // U16 size 2 bytes * num_items // U16 version 2 bytes * num_items // which totals 34+6*num_items try { out->put16bitsLE((const U8*)&(laszip->compressor)); } catch(...) { sprintf(laszip_dll->error, "writing compressor %d", (I32)laszip->compressor); return 1; } try { out->put16bitsLE((const U8*)&(laszip->coder)); } catch(...) { sprintf(laszip_dll->error, "writing coder %d", (I32)laszip->coder); return 1; } try { out->putBytes((const U8*)&(laszip->version_major), 1); } catch(...) { sprintf(laszip_dll->error, "writing version_major %d", (I32)laszip->version_major); return 1; } try { out->putBytes((const U8*)&(laszip->version_minor), 1); } catch(...) { sprintf(laszip_dll->error, "writing version_minor %d", (I32)laszip->version_minor); return 1; } try { out->put16bitsLE((const U8*)&(laszip->version_revision)); } catch(...) { sprintf(laszip_dll->error, "writing version_revision %d", (I32)laszip->version_revision); return 1; } try { out->put32bitsLE((const U8*)&(laszip->options)); } catch(...) { sprintf(laszip_dll->error, "writing options %u", laszip->options); return 1; } try { out->put32bitsLE((const U8*)&(laszip->chunk_size)); } catch(...) { sprintf(laszip_dll->error, "writing chunk_size %u", laszip->chunk_size); return 1; } try { out->put64bitsLE((const U8*)&(laszip->number_of_special_evlrs)); } catch(...) { sprintf(laszip_dll->error, "writing number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs); return 1; } try { out->put64bitsLE((const U8*)&(laszip->offset_to_special_evlrs)); } catch(...) { sprintf(laszip_dll->error, "writing offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs); return 1; } try { out->put16bitsLE((const U8*)&(laszip->num_items)); } catch(...) { sprintf(laszip_dll->error, "writing num_items %d", (I32)laszip->num_items); return 1; } U32 j; for (j = 0; j < laszip->num_items; j++) { U16 type = (U16)(laszip->items[j].type); try { out->put16bitsLE((const U8*)&type); } catch(...) { sprintf(laszip_dll->error, "writing type %d of item %d", (I32)laszip->items[j].type, j); return 1; } try { out->put16bitsLE((const U8*)&(laszip->items[j].size)); } catch(...) { sprintf(laszip_dll->error, "writing size %d of item %d", (I32)laszip->items[j].size, j); return 1; } try { out->put16bitsLE((const U8*)&(laszip->items[j].version)); } catch(...) { sprintf(laszip_dll->error, "writing version %d of item %d", (I32)laszip->items[j].version, j); return 1; } } return 0; } /*---------------------------------------------------------------------------*/ static I32 laszip_write_header( laszip_dll_struct* laszip_dll , const LASzip* laszip , const laszip_BOOL compress ) { U32 i; try { laszip_dll->streamout->putBytes((const U8*)"LASF", 4); } catch(...) { sprintf(laszip_dll->error, "writing header.file_signature"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_source_ID)); } catch(...) { sprintf(laszip_dll->error, "writing header.file_source_ID"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.global_encoding)); } catch(...) { sprintf(laszip_dll->error, "writing header.global_encoding"); return 1; } try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...) { sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_1"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...) { sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_2"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...) { sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_3"); return 1; } try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...) { sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_4"); return 1; } try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_major), 1); } catch(...) { sprintf(laszip_dll->error, "writing header.version_major"); return 1; } try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_minor), 1); } catch(...) { sprintf(laszip_dll->error, "writing header.version_minor"); return 1; } try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.system_identifier, 32); } catch(...) { sprintf(laszip_dll->error, "writing header.system_identifier"); return 1; } if (!laszip_dll->preserve_generating_software) { memset(laszip_dll->header.generating_software, 0, 32); sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE); } try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.generating_software, 32); } catch(...) { sprintf(laszip_dll->error, "writing header.generating_software"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_day)); } catch(...) { sprintf(laszip_dll->error, "writing header.file_creation_day"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_year)); } catch(...) { sprintf(laszip_dll->error, "writing header.file_creation_year"); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.header_size)); } catch(...) { sprintf(laszip_dll->error, "writing header.header_size"); return 1; } if (compress) { laszip_dll->header.offset_to_point_data += (54 + laszip_vrl_payload_size(laszip)); } try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...) { sprintf(laszip_dll->error, "writing header.offset_to_point_data"); return 1; } if (compress) { laszip_dll->header.offset_to_point_data -= (54 + laszip_vrl_payload_size(laszip)); laszip_dll->header.number_of_variable_length_records += 1; } try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...) { sprintf(laszip_dll->error, "writing header.number_of_variable_length_records"); return 1; } if (compress) { laszip_dll->header.number_of_variable_length_records -= 1; laszip_dll->header.point_data_format |= 128; } try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.point_data_format), 1); } catch(...) { sprintf(laszip_dll->error, "writing header.point_data_format"); return 1; } if (compress) { laszip_dll->header.point_data_format &= 127; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.point_data_record_length)); } catch(...) { sprintf(laszip_dll->error, "writing header.point_data_record_length"); return 1; } try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_point_records)); } catch(...) { sprintf(laszip_dll->error, "writing header.number_of_point_records"); return 1; } for (i = 0; i < 5; i++) { try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...) { sprintf(laszip_dll->error, "writing header.number_of_points_by_return %d", i); return 1; } } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "writing header.x_scale_factor"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "writing header.y_scale_factor"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "writing header.z_scale_factor"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_offset)); } catch(...) { sprintf(laszip_dll->error, "writing header.x_offset"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_offset)); } catch(...) { sprintf(laszip_dll->error, "writing header.y_offset"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_offset)); } catch(...) { sprintf(laszip_dll->error, "writing header.z_offset"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_x)); } catch(...) { sprintf(laszip_dll->error, "writing header.max_x"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_x)); } catch(...) { sprintf(laszip_dll->error, "writing header.min_x"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_y)); } catch(...) { sprintf(laszip_dll->error, "writing header.max_y"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_y)); } catch(...) { sprintf(laszip_dll->error, "writing header.min_y"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_z)); } catch(...) { sprintf(laszip_dll->error, "writing header.max_z"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_z)); } catch(...) { sprintf(laszip_dll->error, "writing header.min_z"); return 1; } // special handling for LAS 1.3 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3)) { if (laszip_dll->header.header_size < 235) { sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size); return 1; } else { if (laszip_dll->header.start_of_waveform_data_packet_record != 0) { #ifdef _WIN32 sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %I64d. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record); #else sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %llu. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record); #endif laszip_dll->header.start_of_waveform_data_packet_record = 0; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...) { sprintf(laszip_dll->error, "writing header.start_of_waveform_data_packet_record"); return 1; } laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235; } } else { laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227; } // special handling for LAS 1.4 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4)) { if (laszip_dll->header.header_size < 375) { sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size); return 1; } else { try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...) { sprintf(laszip_dll->error, "writing header.start_of_first_extended_variable_length_record"); return 1; } try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...) { sprintf(laszip_dll->error, "writing header.number_of_extended_variable_length_records"); return 1; } try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...) { sprintf(laszip_dll->error, "writing header.extended_number_of_point_records"); return 1; } for (i = 0; i < 15; i++) { try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...) { sprintf(laszip_dll->error, "writing header.extended_number_of_points_by_return[%d]", i); return 1; } } laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375; } } // write any number of user-defined bytes that might have been added to the header if (laszip_dll->header.user_data_in_header_size) { try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...) { sprintf(laszip_dll->error, "writing %d bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size); return 1; } } // write variable length records into the header if (laszip_dll->header.number_of_variable_length_records) { U32 i; for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { // write variable length records variable after variable (to avoid alignment issues) try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...) { sprintf(laszip_dll->error, "writing header.vlrs[%d].reserved", i); return 1; } try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...) { sprintf(laszip_dll->error, "writing header.vlrs[%d].user_id", i); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...) { sprintf(laszip_dll->error, "writing header.vlrs[%d].record_id", i); return 1; } try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...) { sprintf(laszip_dll->error, "writing header.vlrs[%d].record_length_after_header", i); return 1; } try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...) { sprintf(laszip_dll->error, "writing header.vlrs[%d].description", i); return 1; } // write data following the header of the variable length record if (laszip_dll->header.vlrs[i].record_length_after_header) { try { laszip_dll->streamout->putBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...) { sprintf(laszip_dll->error, "writing %d bytes of data into header.vlrs[%d].data", laszip_dll->header.vlrs[i].record_length_after_header, i); return 1; } } } } if (compress) { // write the LASzip VLR header if (write_laszip_vlr_header(laszip_dll, laszip, laszip_dll->streamout)) { return 1; } // write the LASzip VLR payload if (write_laszip_vlr_payload(laszip_dll, laszip, laszip_dll->streamout)) { return 1; } } // write any number of user-defined bytes that might have been added after the header if (laszip_dll->header.user_data_after_header_size) { try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...) { sprintf(laszip_dll->error, "writing %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size); return 1; } } return 0; } /*----------------------------------------------------------------------------*/ laszip_I32 create_point_writer ( laszip_dll_struct *laszip_dll , const LASzip *laszip ) { // create the point writer laszip_dll->writer = new LASwritePoint(); if (laszip_dll->writer == 0) { sprintf(laszip_dll->error, "could not alloc LASwritePoint"); return 1; } if (!laszip_dll->writer->setup(laszip->num_items, laszip->items, laszip)) { sprintf(laszip_dll->error, "setup of LASwritePoint failed"); return 1; } if (!laszip_dll->writer->init(laszip_dll->streamout)) { sprintf(laszip_dll->error, "init of LASwritePoint failed"); return 1; } return 0; } /*---------------------------------------------------------------------------*/ static I32 setup_laszip_items( laszip_dll_struct* laszip_dll , LASzip* laszip , laszip_BOOL compress ) { laszip_U8 point_type = laszip_dll->header.point_data_format; laszip_U16 point_size = laszip_dll->header.point_data_record_length; if ((point_type > 5) && laszip_dll->request_compatibility_mode) { if (!laszip->request_compatibility_mode(1)) { sprintf(laszip_dll->error, "requesting 'compatibility mode' has failed"); return 1; } } // create point items in the LASzip structure from point format and size if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_NONE)) { sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size); return 1; } // compute offsets (or points item pointers) for data transfer from the point items if (laszip_dll->point_items) { delete [] laszip_dll->point_items; } laszip_dll->point_items = new U8*[laszip->num_items]; if (laszip_dll->point_items == 0) { sprintf(laszip_dll->error, "could not alloc point_items"); return 1; } for (size_t i = 0; i < laszip->num_items; i++) { switch (laszip->items[i].type) { case LASitem::POINT10: case LASitem::POINT14: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X); break; case LASitem::GPSTIME11: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time); break; case LASitem::RGB12: case LASitem::RGB14: case LASitem::RGBNIR14: laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb; break; case LASitem::BYTE: case LASitem::BYTE14: laszip_dll->point.num_extra_bytes = laszip->items[i].size; if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes; laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes]; laszip_dll->point_items[i] = laszip_dll->point.extra_bytes; break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet); break; default: sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type); return 1; } } if (compress) { if ((point_type > 5) && laszip_dll->request_native_extension) { if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_LAYERED_CHUNKED)) { sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d using native", (I32)point_type, (I32)point_size); return 1; } } else { if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_DEFAULT)) { sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d", (I32)point_type, (I32)point_size); return 1; } } // request version (old point types only, new point types always use version 3) laszip->request_version(2); // maybe we should change the chunk size if (laszip_dll->set_chunk_size != LASZIP_CHUNK_SIZE_DEFAULT) { if (!laszip->set_chunk_size(laszip_dll->set_chunk_size)) { sprintf(laszip_dll->error, "setting chunk size %d has failed", laszip_dll->set_chunk_size); return 1; } } } else { laszip->request_version(0); } return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_writer( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL compress ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (file_name == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } // open the file #ifdef _MSC_VER wchar_t* utf16_file_name = UTF8toUTF16(file_name); laszip_dll->file = _wfopen(utf16_file_name, L"wb"); delete [] utf16_file_name; #else laszip_dll->file = fopen(file_name, "wb"); #endif if (laszip_dll->file == 0) { sprintf(laszip_dll->error, "cannot open file '%s'", file_name); return 1; } if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0) { sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n"); } // create the outstream if (IS_LITTLE_ENDIAN()) laszip_dll->streamout = new ByteStreamOutFileLE(laszip_dll->file); else laszip_dll->streamout = new ByteStreamOutFileBE(laszip_dll->file); if (laszip_dll->streamout == 0) { sprintf(laszip_dll->error, "could not alloc ByteStreamOutFile"); return 1; } // setup the items that make up the point LASzip laszip; if (setup_laszip_items(laszip_dll, &laszip, compress)) { return 1; } // prepare header if (laszip_prepare_header_for_write(laszip_dll)) { return 1; } // prepare point if (laszip_prepare_point_for_write(laszip_dll, compress)) { return 1; } // prepare VLRs if (laszip_prepare_vlrs_for_write(laszip_dll)) { return 1; } // write header variable after variable if (laszip_write_header(laszip_dll, &laszip, compress)) { return 1; } // create the point writer if (create_point_writer(laszip_dll, &laszip)) { return 1; } if (laszip_dll->lax_create) { // create spatial indexing information using cell_size = 100.0f and threshold = 1000 LASquadtree* lasquadtree = new LASquadtree; lasquadtree->setup(laszip_dll->header.min_x, laszip_dll->header.max_x, laszip_dll->header.min_y, laszip_dll->header.max_y, 100.0f); laszip_dll->lax_index = new LASindex; laszip_dll->lax_index->prepare(lasquadtree, 1000); // copy the file name for later laszip_dll->lax_file_name = LASCopyString(file_name); } // set the point number and point count laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records); laszip_dll->p_count = 0; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_open_writer '%s'", file_name); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_write_point( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { // temporary fix to avoid corrupt LAZ files if (laszip_dll->point.extended_point_type) { // make sure legacy flags and extended flags are identical if ((laszip_dll->point.extended_classification_flags & 0x7) != ((((U8*)&(laszip_dll->point.intensity))[3]) >> 5)) { sprintf(laszip_dll->error, "legacy flags and extended flags are not identical"); return 1; } // make sure legacy classification is zero or identical to extended classification if (laszip_dll->point.classification != 0) { if (laszip_dll->point.classification != laszip_dll->point.extended_classification) { sprintf(laszip_dll->error, "legacy classification %d and extended classification %d are not consistent", laszip_dll->point.classification, laszip_dll->point.extended_classification); return 1; } } } // special recoding of points (in compatibility mode only) if (laszip_dll->compatibility_mode) { I32 scan_angle_remainder; I32 number_of_returns_increment; I32 return_number_increment; I32 return_count_difference; I32 overlap_bit; I32 scanner_channel; // distill extended attributes struct laszip_point* point = &laszip_dll->point; point->scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*point->extended_scan_angle)); scan_angle_remainder = point->extended_scan_angle - I16_QUANTIZE(((F32)point->scan_angle_rank)/0.006f); if (point->extended_number_of_returns <= 7) { point->number_of_returns = point->extended_number_of_returns; if (point->extended_return_number <= 7) { point->return_number = point->extended_return_number; } else { point->return_number = 7; } } else { point->number_of_returns = 7; if (point->extended_return_number <= 4) { point->return_number = point->extended_return_number; } else { return_count_difference = point->extended_number_of_returns - point->extended_return_number; if (return_count_difference <= 0) { point->return_number = 7; } else if (return_count_difference >= 3) { point->return_number = 4; } else { point->return_number = 7 - return_count_difference; } } } return_number_increment = point->extended_return_number - point->return_number; number_of_returns_increment = point->extended_number_of_returns - point->number_of_returns; if (point->extended_classification > 31) { point->classification = 0; } else { point->extended_classification = 0; } scanner_channel = point->extended_scanner_channel; overlap_bit = (point->extended_classification_flags >> 3); // write distilled extended attributes into extra bytes *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle)) = ((I16)scan_angle_remainder); point->extra_bytes[laszip_dll->start_extended_returns] = (U8)((return_number_increment << 4) | number_of_returns_increment); point->extra_bytes[laszip_dll->start_classification] = (U8)(point->extended_classification); point->extra_bytes[laszip_dll->start_flags_and_channel] = (U8)((scanner_channel << 1) | overlap_bit); if (laszip_dll->start_NIR_band != -1) { *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band)) = point->rgb[3]; } } // write the point if (!laszip_dll->writer->write(laszip_dll->point_items)) { #ifdef _WIN32 sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints); #else sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints); #endif return 1; } laszip_dll->p_count++; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_write_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_write_indexed_point( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { // write the point if (!laszip_dll->writer->write(laszip_dll->point_items)) { #ifdef _WIN32 sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints); #else sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints); #endif return 1; } // index the point F64 x = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset; F64 y = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset; laszip_dll->lax_index->add(x, y, (U32)laszip_dll->p_count); laszip_dll->p_count++; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_write_indexed_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_update_inventory( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->inventory == 0) { laszip_dll->inventory = new laszip_dll_inventory; } laszip_dll->inventory->add(&laszip_dll->point); } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_update_inventory"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_close_writer( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->writer == 0) { sprintf(laszip_dll->error, "closing writer before it was opened"); return 1; } if (!laszip_dll->writer->done()) { sprintf(laszip_dll->error, "done of LASwritePoint failed"); return 1; } delete laszip_dll->writer; laszip_dll->writer = 0; delete [] laszip_dll->point_items; laszip_dll->point_items = 0; // maybe update the header if (laszip_dll->inventory) { if (laszip_dll->header.point_data_format <= 5) // only update legacy counters for old point types { laszip_dll->streamout->seek(107); if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_point_records))) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_point_records"); return 1; } for (I32 i = 0; i < 5; i++) { if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_points_by_return[i+1]))) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_points_by_return[%d]\n", i); return 1; } } } laszip_dll->streamout->seek(179); F64 value; value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->max_X+laszip_dll->header.x_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_X"); return 1; } value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->min_X+laszip_dll->header.x_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_X"); return 1; } value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->max_Y+laszip_dll->header.y_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Y"); return 1; } value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->min_Y+laszip_dll->header.y_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Y"); return 1; } value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->max_Z+laszip_dll->header.z_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Z"); return 1; } value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->min_Z+laszip_dll->header.z_offset; if (!laszip_dll->streamout->put64bitsLE((const U8*)&value)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Z"); return 1; } if (laszip_dll->header.version_minor >= 4) // only update extended counters for LAS 1.4 { laszip_dll->streamout->seek(247); I64 number = laszip_dll->inventory->number_of_point_records; if (!laszip_dll->streamout->put64bitsLE((const U8*)&number)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_point_records"); return 1; } for (I32 i = 0; i < 15; i++) { number = laszip_dll->inventory->number_of_points_by_return[i+1]; if (!laszip_dll->streamout->put64bitsLE((const U8*)&number)) { sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_points_by_return[%d]\n", i); return 1; } } } laszip_dll->streamout->seekEnd(); delete laszip_dll->inventory; laszip_dll->inventory = 0; } if (laszip_dll->lax_index) { laszip_dll->lax_index->complete(100000, -20, FALSE); if (!laszip_dll->lax_index->write(laszip_dll->lax_file_name)) { sprintf(laszip_dll->error, "writing LAX file to '%s'", laszip_dll->lax_file_name); return 1; } free(laszip_dll->lax_file_name); laszip_dll->lax_file_name = 0; delete laszip_dll->lax_index; laszip_dll->lax_index = 0; } delete laszip_dll->streamout; laszip_dll->streamout = 0; if (laszip_dll->file) { fclose(laszip_dll->file); laszip_dll->file = 0; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_writer_close"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_exploit_spatial_index( laszip_POINTER pointer , const laszip_BOOL exploit ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->lax_exploit = exploit; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_exploit_spatial_index"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_decompress_selective( laszip_POINTER pointer , const laszip_U32 decompress_selective ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } laszip_dll->las14_decompress_selective = decompress_selective; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_decompress_selective"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ static I32 laszip_read_header( laszip_dll_struct* laszip_dll , laszip_BOOL* is_compressed ) { U32 i; // read the header variable after variable CHAR file_signature[5]; try { laszip_dll->streamin->getBytes((U8*)file_signature, 4); } catch(...) { sprintf(laszip_dll->error, "reading header.file_signature"); return 1; } if (strncmp(file_signature, "LASF", 4) != 0) { sprintf(laszip_dll->error, "wrong file_signature. not a LAS/LAZ file."); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_source_ID)); } catch(...) { sprintf(laszip_dll->error, "reading header.file_source_ID"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.global_encoding)); } catch(...) { sprintf(laszip_dll->error, "reading header.global_encoding"); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...) { sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_1"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...) { sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_2"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...) { sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_3"); return 1; } try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...) { sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_4"); return 1; } try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_major), 1); } catch(...) { sprintf(laszip_dll->error, "reading header.version_major"); return 1; } try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_minor), 1); } catch(...) { sprintf(laszip_dll->error, "reading header.version_minor"); return 1; } try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.system_identifier, 32); } catch(...) { sprintf(laszip_dll->error, "reading header.system_identifier"); return 1; } try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.generating_software, 32); } catch(...) { sprintf(laszip_dll->error, "reading header.generating_software"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_day)); } catch(...) { sprintf(laszip_dll->error, "reading header.file_creation_day"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_year)); } catch(...) { sprintf(laszip_dll->error, "reading header.file_creation_year"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.header_size)); } catch(...) { sprintf(laszip_dll->error, "reading header.header_size"); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...) { sprintf(laszip_dll->error, "reading header.offset_to_point_data"); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...) { sprintf(laszip_dll->error, "reading header.number_of_variable_length_records"); return 1; } try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.point_data_format), 1); } catch(...) { sprintf(laszip_dll->error, "reading header.point_data_format"); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.point_data_record_length)); } catch(...) { sprintf(laszip_dll->error, "reading header.point_data_record_length"); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_point_records)); } catch(...) { sprintf(laszip_dll->error, "reading header.number_of_point_records"); return 1; } for (i = 0; i < 5; i++) { try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...) { sprintf(laszip_dll->error, "reading header.number_of_points_by_return %d", i); return 1; } } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "reading header.x_scale_factor"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "reading header.y_scale_factor"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_scale_factor)); } catch(...) { sprintf(laszip_dll->error, "reading header.z_scale_factor"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_offset)); } catch(...) { sprintf(laszip_dll->error, "reading header.x_offset"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_offset)); } catch(...) { sprintf(laszip_dll->error, "reading header.y_offset"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_offset)); } catch(...) { sprintf(laszip_dll->error, "reading header.z_offset"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_x)); } catch(...) { sprintf(laszip_dll->error, "reading header.max_x"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_x)); } catch(...) { sprintf(laszip_dll->error, "reading header.min_x"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_y)); } catch(...) { sprintf(laszip_dll->error, "reading header.max_y"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_y)); } catch(...) { sprintf(laszip_dll->error, "reading header.min_y"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_z)); } catch(...) { sprintf(laszip_dll->error, "reading header.max_z"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_z)); } catch(...) { sprintf(laszip_dll->error, "reading header.min_z"); return 1; } // special handling for LAS 1.3 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3)) { if (laszip_dll->header.header_size < 235) { sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size); return 1; } else { try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...) { sprintf(laszip_dll->error, "reading header.start_of_waveform_data_packet_record"); return 1; } laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235; } } else { laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227; } // special handling for LAS 1.4 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4)) { if (laszip_dll->header.header_size < 375) { sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size); return 1; } else { try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...) { sprintf(laszip_dll->error, "reading header.start_of_first_extended_variable_length_record"); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...) { sprintf(laszip_dll->error, "reading header.number_of_extended_variable_length_records"); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...) { sprintf(laszip_dll->error, "reading header.extended_number_of_point_records"); return 1; } for (i = 0; i < 15; i++) { try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...) { sprintf(laszip_dll->error, "reading header.extended_number_of_points_by_return[%d]", i); return 1; } } laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375; } } // load any number of user-defined bytes that might have been added to the header if (laszip_dll->header.user_data_in_header_size) { if (laszip_dll->header.user_data_in_header) { delete [] laszip_dll->header.user_data_in_header; } laszip_dll->header.user_data_in_header = new U8[laszip_dll->header.user_data_in_header_size]; try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...) { sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size); return 1; } } // read variable length records into the header U32 vlrs_size = 0; LASzip* laszip = 0; if (laszip_dll->header.number_of_variable_length_records) { U32 i; laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records); if (laszip_dll->header.vlrs == 0) { sprintf(laszip_dll->error, "allocating %u VLRs", laszip_dll->header.number_of_variable_length_records); return 1; } for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { // make sure there are enough bytes left to read a variable length record before the point block starts if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < 54) { sprintf(laszip_dll->warning, "only %d bytes until point block after reading %d of %d vlrs. skipping remaining vlrs ...", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, i, laszip_dll->header.number_of_variable_length_records); laszip_dll->header.number_of_variable_length_records = i; break; } // read variable length records variable after variable (to avoid alignment issues) try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...) { sprintf(laszip_dll->error, "reading header.vlrs[%u].reserved", i); return 1; } try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...) { sprintf(laszip_dll->error, "reading header.vlrs[%u].user_id", i); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...) { sprintf(laszip_dll->error, "reading header.vlrs[%u].record_id", i); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...) { sprintf(laszip_dll->error, "reading header.vlrs[%u].record_length_after_header", i); return 1; } try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...) { sprintf(laszip_dll->error, "reading header.vlrs[%u].description", i); return 1; } // keep track on the number of bytes we have read so far vlrs_size += 54; // check variable length record contents if ((laszip_dll->header.vlrs[i].reserved != 0xAABB) && (laszip_dll->header.vlrs[i].reserved != 0x0)) { sprintf(laszip_dll->warning,"wrong header.vlrs[%d].reserved: %d != 0xAABB and %d != 0x0", i, laszip_dll->header.vlrs[i].reserved, laszip_dll->header.vlrs[i].reserved); } // make sure there are enough bytes left to read the data of the variable length record before the point block starts if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < laszip_dll->header.vlrs[i].record_length_after_header) { sprintf(laszip_dll->warning, "only %d bytes until point block when trying to read %d bytes into header.vlrs[%d].data", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, laszip_dll->header.vlrs[i].record_length_after_header, i); laszip_dll->header.vlrs[i].record_length_after_header = (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size; } // load data following the header of the variable length record if (laszip_dll->header.vlrs[i].record_length_after_header) { if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204)) { if (laszip) { delete laszip; } laszip = new LASzip(); if (laszip == 0) { sprintf(laszip_dll->error, "could not alloc LASzip"); return 1; } // read the LASzip VLR payload // U16 compressor 2 bytes // U32 coder 2 bytes // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes // U16 num_items 2 bytes // U16 type 2 bytes * num_items // U16 size 2 bytes * num_items // U16 version 2 bytes * num_items // which totals 34+6*num_items try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->compressor)); } catch(...) { sprintf(laszip_dll->error, "reading compressor %d", (I32)laszip->compressor); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->coder)); } catch(...) { sprintf(laszip_dll->error, "reading coder %d", (I32)laszip->coder); return 1; } try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_major), 1); } catch(...) { sprintf(laszip_dll->error, "reading version_major %d", (I32)laszip->version_major); return 1; } try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_minor), 1); } catch(...) { sprintf(laszip_dll->error, "reading version_minor %d", (I32)laszip->version_minor); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->version_revision)); } catch(...) { sprintf(laszip_dll->error, "reading version_revision %d", (I32)laszip->version_revision); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->options)); } catch(...) { sprintf(laszip_dll->error, "reading options %u", laszip->options); return 1; } try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->chunk_size)); } catch(...) { sprintf(laszip_dll->error, "reading chunk_size %u", laszip->chunk_size); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->number_of_special_evlrs)); } catch(...) { sprintf(laszip_dll->error, "reading number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs); return 1; } try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->offset_to_special_evlrs)); } catch(...) { sprintf(laszip_dll->error, "reading offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->num_items)); } catch(...) { sprintf(laszip_dll->error, "reading num_items %d", (I32)laszip->num_items); return 1; } laszip->items = new LASitem[laszip->num_items]; U32 j; for (j = 0; j < laszip->num_items; j++) { U16 type; try { laszip_dll->streamin->get16bitsLE((U8*)&type); } catch(...) { sprintf(laszip_dll->error, "reading type of item %u", j); return 1; } laszip->items[j].type = (LASitem::Type)type; try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].size)); } catch(...) { sprintf(laszip_dll->error, "reading size of item %u", j); return 1; } try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].version)); } catch(...) { sprintf(laszip_dll->error, "reading version of item %u", j); return 1; } } } else { laszip_dll->header.vlrs[i].data = new U8[laszip_dll->header.vlrs[i].record_length_after_header]; try { laszip_dll->streamin->getBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...) { sprintf(laszip_dll->error, "reading %d bytes of data into header.vlrs[%u].data", (I32)laszip_dll->header.vlrs[i].record_length_after_header, i); return 1; } } } else { laszip_dll->header.vlrs[i].data = 0; } // keep track on the number of bytes we have read so far vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header; // special handling for LASzip VLR if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204)) { // we take our the VLR for LASzip away laszip_dll->header.offset_to_point_data -= (54+laszip_dll->header.vlrs[i].record_length_after_header); vlrs_size -= (54+laszip_dll->header.vlrs[i].record_length_after_header); i--; laszip_dll->header.number_of_variable_length_records--; // free or resize the VLR array if (laszip_dll->header.number_of_variable_length_records == 0) { free(laszip_dll->header.vlrs); laszip_dll->header.vlrs = 0; } else { laszip_dll->header.vlrs = (laszip_vlr*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records); } } } } // load any number of user-defined bytes that might have been added after the header laszip_dll->header.user_data_after_header_size = (I32)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size; if (laszip_dll->header.user_data_after_header_size) { if (laszip_dll->header.user_data_after_header) { delete [] laszip_dll->header.user_data_after_header; } laszip_dll->header.user_data_after_header = new U8[laszip_dll->header.user_data_after_header_size]; try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...) { sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size); return 1; } } // remove extra bits in point data type if ((laszip_dll->header.point_data_format & 128) || (laszip_dll->header.point_data_format & 64)) { if (!laszip) { sprintf(laszip_dll->error, "this file was compressed with an experimental version of LASzip. contact 'martin.isenburg@rapidlasso.com' for assistance"); return 1; } laszip_dll->header.point_data_format &= 127; } // check if file is compressed if (laszip) { // yes. check the compressor state *is_compressed = 1; if (!laszip->check(laszip_dll->header.point_data_record_length)) { sprintf(laszip_dll->error, "%s upgrade to the latest release of LASzip or contact 'martin.isenburg@rapidlasso.com' for assistance", laszip->get_error()); return 1; } } else { // no. setup an un-compressed read *is_compressed = 0; laszip = new LASzip; if (laszip == 0) { sprintf(laszip_dll->error, "could not alloc LASzip"); return 1; } if (!laszip->setup(laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length, LASZIP_COMPRESSOR_NONE)) { sprintf(laszip_dll->error, "invalid combination of point_data_format %d and point_data_record_length %d", (I32)laszip_dll->header.point_data_format, (I32)laszip_dll->header.point_data_record_length); return 1; } } // create point's item pointers if (laszip_dll->point_items) { delete [] laszip_dll->point_items; } laszip_dll->point_items = new U8*[laszip->num_items]; if (laszip_dll->point_items == 0) { sprintf(laszip_dll->error, "could not alloc point_items"); return 1; } for (i = 0; i < laszip->num_items; i++) { switch (laszip->items[i].type) { case LASitem::POINT10: case LASitem::POINT14: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X); break; case LASitem::GPSTIME11: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time); break; case LASitem::RGB12: case LASitem::RGB14: case LASitem::RGBNIR14: laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb; break; case LASitem::BYTE: case LASitem::BYTE14: laszip_dll->point.num_extra_bytes = laszip->items[i].size; if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes; laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes]; laszip_dll->point_items[i] = laszip_dll->point.extra_bytes; break; case LASitem::WAVEPACKET13: case LASitem::WAVEPACKET14: laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet); break; default: sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type); return 1; } } // did the user request to recode the compatibility mode points? laszip_dll->compatibility_mode = FALSE; if (laszip_dll->request_compatibility_mode && (laszip_dll->header.version_minor < 4)) { // does this file contain compatibility mode recoded LAS 1.4 content struct laszip_vlr* compatibility_VLR = 0; if (laszip_dll->header.point_data_format == 1 || laszip_dll->header.point_data_format == 3 || laszip_dll->header.point_data_format == 4 || laszip_dll->header.point_data_format == 5) { // if we find the compatibility VLR for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strncmp(laszip_dll->header.vlrs[i].user_id, "lascompatible\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 22204)) { if (laszip_dll->header.vlrs[i].record_length_after_header == 2+2+4+148) { compatibility_VLR = &(laszip_dll->header.vlrs[i]); break; } } } if (compatibility_VLR) { // and we also find the extra bytes VLR with the right attributes LASattributer attributer; for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec\0\0\0\0\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 4)) { attributer.init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/192, (LASattribute*)laszip_dll->header.vlrs[i].data); laszip_dll->start_scan_angle = attributer.get_attribute_start("LAS 1.4 scan angle"); laszip_dll->start_extended_returns = attributer.get_attribute_start("LAS 1.4 extended returns"); laszip_dll->start_classification = attributer.get_attribute_start("LAS 1.4 classification"); laszip_dll->start_flags_and_channel = attributer.get_attribute_start("LAS 1.4 flags and channel"); laszip_dll->start_NIR_band = attributer.get_attribute_start("LAS 1.4 NIR band"); break; } } // can we do it ... ? if ((laszip_dll->start_scan_angle != -1) && (laszip_dll->start_extended_returns != -1) && (laszip_dll->start_classification != -1) && (laszip_dll->start_flags_and_channel != -1)) { // yes ... so let's fix the header (using the content from the compatibility VLR) ByteStreamInArray* in; if (IS_LITTLE_ENDIAN()) in = new ByteStreamInArrayLE(compatibility_VLR->data, compatibility_VLR->record_length_after_header); else in = new ByteStreamInArrayBE(compatibility_VLR->data, compatibility_VLR->record_length_after_header); // read control info U16 laszip_version; in->get16bitsLE((U8*)&laszip_version); U16 compatible_version; in->get16bitsLE((U8*)&compatible_version); U32 unused; in->get32bitsLE((U8*)&unused); // read the 148 bytes of the extended LAS 1.4 header U64 start_of_waveform_data_packet_record; in->get64bitsLE((U8*)&start_of_waveform_data_packet_record); if (start_of_waveform_data_packet_record != 0) { #ifdef _WIN32 fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %I64d. reading 0 instead.\n", start_of_waveform_data_packet_record); #else fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %llu. reading 0 instead.\n", start_of_waveform_data_packet_record); #endif } laszip_dll->header.start_of_waveform_data_packet_record = 0; U64 start_of_first_extended_variable_length_record; in->get64bitsLE((U8*)&start_of_first_extended_variable_length_record); if (start_of_first_extended_variable_length_record != 0) { #ifdef _WIN32 fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %I64d. reading 0 instead.\n", start_of_first_extended_variable_length_record); #else fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %llu. reading 0 instead.\n", start_of_first_extended_variable_length_record); #endif } laszip_dll->header.start_of_first_extended_variable_length_record = 0; U32 number_of_extended_variable_length_records ; in->get32bitsLE((U8*)&number_of_extended_variable_length_records); if (number_of_extended_variable_length_records != 0) { fprintf(stderr,"WARNING: EVLRs not supported. number_of_extended_variable_length_records is %u. reading 0 instead.\n", number_of_extended_variable_length_records); } laszip_dll->header.number_of_extended_variable_length_records = 0; U64 extended_number_of_point_records = 0; in->get64bitsLE((U8*)&extended_number_of_point_records); if (laszip_dll->header.number_of_point_records != 0 && ((U64)(laszip_dll->header.number_of_point_records)) != extended_number_of_point_records) { #ifdef _WIN32 fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %I64u.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records); #else fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %llu.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records); #endif } laszip_dll->header.extended_number_of_point_records = extended_number_of_point_records; U64 extended_number_of_points_by_return; for (U32 r = 0; r < 15; r++) { in->get64bitsLE((U8*)&extended_number_of_points_by_return); if ((r < 5) && laszip_dll->header.number_of_points_by_return[r] != 0 && ((U64)(laszip_dll->header.number_of_points_by_return[r])) != extended_number_of_points_by_return) { #ifdef _WIN32 fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %I64u.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return); #else fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %llu.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return); #endif } laszip_dll->header.extended_number_of_points_by_return[r] = extended_number_of_points_by_return; } delete in; // remove the compatibility VLR if (laszip_remove_vlr(laszip_dll, "lascompatible\0\0", 22204)) { sprintf(laszip_dll->error, "removing the compatibility VLR"); return 1; } // remove the LAS 1.4 attributes from the "extra bytes" description if (laszip_dll->start_NIR_band != -1) attributer.remove_attribute("LAS 1.4 NIR band"); attributer.remove_attribute("LAS 1.4 flags and channel"); attributer.remove_attribute("LAS 1.4 classification"); attributer.remove_attribute("LAS 1.4 extended returns"); attributer.remove_attribute("LAS 1.4 scan angle"); // either rewrite or remove the "extra bytes" VLR if (attributer.number_attributes) { if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(attributer.number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)attributer.attributes)) { sprintf(laszip_dll->error, "rewriting the extra bytes VLR without 'LAS 1.4 compatibility mode' attributes"); return 1; } } else { if (laszip_remove_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4)) { sprintf(laszip_dll->error, "removing the LAS 1.4 attribute VLR"); return 1; } } // upgrade to LAS 1.4 if (laszip_dll->header.version_minor < 3) { // LAS 1.2 header is 148 bytes less than LAS 1.4+ header laszip_dll->header.header_size += 148; laszip_dll->header.offset_to_point_data += 148; } else { // LAS 1.3 header is 140 bytes less than LAS 1.4+ header laszip_dll->header.header_size += 140; laszip_dll->header.offset_to_point_data += 140; } laszip_dll->header.version_minor = 4; // maybe turn on the bit indicating the presence of the OGC WKT for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++) { if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Projection", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 2112)) { laszip_dll->header.global_encoding |= (1<<4); break; } } // update point type and size laszip_dll->point.extended_point_type = 1; if (laszip_dll->header.point_data_format == 1) { laszip_dll->header.point_data_format = 6; laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes } else if (laszip_dll->header.point_data_format == 3) { if (laszip_dll->start_NIR_band == -1) { laszip_dll->header.point_data_format = 7; laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes } else { laszip_dll->header.point_data_format = 8; laszip_dll->header.point_data_record_length += (4 - 7); // record is 4 bytes larger but minus 7 extra bytes } } else { if (laszip_dll->start_NIR_band == -1) { laszip_dll->header.point_data_format = 9; laszip_dll->header.point_data_record_length += (2 - 5); } else { laszip_dll->header.point_data_format = 10; laszip_dll->header.point_data_record_length += (4 - 7); } } // we are operating in compatibility mode laszip_dll->compatibility_mode = TRUE; } } } } else if (laszip_dll->header.point_data_format > 5) { laszip_dll->point.extended_point_type = 1; } // create the point reader laszip_dll->reader = new LASreadPoint(laszip_dll->las14_decompress_selective); if (laszip_dll->reader == 0) { sprintf(laszip_dll->error, "could not alloc LASreadPoint"); return 1; } if (!laszip_dll->reader->setup(laszip->num_items, laszip->items, laszip)) { sprintf(laszip_dll->error, "setup of LASreadPoint failed"); return 1; } if (!laszip_dll->reader->init(laszip_dll->streamin)) { sprintf(laszip_dll->error, "init of LASreadPoint failed"); return 1; } delete laszip; // set the point number and point count laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records); laszip_dll->p_count = 0; laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_reader( laszip_POINTER pointer , const laszip_CHAR* file_name , laszip_BOOL* is_compressed ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (file_name == 0) { sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero"); return 1; } if (is_compressed == 0) { sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } // open the file #ifdef _MSC_VER wchar_t* utf16_file_name = UTF8toUTF16(file_name); laszip_dll->file = _wfopen(utf16_file_name, L"rb"); delete [] utf16_file_name; #else laszip_dll->file = fopen(file_name, "rb"); #endif if (laszip_dll->file == 0) { sprintf(laszip_dll->error, "cannot open file '%s'", file_name); return 1; } if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0) { sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n"); } if (IS_LITTLE_ENDIAN()) laszip_dll->streamin = new ByteStreamInFileLE(laszip_dll->file); else laszip_dll->streamin = new ByteStreamInFileBE(laszip_dll->file); if (laszip_dll->streamin == 0) { sprintf(laszip_dll->error, "could not alloc ByteStreamInFile"); return 1; } // read the header variable after variable if (laszip_read_header(laszip_dll, is_compressed)) { return 1; } // should we try to exploit existing spatial indexing information if (laszip_dll->lax_exploit) { laszip_dll->lax_index = new LASindex(); if (!laszip_dll->lax_index->read(file_name)) { delete laszip_dll->lax_index; laszip_dll->lax_index = 0; } } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_open_reader"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_has_spatial_index( laszip_POINTER pointer , laszip_BOOL* is_indexed , laszip_BOOL* is_appended ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (is_indexed == 0) { sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_indexed' is zero"); return 1; } if (laszip_dll->reader == 0) { sprintf(laszip_dll->error, "reader is not open"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } if (laszip_dll->lax_exploit == 0) { sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader"); return 1; } // check if reader found spatial indexing information when opening file if (laszip_dll->lax_index) { *is_indexed = 1; } else { *is_indexed = 0; } // optional: inform whether spatial index is appended to LAZ file or in separate LAX file if (is_appended) { *is_appended = 0; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_have_spatial_index"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_inside_rectangle( laszip_POINTER pointer , const laszip_F64 r_min_x , const laszip_F64 r_min_y , const laszip_F64 r_max_x , const laszip_F64 r_max_y , laszip_BOOL* is_empty ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader == 0) { sprintf(laszip_dll->error, "reader is not open"); return 1; } if (is_empty == 0) { sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_empty' is zero"); return 1; } if (laszip_dll->lax_exploit == FALSE) { sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader"); return 1; } laszip_dll->lax_r_min_x = r_min_x; laszip_dll->lax_r_min_y = r_min_y; laszip_dll->lax_r_max_x = r_max_x; laszip_dll->lax_r_max_y = r_max_y; if (laszip_dll->lax_index) { if (laszip_dll->lax_index->intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) { *is_empty = 0; } else { // no overlap between spatial indexing cells and query reactangle *is_empty = 1; } } else { if ((laszip_dll->header.min_x > r_max_x) || (laszip_dll->header.min_y > r_max_y) || (laszip_dll->header.max_x < r_min_x) || (laszip_dll->header.max_y < r_min_y)) { // no overlap between header bouding box and query reactangle *is_empty = 1; } else { *is_empty = 0; } } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_inside_rectangle"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_seek_point( laszip_POINTER pointer , laszip_I64 index ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { // seek to the point if (!laszip_dll->reader->seek((U32)laszip_dll->p_count, (U32)index)) { #ifdef _WIN32 sprintf(laszip_dll->error, "seeking from index %I64d to index %I64d for file with %I64d points", laszip_dll->p_count, index, laszip_dll->npoints); #else sprintf(laszip_dll->error, "seeking from index %lld to index %lld for file with %lld points", laszip_dll->p_count, index, laszip_dll->npoints); #endif return 1; } laszip_dll->p_count = index; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_seek_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_read_point( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { // read the point if (!laszip_dll->reader->read(laszip_dll->point_items)) { #ifdef _WIN32 sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints); #else sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints); #endif return 1; } // special recoding of points (in compatibility mode only) if (laszip_dll->compatibility_mode) { I16 scan_angle_remainder; U8 extended_returns; U8 classification; U8 flags_and_channel; I32 return_number_increment; I32 number_of_returns_increment; I32 overlap_bit; I32 scanner_channel; // instill extended attributes struct laszip_point* point = &laszip_dll->point; // get extended attributes from extra bytes scan_angle_remainder = *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle)); extended_returns = point->extra_bytes[laszip_dll->start_extended_returns]; classification = point->extra_bytes[laszip_dll->start_classification]; flags_and_channel = point->extra_bytes[laszip_dll->start_flags_and_channel]; if (laszip_dll->start_NIR_band != -1) { point->rgb[3] = *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band)); } // decompose into individual attributes return_number_increment = (extended_returns >> 4) & 0x0F; number_of_returns_increment = extended_returns & 0x0F; scanner_channel = (flags_and_channel >> 1) & 0x03; overlap_bit = flags_and_channel & 0x01; // instill into point point->extended_scan_angle = scan_angle_remainder + I16_QUANTIZE(((F32)point->scan_angle_rank) / 0.006f); point->extended_return_number = return_number_increment + point->return_number; point->extended_number_of_returns = number_of_returns_increment + point->number_of_returns; point->extended_classification = classification + point->classification; point->extended_scanner_channel = scanner_channel; point->extended_classification_flags = (overlap_bit << 3) | ((point->withheld_flag) << 2) | ((point->keypoint_flag) << 1) | (point->synthetic_flag); } laszip_dll->p_count++; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_read_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_read_inside_point( laszip_POINTER pointer , laszip_BOOL* is_done ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { laszip_F64 xy; *is_done = 1; if (laszip_dll->lax_index) { while (laszip_dll->lax_index->seek_next(laszip_dll->reader, laszip_dll->p_count)) { if (laszip_dll->reader->read(laszip_dll->point_items)) { laszip_dll->p_count++; xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset; if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue; xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset; if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue; *is_done = 0; break; } } } else { while (laszip_dll->reader->read(laszip_dll->point_items)) { laszip_dll->p_count++; xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset; if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue; xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset; if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue; *is_done = 0; break; } if (*is_done) { if (laszip_dll->p_count < laszip_dll->npoints) { #ifdef _WIN32 sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints); #else sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints); #endif return 1; } } } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_read_inside_point"); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_close_reader( laszip_POINTER pointer ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->reader == 0) { sprintf(laszip_dll->error, "closing reader before it was opened"); return 1; } if (!laszip_dll->reader->done()) { sprintf(laszip_dll->error, "done of LASreadPoint failed"); return 1; } delete laszip_dll->reader; laszip_dll->reader = 0; delete [] laszip_dll->point_items; laszip_dll->point_items = 0; delete laszip_dll->streamin; laszip_dll->streamin = 0; if (laszip_dll->lax_index) { delete laszip_dll->lax_index; laszip_dll->lax_index = 0; } if (laszip_dll->file) { fclose(laszip_dll->file); laszip_dll->file = 0; } } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_close_reader"); return 1; } laszip_dll->error[0] = '\0'; return 0; } #ifdef __cplusplus /*---------------------------------------------------------------------------*/ LASZIP_API laszip_I32 laszip_open_reader_stream( laszip_POINTER pointer , istream& stream , laszip_BOOL* is_compressed ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (is_compressed == 0) { sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero"); return 1; } if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } // open the file if (IS_LITTLE_ENDIAN()) laszip_dll->streamin = new ByteStreamInIstreamLE(stream); else laszip_dll->streamin = new ByteStreamInIstreamBE(stream); if (laszip_dll->streamin == 0) { sprintf(laszip_dll->error, "could not alloc ByteStreamInIstream"); return 1; } return laszip_read_header(laszip_dll, is_compressed); } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_open_reader"); return 1; } } /*---------------------------------------------------------------------------*/ // The stream writer also supports software that writes the LAS header on its // own simply by setting the BOOL 'do_not_write_header' to TRUE. This function // should then be called just prior to writing points as data is then written // to the current stream position LASZIP_API laszip_I32 laszip_open_writer_stream( laszip_POINTER pointer , ostream& stream , laszip_BOOL compress , laszip_BOOL do_not_write_header ) { if (pointer == 0) return 1; laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer; try { if (laszip_dll->writer) { sprintf(laszip_dll->error, "writer is already open"); return 1; } if (laszip_dll->reader) { sprintf(laszip_dll->error, "reader is already open"); return 1; } // create the outstream if (IS_LITTLE_ENDIAN()) laszip_dll->streamout = new ByteStreamOutOstreamLE(stream); else laszip_dll->streamout = new ByteStreamOutOstreamBE(stream); if (laszip_dll->streamout == 0) { sprintf(laszip_dll->error, "could not alloc ByteStreamOutOstream"); return 1; } // setup the items that make up the point LASzip laszip; if (setup_laszip_items(laszip_dll, &laszip, compress)) { return 1; } // this supports software that writes the LAS header on its own if (do_not_write_header == FALSE) { // prepare header if (laszip_prepare_header_for_write(laszip_dll)) { return 1; } // prepare point if (laszip_prepare_point_for_write(laszip_dll, compress)) { return 1; } // prepare VLRs if (laszip_prepare_vlrs_for_write(laszip_dll)) { return 1; } // write header variable after variable if (laszip_write_header(laszip_dll, &laszip, compress)) { return 1; } } // create the point writer if (create_point_writer(laszip_dll, &laszip)) { return 1; } // set the point number and point count laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records); laszip_dll->p_count = 0; } catch (...) { sprintf(laszip_dll->error, "internal error in laszip_open_writer_stream."); return 1; } laszip_dll->error[0] = '\0'; return 0; } /*---------------------------------------------------------------------------*/ // creates complete LASzip VLR for currently selected point type and compression // The VLR data is valid until the laszip_dll pointer is destroyed. LASZIP_API laszip_I32 laszip_create_laszip_vlr( laszip_POINTER pointer , laszip_U8** vlr , laszip_U32* vlr_size ) { if (pointer == 0) return 1; laszip_dll_struct *laszip_dll = (laszip_dll_struct *)pointer; LASzip laszip; if (setup_laszip_items(laszip_dll, &laszip, TRUE)) { return 1; } ByteStreamOutArray* out = 0; if (IS_LITTLE_ENDIAN()) out = new ByteStreamOutArrayLE(); else out = new ByteStreamOutArrayBE(); if (out == 0) { sprintf(laszip_dll->error, "could not alloc ByteStreamOutArray"); return 1; } if (write_laszip_vlr_header(laszip_dll, &laszip, out)) { return 1; } if (write_laszip_vlr_payload(laszip_dll, &laszip, out)) { return 1; } *vlr = (laszip_U8*)malloc(out->getSize()); *vlr_size = (U32)out->getSize(); laszip_dll->buffers.push_back(*vlr); memcpy(*vlr, out->getData(), out->getSize()); delete out; laszip_dll->error[0] = '\0'; return 0; } #endif // __cplusplus LASzip-3.4.3/src/laszipper.cpp000066400000000000000000000072021356234217100161740ustar00rootroot00000000000000/* =============================================================================== FILE: laszipper.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "laszipper.hpp" #include #include #include "bytestreamout_file.hpp" #include "bytestreamout_ostream.hpp" #include "laswritepoint.hpp" bool LASzipper::open(FILE* outfile, const LASzip* laszip) { if (!outfile) return return_error("FILE* outfile pointer is NULL"); if (!laszip) return return_error("const LASzip* laszip pointer is NULL"); count = 0; if (writer) delete writer; writer = new LASwritePoint(); if (!writer) return return_error("alloc of LASwritePoint failed"); if (!writer->setup(laszip->num_items, laszip->items, laszip)) return return_error("setup() of LASwritePoint failed"); if (stream) delete stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamOutFileLE(outfile); else stream = new ByteStreamOutFileBE(outfile); if (!stream) return return_error("alloc of ByteStreamOutFile failed"); if (!writer->init(stream)) return return_error("init() of LASwritePoint failed"); return true; } bool LASzipper::open(ostream& outstream, const LASzip* laszip) { if (!laszip) return return_error("const LASzip* laszip pointer is NULL"); count = 0; if (writer) delete writer; writer = new LASwritePoint(); if (!writer) return return_error("alloc of LASwritePoint failed"); if (!writer->setup(laszip->num_items, laszip->items, laszip)) return return_error("setup() of LASwritePoint failed"); if (stream) delete stream; if (IS_LITTLE_ENDIAN()) stream = new ByteStreamOutOstreamLE(outstream); else stream = new ByteStreamOutOstreamBE(outstream); if (!stream) return return_error("alloc of ByteStreamOutStream failed"); if (!writer->init(stream)) return return_error("init() of LASwritePoint failed"); return true; } bool LASzipper::write(const unsigned char * const * point) { count++; return (writer->write(point) == TRUE); } bool LASzipper::chunk() { if (!writer->chunk()) return return_error("chunk() of LASwritePoint failed"); return true; } bool LASzipper::close() { BOOL done = TRUE; if (writer) { done = writer->done(); delete writer; writer = 0; } if (stream) { delete stream; stream = 0; } if (!done) return return_error("done() of LASwritePoint failed"); return true; } const char* LASzipper::get_error() const { return error_string; } bool LASzipper::return_error(const char* error) { char err[256]; sprintf(err, "%s (LASzip v%d.%dr%d)", error, LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION); if (error_string) free(error_string); error_string = LASCopyString(err); return false; } LASzipper::LASzipper() { error_string = 0; count = 0; stream = 0; writer = 0; } LASzipper::~LASzipper() { if (error_string) free(error_string); if (writer || stream) close(); } LASzip-3.4.3/src/laszipper.hpp000066400000000000000000000040211356234217100161750ustar00rootroot00000000000000/* =============================================================================== FILE: laszipper.hpp CONTENTS: Writes (optionally compressed) LIDAR points to LAS formats 1.0 - 1.3. This particular class is only used for adding LASzip to libLAS (not to LASlib). PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2007-2013, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 8 May 2011 -- added an option for variable chunking via chunk() 23 April 2011 -- changed interface for simplicity and chunking support 10 January 2011 -- licensing change for LGPL release and liblas integration 12 December 2010 -- created from LASwriter/LASreader after Howard got pushy (-; =============================================================================== */ #ifndef LAS_ZIPPER_HPP #define LAS_ZIPPER_HPP #include #include "laszip.hpp" #ifdef LZ_WIN32_VC6 #include #else #include #include using namespace std; #endif class ByteStreamOut; class LASwritePoint; class LASzipper { public: bool open(FILE* outfile, const LASzip* laszip); bool open(ostream& outstream, const LASzip* laszip); bool write(const unsigned char* const * point); bool chunk(); bool close(); LASzipper(); ~LASzipper(); // in case a function returns false this string describes the problem const char* get_error() const; private: unsigned int count; ByteStreamOut* stream; LASwritePoint* writer; bool return_error(const char* err); char* error_string; }; #endif LASzip-3.4.3/src/mydefs.cpp000066400000000000000000000022051356234217100154500ustar00rootroot00000000000000/* =============================================================================== FILE: mydefs.cpp CONTENTS: see corresponding header file PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2011-2019, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the LICENSE.txt file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see corresponding header file =============================================================================== */ #include "mydefs.hpp" #if defined(_MSC_VER) #include wchar_t* UTF8toUTF16(const char* utf8) { wchar_t* utf16 = 0; int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, 0, 0); if (len > 0) { utf16 = new wchar_t[len]; MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, len); } return utf16; } #endif LASzip-3.4.3/src/mydefs.hpp000066400000000000000000000174001356234217100154600ustar00rootroot00000000000000/* =============================================================================== FILE: mydefs.hpp CONTENTS: Basic data type definitions and operations to be robust across platforms. PROGRAMMERS: martin.isenburg@rapidlasso.com - http://rapidlasso.com COPYRIGHT: (c) 2005-2015, martin isenburg, rapidlasso - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software Foundation. See the COPYING file for more information. This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 28 October 2015 -- adding DLL bindings via 'COMPILE_AS_DLL' and 'USE_AS_DLL' 10 January 2011 -- licensing change for LGPL release and libLAS integration 13 July 2005 -- created after returning with many mosquito bites from OBX =============================================================================== */ #ifndef MYDEFS_HPP #define MYDEFS_HPP #ifndef _WIN32 #define LASLIB_DLL #else // _WIN32 #ifdef COMPILE_AS_DLL #define LASLIB_DLL __declspec(dllexport) #elif USE_AS_DLL #define LASLIB_DLL __declspec(dllimport) #else #define LASLIB_DLL #endif #endif // _WIN32 typedef char CHAR; typedef int I32; typedef short I16; typedef char I8; typedef unsigned int U32; typedef unsigned short U16; typedef unsigned char U8; #if defined(_WIN32) && ! defined (__MINGW32__) // 64 byte integer under Windows typedef unsigned __int64 U64; typedef __int64 I64; #else // 64 byte integer elsewhere ... typedef unsigned long long U64; typedef long long I64; #endif typedef float F32; typedef double F64; #if defined(_MSC_VER) || defined (__MINGW32__) typedef int BOOL; #else typedef bool BOOL; #endif typedef union U32I32F32 { U32 u32; I32 i32; F32 f32; } U32I32F32; typedef union U64I64F64 { U64 u64; I64 i64; F64 f64; } U64I64F64; typedef union I64U32I32F32 { I64 i64; U32 u32[2]; I32 i32[2]; F32 f32[2]; } I64U32I32F32; #define F32_MAX +2.0e+37f #define F32_MIN -2.0e+37f #define F64_MAX +2.0e+307 #define F64_MIN -2.0e+307 #define U8_MIN ((U8)0x0) // 0 #define U8_MAX ((U8)0xFF) // 255 #define U8_MAX_MINUS_ONE ((U8)0xFE) // 254 #define U8_MAX_PLUS_ONE 0x0100 // 256 #define U16_MIN ((U16)0x0) // 0 #define U16_MAX ((U16)0xFFFF) // 65535 #define U16_MAX_MINUS_ONE ((U16)0xFFFE) // 65534 #define U16_MAX_PLUS_ONE 0x00010000 // 65536 #define U32_MIN ((U32)0x0) // 0 #define U32_MAX ((U32)0xFFFFFFFF) // 4294967295 #define U32_MAX_MINUS_ONE ((U32)0xFFFFFFFE) // 4294967294 #if defined(WIN32) // 64 byte unsigned int constant under Windows #define U32_MAX_PLUS_ONE 0x0000000100000000 // 4294967296 #else // 64 byte unsigned int constant elsewhere ... #define U32_MAX_PLUS_ONE 0x0000000100000000ull // 4294967296 #endif #define I8_MIN ((I8)0x80) // -128 #define I8_MAX ((I8)0x7F) // 127 #define I16_MIN ((I16)0x8000) // -32768 #define I16_MAX ((I16)0x7FFF) // 32767 #define I32_MIN ((I32)0x80000000) // -2147483648 #define I32_MAX ((I32)0x7FFFFFFF) // 2147483647 #define I64_MIN ((I64)0x8000000000000000) #define I64_MAX ((I64)0x7FFFFFFFFFFFFFFF) #define U8_FOLD(n) (((n) < U8_MIN) ? (n+U8_MAX_PLUS_ONE) : (((n) > U8_MAX) ? (n-U8_MAX_PLUS_ONE) : (n))) #define I8_CLAMP(n) (((n) <= I8_MIN) ? I8_MIN : (((n) >= I8_MAX) ? I8_MAX : ((I8)(n)))) #define U8_CLAMP(n) (((n) <= U8_MIN) ? U8_MIN : (((n) >= U8_MAX) ? U8_MAX : ((U8)(n)))) #define I16_CLAMP(n) (((n) <= I16_MIN) ? I16_MIN : (((n) >= I16_MAX) ? I16_MAX : ((I16)(n)))) #define U16_CLAMP(n) (((n) <= U16_MIN) ? U16_MIN : (((n) >= U16_MAX) ? U16_MAX : ((U16)(n)))) #define I32_CLAMP(n) (((n) <= I32_MIN) ? I32_MIN : (((n) >= I32_MAX) ? I32_MAX : ((I32)(n)))) #define U32_CLAMP(n) (((n) <= U32_MIN) ? U32_MIN : (((n) >= U32_MAX) ? U32_MAX : ((U32)(n)))) #define I8_QUANTIZE(n) (((n) >= 0) ? (I8)((n)+0.5) : (I8)((n)-0.5)) #define U8_QUANTIZE(n) (((n) >= 0) ? (U8)((n)+0.5) : (U8)(0)) #define I16_QUANTIZE(n) (((n) >= 0) ? (I16)((n)+0.5) : (I16)((n)-0.5)) #define U16_QUANTIZE(n) (((n) >= 0) ? (U16)((n)+0.5) : (U16)(0)) #define I32_QUANTIZE(n) (((n) >= 0) ? (I32)((n)+0.5) : (I32)((n)-0.5)) #define U32_QUANTIZE(n) (((n) >= 0) ? (U32)((n)+0.5) : (U32)(0)) #define I64_QUANTIZE(n) (((n) >= 0) ? (I64)((n)+0.5) : (I64)((n)-0.5)) #define U64_QUANTIZE(n) (((n) >= 0) ? (U64)((n)+0.5) : (U64)(0)) #define I16_FLOOR(n) ((((I16)(n)) > (n)) ? (((I16)(n))-1) : ((I16)(n))) #define I32_FLOOR(n) ((((I32)(n)) > (n)) ? (((I32)(n))-1) : ((I32)(n))) #define I64_FLOOR(n) ((((I64)(n)) > (n)) ? (((I64)(n))-1) : ((I64)(n))) #define I16_CEIL(n) ((((I16)(n)) < (n)) ? (((I16)(n))+1) : ((I16)(n))) #define I32_CEIL(n) ((((I32)(n)) < (n)) ? (((I32)(n))+1) : ((I32)(n))) #define I64_CEIL(n) ((((I64)(n)) < (n)) ? (((I64)(n))+1) : ((I64)(n))) #define I8_FITS_IN_RANGE(n) (((n) >= I8_MIN) && ((n) <= I8_MAX) ? TRUE : FALSE) #define U8_FITS_IN_RANGE(n) (((n) >= U8_MIN) && ((n) <= U8_MAX) ? TRUE : FALSE) #define I16_FITS_IN_RANGE(n) (((n) >= I16_MIN) && ((n) <= I16_MAX) ? TRUE : FALSE) #define U16_FITS_IN_RANGE(n) (((n) >= U16_MIN) && ((n) <= U16_MAX) ? TRUE : FALSE) #define I32_FITS_IN_RANGE(n) (((n) >= I32_MIN) && ((n) <= I32_MAX) ? TRUE : FALSE) #define U32_FITS_IN_RANGE(n) (((n) >= U32_MIN) && ((n) <= U32_MAX) ? TRUE : FALSE) #define F32_IS_FINITE(n) ((F32_MIN < (n)) && ((n) < F32_MAX)) #define F64_IS_FINITE(n) ((F64_MIN < (n)) && ((n) < F64_MAX)) #define U32_ZERO_BIT_0(n) (((n)&(U32)0xFFFFFFFE)) #define U32_ZERO_BIT_0_1(n) (((n)&(U32)0xFFFFFFFC)) #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef NULL #define NULL 0 #endif inline BOOL IS_LITTLE_ENDIAN() { const U32 i = 1; return (*((const U8*)&i) == 1); } #define ENDIANSWAP16(n) \ ( ((((U16) n) << 8) & 0xFF00) | \ ((((U16) n) >> 8) & 0x00FF) ) #define ENDIANSWAP32(n) \ ( ((((U32) n) << 24) & 0xFF000000) | \ ((((U32) n) << 8) & 0x00FF0000) | \ ((((U32) n) >> 8) & 0x0000FF00) | \ ((((U32) n) >> 24) & 0x000000FF) ) inline void ENDIAN_SWAP_16(U8* field) { U8 help = field[0]; field[0] = field[1]; field[1] = help; } inline void ENDIAN_SWAP_32(U8* field) { U8 help; help = field[0]; field[0] = field[3]; field[3] = help; help = field[1]; field[1] = field[2]; field[2] = help; } inline void ENDIAN_SWAP_64(U8* field) { U8 help; help = field[0]; field[0] = field[7]; field[7] = help; help = field[1]; field[1] = field[6]; field[6] = help; help = field[2]; field[2] = field[5]; field[5] = help; help = field[3]; field[3] = field[4]; field[4] = help; } inline void ENDIAN_SWAP_16(const U8* from, U8* to) { to[0] = from[1]; to[1] = from[0]; } inline void ENDIAN_SWAP_32(const U8* from, U8* to) { to[0] = from[3]; to[1] = from[2]; to[2] = from[1]; to[3] = from[0]; } inline void ENDIAN_SWAP_64(const U8* from, U8* to) { to[0] = from[7]; to[1] = from[6]; to[2] = from[5]; to[3] = from[4]; to[4] = from[3]; to[5] = from[2]; to[6] = from[1]; to[7] = from[0]; } #if defined(_MSC_VER) #include wchar_t* UTF8toUTF16(const char* utf8); #endif #endif LASzip-3.4.3/tools/000077500000000000000000000000001356234217100140275ustar00rootroot00000000000000LASzip-3.4.3/tools/laszip-config.in000066400000000000000000000013531356234217100171260ustar00rootroot00000000000000#!/bin/sh prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ INCLUDES="-I${prefix}/include " LIBS="-L$libdir -llaszip" usage() { cat <&2 fi case $1 in --libs) echo $LIBS ;; --prefix) echo ${prefix} ;; --ldflags) echo -L${libdir} ;; --defines) echo @LASZIP_CONFIG_DEFINITIONS@ @DEFS@ ;; --includes) echo ${INCLUDES} ;; --cflags) echo @CMAKE_C_FLAGS@ @CFLAGS@ ;; --cxxflags) echo @CMAKE_CXX_FLAGS@ @CXXFLAGS@ ;; --version) echo @VERSION@ ;; *) usage 1 1>&2 ;; esac LASzip-3.4.3/unused/000077500000000000000000000000001356234217100141725ustar00rootroot00000000000000LASzip-3.4.3/unused/rangedecoder.cpp000066400000000000000000000151051356234217100173220ustar00rootroot00000000000000/****************************************************************************** * * Project: integrating laszip into liblas - http://liblas.org - * Purpose: * Author: Martin Isenburg * isenburg at cs.unc.edu * ****************************************************************************** * Copyright (c) 2010, Martin Isenburg * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Licence as published * by the Free Software Foundation. * * See the COPYING file for more information. * ****************************************************************************/ /* =============================================================================== FILE: rangedecoder.cpp CONTENTS: see header file PROGRAMMERS: martin isenburg@cs.unc.edu COPYRIGHT: copyright (C) 2003 martin isenburg (isenburg@cs.unc.edu) This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ #include "rangedecoder.hpp" #include "rangemodel.hpp" #include #include RangeDecoder::RangeDecoder() { instream = 0; } RangeDecoder::~RangeDecoder() { } I32 RangeDecoder::init(ByteStreamIn* instream) { assert(instream); this->instream = instream; buffer = instream->getByte(); assert(buffer == HEADERBYTE); buffer = instream->getByte(); low = buffer >> (8-EXTRA_BITS); range = (U32)1 << EXTRA_BITS; return 0; } void RangeDecoder::done() { normalize(); /* use up all bytes */ instream = 0; } EntropyModel* RangeDecoder::createBitModel() { return createSymbolModel(2); } void RangeDecoder::initBitModel(EntropyModel* model) { initSymbolModel(model); } void RangeDecoder::destroyBitModel(EntropyModel* model) { destroySymbolModel(model); } EntropyModel* RangeDecoder::createSymbolModel(U32 n) { RangeModel* m = new RangeModel(n, FALSE); return (EntropyModel*)m; } void RangeDecoder::initSymbolModel(EntropyModel* model, U32 *table) { assert(model); RangeModel* m = (RangeModel*)model; m->init(table); } void RangeDecoder::destroySymbolModel(EntropyModel* model) { RangeModel* m = (RangeModel*)model; delete m; } U32 RangeDecoder::decodeBit(EntropyModel* model) { return decodeSymbol(model); } U32 RangeDecoder::decodeSymbol(EntropyModel* model) { RangeModel* m = (RangeModel*)model; U32 sym; U32 ltfreq; U32 syfreq; U32 tmp; U32 lg_totf = m->lg_totf; normalize(); help = this->range>>lg_totf; ltfreq = low/help; #ifdef EXTRAFAST ltfreq = ltfreq; #else ltfreq = ((ltfreq>>lg_totf) ? (1<getsym(ltfreq); m->getfreq(sym,&syfreq,<freq); tmp = help * ltfreq; low -= tmp; #ifdef EXTRAFAST this->range = help * syfreq; #else if ((ltfreq + syfreq) < (1u<range = help * syfreq; } else { this->range -= tmp; } #endif m->update(sym); return sym; } /* Decode a bit without modelling */ U32 RangeDecoder::readBit() { U32 tmp; tmp = culshift(1); update(1, tmp, 2); return tmp; } /* Decode bits without modelling */ U32 RangeDecoder::readBits(U32 bits) { U32 tmp; if (bits > 21) // 22 bits { tmp = readShort(); U32 tmp1 = readBits(bits - 16) << 16; return (tmp1|tmp); } tmp = culshift(bits); update(1, tmp, 1u<>shift; tmp = low/help; #ifdef EXTRAFAST return tmp; #else return (tmp>>shift ? (1u<range = help * sy_f; #else if (lt_f + sy_f < tot_f) { this->range = help * sy_f; } else { this->range -= tmp; } #endif } inline void RangeDecoder::normalize() { while (range <= BOTTOM_VALUE) { low = (low<<8) | ((buffer<getByte(); low |= buffer >> (8-EXTRA_BITS); range <<= 8; } } /* U32 RangeDecoder::readRange(U32 range) { U32 tmp; U32 tmp1; if (range > 4194303) // 22 bits { tmp = readShort(); range = range >> 16; range++; tmp1 = readRange(range) << 16; return (tmp1|tmp); } normalize(); help = this->range/range; tmp = low/help; #ifdef EXTRAFAST tmp = tmp; #else tmp = (tmp>=range ? range-1 : tmp); #endif tmp1 = (help * tmp); low -= tmp1; #ifdef EXTRAFAST this->range = help; #else if (tmp+1 < range) { this->range = help; } else { this->range -= tmp1; } #endif return tmp; } U64 RangeDecoder::readRange64(U64 range) { if (range > U32_MAX) // 32 bits { U64 tmp; U64 tmp1; tmp = readInt(); range = range >> 32; range++; tmp1 = ((U64)(readRange((U32)(range)))) << 32; return (tmp1|tmp); } else { return (U64)(readRange((U32)(range))); } } */ LASzip-3.4.3/unused/rangedecoder.hpp000066400000000000000000000075761356234217100173440ustar00rootroot00000000000000/****************************************************************************** * * Project: integrating laszip into liblas - http://liblas.org - * Purpose: * Author: Martin Isenburg * isenburg at cs.unc.edu * ****************************************************************************** * Copyright (c) 2010, Martin Isenburg * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Licence as published * by the Free Software Foundation. * * See the COPYING file for more information. * ****************************************************************************/ /* =============================================================================== FILE: rangedecoder.hpp CONTENTS: PROGRAMMERS: martin isenburg@cs.unc.edu COPYRIGHT: Copyright (C) 2003 Martin Isenburg (isenburg@cs.unc.edu) This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 15 December 2010 -- unified framework for all entropy coders 8 December 2010 -- unified framework for all entropy coders 14 January 2003 -- adapted from michael schindler's code before SIGGRAPH =============================================================================== */ #ifndef RANGEDECODER_HPP #define RANGEDECODER_HPP #include "entropydecoder.hpp" class RangeDecoder : public EntropyDecoder { public: /* Constructor & Destructor */ RangeDecoder(); ~RangeDecoder(); /* Manage decoding */ I32 init(ByteStreamIn* instream); void done(); /* Manage an entropy model for a single bit */ EntropyModel* createBitModel(); void initBitModel(EntropyModel* model); void destroyBitModel(EntropyModel* model); /* Manage an entropy model for n symbols (table optional) */ EntropyModel* createSymbolModel(U32 n); void initSymbolModel(EntropyModel* model, U32 *init=0); void destroySymbolModel(EntropyModel* model); /* Decode a bit with modelling */ U32 decodeBit(EntropyModel* model); /* Decode a symbol with modelling */ U32 decodeSymbol(EntropyModel* model); /* Decode a bit without modelling */ U32 readBit(); /* Decode bits without modelling */ U32 readBits(U32 bits); /* Decode an unsigned char without modelling */ U8 readByte(); /* Decode an unsigned short without modelling */ U16 readShort(); /* Decode an unsigned int without modelling */ U32 readInt(); /* Decode a float without modelling */ F32 readFloat(); /* Decode an unsigned 64 bit int without modelling */ U64 readInt64(); /* Decode a double without modelling */ F64 readDouble(); private: ByteStreamIn* instream; /* Calculate culmulative frequency for next symbol, no update*/ /* tot_f is the total frequency */ /* or: totf is 1< #include RangeEncoder::RangeEncoder() { outstream = 0; } RangeEncoder::~RangeEncoder() { } I32 RangeEncoder::init(ByteStreamOut* outstream) { assert(outstream); this->outstream = outstream; low = 0; /* Full code range */ range = TOP_VALUE; /* this buffer is written as first byte in the datastream (header,...) */ buffer = HEADERBYTE; help = 0; /* No bytes to follow */ return 0; } /* Finish encoding */ /* actually not that many bytes need to be output, but who */ /* cares. I output them because decode will read them :) */ /* the return value is the number of bytes written */ void RangeEncoder::done() { U32 tmp; normalize(); /* now we have a normalized state */ bytecount += 5; if ((low & (BOTTOM_VALUE-1)) < ((bytecount&0xffffffL)>>1)) { tmp = low >> SHIFT_BITS; } else { tmp = (low >> SHIFT_BITS) + 1; } if (tmp > 0xff) /* we have a carry */ { outstream->putByte(buffer+1); for(; help; help--) { outstream->putByte(0); } } else /* no carry */ { outstream->putByte(buffer); for(; help; help--) { outstream->putByte(0xff); } } outstream->putByte(tmp & 0xff); outstream->putByte((bytecount>>16) & 0xff); outstream->putByte((bytecount>>8) & 0xff); outstream->putByte(bytecount & 0xff); outstream = 0; } EntropyModel* RangeEncoder::createBitModel() { return createSymbolModel(2); } void RangeEncoder::initBitModel(EntropyModel* model) { initSymbolModel(model); } void RangeEncoder::destroyBitModel(EntropyModel* model) { destroySymbolModel(model); } EntropyModel* RangeEncoder::createSymbolModel(U32 n) { RangeModel* m = new RangeModel(n, TRUE); return (EntropyModel*)m; } void RangeEncoder::initSymbolModel(EntropyModel* model, U32 *table) { assert(model); RangeModel* m = (RangeModel*)model; m->init(table); } void RangeEncoder::destroySymbolModel(EntropyModel* model) { assert(model); RangeModel* m = (RangeModel*)model; delete m; } void RangeEncoder::encodeBit(EntropyModel* model, U32 bit) { encodeSymbol(model, bit); } void RangeEncoder::encodeSymbol(EntropyModel* model, U32 sym) { assert(model); RangeModel* m = (RangeModel*)model; assert(sym >= 0 && sym < (U32)(m->n)); U32 syfreq; U32 ltfreq; U32 r, tmp; U32 lg_totf = m->lg_totf; m->getfreq(sym,&syfreq,<freq); normalize(); r = range >> lg_totf; tmp = r * ltfreq; low += tmp; #ifdef EXTRAFAST range = r * syfreq; #else if ((ltfreq+syfreq) >> lg_totf) { range -= tmp; } else { range = r * syfreq; } #endif m->update(sym); } void RangeEncoder::writeBit(U32 sym) { assert(sym < 2); U32 r, tmp; normalize(); r = range >> 1; tmp = r * sym; low += tmp; #ifdef EXTRAFAST range = r; #else if ((sym+1) >> 1) { range -= tmp; } else { range = r; } #endif } void RangeEncoder::writeBits(U32 bits, U32 sym) { assert(bits && (sym < (1u< 21) // 22 bits { writeShort(sym&U16_MAX); sym = sym >> 16; bits = bits - 16; } U32 r, tmp; normalize(); r = range >> bits; tmp = r * sym; low += tmp; #ifdef EXTRAFAST range = r; #else if ((sym+1) >> bits) { range -= tmp; } else { range = r; } #endif } void RangeEncoder::writeByte(U8 sym) { U32 r, tmp; normalize(); r = range >> 8; tmp = r * (U32)(sym); low += tmp; #ifdef EXTRAFAST range = r; #else if (((U32)(sym)+1) >> 8) { range -= tmp; } else { range = r; } #endif } void RangeEncoder::writeShort(U16 sym) { U32 r, tmp; normalize(); r = range >> 16; tmp = r * (U32)(sym); low += tmp; #ifdef EXTRAFAST range = r; #else if (((U32)(sym)+1) >> 16) { range -= tmp; } else { range = r; } #endif } void RangeEncoder::writeInt(U32 sym) { writeShort((U16)(sym % U16_MAX_PLUS_ONE)); // lower 16 bits writeShort((U16)(sym / U16_MAX_PLUS_ONE)); // UPPER 16 bits } void RangeEncoder::writeInt64(U64 sym) { writeInt((U32)(sym % U32_MAX_PLUS_ONE)); // lower 32 bits writeInt((U32)(sym / U32_MAX_PLUS_ONE)); // UPPER 32 bits } void RangeEncoder::writeFloat(F32 sym) { U32F32 u32f32; u32f32.f32 = sym; writeInt(u32f32.u32); } void RangeEncoder::writeDouble(F64 sym) { U64F64 u64f64; u64f64.f64 = sym; writeInt64(u64f64.u64); } /* I do the normalization before I need a defined state instead of */ /* after messing it up. This simplifies starting and ending. */ inline void RangeEncoder::normalize() { while(range <= BOTTOM_VALUE) /* do we need renormalisation? */ { if (low < (U32)0xff< output */ { outstream->putByte(buffer); for(; help; help--) { outstream->putByte(0xff); } buffer = (U8)(low >> SHIFT_BITS); } else if (low & TOP_VALUE) /* carry now, no future carry */ { outstream->putByte(buffer+1); for(; help; help--) { outstream->putByte(0); } buffer = (U8)(low >> SHIFT_BITS); } else /* passes on a potential carry */ { help++; } range <<= 8; low = (low<<8) & (TOP_VALUE-1); bytecount++; } } /* void RangeEncoder::writeRange(U32 range, U32 sym) { assert(range && (sym < range)); if (range > 4194303) // 22 bits { writeShort(sym&U16_MAX); sym = sym >> 16; range = range >> 16; range++; } U32 r, tmp; normalize(); r = this->range / range; tmp = r * sym; low += tmp; #ifdef EXTRAFAST this->range = r; #else if (sym+1 < range) { this->range = r; } else { this->range -= tmp; } #endif } void RangeEncoder::writeRange64(U64 range, U64 sym) { assert(sym < range); if (range > U32_MAX) // 32 bits { writeInt((U32)(sym&U32_MAX)); sym = sym >> 32; range = range >> 32; range++; } writeRange((U32)range, (U32)sym); } */ LASzip-3.4.3/unused/rangeencoder.hpp000066400000000000000000000071301356234217100173400ustar00rootroot00000000000000/****************************************************************************** * * Project: integrating laszip into liblas - http://liblas.org - * Purpose: * Author: Martin Isenburg * isenburg at cs.unc.edu * ****************************************************************************** * Copyright (c) 2010, Martin Isenburg * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Licence as published * by the Free Software Foundation. * * See the COPYING file for more information. * ****************************************************************************/ /* =============================================================================== FILE: rangeencoder.hpp CONTENTS: PROGRAMMERS: martin isenburg@cs.unc.edu COPYRIGHT: Copyright (C) 2003 Martin Isenburg (isenburg@cs.unc.edu) This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: 15 December 2010 -- unified framework for all entropy coders 8 December 2010 -- unified framework for all entropy coders 28 June 2004 -- added an option for NOT storing the code characters at all 14 January 2003 -- adapted from michael schindler's code before SIGGRAPH =============================================================================== */ #ifndef RANGEENCODER_HPP #define RANGEENCODER_HPP #include "entropyencoder.hpp" class RangeEncoder : public EntropyEncoder { public: /* Constructor & Deconstructor */ RangeEncoder(); ~RangeEncoder(); /* Manage the encoder */ I32 init(ByteStreamOut* outstream); void done(); /* Manage an entropy model for a single bit */ EntropyModel* createBitModel(); void initBitModel(EntropyModel* model); void destroyBitModel(EntropyModel* model); /* Manage an entropy model for n symbols (table optional) */ EntropyModel* createSymbolModel(U32 n); void initSymbolModel(EntropyModel* model, U32 *init=0); void destroySymbolModel(EntropyModel* model); /* Encode with modelling */ void encodeBit(EntropyModel* model, U32 sym); /* Encode with modelling */ void encodeSymbol(EntropyModel* model, U32 sym); /* Encode a bit without modelling */ void writeBit(U32 sym); /* Encode bits without modelling */ void writeBits(U32 bits, U32 sym); /* Encode an unsigned char without modelling */ void writeByte(U8 sym); /* Encode an unsigned short without modelling */ void writeShort(U16 sym); /* Encode an unsigned int without modelling */ void writeInt(U32 sym); /* Encode a float without modelling */ void writeFloat(F32 sym); /* Encode an unsigned 64 bit int without modelling */ void writeInt64(U64 sym); /* Encode a double without modelling */ void writeDouble(F64 sym); private: ByteStreamOut* outstream; inline void normalize(); U32 low; /* low end of interval */ U32 range; /* length of interval */ U32 help; /* bytes_to_follow resp. intermediate value */ U8 buffer; /* buffer for input/output */ /* the following is used only when encoding */ U32 bytecount; /* counter for output bytes */ }; #endif LASzip-3.4.3/unused/rangemodel.cpp000066400000000000000000000124231356234217100170150ustar00rootroot00000000000000/****************************************************************************** * * Project: integrating laszip into liblas - http://liblas.org - * Purpose: * Author: Martin Isenburg * isenburg at cs.unc.edu * ****************************************************************************** * Copyright (c) 2010, Martin Isenburg * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Licence as published * by the Free Software Foundation. * * See the COPYING file for more information. * ****************************************************************************/ /* =============================================================================== FILE: rangemodel.cpp CONTENTS: see header file PROGRAMMERS: martin isenburg@cs.unc.edu COPYRIGHT: copyright (C) 2003 martin isenburg (isenburg@cs.unc.edu) This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. CHANGE HISTORY: see header file =============================================================================== */ #include "rangemodel.hpp" #include #include #include /* initialisation of model */ /* n number of symbols in that model */ /* compress set to 1 on compression, 0 on decompression */ /* targetrescale desired rescaling interval, should be < 1<<(lg_totf+1) */ /* lg_totf base2 log of total frequency count */ RangeModel::RangeModel(U32 n, BOOL compress, I32 targetrescale, I32 lg_totf) { this->n = n; this->targetrescale = targetrescale; this->lg_totf = lg_totf; cf = new U16[n+1]; newf = new U16[n+1]; if (lg_totf == 16) { cf[n] = 65535; } else { cf[n] = (1< targetrescale) { rescale = targetrescale; } } c = missing = cf[n]; /* do actual rescaling */ for(i=n-1; i; i--) { I32 tmp = newf[i]; c -= tmp; cf[i] = c; tmp = tmp>>1 | 1; missing -= tmp; newf[i] = tmp; } if (c!=newf[0]) { // fprintf(stderr,"BUG: rescaling left %d total frequency\n",c); // exit(1); throw std::runtime_error("internal error: RangeModel::dorescale()"); } newf[0] = newf[0]>>1 | 1; missing -= newf[0]; incr = missing / rescale; nextleft = missing % rescale; left = rescale - nextleft; if (search != NULL) { i=n; while (i) { I32 start, end; end = (cf[i]-1) >> searchshift; i--; start = cf[i] >> searchshift; while (start<=end) { search[start] = i; start++; } } } } /* reinitialisation of qsmodel */ /* table array of int's to be used for initialisation (NULL ok) */ void RangeModel::init(U32 *table) { U32 i, end, initval; rescale = n >> 4 | 2; nextleft = 0; if (table) { I32 tmpn = 0; for(i=0; i>searchshift); lo = *tmp; hi = *(tmp+1) + 1; while (lo+1 < hi ) { I32 mid = (lo+hi)>>1; if (lt_f < cf[mid]) { hi = mid; } else { lo = mid; } } return lo; } /* update model */ /* sym symbol that occurred (must be > 8) /* hard-coded definitions for the rangemodels */ #define TBLSHIFT 7 class RangeModel { public: /* initialisation of model */ /* n number of symbols in that model */ /* init array of int's to be used for initialisation (NULL ok) */ /* compress set to 1 on compression, 0 on decompression */ /* targetrescale desired rescaling interval, should be < 1<<(lg_totf+1) */ /* lg_totf base2 log of total frequency count */ RangeModel(U32 n, BOOL compress, I32 targetrescale=2000, I32 lg_totf=14); /* deletion of qsmodel */ ~RangeModel(); /* reinitialisation of qsmodel */ /* init array to be used for initialisation (NULL ok) */ void init(U32 *table); /* retrieval of estimated frequencies for a symbol */ /* sym symbol for which data is desired; must be